src/Eccube/Controller/CartController.php line 144

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\Controller\AbstractController;
  14. use Eccube\Entity\BaseInfo;
  15. use Eccube\Entity\ProductClass;
  16. use Eccube\Event\EccubeEvents;
  17. use Eccube\Event\EventArgs;
  18. use Eccube\Repository\BaseInfoRepository;
  19. use Eccube\Repository\ProductClassRepository;
  20. use Eccube\Service\CartService;
  21. use Eccube\Service\OrderHelper;
  22. use Eccube\Service\PurchaseFlow\PurchaseContext;
  23. use Eccube\Service\PurchaseFlow\PurchaseFlow;
  24. use Eccube\Service\PurchaseFlow\PurchaseFlowResult;
  25. use Plugin\PriceNegotiation\Service\NegotiationPriceService;
  26. use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
  27. use Symfony\Component\HttpFoundation\Request;
  28. use Symfony\Component\Routing\Annotation\Route;
  29. class CartController extends AbstractController
  30. {
  31.   /**
  32.    * @var ProductClassRepository
  33.    */
  34.   protected $productClassRepository;
  35.   /**
  36.    * @var CartService
  37.    */
  38.   protected $cartService;
  39.   /**
  40.    * @var PurchaseFlow
  41.    */
  42.   protected $purchaseFlow;
  43.   /**
  44.    * @var BaseInfo
  45.    */
  46.   protected $baseInfo;
  47.   /**
  48.    * @var NegotiationPriceService
  49.    */
  50.   protected $negotiationPriceService;
  51.   /**
  52.    * CartController constructor.
  53.    *
  54.    * @param ProductClassRepository $productClassRepository
  55.    * @param CartService $cartService
  56.    * @param PurchaseFlow $cartPurchaseFlow
  57.    * @param BaseInfoRepository $baseInfoRepository
  58.    * @param NegotiationPriceService $negotiationPriceService
  59.    */
  60.   public function __construct(
  61.     ProductClassRepository $productClassRepository,
  62.     CartService            $cartService,
  63.     PurchaseFlow           $cartPurchaseFlow,
  64.     BaseInfoRepository     $baseInfoRepository,
  65.     NegotiationPriceService $negotiationPriceService
  66.   )
  67.   {
  68.     $this->productClassRepository $productClassRepository;
  69.     $this->cartService $cartService;
  70.     $this->purchaseFlow $cartPurchaseFlow;
  71.     $this->baseInfo $baseInfoRepository->get();
  72.     $this->negotiationPriceService $negotiationPriceService;
  73.   }
  74.   /**
  75.    * カート画面.
  76.    *
  77.    * @Route("/cart", name="cart", methods={"GET"})
  78.    * @Template("Cart/index.twig")
  79.    */
  80.   public function index(Request $request)
  81.   {
  82.     // カートを取得して明細の正規化を実行
  83.     $Carts $this->cartService->getCarts();
  84.     $this->execPurchaseFlow($Carts);
  85.     // パレスかプラザのチェック
  86.     $session $request->getSession();
  87.     $plaza_flg $session->get('header_footer_layout');
  88.     foreach ($Carts as $Cart) {
  89.       foreach ($Cart->getCartItems() as $CartItem) {
  90.         $ProductClass $CartItem->getProductClass();
  91.         $sale_type_id $ProductClass->getSaleType()->getId();
  92.         if(($plaza_flg == "palace" and $sale_type_id == "2") or
  93.           ($plaza_flg == "plaza" and $sale_type_id == "1")){
  94.            $this->cartService->removeProduct($ProductClass);
  95.         }
  96.       }
  97.     }
  98.     // TODO itemHolderから取得できるように
  99.     $least = [];
  100.     $quantity = [];
  101.     $isDeliveryFree = [];
  102.     $totalPrice 0;
  103.     $totalQuantity 0;
  104.     foreach ($Carts as $Cart) {
  105.       $quantity[$Cart->getCartKey()] = 0;
  106.       $isDeliveryFree[$Cart->getCartKey()] = false;
  107.       if ($this->baseInfo->getDeliveryFreeQuantity()) {
  108.         if ($this->baseInfo->getDeliveryFreeQuantity() > $Cart->getQuantity()) {
  109.           $quantity[$Cart->getCartKey()] = $this->baseInfo->getDeliveryFreeQuantity() - $Cart->getQuantity();
  110.         } else {
  111.           $isDeliveryFree[$Cart->getCartKey()] = true;
  112.         }
  113.       }
  114.       if ($this->baseInfo->getDeliveryFreeAmount()) {
  115.         if (!$isDeliveryFree[$Cart->getCartKey()] && $this->baseInfo->getDeliveryFreeAmount() <= $Cart->getTotalPrice()) {
  116.           $isDeliveryFree[$Cart->getCartKey()] = true;
  117.         } else {
  118.           $least[$Cart->getCartKey()] = $this->baseInfo->getDeliveryFreeAmount() - $Cart->getTotalPrice();
  119.         }
  120.       }
  121.       $totalPrice += $Cart->getTotalPrice();
  122.       $totalQuantity += $Cart->getQuantity();
  123.     }
  124.     // カートが分割された時のセッション情報を削除
  125.     $request->getSession()->remove(OrderHelper::SESSION_CART_DIVIDE_FLAG);
  126.     // 価格交渉価格を取得
  127.     $negotiationPrices = [];
  128.     $negotiatedSubtotals = [];  // 商品IDごとの交渉価格小計
  129.     $negotiatedCartTotals = []; // カートごとの交渉価格合計
  130.     $negotiatedTotalPrice 0;  // 全体の交渉価格合計
  131.     $hasNegotiatedItems false// 交渉成立商品があるかどうか
  132.     $customer $this->getUser();
  133.     if ($customer) {
  134.       $customerId $customer->getId();
  135.       foreach ($Carts as $Cart) {
  136.         $cartKey $Cart->getCartKey();
  137.         $negotiatedCartTotals[$cartKey] = 0;
  138.         foreach ($Cart->getCartItems() as $CartItem) {
  139.           $productId $CartItem->getProductClass()->getProduct()->getId();
  140.           $negoPrice $this->negotiationPriceService->getSuccessfulNegotiationPriceIncTax($customerId$productId);
  141.           if ($negoPrice !== null) {
  142.             $negotiationPrices[$productId] = $negoPrice;
  143.             $subtotal $negoPrice $CartItem->getQuantity();
  144.             $negotiatedSubtotals[$productId] = $subtotal;
  145.             $negotiatedCartTotals[$cartKey] += $subtotal;
  146.             $hasNegotiatedItems true;
  147.           } else {
  148.             // 交渉価格がない場合は元の価格
  149.             $negotiatedCartTotals[$cartKey] += $CartItem->getTotalPrice();
  150.           }
  151.         }
  152.         $negotiatedTotalPrice += $negotiatedCartTotals[$cartKey];
  153.       }
  154.     } else {
  155.       // 未ログインの場合は元の価格をそのまま使用
  156.       $negotiatedTotalPrice $totalPrice;
  157.       foreach ($Carts as $Cart) {
  158.         $negotiatedCartTotals[$Cart->getCartKey()] = $Cart->getTotalPrice();
  159.       }
  160.     }
  161.     return [
  162.       'totalPrice' => $totalPrice,
  163.       'totalQuantity' => $totalQuantity,
  164.       // 空のカートを削除し取得し直す
  165.       'Carts' => $this->cartService->getCarts(true),
  166.       'least' => $least,
  167.       'quantity' => $quantity,
  168.       'is_delivery_free' => $isDeliveryFree,
  169.       'negotiationPrices' => $negotiationPrices,
  170.       'negotiatedSubtotals' => $negotiatedSubtotals,
  171.       'negotiatedCartTotals' => $negotiatedCartTotals,
  172.       'negotiatedTotalPrice' => $negotiatedTotalPrice,
  173.       'hasNegotiatedItems' => $hasNegotiatedItems,
  174.     ];
  175.   }
  176.   /**
  177.    * @param $Carts
  178.    *
  179.    * @return \Symfony\Component\HttpFoundation\RedirectResponse|null
  180.    */
  181.   protected function execPurchaseFlow($Carts)
  182.   {
  183.     /** @var PurchaseFlowResult[] $flowResults */
  184.     $flowResults array_map(function ($Cart) {
  185.       $purchaseContext = new PurchaseContext($Cart$this->getUser());
  186.       return $this->purchaseFlow->validate($Cart$purchaseContext);
  187.     }, $Carts);
  188.     // 復旧不可のエラーが発生した場合はカートをクリアして再描画
  189.     $hasError false;
  190.     foreach ($flowResults as $result) {
  191.       if ($result->hasError()) {
  192.         $hasError true;
  193.         foreach ($result->getErrors() as $error) {
  194.           $this->addRequestError($error->getMessage());
  195.         }
  196.       }
  197.     }
  198.     if ($hasError) {
  199.       $this->cartService->clear();
  200.       return $this->redirectToRoute('cart');
  201.     }
  202.     $this->cartService->save();
  203.     foreach ($flowResults as $index => $result) {
  204.       foreach ($result->getWarning() as $warning) {
  205.         if ($Carts[$index]->getItems()->count() > 0) {
  206.           $cart_key $Carts[$index]->getCartKey();
  207.           $this->addRequestError($warning->getMessage(), "front.cart.${cart_key}");
  208.         } else {
  209.           // キーが存在しない場合はグローバルにエラーを表示する
  210.           $this->addRequestError($warning->getMessage());
  211.         }
  212.       }
  213.     }
  214.     return null;
  215.   }
  216.   /**
  217.    * カート明細の加算/減算/削除を行う.
  218.    *
  219.    * - 加算
  220.    *      - 明細の個数を1増やす
  221.    * - 減算
  222.    *      - 明細の個数を1減らす
  223.    *      - 個数が0になる場合は、明細を削除する
  224.    * - 削除
  225.    *      - 明細を削除する
  226.    *
  227.    * @Route(
  228.    *     path="/cart/{operation}/{productClassId}",
  229.    *     name="cart_handle_item",
  230.    *     methods={"PUT"},
  231.    *     requirements={
  232.    *          "operation": "up|down|remove",
  233.    *          "productClassId": "\d+"
  234.    *     }
  235.    * )
  236.    */
  237.   public function handleCartItem($operation$productClassId)
  238.   {
  239.     log_info('カート明細操作開始', ['operation' => $operation'product_class_id' => $productClassId]);
  240.     $this->isTokenValid();
  241.     /** @var ProductClass $ProductClass */
  242.     $ProductClass $this->productClassRepository->find($productClassId);
  243.     if (is_null($ProductClass)) {
  244.       log_info('商品が存在しないため、カート画面へredirect', ['operation' => $operation'product_class_id' => $productClassId]);
  245.       return $this->redirectToRoute('cart');
  246.     }
  247.     // 明細の増減・削除
  248.     switch ($operation) {
  249.       case 'up':
  250.         $this->cartService->addProduct($ProductClass1);
  251.         break;
  252.       case 'down':
  253.         $this->cartService->addProduct($ProductClass, -1);
  254.         break;
  255.       case 'remove':
  256.         $this->cartService->removeProduct($ProductClass);
  257.         break;
  258.     }
  259.     // カートを取得して明細の正規化を実行
  260.     $Carts $this->cartService->getCarts();
  261.     $this->execPurchaseFlow($Carts);
  262.     log_info('カート演算処理終了', ['operation' => $operation'product_class_id' => $productClassId]);
  263.     return $this->redirectToRoute('cart');
  264.   }
  265.   /**
  266.    * カートをロック状態に設定し、購入確認画面へ遷移する.
  267.    *
  268.    * @Route("/cart/buystep/{cart_key}", name="cart_buystep", requirements={"cart_key" = "[a-zA-Z0-9]+[_][\x20-\x7E]+"}, methods={"GET"})
  269.    */
  270.   public function buystep(Request $request$cart_key)
  271.   {
  272.     $Carts $this->cartService->getCart();
  273.     if (!is_object($Carts)) {
  274.       return $this->redirectToRoute('cart');
  275.     }
  276.     // FRONT_CART_BUYSTEP_INITIALIZE
  277.     $event = new EventArgs(
  278.       [],
  279.       $request
  280.     );
  281.     $this->eventDispatcher->dispatch($eventEccubeEvents::FRONT_CART_BUYSTEP_INITIALIZE);
  282.     $this->cartService->setPrimary($cart_key);
  283.     $this->cartService->save();
  284.     // FRONT_CART_BUYSTEP_COMPLETE
  285.     $event = new EventArgs(
  286.       [],
  287.       $request
  288.     );
  289.     $this->eventDispatcher->dispatch($eventEccubeEvents::FRONT_CART_BUYSTEP_COMPLETE);
  290.     if ($event->hasResponse()) {
  291.       return $event->getResponse();
  292.     }
  293.     return $this->redirectToRoute('shopping');
  294.   }
  295. }