app/Customize/Controller/CartController.php line 1043

Open in your IDE?
  1. <?php
  2. /**
  3.  * @version EC-CUBE4系
  4.  * @copyright 株式会社 翔 kakeru.co.jp
  5.  *
  6.  * 2022年03月21日カスタマイズ
  7.  *
  8.  * app/Customize/Controller/CartController.php
  9.  *
  10.  *
  11.  * カート
  12.  *
  13.  *
  14.  *
  15.  *                                        ≡≡≡┏(^o^)┛
  16.  *****************************************************/
  17. namespace Customize\Controller;
  18. use Customize\Controller\LM\DataLayerTrait;
  19. use Customize\Event\LmEvents;
  20. use Customize\Service\EstimateCharacterizer;
  21. use Customize\Service\GoodsService;
  22. use Customize\Service\LmHelper;
  23. use Customize\Service\MobileDetector as LmMobileDetector;
  24. use Customize\Service\SampleService;
  25. use Eccube\Entity\BaseInfo;
  26. use Eccube\Entity\Customer;
  27. use Eccube\Entity\Layout;
  28. use Eccube\Entity\ProductClass;
  29. use Eccube\Event\EccubeEvents;
  30. use Eccube\Event\EventArgs;
  31. use Eccube\Repository\BaseInfoRepository;
  32. use Eccube\Repository\ProductClassRepository;
  33. use Customize\Service\CartService;
  34. use Customize\Service\OrderHelper;
  35. use Eccube\Service\PurchaseFlow\PurchaseContext;
  36. use Eccube\Service\PurchaseFlow\PurchaseFlow;
  37. use Eccube\Service\PurchaseFlow\PurchaseFlowResult;
  38. use Symfony\Component\DependencyInjection\ContainerInterface;
  39. use Twig\Environment as Twig;
  40. use Lm\Engine\EC\Entity\GoodsWithRelated;
  41. use Lm\Engine\Zaiko\Entity\SkuExtended;
  42. use Lm\Entity\Goods;
  43. use Lm\Entity\GoodsColor;
  44. use Lm\Entity\GoodsPrice;
  45. use Lm\Entity\Jancode;
  46. use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
  47. use Symfony\Component\HttpFoundation\Request;
  48. use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
  49. use Symfony\Component\Routing\Annotation\Route;
  50. use Customize\Service\CommonService;
  51. use Customize\Service\CatalogService;
  52. use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
  53. use Symfony\Component\Validator\Validator\ValidatorInterface;
  54. use Customize\Validator as Assert;
  55. use Customize\Service\EstimateService;
  56. use Customize\Converter\OrderConverter;
  57. use Customize\Service\RecentGoodsService;
  58. use Symfony\Component\HttpFoundation\Session\SessionInterface;
  59. class CartController extends \Eccube\Controller\CartController
  60. {
  61.     use DataLayerTrait {
  62.         DataLayerTrait::__construct as __dataLayerTraitConstruct;
  63.     }
  64.    const URL_NAME_AJAX   = [
  65.        CartService::ROUTE_ADD_NORMAL,
  66.        CartService::ROUTE_VALID_ESTIMATE,
  67.        CartService::ROUTE_ADD_SAMPLE,
  68.        CartService::ROUTE_ADD_LINE,
  69.    ];
  70.    const URL_NANE_SUBMIT = [
  71.        CartService::ROUTE_ADD_CATALOG,
  72.        CartService::ROUTE_ADD_ESTIMATE,
  73.        CartService::ROUTE_ADD_HYBRID,
  74.        CartService::ROUTE_ADD_REPEAT,
  75.    ];
  76.    const CartErrorMessage "front.cart_item_error%02d";
  77.     /**
  78.      * 「カートに入れる」フラグ - 商品をカートに追加しない
  79.      */
  80.    const ADD_PRODUCTS_NONE 0;
  81.     /**
  82.      * 「カートに入れる」フラグ - 商品を1つずつカートに追加する
  83.      */
  84.     const ADD_PRODUCTS_EACH 1;
  85.     /**
  86.      * 「カートに入れる」フラグ - 商品をまとめてカートに追加する
  87.      */
  88.     const ADD_PRODUCTS_BULK 2;
  89.     /**
  90.      * 「カートに入れる」フラグ - リピート注文
  91.      */
  92.     const ADD_PRODUCTS_REPEAT 3;
  93.     /**
  94.      * @var BaseInfo
  95.      */
  96.     protected $baseInfo;
  97.     protected $LmHelper;
  98.     protected $CommonService;
  99.     protected $CatalogService;
  100.     protected $Validator;
  101.     protected $Products;
  102.     protected $Errors = [];
  103.     protected $ItemNum 0;
  104.     protected $CartType;
  105.     protected $EstimateService;
  106.     protected $OrderConverter;
  107.     protected $session;
  108.     protected Twig $Twig;
  109.     /**
  110.      * @var EstimateCharacterizer
  111.      */
  112.     private $EstimateCharacterizer;
  113.     /**
  114.      * @var GoodsService
  115.      */
  116.     private $GoodsService;
  117.     /**
  118.      * @var LmMobileDetector
  119.      */
  120.     private $mobileDetector;
  121.     /**
  122.      * @var SampleService
  123.      */
  124.     private $SampleService;
  125.     /**
  126.      * CartController constructor.
  127.      *
  128.      * @param ProductClassRepository $productClassRepository
  129.      * @param CartService $cartService
  130.      * @param PurchaseFlow $cartPurchaseFlow
  131.      * @param BaseInfoRepository $baseInfoRepository
  132.      */
  133.     public function __construct(
  134.         ProductClassRepository $productClassRepository,
  135.         CartService            $cartService,
  136.         PurchaseFlow           $cartPurchaseFlow,
  137.         BaseInfoRepository     $baseInfoRepository,
  138.         CommonService          $CommonService,
  139.         CatalogService         $CatalogService,
  140.         ValidatorInterface     $Validator,
  141.         EstimateService        $EstimateService,
  142.         EstimateCharacterizer  $EstimateCharacterizer,
  143.         OrderConverter         $OrderConverter,
  144.         GoodsService           $GoodsService,
  145.         LmMobileDetector       $mobileDetector,
  146.         RecentGoodsService     $RecentGoodsService,
  147.         SampleService          $SampleService,
  148.         SessionInterface       $session,
  149.         ContainerInterface     $container,
  150.         Twig                   $Twig
  151.     )
  152.     {
  153.         //
  154.         parent::__construct($productClassRepository,  $cartService,  $cartPurchaseFlow,  $baseInfoRepository);
  155.         //
  156.         $this->baseInfo $baseInfoRepository->get();
  157.         $this->CommonService $CommonService;
  158.         $this->CatalogService $CatalogService;
  159.         $this->Validator $Validator;
  160.         $this->EstimateService $EstimateService;
  161.         $this->EstimateCharacterizer $EstimateCharacterizer;
  162.         $this->OrderConverter $OrderConverter;
  163.         $this->GoodsService $GoodsService;
  164.         $this->mobileDetector $mobileDetector;
  165.         $this->RecentGoodsService $RecentGoodsService;
  166.         $this->SampleService $SampleService;
  167.         $this->session $session;
  168.         $this->Container $container;
  169.         $this->Twig $Twig;
  170.         //
  171.         self::__dataLayerTraitConstruct($CommonService);
  172.     }
  173.     /**
  174.      * カート画面.
  175.      *
  176.      * @Route("/cart/", name="cart", methods={"GET"})
  177.      * @Template("Cart/index.twig")
  178.      */
  179.     public function index(Request $request)
  180.     {
  181.         if (!$this->session->get('referer')) {
  182.             if (($referer $request->headers->get('referer')) && strpos($referer"/cart") === false && strpos($referer"/estimate") === false && strpos($referer"/shopping") === false) {
  183.                 $this->session->set('referer'$referer);
  184.             }
  185.         }
  186.         if (
  187.             $this->cartService->getCartType() ==  CartService::CartTypeCatalog
  188.             && $request->get('from_url') != 'add_catalog'
  189.             && $request->get('_route') !== CartService::ROUTE_ADD_CATALOG
  190.             && empty($this->CommonService->GetLmOrderOption(CommonService::Lm_Option_Catalog))
  191.         ) {
  192.             $this->RemoveCart('catalog',null,'return');
  193.         }
  194.         $isYoyaku false;
  195.         //
  196.         $this->checkCartItemsAvailable();
  197.         //print_r( $_SESSION['data'] ?? []); unset( $_SESSION['data']);
  198.         // カートを取得して明細の正規化を実行
  199.         $Carts $this->cartService->getCarts();
  200.         $this->execPurchaseFlow($Carts);
  201.         list($this->CartTypeId$Products) = $this->cartService->MakeValidationData();
  202.         if ($this->CartTypeId != CartService::CartTypeSample) {
  203.             $this->AddCartValidation($Products,$this->cartService->GetCartType() ,false);
  204.         }
  205.         // TODO itemHolderから取得できるように
  206.         $least = [];
  207.         $isDeliveryFree = [];
  208.         $totalPrice 0;
  209.         $ProductTotal =0;
  210.         $totalQuantity $this->CommonService->calculateTotalQuantityForCarts($Carts);
  211.         $CatalogCartKey null;
  212.         $EstimateOptions = [];
  213.         $EstimatetTotal  0;
  214.         foreach ($Carts as $Cart) {
  215.             $isDeliveryFree[$Cart->getCartKey()] = false;
  216.             $OptionTotal $this->cartService->GetEstimateOptionData($Cart->getCartItems(),'cart');
  217.             list($ETotal,$EstimateOptions[$Cart->getCartKey()]) = $this->EstimateCharacterizer->SetEstimateOption($Cart->getCartItems(),$OptionTotal);
  218.             $EstimatetTotal += $ETotal;
  219.             $ProductTotal   += $Cart->getTotalPrice() + $EstimatetTotal;
  220.             if ($this->baseInfo->getDeliveryFreeAmount()) {
  221.                 if (!$isDeliveryFree[$Cart->getCartKey()] && $this->baseInfo->getDeliveryFreeAmount() <= $ProductTotal) {
  222.                     $isDeliveryFree[$Cart->getCartKey()] = true;
  223.                 } else {
  224.                     $least[$Cart->getCartKey()] = $this->baseInfo->getDeliveryFreeAmount() - $ProductTotal;
  225.                 }
  226.             }
  227.             $CatalogCartKey $Cart->getCartKey();
  228.             /**
  229.              * TODO: モジュール化
  230.              * 予約フラグ
  231.              */
  232.             foreach ($Cart->getCartItems() as $item) {
  233.                 //
  234.                 $janId $item->getProductClass()->getId();
  235.                 //
  236.                 if ($hoge $this->GoodsService->getGoodsReservation(nullnull$janId)) {
  237.                     //
  238.                     $isYoyaku true;
  239.                     break;
  240.                 }
  241.             }
  242.         }
  243.         $LargeDiscountRitu $this->EstimateCharacterizer->SetLargeDiscount($ProductTotal);
  244.         $LargeDiscount     $this->EstimateCharacterizer->GetLargeDiscount();
  245.         // Campaign discount already computed inside SetEstimateOption flow; fetch totals
  246.         $CampaignDiscount  method_exists($this->EstimateCharacterizer'GetCampaignDiscount') ? $this->EstimateCharacterizer->GetCampaignDiscount() : 0;
  247.         $CampaignDetails   method_exists($this->EstimateCharacterizer'GetCampaignDetails') ? $this->EstimateCharacterizer->GetCampaignDetails() : [];
  248.         // Filter campaign details by product type count (ProductClass.code)
  249.         if (!empty($CampaignDetails)) {
  250.             $uniqueProductCodes = [];
  251.             foreach ($this->cartService->getCarts() as $cart) {
  252.                 foreach ($cart->getCartItems() as $cartItem) {
  253.                     $pc $cartItem->getProductClass();
  254.                     if ($pc && $pc->getCode()) {
  255.                         $uniqueProductCodes[$pc->getCode()] = true;
  256.                     }
  257.                 }
  258.             }
  259.             $uniqueProductCount count($uniqueProductCodes);
  260.             $filteredDetails = [];
  261.             $filteredDiscount 0;
  262.             
  263.             // Check if yoridori campaign badge is displayed
  264.             // If there are >= 2 unique products and yoridori campaign exists in CampaignDetails,
  265.             // then yoridori badge is displayed (even if amount = 0, as it may not meet quantity requirement yet)
  266.             // Also check directly from cart items to handle cases where yoridori is not in CampaignDetails yet
  267.             $hasYoridoriBadgeDisplayed false;
  268.             if ($uniqueProductCount >= 2) {
  269.                 // First check if yoridori exists in CampaignDetails (simpler check)
  270.                 foreach ($CampaignDetails as $detail) {
  271.                     $type = (int)($detail['type'] ?? 0);
  272.                     if ($type === 1) {
  273.                         $hasYoridoriBadgeDisplayed true;
  274.                         break;
  275.                     }
  276.                 }
  277.                 
  278.                 // If not found in CampaignDetails, check directly from cart items
  279.                 // (yoridori may not be in CampaignDetails if it doesn't meet quantity requirement yet)
  280.                 if (!$hasYoridoriBadgeDisplayed) {
  281.                     $sqlService = new \Lm\Service\Db\SqlService();
  282.                     $yoridoriCampaignProductCodes = []; // campaign_id => [productCode => true]
  283.                     
  284.                     // Get all yoridori campaign_ids and their product codes
  285.                     foreach ($this->cartService->getCarts() as $cart) {
  286.                         foreach ($cart->getCartItems() as $cartItem) {
  287.                             $pc $cartItem->getProductClass();
  288.                             if (!$pc || !$pc->getCode()) { continue; }
  289.                             
  290.                             $product $pc->getProduct();
  291.                             if (!$product) { continue; }
  292.                             
  293.                             $goodsId $product->getId();
  294.                             $goodsData $sqlService
  295.                                 ->Table('goods_table')
  296.                                 ->Where('goods_id = :goods_id')
  297.                                 ->Param(':goods_id'$goodsId)
  298.                                 ->Find();
  299.                             
  300.                             if ($goodsData && (int)($goodsData['campaign_yoridori'] ?? 0) === 1) {
  301.                                 $goodsHinban trim($goodsData['goods_canonical_hinban'] ?? '');
  302.                                 
  303.                                 // Find yoridori campaigns that match this product
  304.                                 $now = (new \DateTime())->format('Y-m-d H:i:s');
  305.                                 $campaigns $sqlService
  306.                                     ->Table('campaign_table')
  307.                                     ->Where('campaign_ddate IS NULL')
  308.                                     ->Where('campaign_type = 1')
  309.                                     ->Where('campaign_start <= :now')
  310.                                     ->Where('campaign_end >= :now')
  311.                                     ->Where('goods_canonical_hinban IS NOT NULL')
  312.                                     ->Param(':now'$now)
  313.                                     ->FindAll();
  314.                                 
  315.                                 foreach ($campaigns as $campaign) {
  316.                                     $campaignHinbans trim($campaign['goods_canonical_hinban'] ?? '');
  317.                                     $campaignId = (int)($campaign['campaign_id'] ?? 0);
  318.                                     
  319.                                     if ($campaignId 0) {
  320.                                         $shouldInclude false;
  321.                                         if (empty($campaignHinbans)) {
  322.                                             $shouldInclude true;
  323.                                         } elseif (!empty($goodsHinban)) {
  324.                                             $hinbanList array_filter(array_map('trim'explode(','$campaignHinbans)), function ($v) {
  325.                                                 return $v !== '';
  326.                                             });
  327.                                             if (in_array($goodsHinban$hinbanListtrue)) {
  328.                                                 $shouldInclude true;
  329.                                             }
  330.                                         }
  331.                                         
  332.                                         if ($shouldInclude) {
  333.                                             if (!isset($yoridoriCampaignProductCodes[$campaignId])) {
  334.                                                 $yoridoriCampaignProductCodes[$campaignId] = [];
  335.                                             }
  336.                                             $yoridoriCampaignProductCodes[$campaignId][$pc->getCode()] = true;
  337.                                         }
  338.                                     }
  339.                                 }
  340.                             }
  341.                         }
  342.                     }
  343.                     
  344.                     // Check if any yoridori campaign has >= 2 distinct products
  345.                     foreach ($yoridoriCampaignProductCodes as $campaignId => $productCodes) {
  346.                         if (count($productCodes) >= 2) {
  347.                             $hasYoridoriBadgeDisplayed true;
  348.                             break;
  349.                         }
  350.                     }
  351.                 }
  352.             }
  353.             
  354.             // Get product codes that have yoridori applied (for >= 2 distinct products with same campaign_id)
  355.             $yoridoriAppliedProductCodes = [];
  356.             if ($hasYoridoriBadgeDisplayed && $uniqueProductCount >= 2) {
  357.                 $sqlService = new \Lm\Service\Db\SqlService();
  358.                 $yoridoriCampaignProductCodes = []; // campaign_id => [productCode => true]
  359.                 
  360.                 // Get all yoridori campaign_ids and their product codes
  361.                 foreach ($this->cartService->getCarts() as $cart) {
  362.                     foreach ($cart->getCartItems() as $cartItem) {
  363.                         $pc $cartItem->getProductClass();
  364.                         if (!$pc || !$pc->getCode()) { continue; }
  365.                         
  366.                         $product $pc->getProduct();
  367.                         if (!$product) { continue; }
  368.                         
  369.                         $goodsId $product->getId();
  370.                         $goodsData $sqlService
  371.                             ->Table('goods_table')
  372.                             ->Where('goods_id = :goods_id')
  373.                             ->Param(':goods_id'$goodsId)
  374.                             ->Find();
  375.                         
  376.                         if ($goodsData && (int)($goodsData['campaign_yoridori'] ?? 0) === 1) {
  377.                             $goodsHinban trim($goodsData['goods_canonical_hinban'] ?? '');
  378.                             
  379.                             // Find yoridori campaigns that match this product
  380.                             $now = (new \DateTime())->format('Y-m-d H:i:s');
  381.                             $campaigns $sqlService
  382.                                 ->Table('campaign_table')
  383.                                 ->Where('campaign_ddate IS NULL')
  384.                                 ->Where('campaign_type = 1')
  385.                                 ->Where('campaign_start <= :now')
  386.                                 ->Where('campaign_end >= :now')
  387.                                 ->Where('goods_canonical_hinban IS NOT NULL')
  388.                                 ->Param(':now'$now)
  389.                                 ->FindAll();
  390.                             
  391.                             foreach ($campaigns as $campaign) {
  392.                                 $campaignHinbans trim($campaign['goods_canonical_hinban'] ?? '');
  393.                                 $campaignId = (int)($campaign['campaign_id'] ?? 0);
  394.                                 
  395.                                 if ($campaignId 0) {
  396.                                     $shouldInclude false;
  397.                                     if (empty($campaignHinbans)) {
  398.                                         $shouldInclude true;
  399.                                     } elseif (!empty($goodsHinban)) {
  400.                                         $hinbanList array_filter(array_map('trim'explode(','$campaignHinbans)), function ($v) {
  401.                                             return $v !== '';
  402.                                         });
  403.                                         if (in_array($goodsHinban$hinbanListtrue)) {
  404.                                             $shouldInclude true;
  405.                                         }
  406.                                     }
  407.                                     
  408.                                     if ($shouldInclude) {
  409.                                         if (!isset($yoridoriCampaignProductCodes[$campaignId])) {
  410.                                             $yoridoriCampaignProductCodes[$campaignId] = [];
  411.                                         }
  412.                                         $yoridoriCampaignProductCodes[$campaignId][$pc->getCode()] = true;
  413.                                     }
  414.                                 }
  415.                             }
  416.                         }
  417.                     }
  418.                 }
  419.                 
  420.                 // Collect product codes that have yoridori applied (>= 2 distinct products with same campaign_id)
  421.                 foreach ($yoridoriCampaignProductCodes as $campaignId => $productCodes) {
  422.                     if (count($productCodes) >= 2) {
  423.                         foreach ($productCodes as $productCode => $_) {
  424.                             $yoridoriAppliedProductCodes[$productCode] = true;
  425.                         }
  426.                     }
  427.                 }
  428.             }
  429.             
  430.             $matomeGrouped = [];
  431.             foreach ($CampaignDetails as $detail) {
  432.                 $type = (int)($detail['type'] ?? 0);
  433.                 $amount = (int)($detail['amount'] ?? 0);
  434.                 // Filter yoridori campaign when unique product count < 2
  435.                 if ($uniqueProductCount && $type === 1) { continue; }
  436.                 // Only include campaigns with amount > 0
  437.                 if ($amount <= 0) { continue; }
  438.                 // まとめ割は商品別内訳を1行に集約表示する
  439.                 if ($type === 2) {
  440.                     $name = (string)($detail['name'] ?? '');
  441.                     // Remove optional leading [product-code] prefix if present.
  442.                     $normalizedName preg_replace('/^\s*\[[^\]]+\]\s*/u'''$name);
  443.                     $detail['name'] = $normalizedName;
  444.                     $groupKey implode('|', [
  445.                         (string)($detail['id'] ?? ''),
  446.                         $normalizedName,
  447.                         (string)($detail['min'] ?? 0),
  448.                         (string)($detail['percent'] ?? 0),
  449.                     ]);
  450.                     if (!isset($matomeGrouped[$groupKey])) {
  451.                         $matomeGrouped[$groupKey] = $detail;
  452.                         $matomeGrouped[$groupKey]['amount'] = 0;
  453.                     }
  454.                     $matomeGrouped[$groupKey]['amount'] += $amount;
  455.                     continue;
  456.                 }
  457.                 $filteredDetails[] = $detail;
  458.                 $filteredDiscount += $amount;
  459.             }
  460.             // append grouped matome campaigns
  461.             foreach ($matomeGrouped as $grouped) {
  462.                 $filteredDetails[] = $grouped;
  463.                 $filteredDiscount += (int)($grouped['amount'] ?? 0);
  464.             }
  465.             $CampaignDetails $filteredDetails;
  466.             $CampaignDiscount $filteredDiscount;
  467.         }
  468.         // カートが分割された時のセッション情報を削除
  469.         $request->getSession()->remove(OrderHelper::SESSION_CART_DIVIDE_FLAG);
  470.         list($CatalogDAta$CatalogCategoryLabel) = $this->GetCatalogData();
  471.         switch ($this->cartService->getCartType()) {
  472.             case CartService::CartTypeCatalog:
  473.                 $catalogOrderList $this->CommonService->GetLmOrderOption(CommonService::Lm_Option_Catalog);
  474.                 $totalQuantity is_array($catalogOrderList) ? count($catalogOrderList) : 0;
  475.                 $Title 'front.cart_catalog.title';
  476.                 $Twig 'Cart/Catalog.twig';
  477.                 break;
  478.             default:
  479.                 $Title 'front.cart.title';
  480.                 $Twig 'Cart/index.twig';
  481.                 break;
  482.         }
  483.         $Title trans($Title);
  484.         //LM仕様の商品表示順
  485.         $this->cartService->getLmCartItems();
  486.         // Get recent item
  487.         $cookies $this->RecentGoodsService->getRecentView();
  488.         $recentviews = array();
  489.         if (!empty($cookies)) {
  490.             $recentviews $this->RecentGoodsService->LM_getRecentViews2($cookies);
  491.         }
  492.         //
  493.         foreach ($this->cartService->getCarts() as $cart) {
  494.             foreach ($cart->getCartItems() as $cartItem) {
  495.                 //
  496.                 $id $cartItem->getProductClass()->getProduct()->getId();
  497.                 $quantity $cartItem->getQuantity();
  498.                 //
  499.                 $this->dataLayer['ydn']['yahoo_retargeting_items'][] = $this->CommonService->get_yahoo_retargeting_item($id$quantity);
  500.                 $this->dataLayer['criteo']['item'][] = [
  501.                     'id' => $id,
  502.                     'price' => $cartItem->getPriceIncTax(),
  503.                     'quantity' => $quantity,
  504.                 ];
  505.             }
  506.         }
  507.         // 在庫切れの商品が含まれていないかの確認用フラグ
  508.         $isItemsStockAvailable $this->cartService->isItemsStockAvailable();
  509.         if ($request->get('from_url') == CartService::ROUTE_ADD_REPEAT) {
  510.             $listSusoageChange = [];
  511.         } else {
  512.             $listSusoageChange $this->cartService->listSusoageChange();
  513.         }
  514.         //
  515.         return
  516.             $this->render($Twig, [
  517.                 'totalPrice' => $ProductTotal $LargeDiscount $CampaignDiscount,
  518.                 'totalQuantity' => $totalQuantity,
  519.                 // 空のカートを削除し取得し直す
  520.                 'Carts' => $this->cartService->getCarts(true),
  521.                 'least' => $least,
  522.                 'is_delivery_free' => $isDeliveryFree,
  523.                 'title' => $Title,
  524.                 'h1_comment' => "{$this->baseInfo->getShopName()}{$Title}",
  525.                 'CatalogData' => $CatalogDAta,
  526.                 'CatalogCategoryLabel' => $CatalogCategoryLabel,
  527.                 'CatalogCartKey' => $CatalogCartKey,
  528.                 'SubWindoWData' => $this->CommonService->GetYaml('CatalogSubWindow.yaml'),
  529.                 'EstimateOptions' => $EstimateOptions,
  530.                 'EstimateTotla'   => $EstimatetTotal,
  531.                 'ProductTotal'    => $ProductTotal,
  532.                 'LargeDiscount'   => $LargeDiscount,
  533.                 'CampaignDiscount'=> $CampaignDiscount,
  534.                 'CampaignDetails' => $CampaignDetails,
  535.                 'LargeDiscountRitu'=>$LargeDiscountRitu,
  536.                 'BreadCrumbs' =>[],
  537.                 'RepartData' =>$this->CommonService->GetLmOrderOption('repeat'),
  538.                 'isYoyaku' => $isYoyaku,
  539.                 'isMobile' => $this->mobileDetector->isMobile(),
  540.                 'recentviews' => $recentviews,
  541.                 'dataLayer' => $this->dataLayer,
  542.                 'isShowGlobalFooter' => false,
  543.                 'isItemsStockAvailable' => $isItemsStockAvailable,
  544.                 'isSusoageChange' => count($listSusoageChange) > 0,
  545.                 'listSusoageChange' => $listSusoageChange
  546.             ]);
  547.     }
  548.     /**
  549.      * @param $Carts
  550.      *
  551.      * @return \Symfony\Component\HttpFoundation\RedirectResponse|null
  552.      */
  553.     protected function execPurchaseFlow($Carts)
  554.     {
  555.         /** @var PurchaseFlowResult[] $flowResults */
  556.         $flowResults array_map(function ($Cart) {
  557.             $purchaseContext = new PurchaseContext($Cart$this->getUser());
  558.             return $this->purchaseFlow->validate($Cart$purchaseContext);
  559.         }, $Carts);
  560.         // 復旧不可のエラーが発生した場合はカートをクリアして再描画
  561.         $hasError false;
  562.         foreach ($flowResults as $result) {
  563.             if ($result->hasError()) {
  564.                 $hasError true;
  565.                 foreach ($result->getErrors() as $error) {
  566.                     $this->addRequestError($error->getMessage());
  567.                 }
  568.             }
  569.         }
  570.         if ($hasError) {
  571.             $this->cartService->clear();
  572.             return $this->redirectToRoute('cart');
  573.         }
  574.         $this->cartService->save();
  575.         foreach ($flowResults as $index => $result) {
  576.             foreach ($result->getWarning() as $warning) {
  577.                 if ($Carts[$index]->getItems()->count() > 0) {
  578.                     $cart_key $Carts[$index]->getCartKey();
  579.                     $this->addRequestError($warning->getMessage(), "front.cart.${cart_key}");
  580.                 } else {
  581.                     // キーが存在しない場合はグローバルにエラーを表示する
  582.                     $this->addRequestError($warning->getMessage());
  583.                 }
  584.             }
  585.         }
  586.         return null;
  587.     }
  588.     /**
  589.      * カタログのDataを返す
  590.      *
  591.      *
  592.      */
  593.     protected function GetCatalogData()
  594.     {
  595.         if (CartService::CartTypeCatalog != $this->cartService->getCartType()) {
  596.             return [nullnullnull];
  597.         }
  598.         $Catatogs $this->CatalogService->GetCataLog();
  599.         $CatalogCategoryLabel $this->CommonService->GetYaml('catalog_category.yaml');
  600.         return [$Catatogs$CatalogCategoryLabel];
  601.     }
  602.     /**
  603.      * Check if current cart is type 3, 4 when repeat order
  604.      *
  605.      * @Route("/cart/check_mix_cart/", name="check_mix_cart", methods={"POST"} )
  606.      */
  607.     public function CheckMixCart(Request $request)
  608.     {
  609.         $CurrentCartType $this->cartService->GetCartType();
  610.         $showErrorModal $CurrentCartType === CartService::CartTypeSample || $CurrentCartType === CartService::CartTypeCatalog;
  611.         if ($showErrorModal) {
  612.             $this->Errors[] = $this->CommonService->GetExclusionControl(
  613.                 CartService::CartTypeNormal,
  614.                 trans('front.ExclusionControl.repeat_mixed_cart_type_' $CurrentCartType '_warning')
  615.             );
  616.             return $this->json([
  617.                 'status' => 'Error''Errors' => $this->Errors'show_error_modal' => $showErrorModal
  618.             ]);
  619.         } else {
  620.             return $this->json([
  621.                 'status' => 'ok''Errors' => '''show_error_modal' => $showErrorModal
  622.             ]);
  623.         }
  624.     }
  625.     /**
  626.      * カートに商品を追加・変更する
  627.      *
  628.      * @Route("/cart/add_Normal", name=CartService::ROUTE_ADD_NORMAL, methods={"GET","POST"} )
  629.      * @Route("/cart/valid_estimate", name=CartService::ROUTE_VALID_ESTIMATE, methods={"GET","POST"} )
  630.      * @Route("/cart/add_estimate", name=CartService::ROUTE_ADD_ESTIMATE, methods={"GET","POST"} )
  631.      * @Route("/cart/add_sample", name=CartService::ROUTE_ADD_SAMPLE, methods={"GET","POST"} )
  632.      * @Route("/cart/add_catalog", name=CartService::ROUTE_ADD_CATALOG, methods={"GET","POST"} )
  633.      * @Route("/cart/add_line", name=CartService::ROUTE_ADD_LINE, methods={"GET","POST"} )
  634.      * @Route("/cart/add_hybrid", name=CartService::ROUTE_ADD_HYBRID, methods={"GET","POST"} )
  635.      * @Route("/cart/add_repeat", name=CartService::ROUTE_ADD_REPEAT, methods={"GET","POST"} )
  636.       */
  637.     public function AddCart(Request $request)
  638.     {
  639.         $carts $this->cartService->getCarts();
  640.         $UrlName $request->get('_route');
  641.         //
  642.         $goodsId $request->get('goodsId');
  643.         $CartType $this->cartService->GetCartType();
  644.         $ExclusionControl null;
  645.         $showErrorModal false;
  646.         if ($Products $this->cartService->CartItemConv($request->get('product_matrix'))) {
  647.             // セット品番対応
  648.             $Products $this->cartService->convertProductsForSetPurchase($Products);
  649.             // 排他チェック
  650.             if (($checkMixCart $this->cartService->checkMixCart($UrlNamearray_keys($Products))) !== true) {
  651.                 $showErrorModal true;
  652.                 $messageId "front.ExclusionControl.mixed_cart_type_{$checkMixCart[0]}_add_{$checkMixCart[1]}_warning";
  653.                 $messageId.= isset($checkMixCart[2]) ? "_{$checkMixCart[2]}'';
  654.                 $messageId.= isset($checkMixCart[3]) ? "_{$checkMixCart[3]}'';
  655.                 $this->Errors[] = $this->CommonService->GetExclusionControl(
  656.                     CartService::CartTypeNormal,
  657.                     trans($messageId)
  658.                 );
  659.             }
  660.         }
  661. /* 一旦トークンを外す 2022/11/26
  662.         if ('add_catalog' != $UrlName) {
  663.             if ($this->CommonService->GetToken(CommonService::Matrix_Token) != $request->get('OlToken')) {
  664.                 if(in_array($UrlName,self::URL_NANE_SUBMIT)) {
  665.                     throw new NotFoundHttpException();
  666.                 }else{
  667.                    // $Token = $this->CommonService->ResetToken(CommonService::Matrix_Token);
  668.                     return $this->json(['status' => 'Error', 'Error' =>''],400);
  669.                 }
  670.             }
  671.         }
  672. */
  673.         #排他制御解除 カタログ
  674.          if(CartService::CartTypeCatalog == $this->cartService->GetCartType()){
  675.             if(!$this->CommonService->GetLmOrderOption('catalog')){
  676.                 $this->RemoveCart('catalog',null,'return');
  677.             }
  678.         }
  679.        #OrderOption 初期化
  680.         if(!$this->cartService->GetCartType()){
  681.             $this->CommonService->InitializeLmOrderOption();
  682.         }
  683.         $Errors = [];
  684.         $AddProductsFlg self::ADD_PRODUCTS_EACH//2 = オリジナル カートに追加を一気におこなう
  685.         //
  686.         $MaxEstimateId$this->cartService->getMaxEstimateId();
  687.         switch ($UrlName) {
  688.             case CartService::ROUTE_ADD_REPEAT:
  689.                 if(!$LmOrderId $request->get('order_id')){
  690.                     $ExclusionControl CartService::RepeatError01;
  691.                     break;
  692.                 }
  693.                 if(!$Datas $this->OrderConverter->GetCartFromLmOrderId($LmOrderId)){
  694.                     $ExclusionControl CartService::RepeatError01;
  695.                     break;
  696.                 }
  697.                 // 非表示商品のチェック
  698.                 if (!LmHelper::isSecret()) {
  699.                     foreach ($Datas['orderList'] as $index => $order) {
  700.                         if (($goods = new Goods($order['goodsId'])) && $goods->getGoodsStatus() === Goods::GOODS_STATUS_UNAVAIABLE) {
  701.                             //
  702.                             unset($Datas['orderList'][$index]);
  703.                             //
  704.                             $this->addRequestError('現在、ご購入頂けない商品が含まれていましたのでカートから削除しました。'"front.cart");
  705.                         }
  706.                     }
  707.                     $Datas['orderList'] = array_values($Datas['orderList']);
  708.                 }
  709.                 /**
  710.                  * TODO: Revert me.
  711.                  * @var Customer $user
  712.                  * @var int|null $LmOrderId
  713.                  */
  714.                 function _log_20230414_03(Customer $user$LmOrderId) {
  715.                     $lmCustomerId '';
  716.                     if (!empty($user)) {
  717.                         $lmCustomerId $user->getLmCustomerId();
  718.                     }
  719.                     log_info("[LM]/cart/add_repeat/ - \{ \$lmCustoerId: {$lmCustomerId}, \$lmOrderId: {$LmOrderId} \}");
  720.                 }
  721.                 _log_20230414_03($this->CommonService->getUser(), $LmOrderId);
  722.                 $ItemRepeatCartType $this->RepeatCartType($Datas['orderList']);
  723.                 $CurrentCartType $this->cartService->GetCartType();
  724.                 $filterRepeatOrderTypeEstimate array_filter($Datas['orderList'], function ($item) {
  725.                     return !empty($item['Options']);
  726.                 });
  727.                 if ($CurrentCartType == CartService::CartTypeSample || $CurrentCartType == CartService::CartTypeCatalog) {
  728.                     $ExclusionControl CartService::RepeatError03;
  729.                     break;
  730.                 }
  731.                 $CartType = ($ItemRepeatCartType == CartService::CartTypeEstimate ||
  732.                     $CurrentCartType == CartService::CartTypeEstimate) ?
  733.                     CartService::CartTypeEstimate :
  734.                     CartService::CartTypeNormal;
  735.                 $AddProductsFlg self::ADD_PRODUCTS_REPEAT;
  736.                 #カートタイプの登録
  737.                 $this->cartService->SetCartType($CartType);
  738.                 $this->CommonService->AddLmOrderOption('repeat',['ohid'=>$Datas['ohId']]);
  739.              break;
  740.             case CartService::ROUTE_ADD_LINE:
  741.                 $AddProductsFlg self::ADD_PRODUCTS_BULK;
  742.                 if ($Data $request->get('CartItem')) {
  743.                     list($Products$Errors) = $this->cartService->AddCartLine($Data);
  744.                     if (count($Errors) > 0) {
  745.                         foreach ($Errors as $Id => $ErrorId) {
  746.                             $this->SetCartError($ErrorId$Id);
  747.                         }
  748.                     }
  749.                     if ($CartType == CartService::CartTypeSample) {
  750.                         $this->SetSampleItemMax($Productsfalse);
  751.                     }
  752.                     $this->AddCartValidation($Products,$this->cartService->GetCartType() ,false);
  753.                 } else {
  754.                     $this->SetCartError(12);
  755.                 }
  756.                 break;
  757.             case CartService::ROUTE_ADD_CATALOG:
  758.                 $layoutId $this->mobileDetector->isMobile() ? 30 29;
  759.                 $em $this->Container->get('doctrine.orm.entity_manager');
  760.                 $Layout $em->getRepository(Layout::class)->find($layoutId);
  761.                 $this->Twig->addGlobal('Layout'$Layout);
  762.                 if ($this->cartService->getCartType()) {
  763.                     if (CartService::CartTypeCatalog != $this->cartService->getCartType()) {
  764.                         $ExclusionControl CartService::CartTypeCatalog;
  765.                         break;
  766.                     }
  767.                 }
  768.                 // 一旦 全てのカート商品を削除する
  769.                 $this->cartService->clear();
  770.                 #カートタイプの設定
  771.                 $this->cartService->SetCartType(CartService::CartTypeCatalog);
  772.                 $this->Products[$this->CommonService->GetConfig('CatalogProdctClassId')] = 1;
  773.                 break;
  774.             case CartService::ROUTE_ADD_SAMPLE:
  775.                 if ($this->cartService->getCartType()) {
  776.                     if (CartService::CartTypeSample != $this->cartService->getCartType()) {
  777.                         $cartType $this->cartService->getCartType();
  778.                         $showErrorModal true;
  779.                         $this->Errors[] = $this->CommonService->GetExclusionControl(
  780.                             CartService::CartTypeNormal,
  781.                             trans('front.ExclusionControl.mixed_cart_type_' $cartType '_add_' CartService::CartTypeSample '_warning')
  782.                         );
  783.                         break;
  784.                     }
  785.                 }
  786.                 #カートタイプの設定
  787.                 $this->cartService->SetCartType(CartService::CartTypeSample);
  788.                 $this->AddCartValidation($Products,CartService::CartTypeSample);
  789.                 $this->SetSampleItemMax($Products);
  790.                 break;
  791.             case CartService::ROUTE_VALID_ESTIMATE:
  792.                 if ($this->cartService->getCartType()) {
  793.                     if (CartService::CartTypeSample <= $this->cartService->getCartType()) {
  794.                         $cartType $this->cartService->getCartType();
  795.                         $showErrorModal true;
  796.                         $this->Errors[] = $this->CommonService->GetExclusionControl(
  797.                             CartService::CartTypeNormal,
  798.                             trans('front.ExclusionControl.mixed_cart_type_' $cartType '_add_' CartService::CartTypeEstimate '_warning')
  799.                         );
  800.                         break;
  801.                     }
  802.                 }
  803.                 $AddProductsFlg self::ADD_PRODUCTS_NONE#登録を行わない
  804.                 $this->AddCartValidation($Products,$this->cartService->getCartType());
  805.                 break;
  806.             case CartService::ROUTE_ADD_ESTIMATE:
  807.                 if ($this->cartService->getCartType()) {
  808.                     if (CartService::CartTypeSample <= $this->cartService->getCartType()) {
  809.                         $ExclusionControl CartService::CartTypeEstimate;
  810.                         break;
  811.                     }
  812.                 }
  813.                 $this->cartService->SetCartType(CartService::CartTypeEstimate);
  814.                 $this->cartService->SetEstimates($request->get('estimate'));
  815.                 $this->AddCartValidation($Products,$this->cartService->getCartType());
  816.                 break;
  817.             case CartService::ROUTE_ADD_HYBRID:
  818.                 if ($this->cartService->getCartType()) {
  819.                     if (CartService::CartTypeSample <= $this->cartService->getCartType()) {
  820.                         $ExclusionControl CartService::CartTypeEstimate;
  821.                         break;
  822.                     }
  823.                 }
  824.                 $AddProductsFlg self::ADD_PRODUCTS_NONE;
  825.                 $Hybrid $request->get('Hybrid');
  826.                 if ($CasrtItemIds $Hybrid['cart_item_ids'] ?? null) {
  827.                     $this->cartService->SetCartType(CartService::CartTypeEstimate);
  828.                     $this->cartService->SetEstimates($request->get('estimate'));
  829.                     $this->cartService->setPreOrderId(null);
  830.                     $this->cartService->SetHybrid($CasrtItemIds);
  831.                 }
  832.                 break;
  833.             case CartService::ROUTE_ADD_NORMAL:
  834.             default:
  835.                 if ($this->cartService->getCartType()) {
  836.                     if (CartService::CartTypeSample <= $this->cartService->getCartType()) {
  837.                         $cartType $this->cartService->getCartType();
  838.                         $showErrorModal true;
  839.                         $this->Errors[] = $this->CommonService->GetExclusionControl(
  840.                             CartService::CartTypeNormal,
  841.                             trans('front.ExclusionControl.mixed_cart_type_' $cartType '_add_' CartService::CartTypeNormal '_warning')
  842.                         );
  843.                         break;
  844.                     }
  845.                 }
  846.                 #カートタイプの設定
  847.                 if ($this->cartService->getCartType() == CartService::CartTypeEstimate) {
  848.                     $this->cartService->SetCartType(CartService::CartTypeComposite);
  849.                 } else {
  850.                     $this->cartService->SetCartType(CartService::CartTypeNormal);
  851.                 }
  852.                 //
  853.                 $cartItemIds = [];
  854.                 $cartItems $this->cartService->getAllCartsItems();
  855.                 if ($cartItems) {
  856.                     foreach ($cartItems as $cartItem) {
  857.                         $cartItemIds[] = $cartItem->getProductClass()->getId();
  858.                     }
  859.                 }
  860.                 if (!empty($goodsId)) {
  861.                     $goods = new GoodsWithRelated($goodsId);
  862.                     if ($goods->isGoodsSetPurchase()) {
  863.                         $productKeys array_keys($Products);
  864.                         $allKeysExist true;
  865.                         foreach ($productKeys as $key) {
  866.                             if (!in_array($key$cartItemIds)) {
  867.                                 $allKeysExist false;
  868.                                 break;
  869.                             }
  870.                         }
  871.                         if (!$allKeysExist) {
  872.                             $MaxEstimateId++;
  873.                         }
  874.                         $this->cartService->SetEstimateId($MaxEstimateId);
  875.                     }
  876.                 }
  877.                 $this->AddCartValidation($ProductsCartService::CartTypeNormal);
  878.                 break;
  879.         }
  880.         /** 排他モード */
  881.         if ($ExclusionControl) {
  882.             $this->session->set(CartService::Session_ExclusionControlFlg$ExclusionControl);
  883.             if(in_array($UrlName,self::URL_NANE_SUBMIT)) {
  884.                 return $this->redirectToRoute('cart');
  885.             }else{
  886.                 return $this->json(['status' => 'Error''Error' =>'排他制御エラーカートにリダイレクトしてください。'],400);
  887.             }
  888.         }
  889.         //$this->Errors[] = ['errid' => 1, 'message' => $AddProductsFlg ];
  890.         #エラーがある
  891.         if (count($this->Errors) > 0) {
  892.             $Token $this->CommonService->ResetToken(CommonService::Matrix_Token);
  893.             return $this->json([
  894.                 'status' => 'Error''OlToken' => $Token'Errors' => $this->Errors'show_error_modal' => $showErrorModal
  895.             ]);
  896.         }
  897.         try {
  898.             log_info("----AddProductsFlg: "$AddProductsFlg " Cart: ", [
  899.                 "CartType" => $this->cartService->GetCartType(),
  900.                 "request" => $request->request->all()
  901.             ]);
  902.         } catch (\Exception $exception) {
  903.             log_error("cart_error:AddProductsFlg " $exception->getMessage());
  904.         }
  905.         # EC-CUBE のデフォルトでは iSKU ごとの登録ですが 一挙に登録します
  906.         switch ($AddProductsFlg) {
  907.             case self::ADD_PRODUCTS_REPEAT:
  908.                 foreach ($Datas['orderList'] as $Data) {
  909.                     #見積もりシミュレーションの初期化
  910.                     $this->cartService->InitiarizeEstimate();
  911.                     $this->SetProduct($Data['Products']);
  912.                     if (count($Data['Options']) > 0) {
  913.                         $Options $Data['Options'][0] ?? $Data['Options'];
  914.                         $Options['repeat'] = $Datas['ohId'];
  915.                         $Options['product_class_id'] = array_key_first($this->Products);
  916.                         $this->cartService->SetEstimates($Options);
  917.                     }
  918.                     $MaxEstimateId++;
  919.                     $this->cartService->SetEstimateId($MaxEstimateId);
  920.                     $this->cartService->AddCartProduct($this->Products);
  921.                     $this->cartService->UpRepeatEstimateOption();
  922.                     $this->handleDispathEventAddProductToCart($Data['Products'], $Data['goodsId']);
  923.                 }
  924.                 break;
  925.             case self::ADD_PRODUCTS_BULK:
  926.                 $this->cartService->AddProducts();
  927.                 $this->cartService->save();
  928.                 $this->cartService->UpEstimateOption();
  929.                 break;
  930.             case self::ADD_PRODUCTS_EACH;
  931.                 #一つづつカートへ追加
  932.                 $this->cartService->AddCartProduct($this->Products);
  933.                /*foreach ($this->Products as $ClassId => $Quantity) {
  934.                     if (!$Quantity) {
  935.                         continue;
  936.                     }
  937.                     $ProductClass = $this->cartService->GetProductClass($ClassId) ?? $ClassId;
  938.                     $this->cartService->addProduct($ProductClass, $Quantity);
  939.                 }
  940.                 $this->cartService->save();*/
  941.                 break;
  942.         }
  943.         $this->session->set(LmEvents::SESSION_FRONT_PRODUCT_CARTtrue);
  944.         // use screen detail block matrix
  945.         if (!empty($goodsId)) {
  946.             $this->handleDispathEventAddProductToCart($Products$goodsId);
  947.         }
  948.         //
  949.         if ($returnUrl $request->get('returnUrl')) {
  950.             $this->session->set('referer'$returnUrl);
  951.         }
  952.         if ($UrlName === CartService::ROUTE_ADD_CATALOG) {
  953.             return $this->index($request);
  954.         } else if(in_array($UrlName,self::URL_NANE_SUBMIT)) {
  955.             return $this->redirectToRoute('cart', ['from_url' => $UrlName]);
  956.         }
  957.         $Token $this->CommonService->ResetToken(CommonService::Matrix_Token);
  958.         return $this->json(['status' => 'OK''data' => $Products'OlToken' => $Token]);
  959.     }
  960.     /**
  961.      * カートを削除する
  962.      *
  963.      * @Route("/cart/remove/{mode}/{Token}/{id}", name="remove_cart_item", methods={"GET"}, requirements={"mode" = "[a-z]+","Token" = "\w+","id" = "\d+"  })
  964.      */
  965.     public function RemoveCart($mode null$Token null$id null)
  966.     {
  967.         if (is_null($mode)) {
  968.             throw new NotFoundHttpException();
  969.         }
  970.         if (!$mode == 'all') {
  971.             if ($this->CommonService->GetToken(CommonService::RemoveCartItme) != $Token) {
  972.                 throw new NotFoundHttpException();
  973.             }
  974.             $this->CommonService->RemoveToken(CommonService::RemoveCartItme);
  975.         }
  976.         $Url 'homepage';
  977.         switch ($mode) {
  978.             case 'item':
  979.                 $cart $this->cartService->getCart();
  980.                 if (!empty($cart)) {
  981.                     foreach($cart->getItems() as $item ) {
  982.                         if ($item->getId() == $id) {
  983.                             $productId $item->getProductClass()->getProduct()->getId();
  984.                             $janId$item->getProductClass()->getId();
  985.                             $event = new EventArgs([
  986.                                 'deleted_item_id' => $productId,
  987.                                 'deleted_item_sku_id' => $janId
  988.                             ]);
  989.                             $this->eventDispatcher->dispatch($event,LmEvents::SESSION_FRONT_PRODUCT_CART_DELETE_PRODUCT );
  990.                             $this->session->set(LmEvents::SESSION_FRONT_PRODUCT_CARTtrue);
  991.                         }
  992.                     }
  993.                 }
  994.                 $this->cartService
  995.                     ->RemoveItem($id# $Param = CartItem ItemId
  996.                     ->UpEstimateOption()
  997.                 ;
  998.                 $Url 'cart';
  999.                 break;
  1000.             case 'all':
  1001.                 $Url 'cart';
  1002.             case 'catalog':
  1003.                 //全てのカート商品を削除する
  1004.                 $this->cartService->clear();
  1005.                 //LmOrderOption の削除
  1006.                 $this->CommonService->InitializeLmOrderOption();
  1007.                 if ($id=='return'){
  1008.                     return [];
  1009.                 }
  1010.                 break;
  1011.         }
  1012.         return $this->redirectToRoute($Url);
  1013.     }
  1014.     /**
  1015.      * カートをロック状態に設定し、購入確認画面へ遷移する.
  1016.      *
  1017.      * @Route("/cart/buystep/{cart_key}", name="cart_buystep", requirements={"cart_key" = "[a-zA-Z0-9]+[_][\x20-\x7E]+"}, methods={"POST","GET"})
  1018.      */
  1019.     public function buystep(Request $request$cart_key)
  1020.     {
  1021.         $Carts $this->cartService->getCart();
  1022.         if (!is_object($Carts)) {
  1023.             return $this->redirectToRoute('cart');
  1024.         }
  1025.         // FRONT_CART_BUYSTEP_INITIALIZE
  1026.         $event = new EventArgs(
  1027.             [],
  1028.             $request
  1029.         );
  1030.         $this->eventDispatcher->dispatch($event,EccubeEvents::FRONT_CART_BUYSTEP_INITIALIZE );
  1031.         #202203/31 カタログを追加する
  1032.         if (CartService::CartTypeCatalog == $Carts->getCartType()) {
  1033.             // CSRFトークンの検査
  1034.             if (empty($token $request->get('OlToken')) || ($token !== $this->CommonService->GetToken('catalog'))) {
  1035.                 //
  1036.                 throw new AccessDeniedHttpException('[LM]CSRF token is invalid.');
  1037.             }
  1038.             //
  1039.             $this->CommonService->RequestLmOrderOption();
  1040.             $options $this->CommonService->GetLmOrderOption();
  1041.             if (empty($options)) {
  1042.                 return $this->redirectToRoute('cart', ['from_url' => 'add_catalog']);
  1043.             }
  1044.         }
  1045.         $this->cartService->SetCartType($Carts->getCartType());
  1046.         $this->cartService->setPrimary($cart_key);
  1047.         $this->cartService->save();
  1048.         // FRONT_CART_BUYSTEP_COMPLETE
  1049.         $event = new EventArgs(
  1050.             [],
  1051.             $request
  1052.         );
  1053.         $this->eventDispatcher->dispatch($event,EccubeEvents::FRONT_CART_BUYSTEP_COMPLETE);
  1054.         if ($event->hasResponse()) {
  1055.             return $event->getResponse();
  1056.         }
  1057.         return $this->redirectToRoute($request->get('next_step''shopping'));
  1058.     }
  1059.     /**
  1060.      * ポップアップ詳細見出し
  1061.      * /catalog/detail/{id}
  1062.      * ポップアップ詳細見出し catalog_detail_headline
  1063.      *
  1064.      * @Route("/catalog/detail/{id}/", name="catalog_ditail", methods={"GET"},requirements={"id" = "\d+"}))
  1065.      * @Template("Cart/CatalogDetail.twig")
  1066.      */
  1067.     public function CatalogDitail(Request $request$id null)
  1068.     {
  1069.         $Data $this->CatalogService->GetCatalog(['id' => $id]);
  1070.         if($Data && isset($Data['catalog_detail_uploaded_image_list'])){
  1071.             $Data['image_lists'] = json_decode($Data['catalog_detail_uploaded_image_list'], true);
  1072.         }else{
  1073.             $Data['image_lists'] = null;
  1074.         }
  1075.         return [
  1076.             'Data' => $Data,
  1077.             'SubWindoWData' => $this->CommonService->GetYaml('CatalogSubWindow.yaml'),
  1078.         ];
  1079.     }
  1080.     /**
  1081.      * エラーを返す
  1082.      * 1 X個以上
  1083.      * 2 既にカートにある
  1084.      * 3 在庫なし
  1085.      * 4 数字以外
  1086.      * 5 商品が削除されている
  1087.      * 6 サンプルは1個までです
  1088.      * 7 サンプルカートにある
  1089.      * 8 個数を入れてくださお
  1090.      * 0 11 サンプルMAX 
  1091.      * 0 12 数量が入っていない
  1092.      * 0 13 DATAが確認できないDATAあります
  1093.      * 0 14 変更するDATAがありません。
  1094.      */
  1095.     public function AddCartValidation($Products$CartType ,$Flg true)
  1096.     {
  1097.         if (!is_array($Products)) {
  1098.             return $this->SetCartError(14);
  1099.         }
  1100.         if (count($Products) < 1) {
  1101.             return $this->SetCartError(14);
  1102.         }
  1103.         $Limit $CartType == CartService::CartTypeSample $this->CommonService->GetConfig('SampleLimit') : null;
  1104.         #オブジェクトからエラーIDを取得する
  1105.         $SetError = function ($ClassId$Error) {
  1106.             if ($Error->count() < 1) {
  1107.                 return null;
  1108.             }
  1109.             return $Error[0]->getMessage();
  1110.         };
  1111.         // 入力チェック
  1112.         foreach ($Products as $ClassId => $Quantity) {
  1113.             $this->ItemNum++;
  1114.             $this->Products[$ClassId] = $Quantity;
  1115.             if (!$ProductClass $this->cartService->GetProductClass($ClassId)) {
  1116.                 $this->SetCartError(5);
  1117.             } else {
  1118.                 $ClassCategory1 $ProductClass->getClassCategory1();
  1119.                 if ($ClassCategory1 && !$ClassCategory1->isVisible()) {
  1120.                     $this->SetCartError(5);
  1121.                 } else {
  1122.                     $ClassCategory2 $ProductClass->getClassCategory2();
  1123.                     if ($ClassCategory2 && !$ClassCategory2->isVisible()) {
  1124.                         $this->SetCartError(5);;
  1125.                     }
  1126.                 }
  1127.             }//Classの検証
  1128.             if ($ErrId $SetError($ClassId$this->Validator->validate(
  1129.                 $Quantity,
  1130.                 [
  1131.                     new Assert\Quantity(['ClassId' => $ClassId,
  1132.                         'Limit' => $Limit,
  1133.                         'StockLimit' => $this->CommonService->GetConfig('Stocklimit'),
  1134.                         'Flg' => $Flg,
  1135.                         'CartType' => $CartType,
  1136.                     ])
  1137.                 ]
  1138.             ))
  1139.             ) {
  1140.                 $this->SetCartError($ErrId$ClassId$ProductClass$Flg);
  1141.             }//ヴァり
  1142.         }
  1143.         return;
  1144.     }
  1145.     /**
  1146.      * @param int error id
  1147.      * @param int product_class_id
  1148.      *
  1149.      * @return string ErrorMessage
  1150.      */
  1151.     protected function SetCartError($ErrId$ClassId 0$Class null$Flg false$MessageParams = [])
  1152.     {
  1153.         $ClassName '';
  1154.         if ($Flg) {
  1155.             $Name1 '';
  1156.             $Name2 '';
  1157.             if ($Class) {
  1158.                 if ($Classcategory1 $Class->getClassCategory1()){
  1159.                     $Name1 $Classcategory1->getName();
  1160.                 }
  1161.                 if ($Classcategory2 $Class->getClassCategory2()){
  1162.                     $Name2 $Classcategory2->getName();
  1163.                 }
  1164.                 $ClassName $Name1  ':' $Name2   ' ';
  1165.             }
  1166.         }
  1167.         $Msg sprintf(self::CartErrorMessage$ErrId);
  1168.         $Msg trans($Msg$MessageParams);
  1169.         $Msg $this->CommonService->BaseInfo($Msg);
  1170.         $Msg $ClassName $Msg;
  1171.         switch ($ErrId) {
  1172.             case :
  1173.                 $Msg .= ' ClassId=' $ClassId;
  1174.                 break;
  1175.         }
  1176.         $this->Errors[] = ['errid' => $ErrId'message' => $Msg'class_id' => $ClassId'add_lines' => $this->cartService->getAddlines($ClassId)];
  1177.     }
  1178.     protected function SetProduct($Products){
  1179.         $this->Products null;
  1180.         foreach ($Products as $Product){
  1181.             $this->Products[$Product['product_class_id']] = $Product['quantity'];
  1182.         }
  1183.     }
  1184.     protected function RepeatCartType($Datas){
  1185.         $CartType CartService::CartTypeNormal;
  1186.         foreach ($Datas as $i=> $Data){
  1187.             if(count($Data['Options'])>0){
  1188.                 $CartType CartService::CartTypeEstimate;
  1189.             }
  1190.         }
  1191.         return $CartType;
  1192.     }
  1193.     protected function SetSampleItemMax($Products $Flg true)
  1194.     {
  1195.         $CartItemNum 0;
  1196.         if($Flg){
  1197.             foreach ($this->cartService->getCarts() as $Cart) {
  1198.                 $CartItemNum += count($Cart->getCartItems());
  1199.             }
  1200.         }
  1201.         $sampleLimit $this->SampleService->getSampleLimit();
  1202.         if (!$sampleLimit) {
  1203.             return true;
  1204.         }
  1205.         if ($sampleLimit['sl_quantity_limit'] < ($CartItemNum  +  count($Products))) {
  1206.             return $this->SetCartError(150nullfalse, ['%sl_quantity_limit%' => $sampleLimit['sl_quantity_limit']]);
  1207.         }
  1208.         if (!$Customer $this->CommonService->getUser()) {
  1209.             return true;
  1210.         }
  1211.         if ($this->SampleService->getOrderCountAfterPurchase($Customer->getLmCustomerId()) >= $sampleLimit['sl_no_purchase_limit']) {
  1212.             return $this->SetCartError(160nullfalse, ['%sl_no_purchase_limit%' => $sampleLimit['sl_no_purchase_limit']]);
  1213.         }
  1214.         if ($sampleLimit['sl_number_limit'] == 0) {
  1215.             return $this->SetCartError(17);
  1216.         }
  1217.         if ($this->SampleService->getOrderCountOfToday($Customer->getLmCustomerId()) >= $sampleLimit['sl_number_limit']) {
  1218.             return $this->SetCartError(180nullfalse, ['%sl_number_limit%' => $sampleLimit['sl_number_limit']]);
  1219.         }
  1220.     }
  1221.     protected function hasExitedGoodsSusoageOnCurrentCart()
  1222.     {
  1223.         $existSusoage false;
  1224.         foreach ($this->cartService->getCarts() as $Cart) {
  1225.             foreach ($Cart->getCartItems() as $CartItem) {
  1226.                 $ProductCode $CartItem->getProductClass()->getCode();
  1227.                 $GoodsSusoage $this->GoodsService->getGoodsSusoageByHinban($ProductCode);
  1228.                 if ($GoodsSusoage == 1) {
  1229.                     $existSusoage true;
  1230.                     break;
  1231.                 }
  1232.             }
  1233.             if ($existSusoage) {
  1234.                 break;
  1235.             }
  1236.         }
  1237.         return $existSusoage;
  1238.     }
  1239.     protected function hasExitedGoodsSusoageOnRepeatItems(array $orderList)
  1240.     {
  1241.         $existSusoage false;
  1242.         foreach ($orderList as $item) {
  1243.             $GoodsSusoage $this->GoodsService->getGoodsSusoageById($item['goodsId']);
  1244.             if ($GoodsSusoage == 1) {
  1245.                 $existSusoage true;
  1246.                 break;
  1247.             }
  1248.         }
  1249.         return $existSusoage;
  1250.     }
  1251.     /***
  1252.      * Function use to dispath event Add product to Cart
  1253.      *
  1254.      * @param array $products
  1255.      * @param int|null $goodsId
  1256.      * @return void
  1257.      */
  1258.     private function handleDispathEventAddProductToCart(Array $products, ?int $goodsId)
  1259.     {
  1260.         $addedItemSkuId implode(','array_keys($products));
  1261.         $event = new EventArgs([
  1262.             'added_item_id' => $goodsId,
  1263.             'added_item_sku_id' => $addedItemSkuId
  1264.         ]);
  1265.         $this->eventDispatcher->dispatch($event,LmEvents::SESSION_FRONT_PRODUCT_CART_ADD_PRODUCT );
  1266.     }
  1267.     /**
  1268.     * #Route("/cart/remove_cart_items", methods={"DELETE"} )
  1269.     */
  1270.     public function removeCartItems(Request $request)
  1271.     {
  1272.         $cartItems $request->get('cartItems', []);
  1273.         if (!empty($cartItems)) {
  1274.             $this->cartService->removeCartItems($cartItems);
  1275.             return $this->json(['status' => 'OK']);
  1276.         }
  1277.         return $this->json(['status' => 'Error']);
  1278.     }
  1279.     /**
  1280.      * @return void
  1281.      * @throws \Exception
  1282.      */
  1283.     public function checkCartItemsAvailable()
  1284.     {
  1285.         //
  1286.         $cartItemIdsToBeRemoved = [];
  1287.         //
  1288.         foreach ($this->cartService->getCarts() as $Cart) {
  1289.             //
  1290.             foreach ($Cart->getCartItems() as $CartItem) {
  1291.                 /**
  1292.                  * @var SkuExtended $sku
  1293.                  */
  1294.                 $jancode = new Jancode($CartItem->getProductClass()->getId());
  1295.                 $sku SkuExtended::getInstance($jancode->getJanGoods(), $jancode->getJanId());
  1296.                 //
  1297.                 if ($sku->isNoDisplay() || $sku->getGclDisplayStatus() === GoodsColor::DISPLAY_STATUS_UNAVAILABLE || $sku->getGpDisplay() === GoodsPrice::DISPLAY_HIDDEN) {
  1298.                     //
  1299.                     $cartItemIdsToBeRemoved[] = $CartItem->getId();
  1300.                 }
  1301.             }
  1302.         }
  1303.         //
  1304.         if (!empty($cartItemIdsToBeRemoved)) {
  1305.             $this->cartService->removeCartItems($cartItemIdsToBeRemoved);
  1306.             $this->addRequestError('現在、ご購入頂けない商品が含まれていましたのでカートから削除されました。'"front.cart");
  1307.         }
  1308.     }
  1309. }