Failed Conditions
Push — experimental/sf ( c0fd88...ff71e4 )
by
unknown
269:51 queued 261:57
created

PointProcessor::supports()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 16

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 4.25

Importance

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