[EC-CUBE4] 特定の条件で決済時の手数料を無料にする

EC-CUBE4の決済周り

 通販サイトの運用保守をやっているとしばしば「○○を購入すると今なら手数料が無料」「○○○○円以上お買い上げの方は10%OFF」といったいわゆるキャンペーン的な対応が発生します。

 これまでにEC-CUBE4を使った通販サイトの機能開発をやっていてそういった対応をいろいろな形で行ってきたのですが、今回は代引きを想定して「特定の商品がカートに入っている場合、手数料を無料にする」やり方を紹介します。これは一例でひょっとするともっといいやり方があるかもしれません。実際、他のやり方もあるので「このやり方もいいよ」と言うのがあれば教えてください。

PurchaseFlow https://doc4.ec-cube.net/customize_service#purchaseflow

 EC-CUBE4にはPurchaseFlowというクラスがあります。お届け先の追加・削除だとか商品数量の変更といった通販サイトでよくある基本的な操作に合わせて、PurchaseFlowクラスが動いてカート・お届け先情報に合わせて明細・集計処理を行ってくれるようになっています。どのような流れで行われているかは公式のドキュメントに詳しく解説が載っています。クラスとそれに連なるProcessorがsrc/Eccube/Service/PurchaseFlowにあるのでドキュメントを一通り読み込んだ上で対象のファイルを読む内になんとなく雰囲気が分かるかもしれません。

 今回はPurchaseFlowに含まれる一部のProcessorをカスタマイズして対応します。これもどうやるのが良いかいろいろ調べた結果、今回の手数料周りに限らず明細・集計に関わる処理は基本的にこの枠組の中でやった方が変なことになりにくい気はします。

仕様をイメージする

 実装したい機能としては、特定の商品がカートに入っている場合に、手数料を無料にする。という機能です。金額の集計処理の中で手数料を加算しないという処理が必要なのでPurchaseFlowが制御する各Processorの中から実現しやすい挙動を探します。

 先程のドキュメントに記載されている一連のProcessorの内容を眺めているとItemHolderPreprocessorというProcessorがあります。これは、税額計算や送料の更新など、カートや注文全体の前処理を実行するProcessorです。今回のような無料化・割引処理を行う場合基本的には前処理の段階で判定を確定出来ると思うので、ItemHolderPreprocessorを拡張して対応します。

 EC-CUBE4の場合通常の商品と同様の形式で手数料のデータを持っているので、お届け先ごとの商品情報を確認していく過程で特定の商品が入っていたら手数料を0円とし、集計の本処理の際に加算されないようにする処理を書いたほうが良さそうです。

実装例

 今回カスタマイズ形式で対応するため直下のappフォルダ以下にファイルを設置します。

app/Customize/Service/PurchaseFlow/Processor/DeliveryChargeValidator.php

<?php namespace Customize\Service\PurchaseFlow\Processor; use Eccube\Annotation\ShoppingFlow; use Eccube\Entity\ItemInterface; use Eccube\Service\PurchaseFlow\PurchaseContext; use Eccube\Entity\ItemHolderInterface; use Eccube\Service\PurchaseFlow\ItemHolderPreprocessor; use Eccube\Entity\Order; /** * @ShoppingFlow */ class DeliveryChargeValidator implements ItemHolderPreprocessor { /** * constructor. * */ public function __construct() { } /** * @param ItemHolderInterface $itemHolder * @param PurchaseContext $context * * @throws \Doctrine\ORM\NoResultException */ public function process(ItemHolderInterface $itemHolder, PurchaseContext $context) { // Orderの場合はお届け先ごとに判定する. if ($itemHolder instanceof Order) { /** @var Order $Order */ $Order = $itemHolder; // 手数料無料商品の商品IDをセット $charge_discount_product_id = [1, 2, 3]; /* @var Shipping $Shipping */ foreach ($Order->getShippings() as $Shipping) { $isChargeDiscount = false; foreach ($Shipping->getOrderItems() as $Item) { if($Item->isProduct()) { if(in_array($Item->getProduct()->getId(), $charge_discount_product_id, true)) { $isChargeDiscount = true; } } } if($isChargeDiscount) { foreach ($Order->getItems() as $Item) { if($Item->isCharge()) { $Item->setPrice(0); break; } } } } } } }

 $charge_discount_product_id変数に手数料を無料にする商品のIDをセットしています。その後のforeachの処理ではお届け先ごとに追加されている商品を取得し、追加されている商品が対象の商品の場合はフラグをtrueにしています。

 EC-CUBE4では手数料の情報もお届け先に追加されている商品と同じ形式で管理されています。最後の処理ではフラグがtrueの場合にOrderのエンティティからItemを取ってきて手数料の情報の場合に手数料の金額を直接0円にしています。

 今回のやり方では手数料を直接0円にしていますが、割引のItemを追加して値引きするやり方もあります。どっちが良いのかな・・・というと個人的にはどちらを取っても良いような気がしています。

というわけで

 久しぶりのEC-CUBE4の記事でした。しばらくはまたEC-CUBE4に関する記事を書いていこうかと思うので、このやり方知りたい。というのがもしあったらTwtter等でご連絡ください。(Twitterのリンクは下の著者紹介欄よりどうぞ)