Failed Conditions
Push — experimental/sf ( 350ddf...26236d )
by chihiro
166:47 queued 159:16
created

OrderStateMachine::commitStock()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 1
dl 0
loc 6
ccs 3
cts 3
cp 1
crap 1
rs 10
c 0
b 0
f 0
1
<?php
2
3
/*
4
 * This file is part of EC-CUBE
5
 *
6
 * Copyright(c) LOCKON CO.,LTD. All Rights Reserved.
7
 *
8
 * http://www.lockon.co.jp/
9
 *
10
 * For the full copyright and license information, please view the LICENSE
11
 * file that was distributed with this source code.
12
 */
13
14
namespace Eccube\Service;
15
16
use Doctrine\ORM\EntityManagerInterface;
17
use Eccube\Entity\Master\OrderStatus;
18
use Eccube\Entity\Order;
19
use Eccube\Entity\Shipping;
20
use Eccube\Repository\Master\OrderStatusRepository;
21
use Eccube\Service\PurchaseFlow\Processor\PointProcessor;
22
use Eccube\Service\PurchaseFlow\Processor\StockReduceProcessor;
23
use Eccube\Service\PurchaseFlow\PurchaseContext;
24
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
25
use Symfony\Component\Workflow\Event\Event;
26
use Symfony\Component\Workflow\Event\GuardEvent;
27
use Symfony\Component\Workflow\StateMachine;
28
29
class OrderStateMachine implements EventSubscriberInterface
0 ignored issues
show
introduced by
Missing class doc comment
Loading history...
30
{
31
    /**
32
     * @var StateMachine
33
     */
34
    private $machine;
35
36
    /**
37
     * @var OrderStatusRepository
38
     */
39
    private $orderStatusRepository;
40
41
    /**
42
     * @var PointProcessor
43
     */
44
    private $pointProcessor;
45
    /**
46
     * @var StockReduceProcessor
47
     */
48
    private $stockReduceProcessor;
49
50
    /**
51
     * @var EntityManagerInterface
52
     */
53
    private $entityManager;
54
55 108
    public function __construct(StateMachine $_orderStateMachine, OrderStatusRepository $orderStatusRepository, PointProcessor $pointProcessor, StockReduceProcessor $stockReduceProcessor, EntityManagerInterface $entityManager)
56
    {
57 108
        $this->machine = $_orderStateMachine;
58 108
        $this->orderStatusRepository = $orderStatusRepository;
59 108
        $this->pointProcessor = $pointProcessor;
60 108
        $this->stockReduceProcessor = $stockReduceProcessor;
61 108
        $this->entityManager = $entityManager;
62
    }
63
64
    /**
65
     * 指定ステータスに遷移.
66
     *
67
     * @param Order $Order 受注
0 ignored issues
show
introduced by
Expected 7 spaces after parameter type; 1 found
Loading history...
introduced by
Expected 7 spaces after parameter name; 1 found
Loading history...
68
     * @param OrderStatus $OrderStatus 遷移先ステータス
69
     */
70 10
    public function apply(Order $Order, OrderStatus $OrderStatus)
71
    {
72 10
        $transition = $this->getTransition($Order, $OrderStatus);
73 10
        if ($transition) {
74 10
            $this->machine->apply($Order, $transition->getName());
75
        } else {
76
            throw new \InvalidArgumentException();
77
        }
78
    }
79
80
    /**
81
     * 指定ステータスに遷移できるかどうかを判定.
82
     *
83
     * @param Order $Order 受注
0 ignored issues
show
introduced by
Expected 7 spaces after parameter type; 1 found
Loading history...
introduced by
Expected 7 spaces after parameter name; 1 found
Loading history...
84
     * @param OrderStatus $OrderStatus 遷移先ステータス
85
     *
86
     * @return boolean 指定ステータスに遷移できる場合はtrue
87
     */
88 43
    public function can(Order $Order, OrderStatus $OrderStatus)
89
    {
90 43
        return !is_null($this->getTransition($Order, $OrderStatus));
91
    }
92
93 49
    private function getTransition(Order $Order, OrderStatus $OrderStatus)
94
    {
95 49
        $transitions = $this->machine->getEnabledTransitions($Order);
96 49
        foreach ($transitions as $t) {
97 47
            if (in_array($OrderStatus->getId(), $t->getTos())) {
98 47
                return $t;
99
            }
100
        }
101
102 27
        return null;
103
    }
104
105
    /**
106
     * {@inheritdoc}
107
     */
108 1
    public static function getSubscribedEvents()
0 ignored issues
show
introduced by
Declare public methods first, then protected ones and finally private ones
Loading history...
109
    {
110
        return [
111 1
            'workflow.order.completed' => ['onCompleted'],
112
            'workflow.order.transition.pay' => ['updatePaymentDate'],
113
            'workflow.order.transition.cancel' => [['rollbackStock'], ['rollbackUsePoint']],
114
            'workflow.order.transition.back_to_in_progress' => [['commitStock'], ['commitUsePoint']],
115
            'workflow.order.transition.ship' => ['commitAddPoint'],
116
            'workflow.order.transition.return' => [['rollbackUsePoint'], ['rollbackAddPoint']],
117
            'workflow.order.transition.cancel_return' => [['commitUsePoint'], ['commitAddPoint']],
118
            'workflow.order.guard.ship' => ['guardShip'],
119
        ];
120
    }
121
122
    /*
123
     * Event handlers.
124
     */
125
126
    /**
127
     * 購入日を更新する.
128
     *
129
     * @param Event $event
130
     */
131 2
    public function updatePaymentDate(Event $event)
132
    {
133
        /* @var Order $Order */
134 2
        $Order = $event->getSubject();
135 2
        $Order->setPaymentDate(new \DateTime());
136
    }
137
138
    /**
139
     * 会員の保有ポイントを減らす.
140
     *
141
     * @param Event $event
142
     *
143
     * @throws PurchaseFlow\PurchaseException
144
     */
145 2
    public function commitUsePoint(Event $event)
146
    {
147
        /* @var Order $Order */
148 2
        $Order = $event->getSubject();
149 2
        $this->pointProcessor->prepare($Order, new PurchaseContext());
150
    }
151
152
    /**
153
     * 利用ポイントを会員に戻す.
154
     *
155
     * @param Event $event
156
     */
157 2
    public function rollbackUsePoint(Event $event)
158
    {
159
        /* @var Order $Order */
160 2
        $Order = $event->getSubject();
161 2
        $this->pointProcessor->rollback($Order, new PurchaseContext());
162
    }
163
164
    /**
165
     * 在庫を減らす.
166
     *
167
     * @param Event $event
168
     *
169
     * @throws PurchaseFlow\PurchaseException
170
     */
171 1
    public function commitStock(Event $event)
172
    {
173
        /* @var Order $Order */
174 1
        $Order = $event->getSubject();
175 1
        $this->stockReduceProcessor->prepare($Order, new PurchaseContext());
176
    }
177
178
    /**
179
     * 在庫を戻す.
180
     *
181
     * @param Event $event
182
     */
183 1
    public function rollbackStock(Event $event)
184
    {
185
        /* @var Order $Order */
186 1
        $Order = $event->getSubject();
187 1
        $this->stockReduceProcessor->rollback($Order, new PurchaseContext());
188
    }
189
190
    /**
191
     * 会員に加算ポイントを付与する.
192
     *
193
     * @param Event $event
194
     */
195 5 View Code Duplication
    public function commitAddPoint(Event $event)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
196
    {
197
        /* @var Order $Order */
198 5
        $Order = $event->getSubject();
199 5
        $Customer = $Order->getCustomer();
200 5
        if ($Customer) {
201 5
            $Customer->setPoint(intval($Customer->getPoint()) + intval($Order->getAddPoint()));
202
        }
203
    }
204
205
    /**
206
     * 会員に付与した加算ポイントを取り消す.
207
     *
208
     * @param Event $event
209
     */
210 1 View Code Duplication
    public function rollbackAddPoint(Event $event)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
211
    {
212
        /* @var Order $Order */
213 1
        $Order = $event->getSubject();
214 1
        $Customer = $Order->getCustomer();
215 1
        if ($Customer) {
216 1
            $Customer->setPoint(intval($Customer->getPoint()) - intval($Order->getAddPoint()));
217
        }
218
    }
219
220
    /**
221
     * 受注ステータスを再設定.
222
     * {@link StateMachine}によって遷移が終了したときには{@link Order#OrderStatus}のidが変更されるだけなのでOrderStatusを設定し直す.
223
     *
224
     * @param Event $event
225
     */
226 10
    public function onCompleted(Event $event)
227
    {
228
        /** @var Order $Order */
229 10
        $Order = $event->getSubject();
230 10
        $OrderStatusId = $Order->getOrderStatus()->getId();
231
232
        // XXX このまま EntityManager::flush() をコールすると、 OrderStatus::id が更新されてしまうため元に戻す
233 10
        $TransitionlStatus = $Order->getOrderStatus();
234 10
        $this->entityManager->detach($TransitionlStatus);
235
236 10
        $CompletedOrderStatus = $this->orderStatusRepository->find($OrderStatusId);
237 10
        $Order->setOrderStatus($CompletedOrderStatus);
238
    }
239
240
    /**
241
     * すべての出荷が発送済みなら、受注も発送済みに遷移できる.
242
     *
243
     * @param GuardEvent $event
244
     */
245 27
    public function guardShip(GuardEvent $event)
246
    {
247
        /** @var Order $Order */
248 27
        $Order = $event->getSubject();
249 27
        $UnShipped = $Order->getShippings()->filter(function (Shipping $Shipping) {
250 9
            return $Shipping->getShippingDate() == null;
251 27
        });
252 27
        if (!$UnShipped->isEmpty()) {
253 5
            $event->setBlocked(true);
254
        }
255
    }
256
}
257