Completed
Pull Request — experimental/sf (#3416)
by
unknown
54:55
created

PointProcessor::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

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