Completed
Pull Request — experimental/sf (#3420)
by chihiro
244:13 queued 235:15
created

PointProcessor::addPointDiscountItem()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 16

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 13
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 2
dl 0
loc 16
ccs 13
cts 13
cp 1
crap 1
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 748
    public function __construct(EntityManagerInterface $entityManager, BaseInfo $BaseInfo)
52
    {
53 748
        $this->entityManager = $entityManager;
54 748
        $this->BaseInfo = $BaseInfo;
55
    }
56
57
    /*
58
     * ItemHolderPreprocessor
59
     */
60
61
    /**
62
     * {@inheritdoc}
63
     */
64 210
    public function process(ItemHolderInterface $itemHolder, PurchaseContext $context)
65
    {
66 210
        if (!$this->supports($itemHolder)) {
67 17
            return;
68
        }
69
70
        // 付与ポイントを計算
71 193
        $addPoint = $this->calculateAddPoint($itemHolder);
72 193
        $itemHolder->setAddPoint($addPoint);
73
74
        // 利用ポイントがある場合は割引明細を追加
75 193
        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 221
    private function supports(ItemHolderInterface $itemHolder)
168
    {
169 221
        if (!$this->BaseInfo->isOptionPoint()) {
170
            return false;
171
        }
172
173 221
        if (!$itemHolder instanceof Order) {
174
            return false;
175
        }
176
177 221
        if (!$itemHolder->getCustomer()) {
178 17
            return false;
179
        }
180
181 204
        return true;
182
    }
183
184
    /**
185
     * 付与ポイントを計算.
186
     *
187
     * @param ItemHolderInterface $itemHolder
188
     *
189
     * @return int
190
     */
191 193
    private function calculateAddPoint(ItemHolderInterface $itemHolder)
192
    {
193 193
        $basicPointRate = $this->BaseInfo->getBasicPointRate();
194
195
        // 明細ごとのポイントを集計
196 193
        $totalPoint = array_reduce($itemHolder->getItems()->toArray(), function ($carry, ItemInterface $item) use ($basicPointRate) {
197 192
            $pointRate = $item->getPointRate();
198 192
            if ($pointRate === null) {
199 192
                $pointRate = $basicPointRate;
200
            }
201
202
            // ポイント = 単価 * ポイント付与率 * 数量
203 192
            $point = round($item->getPriceIncTax() * ($pointRate / 100)) * $item->getQuantity();
204
205 192
            return $carry + $point;
206 193
        }, 0);
207
208
        // 利用したポイントの割合に対して付与するポイントを減算
209
        // 明細のポイント合計 - (利用ポイント * ポイント付与率)
210 193
        $totalPoint -= intval($itemHolder->getUsePoint() * $basicPointRate / 100);
211
212 193
        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
            ->setQuantity(1)
231 1
            ->setOrderItemType($DiscountType)
232 1
            ->setTaxDisplayType($TaxInclude)
233 1
            ->setTaxType($Taxation)
234 1
            ->setOrder($itemHolder);
235 1
        $itemHolder->addItem($OrderItem);
236
    }
237
238
    /**
239
     * 既存のポイント明細を削除する.
240
     *
241
     * @param ItemHolderInterface $itemHolder
242
     */
243 1
    private function removePointDiscountItem(ItemHolderInterface $itemHolder)
244
    {
245 1
        foreach ($itemHolder->getItems() as $item) {
246
            if ($item->isDiscount() && $item->getProductName() == 'ポイント値引') {
247
                $itemHolder->removeOrderItem($item);
248
                $this->entityManager->remove($item);
249
            }
250
        }
251
    }
252
253
    /**
254
     * ポイントを金額に変換する.
255
     *
256
     * @param $point int ポイント
257
     *
258
     * @return int 金額
259
     */
260 11
    private function pointToPrice($point)
261
    {
262 11
        return intval($point * $this->BaseInfo->getPointConversionRate()) * -1;
263
    }
264
}
265