Failed Conditions
Pull Request — experimental/sf (#3416)
by
unknown
329:25 queued 320:39
created

PointProcessor::rollback()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10

Duplication

Lines 10
Ratio 100 %

Code Coverage

Tests 4
CRAP Score 2.032

Importance

Changes 0
Metric Value
cc 2
nc 2
nop 2
dl 10
loc 10
ccs 4
cts 5
cp 0.8
crap 2.032
rs 9.9332
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\PurchaseFlow\Processor;
15
16
use Doctrine\ORM\EntityManagerInterface;
17
use Eccube\Entity\BaseInfo;
18
use Eccube\Entity\ItemHolderInterface;
19
use Eccube\Entity\ItemInterface;
20
use Eccube\Entity\Master\OrderItemType;
21
use Eccube\Entity\Master\TaxDisplayType;
22
use Eccube\Entity\Master\TaxType;
23
use Eccube\Entity\Order;
24
use Eccube\Entity\OrderItem;
25
use Eccube\Service\PurchaseFlow\ItemHolderPreprocessor;
26
use Eccube\Service\PurchaseFlow\ItemHolderValidator;
27
use Eccube\Service\PurchaseFlow\PurchaseContext;
28
use Eccube\Service\PurchaseFlow\PurchaseProcessor;
29
30
/**
31
 * 購入フローにおけるポイント処理.
32
 */
33
class PointProcessor extends ItemHolderValidator implements ItemHolderPreprocessor, PurchaseProcessor
34
{
35
    /**
36
     * @var EntityManagerInterface
37
     */
38
    protected $entityManager;
39
40
    /**
41
     * @var BaseInfo
42
     */
43
    protected $BaseInfo;
44
45
    /**
46
     * AddPointProcessor constructor.
47
     *
48
     * @param EntityManagerInterface $entityManager
49
     * @param BaseInfo $BaseInfo
0 ignored issues
show
introduced by
Expected 15 spaces after parameter type; 1 found
Loading history...
50
     */
51 789
    public function __construct(EntityManagerInterface $entityManager, BaseInfo $BaseInfo)
52
    {
53 789
        $this->entityManager = $entityManager;
54 789
        $this->BaseInfo = $BaseInfo;
55
    }
56
57
    /*
58
     * ItemHolderPreprocessor
59
     */
60
61
    /**
62
     * {@inheritdoc}
63
     */
64 231
    public function process(ItemHolderInterface $itemHolder, PurchaseContext $context)
65
    {
66 231
        if (!$this->supports($itemHolder)) {
67 17
            return;
68
        }
69
70 214
        $this->removePointDiscountItem($itemHolder);
71
72
        // 利用ポイントがある場合は割引明細を追加
73 214
        if ($itemHolder->getUsePoint() > 0) {
74 17
            $discount = $this->pointToPrice($itemHolder->getUsePoint());
75 17
            $this->addPointDiscountItem($itemHolder, $discount);
76
        }
77
78
        // 付与ポイントを計算
79 214
        $addPoint = $this->calculateAddPoint($itemHolder);
80 214
        $itemHolder->setAddPoint($addPoint);
81
    }
82
83
    /*
84
     * ItemHolderValidator
85
     */
86
87
    /**
88
     * {@inheritdoc}
89
     */
90 61
    protected function validate(ItemHolderInterface $itemHolder, PurchaseContext $context)
91
    {
92 61
        if (!$this->supports($itemHolder)) {
93 17
            return;
94
        }
95
96
        // 所有ポイント < 利用ポイント
97 44
        $Customer = $itemHolder->getCustomer();
98 44
        if ($Customer->getPoint() < $itemHolder->getUsePoint()) {
99
            // 利用ポイントが所有ポイントを上回っていた場合は所有ポイントで上書き
100 2
            $itemHolder->setUsePoint($Customer->getPoint());
101 2
            $this->throwInvalidItemException('利用ポイントが所有ポイントを上回っています.');
102
        }
103
104
        // 支払い金額 < 利用ポイント
105 42
        if ($itemHolder->getTotal() < 0) {
106
            // 利用ポイントが支払い金額を上回っていた場合は支払い金額が0円以上となるようにポイントを調整
107 1
            $overPoint = floor($itemHolder->getTotal() / $this->BaseInfo->getPointConversionRate());
108 1
            $itemHolder->setUsePoint($itemHolder->getUsePoint() + $overPoint);
109 1
            $this->throwInvalidItemException('利用ポイントがお支払い金額を上回っています.');
110
        }
111
    }
112
113
    /*
114
     * PurchaseProcessor
115
     */
116
117
    /**
118
     * {@inheritdoc}
119
     */
120 12 View Code Duplication
    public function prepare(ItemHolderInterface $itemHolder, PurchaseContext $context)
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...
introduced by
Declare public methods first, then protected ones and finally private ones
Loading history...
121
    {
122 12
        if (!$this->supports($itemHolder)) {
123 3
            return;
124
        }
125
126
        // ユーザの保有ポイントを減算
127 9
        $Customer = $itemHolder->getCustomer();
128 9
        $Customer->setPoint($Customer->getPoint() - $itemHolder->getUsePoint());
129
    }
130
131
    /**
0 ignored issues
show
introduced by
Doc comment for parameter "$target" missing
Loading history...
introduced by
Doc comment for parameter "$context" missing
Loading history...
132
     * {@inheritdoc
133
     */
134
    public function commit(ItemHolderInterface $target, PurchaseContext $context)
135
    {
136
        // 何もしない
137
    }
138
139
    /**
0 ignored issues
show
introduced by
Doc comment for parameter "$itemHolder" missing
Loading history...
introduced by
Doc comment for parameter "$context" missing
Loading history...
140
     * {@inheritdoc
141
     */
142 2 View Code Duplication
    public function rollback(ItemHolderInterface $itemHolder, PurchaseContext $context)
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...
143
    {
144
        // 利用したポイントをユーザに戻す.
145 2
        if (!$this->supports($itemHolder)) {
146
            return;
147
        }
148
149 2
        $Customer = $itemHolder->getCustomer();
150 2
        $Customer->setPoint($Customer->getPoint() + $itemHolder->getUsePoint());
151
    }
152
153
    /*
154
     * Helper methods
155
     */
156
157
    /**
158
     * Processorが実行出来るかどうかを返す.
159
     *
160
     * 以下を満たす場合に実行できる.
161
     *
162
     * - ポイント設定が有効であること.
163
     * - $itemHolderがOrderエンティティであること.
164
     * - 会員のOrderであること.
165
     *
166
     * @param ItemHolderInterface $itemHolder
167
     *
168
     * @return bool
169
     */
170 238
    private function supports(ItemHolderInterface $itemHolder)
171
    {
172 238
        if (!$this->BaseInfo->isOptionPoint()) {
173
            return false;
174
        }
175
176 238
        if (!$itemHolder instanceof Order) {
177
            return false;
178
        }
179
180 238
        if (!$itemHolder->getCustomer()) {
181 17
            return false;
182
        }
183
184 221
        return true;
185
    }
186
187
    /**
188
     * 付与ポイントを計算.
189
     *
190
     * @param ItemHolderInterface $itemHolder
191
     *
192
     * @return int
193
     */
194 214
    private function calculateAddPoint(ItemHolderInterface $itemHolder)
195
    {
196 214
        $basicPointRate = $this->BaseInfo->getBasicPointRate();
197
198
        // 明細ごとのポイントを集計
199 214
        $totalPoint = array_reduce($itemHolder->getItems()->toArray(), function ($carry, ItemInterface $item) use ($basicPointRate) {
200 214
            $pointRate = $item->getPointRate();
201 214
            if ($pointRate === null) {
202 214
                $pointRate = $basicPointRate;
203
            }
204
205
            // TODO: ポイントは税抜き分しか割引されない、ポイント明細は税抜きのままでいいのか?
206 214
            if ($item->isPoint()) {
207 17
                $point = round($item->getPrice() * ($pointRate / 100)) * $item->getQuantity();
208
            } else {
209
                // ポイント = 単価 * ポイント付与率 * 数量
210 213
                $point = round($item->getPriceIncTax() * ($pointRate / 100)) * $item->getQuantity();
211
            }
212
213 214
            return $carry + $point;
214 214
        }, 0);
215
216 214
        return $totalPoint < 0 ? 0 : $totalPoint;
217
    }
218
219
    /**
220
     * 明細追加処理.
221
     *
222
     * @param ItemHolderInterface $itemHolder
223
     * @param $discount
224
     */
225 17
    private function addPointDiscountItem(ItemHolderInterface $itemHolder, $discount)
226
    {
227 17
        $DiscountType = $this->entityManager->find(OrderItemType::class, OrderItemType::POINT);
228 17
        $TaxInclude = $this->entityManager->find(TaxDisplayType::class, TaxDisplayType::INCLUDED);
229 17
        $Taxation = $this->entityManager->find(TaxType::class, TaxType::TAXATION);
230
231 17
        $OrderItem = new OrderItem();
232 17
        $OrderItem->setProductName('ポイント値引')
233 17
            ->setPrice($discount)
234 17
            ->setPriceIncTax($discount)
235 17
            ->setTaxRate(8)
236 17
            ->setQuantity(1)
237 17
            ->setOrderItemType($DiscountType)
238 17
            ->setTaxDisplayType($TaxInclude)
239 17
            ->setTaxType($Taxation)
240 17
            ->setOrder($itemHolder);
241 17
        $itemHolder->addItem($OrderItem);
242
    }
243
244
    /**
245
     * 既存のポイント明細を削除する.
246
     *
247
     * @param ItemHolderInterface $itemHolder
248
     */
249 214
    private function removePointDiscountItem(ItemHolderInterface $itemHolder)
250
    {
251 214
        foreach ($itemHolder->getItems() as $item) {
252 213
            if ($item->isPoint()) {
253
                $itemHolder->removeOrderItem($item);
254 213
                $this->entityManager->remove($item);
255
            }
256
        }
257
    }
258
259
    /**
260
     * ポイントを金額に変換する.
261
     *
262
     * @param $point int ポイント
263
     *
264
     * @return int 金額
265
     */
266 17
    private function pointToPrice($point)
267
    {
268 17
        return intval($point * $this->BaseInfo->getPointConversionRate()) * -1;
269
    }
270
}
271