src/Eccube/Controller/ShippingMultipleController.php line 101

Open in your IDE?
  1. <?php
  2. /*
  3.  * This file is part of EC-CUBE
  4.  *
  5.  * Copyright(c) EC-CUBE CO.,LTD. All Rights Reserved.
  6.  *
  7.  * http://www.ec-cube.co.jp/
  8.  *
  9.  * For the full copyright and license information, please view the LICENSE
  10.  * file that was distributed with this source code.
  11.  */
  12. namespace Eccube\Controller;
  13. use Eccube\Entity\Customer;
  14. use Eccube\Entity\CustomerAddress;
  15. use Eccube\Entity\Master\OrderItemType;
  16. use Eccube\Entity\OrderItem;
  17. use Eccube\Entity\Shipping;
  18. use Eccube\Event\EccubeEvents;
  19. use Eccube\Event\EventArgs;
  20. use Eccube\Form\Type\Front\ShoppingShippingType;
  21. use Eccube\Form\Type\ShippingMultipleType;
  22. use Eccube\Repository\Master\OrderItemTypeRepository;
  23. use Eccube\Repository\Master\PrefRepository;
  24. use Eccube\Repository\OrderRepository;
  25. use Eccube\Service\CartService;
  26. use Eccube\Service\OrderHelper;
  27. use Eccube\Service\PurchaseFlow\PurchaseContext;
  28. use Eccube\Service\PurchaseFlow\PurchaseFlow;
  29. use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
  30. use Symfony\Component\Form\Extension\Core\Type\CollectionType;
  31. use Symfony\Component\HttpFoundation\Request;
  32. use Symfony\Component\Routing\Annotation\Route;
  33. class ShippingMultipleController extends AbstractShoppingController
  34. {
  35.     /**
  36.      * @var PrefRepository
  37.      */
  38.     protected $prefRepository;
  39.     /**
  40.      * @var OrderItemTypeRepository
  41.      */
  42.     protected $orderItemTypeRepository;
  43.     /**
  44.      * @var OrderHelper
  45.      */
  46.     protected $orderHelper;
  47.     /**
  48.      * @var CartService
  49.      */
  50.     protected $cartService;
  51.     /**
  52.      * @var PurchaseFlow
  53.      */
  54.     protected $cartPurchaseFlow;
  55.     /**
  56.      * @var OrderRepository
  57.      */
  58.     protected $orderRepository;
  59.     /**
  60.      * ShippingMultipleController constructor.
  61.      *
  62.      * @param PrefRepository $prefRepository
  63.      * @param OrderRepository $orderRepository
  64.      * @param OrderItemTypeRepository $orderItemTypeRepository
  65.      * @param OrderHelper $orderHelper
  66.      * @param CartService $cartService
  67.      * @param PurchaseFlow $cartPurchaseFlow
  68.      */
  69.     public function __construct(
  70.         PrefRepository $prefRepository,
  71.         OrderRepository $orderRepository,
  72.         OrderItemTypeRepository $orderItemTypeRepository,
  73.         OrderHelper $orderHelper,
  74.         CartService $cartService,
  75.         PurchaseFlow $cartPurchaseFlow
  76.     ) {
  77.         $this->prefRepository $prefRepository;
  78.         $this->orderRepository $orderRepository;
  79.         $this->orderItemTypeRepository $orderItemTypeRepository;
  80.         $this->orderHelper $orderHelper;
  81.         $this->cartService $cartService;
  82.         $this->cartPurchaseFlow $cartPurchaseFlow;
  83.     }
  84.     /**
  85.      * 複数配送処理
  86.      *
  87.      * @Route("/shopping/shipping_multiple", name="shopping_shipping_multiple", methods={"GET", "POST"})
  88.      * @Template("Shopping/shipping_multiple.twig")
  89.      */
  90.     public function index(Request $request)
  91.     {
  92.         // ログイン状態のチェック.
  93.         if ($this->orderHelper->isLoginRequired()) {
  94.             return $this->redirectToRoute('shopping_login');
  95.         }
  96.         // 受注の存在チェック
  97.         $preOrderId $this->cartService->getPreOrderId();
  98.         $Order $this->orderHelper->getPurchaseProcessingOrder($preOrderId);
  99.         if (!$Order) {
  100.             return $this->redirectToRoute('shopping_error');
  101.         }
  102.         // 処理しやすいようにすべてのShippingItemをまとめる
  103.         $OrderItems $Order->getProductOrderItems();
  104.         // Orderに含まれる商品ごとの数量を求める
  105.         $ItemQuantitiesByClassId = [];
  106.         foreach ($OrderItems as $item) {
  107.             $itemId $item->getProductClass()->getId();
  108.             $quantity $item->getQuantity();
  109.             if (array_key_exists($itemId$ItemQuantitiesByClassId)) {
  110.                 $ItemQuantitiesByClassId[$itemId] += $quantity;
  111.             } else {
  112.                 $ItemQuantitiesByClassId[$itemId] = $quantity;
  113.             }
  114.         }
  115.         // FormBuilder用に商品ごとにShippingItemをまとめる
  116.         $OrderItemsForFormBuilder = [];
  117.         $tmpAddedClassIds = [];
  118.         foreach ($OrderItems as $item) {
  119.             $itemId $item->getProductClass()->getId();
  120.             if (!in_array($itemId$tmpAddedClassIds)) {
  121.                 $OrderItemsForFormBuilder[] = $item;
  122.                 $tmpAddedClassIds[] = $itemId;
  123.             }
  124.         }
  125.         // Form生成
  126.         $builder $this->formFactory->createBuilder();
  127.         $builder
  128.             ->add('shipping_multiple'CollectionType::class, [
  129.                 'entry_type' => ShippingMultipleType::class,
  130.                 'data' => $OrderItemsForFormBuilder,
  131.                 'allow_add' => true,
  132.                 'allow_delete' => true,
  133.             ]);
  134.         // Event
  135.         $event = new EventArgs(
  136.             [
  137.                 'builder' => $builder,
  138.                 'Order' => $Order,
  139.             ],
  140.             $request
  141.         );
  142.         $this->eventDispatcher->dispatch($eventEccubeEvents::FRONT_SHOPPING_SHIPPING_MULTIPLE_INITIALIZE);
  143.         $form $builder->getForm();
  144.         $form->handleRequest($request);
  145.         $errors = [];
  146.         if ($form->isSubmitted() && $form->isValid()) {
  147.             log_info('複数配送設定処理開始', [$Order->getId()]);
  148.             $data $form['shipping_multiple'];
  149.             // フォームの入力から、送り先ごとに商品の数量を集計する
  150.             $arrOrderItemTemp = [];
  151.             foreach ($data as $multiples) {
  152.                 $OrderItem $multiples->getData();
  153.                 foreach ($multiples as $items) {
  154.                     foreach ($items as $item) {
  155.                         $CustomerAddress $item['customer_address']->getData();
  156.                         $customerAddressName $CustomerAddress->getShippingMultipleDefaultName();
  157.                         $itemId $OrderItem->getProductClass()->getId();
  158.                         $quantity $item['quantity']->getData();
  159.                         if (isset($arrOrderItemTemp[$customerAddressName]) && array_key_exists($itemId$arrOrderItemTemp[$customerAddressName])) {
  160.                             $arrOrderItemTemp[$customerAddressName][$itemId] = $arrOrderItemTemp[$customerAddressName][$itemId] + $quantity;
  161.                         } else {
  162.                             $arrOrderItemTemp[$customerAddressName][$itemId] = $quantity;
  163.                         }
  164.                     }
  165.                 }
  166.             }
  167.             // フォームの入力から、商品ごとの数量を集計する
  168.             $itemQuantities = [];
  169.             foreach ($arrOrderItemTemp as $FormItemByAddress) {
  170.                 foreach ($FormItemByAddress as $itemId => $quantity) {
  171.                     if (array_key_exists($itemId$itemQuantities)) {
  172.                         $itemQuantities[$itemId] = $itemQuantities[$itemId] + $quantity;
  173.                     } else {
  174.                         $itemQuantities[$itemId] = $quantity;
  175.                     }
  176.                 }
  177.             }
  178.             // -- ここから先がお届け先を再生成する処理 --
  179.             // お届け先情報をすべて削除
  180.             /** @var Shipping $Shipping */
  181.             foreach ($Order->getShippings() as $Shipping) {
  182.                 foreach ($Shipping->getOrderItems() as $OrderItem) {
  183.                     $Shipping->removeOrderItem($OrderItem);
  184.                     $Order->removeOrderItem($OrderItem);
  185.                     $this->entityManager->remove($OrderItem);
  186.                 }
  187.                 $Order->removeShipping($Shipping);
  188.                 $this->entityManager->remove($Shipping);
  189.             }
  190.             // お届け先のリストを作成する
  191.             $ShippingList = [];
  192.             foreach ($data as $multiples) {
  193.                 $OrderItem $multiples->getData();
  194.                 $ProductClass $OrderItem->getProductClass();
  195.                 $Delivery $OrderItem->getShipping()->getDelivery();
  196.                 $saleTypeId $ProductClass->getSaleType()->getId();
  197.                 foreach ($multiples as $items) {
  198.                     foreach ($items as $item) {
  199.                         $CustomerAddress $item['customer_address']->getData();
  200.                         $customerAddressName $CustomerAddress->getShippingMultipleDefaultName();
  201.                         if (isset($ShippingList[$customerAddressName][$saleTypeId])) {
  202.                             continue;
  203.                         }
  204.                         $Shipping = new Shipping();
  205.                         $Shipping
  206.                             ->setOrder($Order)
  207.                             ->setFromCustomerAddress($CustomerAddress)
  208.                             ->setDelivery($Delivery);
  209.                         $Order->addShipping($Shipping);
  210.                         $ShippingList[$customerAddressName][$saleTypeId] = $Shipping;
  211.                     }
  212.                 }
  213.             }
  214.             // お届け先のリストを保存
  215.             foreach ($ShippingList as $ShippingListByAddress) {
  216.                 foreach ($ShippingListByAddress as $Shipping) {
  217.                     $this->entityManager->persist($Shipping);
  218.                 }
  219.             }
  220.             $ProductOrderType $this->orderItemTypeRepository->find(OrderItemType::PRODUCT);
  221.             // お届け先に、配送商品の情報(OrderItem)を関連付ける
  222.             foreach ($data as $multiples) {
  223.                 /** @var OrderItem $OrderItem */
  224.                 $OrderItem $multiples->getData();
  225.                 $ProductClass $OrderItem->getProductClass();
  226.                 $Product $OrderItem->getProduct();
  227.                 $saleTypeId $ProductClass->getSaleType()->getId();
  228.                 $productClassId $ProductClass->getId();
  229.                 foreach ($multiples as $items) {
  230.                     foreach ($items as $item) {
  231.                         $CustomerAddress $item['customer_address']->getData();
  232.                         $customerAddressName $CustomerAddress->getShippingMultipleDefaultName();
  233.                         // お届け先から商品の数量を取得
  234.                         $quantity 0;
  235.                         if (isset($arrOrderItemTemp[$customerAddressName]) && array_key_exists($productClassId$arrOrderItemTemp[$customerAddressName])) {
  236.                             $quantity $arrOrderItemTemp[$customerAddressName][$productClassId];
  237.                             unset($arrOrderItemTemp[$customerAddressName][$productClassId]);
  238.                         } else {
  239.                             // この配送先には送る商品がないのでスキップ(通常ありえない)
  240.                             continue;
  241.                         }
  242.                         // 関連付けるお届け先のインスタンスを取得
  243.                         $Shipping $ShippingList[$customerAddressName][$saleTypeId];
  244.                         // インスタンスを生成して保存
  245.                         $OrderItem = new OrderItem();
  246.                         $OrderItem->setShipping($Shipping)
  247.                             ->setOrder($Order)
  248.                             ->setProductClass($ProductClass)
  249.                             ->setProduct($Product)
  250.                             ->setProductName($Product->getName())
  251.                             ->setProductCode($ProductClass->getCode())
  252.                             ->setPrice($ProductClass->getPrice02())
  253.                             ->setQuantity($quantity)
  254.                             ->setOrderItemType($ProductOrderType);
  255.                         $ClassCategory1 $ProductClass->getClassCategory1();
  256.                         if (!is_null($ClassCategory1)) {
  257.                             $OrderItem->setClasscategoryName1($ClassCategory1->getName());
  258.                             $OrderItem->setClassName1($ClassCategory1->getClassName()->getName());
  259.                         }
  260.                         $ClassCategory2 $ProductClass->getClassCategory2();
  261.                         if (!is_null($ClassCategory2)) {
  262.                             $OrderItem->setClasscategoryName2($ClassCategory2->getName());
  263.                             $OrderItem->setClassName2($ClassCategory2->getClassName()->getName());
  264.                         }
  265.                         $Shipping->addOrderItem($OrderItem);
  266.                         $Order->addOrderItem($OrderItem);
  267.                         $this->entityManager->persist($OrderItem);
  268.                     }
  269.                 }
  270.             }
  271.             // 合計金額の再計算
  272.             $flowResult $this->executePurchaseFlow($Orderfalse);
  273.             if ($flowResult->hasError()) {
  274.                 return $this->redirectToRoute('shopping_error');
  275.             }
  276.             $this->entityManager->flush();
  277.             $event = new EventArgs(
  278.                 [
  279.                     'form' => $form,
  280.                     'Order' => $Order,
  281.                 ],
  282.                 $request
  283.             );
  284.             $this->eventDispatcher->dispatch($eventEccubeEvents::FRONT_SHOPPING_SHIPPING_MULTIPLE_COMPLETE);
  285.             log_info('複数配送設定処理完了', [$Order->getId()]);
  286.             $this->entityManager->refresh($Order);
  287.             $quantityByProductClass = [];
  288.             foreach ($Order->getProductOrderItems() as $Item) {
  289.                 $id $Item->getProductClass()->getId();
  290.                 if (isset($quantityByProductClass[$id])) {
  291.                     $quantityByProductClass[$id] += $Item->getQuantity();
  292.                 } else {
  293.                     $quantityByProductClass[$id] = $Item->getQuantity();
  294.                 }
  295.             }
  296.             $Cart $this->cartService->getCart();
  297.             if ($Cart) {
  298.                 foreach ($Cart->getCartItems() as $CartItem) {
  299.                     $id $CartItem->getProductClass()->getId();
  300.                     if (isset($quantityByProductClass[$id])) {
  301.                         $CartItem->setQuantity($quantityByProductClass[$id]);
  302.                     }
  303.                 }
  304.                 $this->cartPurchaseFlow->validate($Cart, new PurchaseContext($Cart$this->getUser()));
  305.                 // 注文フローで取得されるカートの入れ替わりを防止する
  306.                 // @see https://github.com/EC-CUBE/ec-cube/issues/4293
  307.                 $this->cartService->setPrimary($Cart->getCartKey());
  308.             }
  309.             return $this->redirectToRoute('shopping');
  310.         }
  311.         return [
  312.             'form' => $form->createView(),
  313.             'OrderItems' => $OrderItemsForFormBuilder,
  314.             'compItemQuantities' => $ItemQuantitiesByClassId,
  315.             'errors' => $errors,
  316.         ];
  317.     }
  318.     /**
  319.      * 複数配送設定時の新規お届け先の設定
  320.      *
  321.      * 会員ログイン時は会員のお届け先に追加する
  322.      * 非会員時はセッションに追加する
  323.      *
  324.      * @Route("/shopping/shipping_multiple_edit", name="shopping_shipping_multiple_edit", methods={"GET", "POST"})
  325.      * @Template("Shopping/shipping_multiple_edit.twig")
  326.      */
  327.     public function shippingMultipleEdit(Request $request)
  328.     {
  329.         // ログイン状態のチェック.
  330.         if ($this->orderHelper->isLoginRequired()) {
  331.             return $this->redirectToRoute('shopping_login');
  332.         }
  333.         // 受注の存在チェック
  334.         $preOrderId $this->cartService->getPreOrderId();
  335.         $Order $this->orderHelper->getPurchaseProcessingOrder($preOrderId);
  336.         if (!$Order) {
  337.             return $this->redirectToRoute('shopping_error');
  338.         }
  339.         /** @var Customer $Customer */
  340.         $Customer $this->getUser();
  341.         $CustomerAddress = new CustomerAddress();
  342.         $builder $this->formFactory->createBuilder(ShoppingShippingType::class, $CustomerAddress);
  343.         $event = new EventArgs(
  344.             [
  345.                 'builder' => $builder,
  346.                 'Customer' => $Customer,
  347.             ],
  348.             $request
  349.         );
  350.         $this->eventDispatcher->dispatch($eventEccubeEvents::FRONT_SHOPPING_SHIPPING_MULTIPLE_EDIT_INITIALIZE);
  351.         $form $builder->getForm();
  352.         $form->handleRequest($request);
  353.         if ($form->isSubmitted() && $form->isValid()) {
  354.             log_info('複数配送のお届け先追加処理開始');
  355.             if ($this->isGranted('ROLE_USER')) {
  356.                 $CustomerAddresses $Customer->getCustomerAddresses();
  357.                 $count count($CustomerAddresses);
  358.                 if ($count >= $this->eccubeConfig['eccube_deliv_addr_max']) {
  359.                     return [
  360.                         'error' => trans('common.customer_address_count_is_over', [
  361.                             '%eccube_deliv_addr_max%' => $this->eccubeConfig->get('eccube_deliv_addr_max'),
  362.                         ]),
  363.                         'form' => $form->createView(),
  364.                     ];
  365.                 }
  366.                 $CustomerAddress->setCustomer($Customer);
  367.                 $this->entityManager->persist($CustomerAddress);
  368.                 $this->entityManager->flush();
  369.             } else {
  370.                 // 非会員用のセッションに追加
  371.                 $CustomerAddresses $this->session->get(OrderHelper::SESSION_NON_MEMBER_ADDRESSES);
  372.                 $CustomerAddresses unserialize($CustomerAddresses);
  373.                 $CustomerAddresses[] = $CustomerAddress;
  374.                 $this->session->set(OrderHelper::SESSION_NON_MEMBER_ADDRESSESserialize($CustomerAddresses));
  375.             }
  376.             $event = new EventArgs(
  377.                 [
  378.                     'form' => $form,
  379.                     'CustomerAddresses' => $CustomerAddresses,
  380.                 ],
  381.                 $request
  382.             );
  383.             $this->eventDispatcher->dispatch($eventEccubeEvents::FRONT_SHOPPING_SHIPPING_MULTIPLE_EDIT_COMPLETE);
  384.             log_info('複数配送のお届け先追加処理完了');
  385.             return $this->redirectToRoute('shopping_shipping_multiple');
  386.         }
  387.         return [
  388.             'form' => $form->createView(),
  389.         ];
  390.     }
  391. }