商品情報、注文情報に「のし・ラッピングオプション」を追加するサンプルです。 3.n にて追加された拡張機能を使用して実装します。 以下のカスタマイズを実施します。
- 商品情報に「のし・ラッピング対応」フラグ追加
- 商品詳細に「のし・ラッピング対応」オプション表示
- のし・ラッピング種別マスタ追加(名称・追加料金)
- 注文画面に、のし・ラッピング選択・記載内容フォーム表示
- 注文情報に、のし・ラッピング明細追加
商品情報に、のし・ラッピング対応フラグを追加します。 Entity拡張機構(#2267) を使用します。
<?php
namespace Acme\Entity;
use Doctrine\ORM\Mapping as ORM;
use Eccube\Annotation\EntityExtension;
/**
* @EntityExtension("Eccube\Entity\Product")
*/
trait WrappingOptionTrait
{
/**
* @ORM\Column(name="wrapping_option_flg", type="smallint", options={"unsigned":true,"default":0})
*/
public $wrapping_option_flg;
}
<?php
namespace Acme\Entity;
use Doctrine\ORM\Mapping as ORM;
use Eccube\Annotation as Eccube;
/**
* @Eccube\EntityExtension("Eccube\Entity\Order")
*/
trait OrderWrappingOptionTrait
{
/**
* @var string|null
*
* @ORM\Column(
* name="wrapping_comment", type="string", length=4000, nullable=true
* )
* @Eccube\FormAppend(
* auto_render=true,
* type="\Symfony\Component\Form\Extension\Core\Type\TextAreaType",
* options={
* "required": false,
* "label": "のし・ラッピングの宛名等ご記入ください"
* })
*/
public $wrapping_comment;
/**
* @var \Acme\Entity\Wrapping
*
* @ORM\ManyToOne(targetEntity="Acme\Entity\Wrapping")
* @ORM\JoinColumns({
* @ORM\JoinColumn(name="wrapping_id", referencedColumnName="wrapping_id")
* })
* @Eccube\FormAppend(
* auto_render=true,
* options={
* "label": "のし・ラッピング種別",
* "placeholder": "のし・ラッピング種別を選択してください"
* }
* )
*/
public $Wrapping;
public function isWrappingSupport()
{
foreach ($this->getItems() as $Item) {
if ($Item->getProduct()->wrapping_option_flg == 1) {
return true;
}
}
return false;
}
}
以下のコマンドを実行し、 Trait を反映します。
app/console generate-proxies
ATTENTION 古い Proxy クラスが残っていると誤作動する場合がある. 再生成時にきちんと消した方が良い
のし・ラッピング種別マスタを追加します。名称とオプション金額のフィールドを用意します。
<?php
namespace Acme\Entity;
use Doctrine\Common\Collections\ArrayCollection;
use Eccube\Common\Constant;
use Doctrine\ORM\Mapping as ORM;
/**
* Wrapping
*
* @ORM\Table(name="dtb_wrapping")
* @ORM\InheritanceType("SINGLE_TABLE")
* @ORM\DiscriminatorColumn(name="discriminator_type", type="string", length=255)
* @ORM\HasLifecycleCallbacks()
* @ORM\Entity(repositoryClass="Acme\Repository\WrappingRepository")
*/
class Wrapping extends \Eccube\Entity\AbstractEntity
{
/**
* @var integer
*
* @ORM\Column(name="wrapping_id", type="integer", options={"unsigned":true})
* @ORM\Id
* @ORM\GeneratedValue(strategy="IDENTITY")
*/
public $id;
/**
* @var string
*
* @ORM\Column(name="name", type="string", length=255)
*/
public $name;
/**
* @var string
*
* @ORM\Column(name="option_price", type="decimal", precision=10, scale=0, options={"unsigned":true})
*/
public $option_price;
/**
* @var int
*
* @ORM\Column(name="del_flg", type="smallint", options={"unsigned":true,"default":0})
*/
public $del_flg = 0;
/**
* @var \DateTime
*
* @ORM\Column(name="create_date", type="datetimetz")
*/
public $create_date;
/**
* @var \DateTime
*
* @ORM\Column(name="update_date", type="datetimetz")
*/
public $update_date;
}
以下のコマンドを実行し、 Entity と Repository を生成します。
vendor/bin/doctrine orm:schema-tool:update --force
vendor/bin/doctrine orm:generate-repositories --filter=Wrapping app
注文画面に、のし選択・記載内容フォーム表示を表示します。 エンティティからフォームを生成する機構(#2268, #2321) を使用します。
Shopping/index.twig
に以下の対応が入っていれば、自動的に表示します。
*** src/Eccube/Resource/template/default/Shopping/index.twig.HEAD 2017-07-24 10:39:49.000000000 +0900
--- src/Eccube/Resource/template/default/Shopping/index.twig 2017-07-24 10:39:49.000000000 +0900
***************
*** 340,345 ****
--- 340,356 ----
{% endif %}
{% endfor %}
</div>
+ {# エンティティ拡張の自動出力 #}
+ {% for f in form %}
+ {# auto_render有効時に出力 #}
+ {% if f.vars.eccube_form_options.auto_render %}
+ {# form_themeが設定されている場合にthemeを適用 #}
+ {% if f.vars.eccube_form_options.form_theme %}
+ {% form_theme f f.vars.eccube_form_options.form_theme %}
+ {% endif %}
+ {{ form_row(f) }}
+ {% endif %}
+ {% endfor %}
</div><!-- /.col -->
<div id="confirm_side" class="col-sm-4">
のし・オプション対応商品で絞り込みできるようにします。 QueryBuilderの拡張(#2285, #2298) を使用します。
ここでは簡易的に、 wrapping=1
という URLパラメータで絞り込みできるようにしています。
<?php
namespace Acme\Entity;
use Eccube\Annotation\QueryExtension;
use Eccube\Doctrine\Query\WhereClause;
use Eccube\Doctrine\Query\WhereCustomizer;
use Eccube\Repository\QueryKey;
/**
* @QueryExtension(QueryKey::PRODUCT_SEARCH)
*/
class ProductListCustomizer extends WhereCustomizer
{
/**
* ラッピング対応で絞り込む
*
* @param array $params
* @param string $queryKey
* @return WhereByClause[]
*/
protected function createStatements($params, $queryKey)
{
if (isset($_REQUEST['wrapping'])) { // TODO
return [WhereClause::eq('p.wrapping_option_flg', ':wrapping_option_flg', $_REQUEST['wrapping'])];
}
return [];
}
}
ServiceProvider に以下を追加
$app['eccube.queries']->addCustomizer(new \Acme\Entity\ProductListCustomizer());
ATTENTION 検索パラメータも簡単に渡せるようにしたい
商品詳細にのし・ラッピングオプションを表示するカスタムファンクションを作成します。 Twig のユーザー定義関数(#2263) を使用します。
render_block_twig に以下を定義
{% block wrapping %}
{% if Product.wrapping_option_flg == 1 %}
のし・ラッピング対応
{% endif %}
{% endblock %}
detail.twig で以下のタグが使用可能となる
{{ eccube_block_wrapping({'Product': Product}) }}
- のし説明ページ追加
SensioFrameworkExtraBundle(#2127)
のし・ラッピングオプション付きの場合のみ、選択フォームを表示させる場合は、{% if Order->isSupportWrapping() %}{% endif %}
で囲む必要があります。
このサンプルでは、エンティティからフォームを生成する機構を使用するため割愛します。
注文情報に、のし・ラッピング明細を追加します。 以下のような条件で、明細を追加します。
- のし種別に応じて, 追加料金
- 10000円以上は追加料金無料
eccube.purchase.flow.shopping
に WrappingProcessor
を追加します。
単価集計、支払処理拡張(#2127) を使用します。
$app['eccube.purchase.flow.shopping'] = function () use ($app) {
$flow = new PurchaseFlow();
$flow->addItemProcessor(new StockValidator());
$flow->addItemProcessor(new DisplayStatusValidator());
$flow->addItemHolderProcessor(new PaymentTotalLimitValidator($app['config']['max_total_fee']));
$flow->addItemHolderProcessor(new DeliveryFeeProcessor($app));
$flow->addItemHolderProcessor(new PaymentTotalNegativeValidator());
$flow->addItemHolderProcessor(new \Acme\Service\PurchaseFlow\Processor\WrappingProcessor($app)); // 追加
return $flow;
};
<?php
namespace Acme\Service\PurchaseFlow\Processor;
use Eccube\Entity\ItemHolderInterface;
use Eccube\Entity\Master\OrderItemType;
use Eccube\Entity\Master\TaxDisplayType;
use Eccube\Entity\Master\TaxType;
use Eccube\Entity\Order;
use Acme\Entity\Wrapping;
use Eccube\Entity\ShipmentItem;
use Eccube\Entity\Shipping;
use Eccube\Service\PurchaseFlow\ItemHolderProcessor;
use Eccube\Service\PurchaseFlow\ProcessResult;
use Eccube\Service\PurchaseFlow\PurchaseContext;
/**
* ラッピング明細追加.
*/
class WrappingProcessor implements ItemHolderProcessor
{
private $app;
public function __construct($app)
{
$this->app = $app;
}
/**
* @param ItemHolderInterface $itemHolder
* @param PurchaseContext $context
*
* @return ProcessResult
*/
public function process(ItemHolderInterface $itemHolder, PurchaseContext $context)
{
if ($this->containsWrappingItem($itemHolder) == false) {
$this->addWrappingItem($itemHolder);
}
return ProcessResult::success();
}
protected function addWrappingItem(ItemHolderInterface $itemHolder)
{
// TODO
$TaxInclude = $this->app['orm.em']->getRepository(TaxDisplayType::class)->find(TaxDisplayType::INCLUDED);
$Taxion = $this->app['orm.em']->getRepository(TaxType::class)->find(TaxType::TAXATION);
/** @var Order $Order */
$Order = $itemHolder;
/** @var Wrapping $Wrapping */
$Wrapping = $Order->Wrapping;
if (is_object($Wrapping)) {
if ($Order->getSubtotal() >= 10000) {
$option_price = 0;
} else {
$option_price = $Wrapping->option_price;
// TODO 暫定対応. 明細追加と集計のロジックは分ける
$Order->setCharge($Order->getCharge() + $option_price);
$Order->setTotal($Order->getTotal() + $option_price);
$Order->setPaymentTotal($Order->getPaymentTotal() + $option_price);
}
$ShipmentItem = new ShipmentItem();
$ShipmentItem->setProductName('のし・ラッピングオプション')
->setPrice($option_price)
->setPriceIncTax($option_price)
->setTaxRate(8)
->setQuantity(1)
->setOrder($Order)
->setTaxDisplayType($TaxInclude)
->setTaxType($Taxion);
$itemHolder->addItem($ShipmentItem);
}
}
protected function containsWrappingItem(ItemHolderInterface $itemHolder)
{
foreach ($itemHolder->getItems() as $item) {
if (strpos('のし・ラッピングオプション', $item->getProductName()) !== false) {
return true;
}
return false;
}
}
}
環境
報告
/app/Acme/Entity/Wrapping.php
に__toString()
が必要です。/src/Eccube/Resource/template/default/Shopping/index.twig
の記述を下記のように変更する。dtb_wrapping.discriminator_type列に'wrapping'を登録する必要がある。
OrderWrappingOptionTrait::$wrapping_comment
の@Eccube\FormAppend
のtypeに"\Symfony\Component\Form\Extension\Core\Type\TextAreaType"を指定すると、フロント画面側の会員登録画面でエラーが発生。