src/Eccube/Service/OrderStateMachine.php line 221

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