app/Customize/Service/OrderStateMachine.php line 151

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 Customize\Service;
  13. use DateTime;
  14. use Eccube\Entity\Master\OrderStatus;
  15. use Eccube\Entity\Order;
  16. use Eccube\Repository\Master\OrderStatusRepository;
  17. use Eccube\Service\PurchaseFlow\Processor\PointProcessor;
  18. use Eccube\Service\PurchaseFlow\Processor\StockReduceProcessor;
  19. use Eccube\Service\PurchaseFlow\PurchaseContext;
  20. use Eccube\Service\PurchaseFlow\PurchaseException;
  21. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  22. use Symfony\Component\Workflow\Event\Event;
  23. use Symfony\Component\Workflow\StateMachine;
  24. class OrderStateMachine implements EventSubscriberInterface
  25. {
  26.     /**
  27.      * @var StateMachine
  28.      */
  29.     private $machine;
  30.     /**
  31.      * @var OrderStatusRepository
  32.      */
  33.     private $orderStatusRepository;
  34.     /**
  35.      * @var PointProcessor
  36.      */
  37.     private $pointProcessor;
  38.     /**
  39.      * @var StockReduceProcessor
  40.      */
  41.     private $stockReduceProcessor;
  42.     public function __construct(StateMachine $_orderStateMachineOrderStatusRepository $orderStatusRepositoryPointProcessor $pointProcessorStockReduceProcessor $stockReduceProcessor)
  43.     {
  44.         $this->machine $_orderStateMachine;
  45.         $this->orderStatusRepository $orderStatusRepository;
  46.         $this->pointProcessor $pointProcessor;
  47.         $this->stockReduceProcessor $stockReduceProcessor;
  48.     }
  49.     /**
  50.      * 指定ステータスに遷移.
  51.      *
  52.      * @param Order $Order 受注
  53.      * @param OrderStatus $OrderStatus 遷移先ステータス
  54.      */
  55.     public function apply(Order $OrderOrderStatus $OrderStatus)
  56.     {
  57.         $context $this->newContext($Order);
  58.         $transition $this->getTransition($context$OrderStatus);
  59.         if ($transition) {
  60.             $this->machine->apply($context$transition->getName());
  61.         } else {
  62.             throw new \InvalidArgumentException();
  63.         }
  64.     }
  65.     /**
  66.      * 指定ステータスに遷移できるかどうかを判定.
  67.      *
  68.      * @param Order $Order 受注
  69.      * @param OrderStatus $OrderStatus 遷移先ステータス
  70.      *
  71.      * @return boolean 指定ステータスに遷移できる場合はtrue
  72.      */
  73.     public function can(Order $OrderOrderStatus $OrderStatus)
  74.     {
  75.         return !is_null($this->getTransition($this->newContext($Order), $OrderStatus));
  76.     }
  77.     private function getTransition(OrderStateMachineContext $contextOrderStatus $OrderStatus)
  78.     {
  79.         $transitions $this->machine->getEnabledTransitions($context);
  80.         foreach ($transitions as $t) {
  81.             if (in_array($OrderStatus->getId(), $t->getTos())) {
  82.                 return $t;
  83.             }
  84.         }
  85.         return null;
  86.     }
  87.     /**
  88.      * {@inheritdoc}
  89.      */
  90.     public static function getSubscribedEvents()
  91.     {
  92.         return [
  93.             'workflow.order.completed' => ['onCompleted'],
  94.             'workflow.order.transition.cancel' => [['rollbackStock'], ['rollbackUsePoint']],
  95.             'workflow.order.transition.back_to_in_progress' => [['commitStock'], ['commitUsePoint']],
  96.             'workflow.order.transition.back_to_new' => [['commitStock'], ['commitUsePoint']],
  97.             'workflow.order.transition.back_to_plan_order' => [['commitStock'], ['commitUsePoint']],
  98.             'workflow.order.transition.ship' => [['commitAddPoint']],
  99.             'workflow.order.transition.return' => [['rollbackUsePoint'], ['rollbackAddPoint']],
  100.             'workflow.order.transition.cancel_return' => [['commitUsePoint'], ['commitAddPoint']],
  101.         ];
  102.     }
  103.     /*
  104.      * Event handlers.
  105.      */
  106.     /**
  107.      * 入金日を更新する.
  108.      *
  109.      * @param Event $event
  110.      */
  111.     public function updatePaymentDate(Event $event)
  112.     {
  113.         /* @var Order $Order */
  114.         $Order $event->getSubject()->getOrder();
  115.         $Order->setPaymentDate(new \DateTime());
  116.     }
  117.     /**
  118.      * 会員の保有ポイントを減らす.
  119.      *
  120.      * @param Event $event
  121.      *
  122.      * @throws PurchaseException
  123.      */
  124.     public function commitUsePoint(Event $event)
  125.     {
  126.         /* @var Order $Order */
  127.         $Order $event->getSubject()->getOrder();
  128.         $this->pointProcessor->prepare($Order, new PurchaseContext());
  129.     }
  130.     /**
  131.      * 利用ポイントを会員に戻す.
  132.      *
  133.      * @param Event $event
  134.      */
  135.     public function rollbackUsePoint(Event $event)
  136.     {
  137.         /* @var Order $Order */
  138.         $Order $event->getSubject()->getOrder();
  139.         $this->pointProcessor->rollback($Order, new PurchaseContext());
  140.     }
  141.     /**
  142.      * 在庫を減らす.
  143.      *
  144.      * @param Event $event
  145.      *
  146.      * @throws PurchaseException
  147.      */
  148.     public function commitStock(Event $event)
  149.     {
  150.         /* @var Order $Order */
  151.         $Order $event->getSubject()->getOrder();
  152.         $this->stockReduceProcessor->prepare($Order, new PurchaseContext());
  153.     }
  154.     /**
  155.      * 在庫を戻す.
  156.      *
  157.      * @param Event $event
  158.      */
  159.     public function rollbackStock(Event $event)
  160.     {
  161.         /* @var Order $Order */
  162.         $Order $event->getSubject()->getOrder();
  163.         $this->stockReduceProcessor->rollback($Order, new PurchaseContext());
  164.     }
  165.     /**
  166.      * 会員に加算ポイントを付与する.
  167.      *
  168.      * @param Event $event
  169.      */
  170.     public function commitAddPoint(Event $event)
  171.     {
  172.         /* @var Order $Order */
  173.         $Order $event->getSubject()->getOrder();
  174.         $Customer $Order->getCustomer();
  175.         if ($Customer) {
  176.             // ポイント有効期限
  177.             $expire_date = new DateTime();
  178.             $expire_date->modify('+1 year')->setTime(23,59,59)->format('Y-m-d H:i:s');
  179.             $Customer
  180.                 ->setPoint(intval($Customer->getPoint()) + intval($Order->getAddPoint()))
  181.                 ->setPointExpireDate($expire_date);
  182.         }
  183.     }
  184.     /**
  185.      * 会員に付与した加算ポイントを取り消す.
  186.      *
  187.      * @param Event $event
  188.      */
  189.     public function rollbackAddPoint(Event $event)
  190.     {
  191.         /* @var Order $Order */
  192.         $Order $event->getSubject()->getOrder();
  193.         $Customer $Order->getCustomer();
  194.         if ($Customer) {
  195.             // TODO: rollback場合のポイント有効期限
  196.             $Customer->setPoint(intval($Customer->getPoint()) - intval($Order->getAddPoint()));
  197.         }
  198.     }
  199.     /**
  200.      * 受注ステータスを再設定.
  201.      * {@link StateMachine}によって遷移が終了したときには{@link Order#OrderStatus}のidが変更されるだけなのでOrderStatusを設定し直す.
  202.      *
  203.      * @param Event $event
  204.      */
  205.     public function onCompleted(Event $event)
  206.     {
  207.         /** @var $context OrderStateMachineContext */
  208.         $context $event->getSubject();
  209.         $Order $context->getOrder();
  210.         $CompletedOrderStatus $this->orderStatusRepository->find($context->getStatus());
  211.         $Order->setOrderStatus($CompletedOrderStatus);
  212.     }
  213.     private function newContext(Order $Order)
  214.     {
  215.         return new OrderStateMachineContext((string) $Order->getOrderStatus()->getId(), $Order);
  216.     }
  217. }
  218. class OrderStateMachineContext
  219. {
  220.     /** @var string */
  221.     private $status;
  222.     /** @var Order */
  223.     private $Order;
  224.     /**
  225.      * OrderStateMachineContext constructor.
  226.      *
  227.      * @param string $status
  228.      * @param Order $Order
  229.      */
  230.     public function __construct($statusOrder $Order)
  231.     {
  232.         $this->status $status;
  233.         $this->Order $Order;
  234.     }
  235.     /**
  236.      * @return string
  237.      */
  238.     public function getStatus()
  239.     {
  240.         return $this->status;
  241.     }
  242.     /**
  243.      * @param string $status
  244.      */
  245.     public function setStatus($status)
  246.     {
  247.         $this->status $status;
  248.     }
  249.     /**
  250.      * @return Order
  251.      */
  252.     public function getOrder()
  253.     {
  254.         return $this->Order;
  255.     }
  256.     // order_state_machine.php の marking_store => property は、デフォルト値である marking を使用するよう強く推奨されている.
  257.     // EC-CUBE4.1 までは status を指定していたが、 Symfony5 よりエラーになるためエイリアスを作成して対応する.
  258.     /**
  259.      * Alias of getStatus()
  260.      */
  261.     public function getMarking(): string
  262.     {
  263.         return $this->getStatus();
  264.     }
  265.     /**
  266.      * Alias of setStatus()
  267.      */
  268.     public function setMarking(string $status): void
  269.     {
  270.         $this->setStatus($status);
  271.     }
  272. }