src/Eccube/Service/OrderStateMachine.php line 267

Open in your IDE?
  1. <?php
  2. /*
  3.  * This file is part of EC-CUBE
  4.  *
  5.  * Copyright(c) EC-CUBE CO.,LTD. All Rights Reserved.
  6.  *
  7.  * http://www.ec-cube.co.jp/
  8.  *
  9.  * For the full copyright and license information, please view the LICENSE
  10.  * file that was distributed with this source code.
  11.  */
  12. namespace Eccube\Service;
  13. use Eccube\Entity\Master\OrderStatus;
  14. use Eccube\Entity\Order;
  15. use Eccube\Repository\Master\OrderStatusRepository;
  16. use Eccube\Service\PurchaseFlow\Processor\PointProcessor;
  17. use Eccube\Service\PurchaseFlow\Processor\StockReduceProcessor;
  18. use Eccube\Service\PurchaseFlow\PurchaseContext;
  19. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  20. use Symfony\Component\Workflow\Event\Event;
  21. use Symfony\Component\Workflow\StateMachine;
  22. class OrderStateMachine implements EventSubscriberInterface
  23. {
  24.     /**
  25.      * @var StateMachine
  26.      */
  27.     private $machine;
  28.     /**
  29.      * @var OrderStatusRepository
  30.      */
  31.     private $orderStatusRepository;
  32.     /**
  33.      * @var PointProcessor
  34.      */
  35.     private $pointProcessor;
  36.     /**
  37.      * @var StockReduceProcessor
  38.      */
  39.     private $stockReduceProcessor;
  40.     public function __construct(StateMachine $_orderStateMachineOrderStatusRepository $orderStatusRepositoryPointProcessor $pointProcessorStockReduceProcessor $stockReduceProcessor)
  41.     {
  42.         $this->machine $_orderStateMachine;
  43.         $this->orderStatusRepository $orderStatusRepository;
  44.         $this->pointProcessor $pointProcessor;
  45.         $this->stockReduceProcessor $stockReduceProcessor;
  46.     }
  47.     /**
  48.      * 指定ステータスに遷移.
  49.      *
  50.      * @param Order $Order 受注
  51.      * @param OrderStatus $OrderStatus 遷移先ステータス
  52.      */
  53.     public function apply(Order $OrderOrderStatus $OrderStatus)
  54.     {
  55.         $context $this->newContext($Order);
  56.         $transition $this->getTransition($context$OrderStatus);
  57.         if ($transition) {
  58.             $this->machine->apply($context$transition->getName());
  59.         } else {
  60.             throw new \InvalidArgumentException();
  61.         }
  62.     }
  63.     /**
  64.      * 指定ステータスに遷移できるかどうかを判定.
  65.      *
  66.      * @param Order $Order 受注
  67.      * @param OrderStatus $OrderStatus 遷移先ステータス
  68.      *
  69.      * @return boolean 指定ステータスに遷移できる場合はtrue
  70.      */
  71.     public function can(Order $OrderOrderStatus $OrderStatus)
  72.     {
  73.         return !is_null($this->getTransition($this->newContext($Order), $OrderStatus));
  74.     }
  75.     private function getTransition(OrderStateMachineContext $contextOrderStatus $OrderStatus)
  76.     {
  77.         $transitions $this->machine->getEnabledTransitions($context);
  78.         foreach ($transitions as $t) {
  79.             if (in_array($OrderStatus->getId(), $t->getTos())) {
  80.                 return $t;
  81.             }
  82.         }
  83.         return null;
  84.     }
  85.     /**
  86.      * {@inheritdoc}
  87.      */
  88.     public static function getSubscribedEvents()
  89.     {
  90.         return [
  91.             // 受注ステータスワークフローイベント定義
  92.             'workflow.order.completed' => ['onCompleted'],
  93.             // 入金処理時:入金日更新
  94.             'workflow.order.transition.to_paid' => ['updatePaymentDate'],
  95.             // キャンセル処理(在庫戻し & 使用/加算ポイント取り消し)
  96.             'workflow.order.transition.cancel' => [
  97.                 ['rollbackStock'],
  98.                 ['rollbackUsePoint'],
  99.                 ['rollbackAddPoint'],
  100.             ],
  101.             // 返品 → 対応中:在庫確保と使用ポイント再付与
  102.             'workflow.order.transition.return_to_in_progress' => [
  103.                 ['commitStock'],
  104.                 ['commitUsePoint'],
  105.             ],
  106.             // 発送済み → 受取済み(ポイント加算)
  107.             'workflow.order.transition.to_received' => [
  108.                 ['commitAddPoint'],
  109.             ],
  110.             // 再発送 → 再発送受取済み(ポイント加算)
  111.             'workflow.order.transition.resend_received' => [
  112.                 ['commitAddPoint'],
  113.             ],
  114.             // 受取済み → 返品(ポイント減算)
  115.             'workflow.order.transition.to_returned' => [
  116.                 ['rollbackUsePoint'],
  117.                 ['rollbackAddPoint'],
  118.             ],
  119.             // 再発送受取済み → 返品(ポイント減算)
  120.             'workflow.order.transition.resend_received_to_returned' => [
  121.                 ['rollbackUsePoint'],
  122.                 ['rollbackAddPoint'],
  123.             ],
  124.             /*
  125.             'workflow.order.completed' => ['onCompleted'],
  126.             'workflow.order.transition.pay' => ['updatePaymentDate'],
  127.             'workflow.order.transition.cancel' => [['rollbackStock'], ['rollbackUsePoint']],
  128.             'workflow.order.transition.back_to_in_progress' => [['commitStock'], ['commitUsePoint']],
  129.             'workflow.order.transition.receive' => [['commitAddPoint']],
  130.             //'workflow.order.transition.ship' => [['commitAddPoint']],
  131.             'workflow.order.transition.return' => [['rollbackUsePoint'], ['rollbackAddPoint']],
  132.             'workflow.order.transition.cancel_return' => [['commitUsePoint'], ['commitAddPoint']],
  133.             */
  134.         ];
  135.     }
  136.     /*
  137.      * Event handlers.
  138.      */
  139.     /**
  140.      * 入金日を更新する.
  141.      *
  142.      * @param Event $event
  143.      */
  144.     public function updatePaymentDate(Event $event)
  145.     {
  146.         /* @var Order $Order */
  147.         $Order $event->getSubject()->getOrder();
  148.         $Order->setPaymentDate(new \DateTime());
  149.     }
  150.     /**
  151.      * 会員の保有ポイントを減らす.
  152.      *
  153.      * @param Event $event
  154.      *
  155.      * @throws PurchaseFlow\PurchaseException
  156.      */
  157.     public function commitUsePoint(Event $event)
  158.     {
  159.         log_info("ポイント減算開始");
  160.         /* @var Order $Order */
  161.         $Order $event->getSubject()->getOrder();
  162.         $this->pointProcessor->prepare($Order, new PurchaseContext());
  163.         log_info("ポイント減算終了");
  164.     }
  165.     /**
  166.      * 利用ポイントを会員に戻す.
  167.      *
  168.      * @param Event $event
  169.      */
  170.     public function rollbackUsePoint(Event $event)
  171.     {
  172.         /* @var Order $Order */
  173.         $Order $event->getSubject()->getOrder();
  174.         $Customer $Order->getCustomer();
  175.         $this->pointProcessor->rollback($Order, new PurchaseContext());
  176.     }
  177.     /**
  178.      * 在庫を減らす.
  179.      *
  180.      * @param Event $event
  181.      *
  182.      * @throws PurchaseFlow\PurchaseException
  183.      */
  184.     public function commitStock(Event $event)
  185.     {
  186.         /* @var Order $Order */
  187.         $Order $event->getSubject()->getOrder();
  188.         $this->stockReduceProcessor->prepare($Order, new PurchaseContext());
  189.     }
  190.     /**
  191.      * 在庫を戻す.
  192.      *
  193.      * @param Event $event
  194.      */
  195.     public function rollbackStock(Event $event)
  196.     {
  197.         /* @var Order $Order */
  198.         $Order $event->getSubject()->getOrder();
  199.         $this->stockReduceProcessor->rollback($Order, new PurchaseContext());
  200.     }
  201.     /**
  202.      * 会員に加算ポイントを付与する.
  203.      *
  204.      * @param Event $event
  205.      */
  206.     public function commitAddPoint(Event $event)
  207.     {
  208.         /* @var Order $Order */
  209.         $Order $event->getSubject()->getOrder();
  210.         $Customer $Order->getCustomer();
  211.         if ($Customer) {
  212.             $Customer->setPoint(intval($Customer->getPoint()) + intval($Order->getAddPoint()));
  213.         }
  214.     }
  215.     /**
  216.      * 会員に付与した加算ポイントを取り消す.
  217.      *
  218.      * @param Event $event
  219.      */
  220.     public function rollbackAddPoint(Event $event)
  221.     {
  222.         /* @var Order $Order */
  223.         $Order $event->getSubject()->getOrder();
  224.         $Customer $Order->getCustomer();
  225.         if ($Customer) {
  226.             $Customer->setPoint(intval($Customer->getPoint()) - intval($Order->getAddPoint()));
  227.         }
  228.     }
  229.     /**
  230.      * 受注ステータスを再設定.
  231.      * {@link StateMachine}によって遷移が終了したときには{@link Order#OrderStatus}のidが変更されるだけなのでOrderStatusを設定し直す.
  232.      *
  233.      * @param Event $event
  234.      */
  235.     public function onCompleted(Event $event)
  236.     {
  237.         /** @var $context OrderStateMachineContext */
  238.         $context $event->getSubject();
  239.         $Order $context->getOrder();
  240.         $CompletedOrderStatus $this->orderStatusRepository->find($context->getStatus());
  241.         $Order->setOrderStatus($CompletedOrderStatus);
  242.     }
  243.     private function newContext(Order $Order)
  244.     {
  245.         return new OrderStateMachineContext((string) $Order->getOrderStatus()->getId(), $Order);
  246.     }
  247. }
  248. class OrderStateMachineContext
  249. {
  250.     /** @var string */
  251.     private $status;
  252.     /** @var Order */
  253.     private $Order;
  254.     /**
  255.      * OrderStateMachineContext constructor.
  256.      *
  257.      * @param string $status
  258.      * @param Order $Order
  259.      */
  260.     public function __construct($statusOrder $Order)
  261.     {
  262.         $this->status $status;
  263.         $this->Order $Order;
  264.     }
  265.     /**
  266.      * @return string
  267.      */
  268.     public function getStatus()
  269.     {
  270.         return $this->status;
  271.     }
  272.     /**
  273.      * @param string $status
  274.      */
  275.     public function setStatus($status)
  276.     {
  277.         $this->status $status;
  278.     }
  279.     /**
  280.      * @return Order
  281.      */
  282.     public function getOrder()
  283.     {
  284.         return $this->Order;
  285.     }
  286.     // order_state_machine.php の marking_store => property は、デフォルト値である marking を使用するよう強く推奨されている.
  287.     // EC-CUBE4.1 までは status を指定していたが、 Symfony5 よりエラーになるためエイリアスを作成して対応する.
  288.     /**
  289.      * Alias of getStatus()
  290.      */
  291.     public function getMarking(): string
  292.     {
  293.         return $this->getStatus();
  294.     }
  295.     /**
  296.      * Alias of setStatus()
  297.      */
  298.     public function setMarking(string $status): void
  299.     {
  300.         $this->setStatus($status);
  301.     }
  302. }