Completed
Push — experimental/sf ( 62d5bb...ebcb49 )
by Ryo
935:43 queued 928:36
created

PointProcessor::rollback()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9

Duplication

Lines 9
Ratio 100 %

Code Coverage

Tests 4
CRAP Score 2.032

Importance

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