Completed
Push — 4.0 ( 1398d6...6044ef )
by Kiyotaka
05:20 queued 12s
created

OrderHelper::setDefaultPayment()   B

Complexity

Conditions 7
Paths 6

Size

Total Lines 40

Duplication

Lines 9
Ratio 22.5 %

Code Coverage

Tests 0
CRAP Score 56

Importance

Changes 0
Metric Value
cc 7
nc 6
nop 1
dl 9
loc 40
ccs 0
cts 0
cp 0
crap 56
rs 8.3466
c 0
b 0
f 0
1
<?php
2
3
/*
4
 * This file is part of EC-CUBE
5
 *
6
 * Copyright(c) EC-CUBE CO.,LTD. All Rights Reserved.
7
 *
8
 * http://www.ec-cube.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;
15
16
use Doctrine\Common\Collections\ArrayCollection;
17
use Doctrine\Common\Collections\Collection;
18
use Doctrine\ORM\EntityManagerInterface;
19
use Eccube\Entity\Cart;
20
use Eccube\Entity\CartItem;
21
use Eccube\Entity\Customer;
22
use Eccube\Entity\Master\DeviceType;
23
use Eccube\Entity\Master\OrderItemType;
24
use Eccube\Entity\Master\OrderStatus;
25
use Eccube\Entity\Order;
26
use Eccube\Entity\OrderItem;
27
use Eccube\Entity\Payment;
28
use Eccube\Entity\Shipping;
29
use Eccube\EventListener\SecurityListener;
30
use Eccube\Repository\DeliveryRepository;
31
use Eccube\Repository\Master\DeviceTypeRepository;
32
use Eccube\Repository\Master\OrderItemTypeRepository;
33
use Eccube\Repository\Master\OrderStatusRepository;
34
use Eccube\Repository\Master\PrefRepository;
35
use Eccube\Repository\OrderRepository;
36
use Eccube\Repository\PaymentRepository;
37
use Eccube\Util\StringUtil;
38
use SunCat\MobileDetectBundle\DeviceDetector\MobileDetector;
39
use Symfony\Bundle\FrameworkBundle\Controller\ControllerTrait;
40
use Symfony\Component\DependencyInjection\ContainerInterface;
41
use Symfony\Component\HttpFoundation\Session\SessionInterface;
42
43
class OrderHelper
44
{
45
    // FIXME 必要なメソッドのみ移植する
46
    use ControllerTrait;
47
48
    /**
49
     * @var ContainerInterface
50
     */
51
    protected $container;
52
53
    /**
54
     * @var string 非会員情報を保持するセッションのキー
55
     */
56
    const SESSION_NON_MEMBER = 'eccube.front.shopping.nonmember';
57
58
    /**
59
     * @var string 非会員の住所情報を保持するセッションのキー
60
     */
61
    const SESSION_NON_MEMBER_ADDRESSES = 'eccube.front.shopping.nonmember.customeraddress';
62
63
    /**
64
     * @var string 受注IDを保持するセッションのキー
65
     */
66
    const SESSION_ORDER_ID = 'eccube.front.shopping.order.id';
67
68
    /**
69
     * @var string カートが分割されているかどうかのフラグ. 購入フローからのログイン時にカートが分割された場合にtrueがセットされる.
70
     *
71
     * @see SecurityListener
72
     */
73
    const SESSION_CART_DIVIDE_FLAG = 'eccube.front.cart.divide';
74
75
    /**
76
     * @var SessionInterface
77
     */
78
    protected $session;
79
80
    /**
81
     * @var PrefRepository
82
     */
83
    protected $prefRepository;
84
85
    /**
86
     * @var OrderRepository
87
     */
88
    protected $orderRepository;
89
90
    /**
91
     * @var OrderItemTypeRepository
92
     */
93
    protected $orderItemTypeRepository;
94
95
    /**
96
     * @var OrderStatusRepository
97
     */
98
    protected $orderStatusRepository;
99
100
    /**
101
     * @var DeliveryRepository
102
     */
103
    protected $deliveryRepository;
104
105
    /**
106
     * @var PaymentRepository
107
     */
108
    protected $paymentRepository;
109
110
    /**
111
     * @var DeviceTypeRepository
112
     */
113
    protected $deviceTypeRepository;
114
115 175
    /**
116
     * @var MobileDetector
117
     */
118
    protected $mobileDetector;
119
120
    /**
121
     * @var EntityManagerInterface
122
     */
123
    protected $entityManager;
124
125
    public function __construct(
126
        ContainerInterface $container,
127
        EntityManagerInterface $entityManager,
128 175
        OrderRepository $orderRepository,
129 175
        OrderItemTypeRepository $orderItemTypeRepository,
130 175
        OrderStatusRepository $orderStatusRepository,
131 175
        DeliveryRepository $deliveryRepository,
132 175
        PaymentRepository $paymentRepository,
133 175
        DeviceTypeRepository $deviceTypeRepository,
134 175
        PrefRepository $prefRepository,
135 175
        MobileDetector $mobileDetector,
136 175
        SessionInterface $session
137 175
    ) {
138 175
        $this->container = $container;
139
        $this->orderRepository = $orderRepository;
140
        $this->orderStatusRepository = $orderStatusRepository;
141
        $this->orderItemTypeRepository = $orderItemTypeRepository;
142
        $this->deliveryRepository = $deliveryRepository;
143
        $this->paymentRepository = $paymentRepository;
144
        $this->deviceTypeRepository = $deviceTypeRepository;
145
        $this->entityManager = $entityManager;
146
        $this->prefRepository = $prefRepository;
147
        $this->mobileDetector = $mobileDetector;
148
        $this->session = $session;
149 51
    }
150
151 51
    /**
152 51
     * 購入処理中の受注を生成する.
153
     *
154 51
     * @param Customer $Customer
155
     * @param $CartItems
156 51
     *
157
     * @return Order
158
     */
159
    public function createPurchaseProcessingOrder(Cart $Cart, Customer $Customer)
160 51
    {
161
        $OrderStatus = $this->orderStatusRepository->find(OrderStatus::PROCESSING);
162 51
        $Order = new Order($OrderStatus);
0 ignored issues
show
Bug introduced by
It seems like $OrderStatus defined by $this->orderStatusReposi...rderStatus::PROCESSING) on line 161 can also be of type object; however, Eccube\Entity\Order::__construct() does only seem to accept null|object<Eccube\Entity\Master\OrderStatus>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
163 51
164
        $preOrderId = $this->createPreOrderId();
165
        $Order->setPreOrderId($preOrderId);
166 51
167 51
        // 顧客情報の設定
168
        $this->setCustomer($Order, $Customer);
169 51
170 51
        $DeviceType = $this->deviceTypeRepository->find($this->mobileDetector->isMobile() ? DeviceType::DEVICE_TYPE_MB : DeviceType::DEVICE_TYPE_PC);
171
        $Order->setDeviceType($DeviceType);
0 ignored issues
show
Bug introduced by
It seems like $DeviceType defined by $this->deviceTypeReposit...ceType::DEVICE_TYPE_PC) on line 170 can also be of type object; however, Eccube\Entity\Order::setDeviceType() does only seem to accept null|object<Eccube\Entity\Master\DeviceType>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
172 51
173 51
        // 明細情報の設定
174
        $OrderItems = $this->createOrderItemsFromCartItems($Cart->getCartItems());
175 51
        $OrderItemsGroupBySaleType = array_reduce($OrderItems, function ($result, $item) {
176 51
            /* @var OrderItem $item */
177 51
            $saleTypeId = $item->getProductClass()->getSaleType()->getId();
178 51
            $result[$saleTypeId][] = $item;
179 51
180 51
            return $result;
181 51
        }, []);
182
183
        foreach ($OrderItemsGroupBySaleType as $OrderItems) {
184 51
            $Shipping = $this->createShippingFromCustomer($Customer);
185
            $Shipping->setOrder($Order);
186 51
            $this->addOrderItems($Order, $Shipping, $OrderItems);
187
            $this->setDefaultDelivery($Shipping);
188
            $this->entityManager->persist($Shipping);
189 51
            $Order->addShipping($Shipping);
190
        }
191
192
        $this->setDefaultPayment($Order);
193
194
        $this->entityManager->persist($Order);
195
196
        return $Order;
197
    }
198
199 2
    /**
200
     * @param Cart $Cart
201 2
     *
202 2
     * @return bool
203
     */
204 2
    public function verifyCart(Cart $Cart)
205 1
    {
206 1
        if (count($Cart->getCartItems()) > 0) {
207 1
            $divide = $this->session->get(self::SESSION_CART_DIVIDE_FLAG);
208 1
            if ($divide) {
209 1
                log_info('ログイン時に販売種別が異なる商品がカートと結合されました。');
210 1
211 1
                return false;
212
            }
213
214 2
            return true;
215
        }
216
217 51
        log_info('カートに商品が入っていません。');
218
219
        return false;
220
    }
221 51
222
    /**
223 51
     * 注文手続き画面でログインが必要かどうかの判定
224
     *
225 51
     * @return bool
226
     */
227
    public function isLoginRequired()
228
    {
229 51
        // フォームログイン済はログイン不要
230
        if ($this->isGranted('IS_AUTHENTICATED_FULLY')) {
231 51
            return false;
232
        }
233
234 51
        // Remember Meログイン済の場合はフォームからのログインが必要
235
        if ($this->isGranted('IS_AUTHENTICATED_REMEMBERED')) {
236 51
            return true;
237 34
        }
238
239
        // 未ログインだがお客様情報を入力している場合はログイン不要
240 51
        if (!$this->getUser() && $this->getNonMember()) {
241 51
            return false;
242
        }
243 51
244
        return true;
245
    }
246
247
    /**
248
     * 購入処理中の受注を取得する.
249
     *
250
     * @param null|string $preOrderId
251
     *
252
     * @return null|Order
253
     */
254
    public function getPurchaseProcessingOrder($preOrderId = null)
255
    {
256 51
        if (null === $preOrderId) {
257
            return null;
258 51
        }
259
260 51
        return $this->orderRepository->findOneBy([
261
            'pre_order_id' => $preOrderId,
262
            'OrderStatus' => OrderStatus::PROCESSING,
263 51
        ]);
264
    }
265 51
266
    /**
267 51
     * セッションに保持されている非会員情報を取得する.
268
     * 非会員購入時に入力されたお客様情報を返す.
269 51
     *
270 51
     * @return Customer
271 51
     */
272 51
    public function getNonMember()
273 51
    {
274 51
        $NonMember = $this->session->get(self::SESSION_NON_MEMBER);
275 51
        if ($NonMember && $NonMember->getPref()) {
276
            $Pref = $this->prefRepository->find($NonMember->getPref()->getId());
277 51
            $NonMember->setPref($Pref);
278 51
        }
279 51
280 51
        return $NonMember;
281
    }
282 51
283 51
    /**
284 42
     * @param Cart $Cart
285 42
     * @param Customer $Customer
286
     *
287
     * @return Order|null
288 51
     */
289 51
    public function initializeOrder(Cart $Cart, Customer $Customer)
290
    {
291
        // 購入処理中の受注情報を取得
292 51
        if ($Order = $this->getPurchaseProcessingOrder($Cart->getPreOrderId())) {
293
            return $Order;
294 51
        }
295
296 51
        // 受注情報を作成
297 51
        $Order = $this->createPurchaseProcessingOrder($Cart, $Customer);
298 51
        $Cart->setPreOrderId($Order->getPreOrderId());
299 51
300 51
        return $Order;
301 51
    }
302 51
303 51
    public function removeSession()
304 51
    {
305 51
        $this->session->remove(self::SESSION_ORDER_ID);
306
        $this->session->remove(self::SESSION_ORDER_ID);
307 51
        $this->session->remove(self::SESSION_NON_MEMBER);
308
        $this->session->remove(self::SESSION_NON_MEMBER_ADDRESSES);
309
    }
310 51
311
    /**
312
     * 会員情報の更新日時が受注の作成日時よりも新しければ, 受注の注文者情報を更新する.
313 51
     *
314 51
     * @param Order $Order
315
     * @param Customer $Customer
316 51
     */
317 51
    public function updateCustomerInfo(Order $Order, Customer $Customer)
318 51
    {
319 51
        if ($Order->getCreateDate() < $Customer->getUpdateDate()) {
320
            $this->setCustomer($Order, $Customer);
321
        }
322
    }
323 51
324
    public function createPreOrderId()
325
    {
326 51
        // ランダムなpre_order_idを作成
327 51
        do {
328 51
            $preOrderId = sha1(StringUtil::random(32));
329
330
            $Order = $this->orderRepository->findOneBy(
331 51
                [
332
                    'pre_order_id' => $preOrderId,
333 51
                ]
334
            );
335
        } while ($Order);
336 51
337
        return $preOrderId;
338 51
    }
339 51
340 51
    protected function setCustomer(Order $Order, Customer $Customer)
341
    {
342
        if ($Customer->getId()) {
343
            $Order->setCustomer($Customer);
344 51
        }
345 51
346
        $Order->copyProperties(
347
            $Customer,
348
            [
349 51
                'id',
350
                'create_date',
351
                'update_date',
352 51
                'del_flg',
353
            ]
354
        );
355 51
    }
356 51
357 51
    /**
358 51
     * @param Collection|ArrayCollection|CartItem[] $CartItems
359
     *
360
     * @return OrderItem[]
361
     */
362 51
    protected function createOrderItemsFromCartItems($CartItems)
363
    {
364 51
        $ProductItemType = $this->orderItemTypeRepository->find(OrderItemType::PRODUCT);
365 51
366 51
        return array_map(function ($item) use ($ProductItemType) {
367 51
            /* @var $item CartItem */
368 51
            /* @var $ProductClass \Eccube\Entity\ProductClass */
369
            $ProductClass = $item->getProductClass();
370
            /* @var $Product \Eccube\Entity\Product */
371
            $Product = $ProductClass->getProduct();
372
373
            $OrderItem = new OrderItem();
374
            $OrderItem
375
                ->setProduct($Product)
376
                ->setProductClass($ProductClass)
377
                ->setProductName($Product->getName())
378
                ->setProductCode($ProductClass->getCode())
379
                ->setPrice($ProductClass->getPrice02())
380
                ->setQuantity($item->getQuantity())
381
                ->setOrderItemType($ProductItemType);
0 ignored issues
show
Bug introduced by
It seems like $ProductItemType defined by $this->orderItemTypeRepo...OrderItemType::PRODUCT) on line 364 can also be of type object; however, Eccube\Entity\OrderItem::setOrderItemType() does only seem to accept null|object<Eccube\Entity\Master\OrderItemType>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
382
383
            $ClassCategory1 = $ProductClass->getClassCategory1();
384
            if (!is_null($ClassCategory1)) {
385
                $OrderItem->setClasscategoryName1($ClassCategory1->getName());
386
                $OrderItem->setClassName1($ClassCategory1->getClassName()->getName());
387
            }
388
            $ClassCategory2 = $ProductClass->getClassCategory2();
389
            if (!is_null($ClassCategory2)) {
390
                $OrderItem->setClasscategoryName2($ClassCategory2->getName());
391
                $OrderItem->setClassName2($ClassCategory2->getClassName()->getName());
392
            }
393
394
            return $OrderItem;
395
        }, $CartItems instanceof Collection ? $CartItems->toArray() : $CartItems);
396
    }
397
398
    /**
399
     * @param Customer $Customer
400
     *
401
     * @return Shipping
402
     */
403
    protected function createShippingFromCustomer(Customer $Customer)
404
    {
405
        $Shipping = new Shipping();
406
        $Shipping
407
            ->setName01($Customer->getName01())
408
            ->setName02($Customer->getName02())
409
            ->setKana01($Customer->getKana01())
410
            ->setKana02($Customer->getKana02())
411
            ->setCompanyName($Customer->getCompanyName())
412
            ->setPhoneNumber($Customer->getPhoneNumber())
413
            ->setPostalCode($Customer->getPostalCode())
414
            ->setPref($Customer->getPref())
415
            ->setAddr01($Customer->getAddr01())
416
            ->setAddr02($Customer->getAddr02());
417
418
        return $Shipping;
419
    }
420
421
    /**
422
     * @param Shipping $Shipping
423
     */
424
    protected function setDefaultDelivery(Shipping $Shipping)
425
    {
426
        // 配送商品に含まれる販売種別を抽出.
427
        $OrderItems = $Shipping->getOrderItems();
428
        $SaleTypes = [];
429
        /** @var OrderItem $OrderItem */
430 View Code Duplication
        foreach ($OrderItems as $OrderItem) {
431
            $ProductClass = $OrderItem->getProductClass();
432
            $SaleType = $ProductClass->getSaleType();
433
            $SaleTypes[$SaleType->getId()] = $SaleType;
434
        }
435
436
        // 販売種別に紐づく配送業者を取得.
437
        $Deliveries = $this->deliveryRepository->getDeliveries($SaleTypes);
438
439
        // 初期の配送業者を設定
440
        $Delivery = current($Deliveries);
441
        $Shipping->setDelivery($Delivery);
442
        $Shipping->setShippingDeliveryName($Delivery->getName());
443
    }
444
445
    /**
446
     * @param Order $Order
447
     */
448
    protected function setDefaultPayment(Order $Order)
449
    {
450
        $OrderItems = $Order->getOrderItems();
451
452
        // 受注明細に含まれる販売種別を抽出.
453
        $SaleTypes = [];
454
        /** @var OrderItem $OrderItem */
455 View Code Duplication
        foreach ($OrderItems as $OrderItem) {
456
            $ProductClass = $OrderItem->getProductClass();
457
            if (is_null($ProductClass)) {
458
                // 商品明細のみ対象とする. 送料明細等はスキップする.
459
                continue;
460
            }
461
            $SaleType = $ProductClass->getSaleType();
462
            $SaleTypes[$SaleType->getId()] = $SaleType;
463
        }
464
465
        // 販売種別に紐づく配送業者を抽出
466
        $Deliveries = $this->deliveryRepository->getDeliveries($SaleTypes);
467
468
        // 利用可能な支払い方法を抽出.
469
        $Payments = $this->paymentRepository->findAllowedPayments($Deliveries, true);
470
        // ここでは支払総額はまだ決まっていないため、利用条件が設定されているものは初期選択の支払い方法として除外する
471
        $Payments = array_filter($Payments, function (Payment $Payment) {
472
            $min = $Payment->getRuleMin();
473
            $max = $Payment->getRuleMax();
474
            if ($max === null && ($min === null || $min <= 1)) {
475
                return true;
476
            }
477
478
            return false;
479
        });
480
481
        // 初期の支払い方法を設定.
482
        $Payment = current($Payments);
483
        if ($Payment) {
484
            $Order->setPayment($Payment);
485
            $Order->setPaymentMethod($Payment->getMethod());
486
        }
487
    }
488
489
    /**
490
     * @param Order $Order
491
     * @param Shipping $Shipping
492
     * @param array $OrderItems
493
     */
494
    protected function addOrderItems(Order $Order, Shipping $Shipping, array $OrderItems)
495
    {
496
        foreach ($OrderItems as $OrderItem) {
497
            $Shipping->addOrderItem($OrderItem);
498
            $Order->addOrderItem($OrderItem);
499
            $OrderItem->setOrder($Order);
500
            $OrderItem->setShipping($Shipping);
501
        }
502
    }
503
}
504