src/Eccube/Service/OrderHelper.php line 514

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\Service;
  13. use Detection\MobileDetect;
  14. use Doctrine\Common\Collections\ArrayCollection;
  15. use Doctrine\Common\Collections\Collection;
  16. use Doctrine\ORM\EntityManagerInterface;
  17. use Eccube\Entity\Cart;
  18. use Eccube\Entity\CartItem;
  19. use Eccube\Entity\Customer;
  20. use Eccube\Entity\Master\DeviceType;
  21. use Eccube\Entity\Master\OrderItemType;
  22. use Eccube\Entity\Master\OrderStatus;
  23. use Eccube\Entity\Order;
  24. use Eccube\Entity\OrderItem;
  25. use Eccube\Entity\Shipping;
  26. use Eccube\Entity\Master\TaxDisplayType;
  27. use Eccube\EventListener\SecurityListener;
  28. use Eccube\Repository\DeliveryRepository;
  29. use Eccube\Repository\Master\DeviceTypeRepository;
  30. use Eccube\Repository\Master\OrderItemTypeRepository;
  31. use Eccube\Repository\Master\OrderStatusRepository;
  32. use Eccube\Repository\Master\PrefRepository;
  33. use Eccube\Repository\OrderRepository;
  34. use Eccube\Repository\PaymentRepository;
  35. use Eccube\Util\StringUtil;
  36. use Symfony\Component\DependencyInjection\ContainerInterface;
  37. use Symfony\Component\HttpFoundation\Session\SessionInterface;
  38. use Symfony\Component\Security\Core\User\UserInterface;
  39. class OrderHelper
  40. {
  41.     /**
  42.      * @var ContainerInterface
  43.      */
  44.     protected $container;
  45.     /**
  46.      * @var string 非会員情報を保持するセッションのキー
  47.      */
  48.     public const SESSION_NON_MEMBER 'eccube.front.shopping.nonmember';
  49.     /**
  50.      * @var string 非会員の住所情報を保持するセッションのキー
  51.      */
  52.     public const SESSION_NON_MEMBER_ADDRESSES 'eccube.front.shopping.nonmember.customeraddress';
  53.     /**
  54.      * @var string 受注IDを保持するセッションのキー
  55.      */
  56.     public const SESSION_ORDER_ID 'eccube.front.shopping.order.id';
  57.     /**
  58.      * @var string カートが分割されているかどうかのフラグ. 購入フローからのログイン時にカートが分割された場合にtrueがセットされる.
  59.      *
  60.      * @see SecurityListener
  61.      */
  62.     public const SESSION_CART_DIVIDE_FLAG 'eccube.front.cart.divide';
  63.     /**
  64.      * @var SessionInterface
  65.      */
  66.     protected $session;
  67.     /**
  68.      * @var PrefRepository
  69.      */
  70.     protected $prefRepository;
  71.     /**
  72.      * @var OrderRepository
  73.      */
  74.     protected $orderRepository;
  75.     /**
  76.      * @var OrderItemTypeRepository
  77.      */
  78.     protected $orderItemTypeRepository;
  79.     /**
  80.      * @var OrderStatusRepository
  81.      */
  82.     protected $orderStatusRepository;
  83.     /**
  84.      * @var DeliveryRepository
  85.      */
  86.     protected $deliveryRepository;
  87.     /**
  88.      * @var PaymentRepository
  89.      */
  90.     protected $paymentRepository;
  91.     /**
  92.      * @var DeviceTypeRepository
  93.      */
  94.     protected $deviceTypeRepository;
  95.     /**
  96.      * @var MobileDetector
  97.      */
  98.     protected $mobileDetector;
  99.     /**
  100.      * @var EntityManagerInterface
  101.      */
  102.     protected $entityManager;
  103.     public function __construct(
  104.         ContainerInterface $container,
  105.         EntityManagerInterface $entityManager,
  106.         OrderRepository $orderRepository,
  107.         OrderItemTypeRepository $orderItemTypeRepository,
  108.         OrderStatusRepository $orderStatusRepository,
  109.         DeliveryRepository $deliveryRepository,
  110.         PaymentRepository $paymentRepository,
  111.         DeviceTypeRepository $deviceTypeRepository,
  112.         PrefRepository $prefRepository,
  113.         MobileDetect $mobileDetector,
  114.         SessionInterface $session
  115.     ) {
  116.         $this->container $container;
  117.         $this->orderRepository $orderRepository;
  118.         $this->orderStatusRepository $orderStatusRepository;
  119.         $this->orderItemTypeRepository $orderItemTypeRepository;
  120.         $this->deliveryRepository $deliveryRepository;
  121.         $this->paymentRepository $paymentRepository;
  122.         $this->deviceTypeRepository $deviceTypeRepository;
  123.         $this->entityManager $entityManager;
  124.         $this->prefRepository $prefRepository;
  125.         $this->mobileDetector $mobileDetector;
  126.         $this->session $session;
  127.     }
  128.     /**
  129.      * 購入処理中の受注を生成する.
  130.      *
  131.      * @param Customer $Customer
  132.      * @param $CartItems
  133.      *
  134.      * @return Order
  135.      */
  136.     public function createPurchaseProcessingOrder(Cart $CartCustomer $Customer)
  137.     {
  138.         $OrderStatus $this->orderStatusRepository->find(OrderStatus::PROCESSING);
  139.         $Order = new Order($OrderStatus);
  140.         $preOrderId $this->createPreOrderId();
  141.         $Order->setPreOrderId($preOrderId);
  142.         // 顧客情報の設定
  143.         $this->setCustomer($Order$Customer);
  144.         $DeviceType $this->deviceTypeRepository->find($this->mobileDetector->isMobile() ? DeviceType::DEVICE_TYPE_MB DeviceType::DEVICE_TYPE_PC);
  145.         $Order->setDeviceType($DeviceType);
  146.         // 明細情報の設定
  147.         $OrderItems $this->createOrderItemsFromCartItems($Cart->getCartItems());
  148.         $OrderItemsGroupBySaleType array_reduce($OrderItems, function ($result$item) {
  149.             /* @var OrderItem $item */
  150.             $saleTypeId $item->getProductClass()->getSaleType()->getId();
  151.             $result[$saleTypeId][] = $item;
  152.             return $result;
  153.         }, []);
  154.         foreach ($OrderItemsGroupBySaleType as $OrderItems) {
  155.             $Shipping $this->createShippingFromCustomer($Customer);
  156.             $Shipping->setOrder($Order);
  157.             $this->addOrderItems($Order$Shipping$OrderItems);
  158.             $this->setDefaultDelivery($Shipping);
  159.             $this->entityManager->persist($Shipping);
  160.             $Order->addShipping($Shipping);
  161.         }
  162.         $this->setDefaultPayment($Order);
  163.         $this->entityManager->persist($Order);
  164.         return $Order;
  165.     }
  166.     /**
  167.      * @param Cart $Cart
  168.      *
  169.      * @return bool
  170.      */
  171.     public function verifyCart(Cart $Cart)
  172.     {
  173.         if (count($Cart->getCartItems()) > 0) {
  174.             $divide $this->session->get(self::SESSION_CART_DIVIDE_FLAG);
  175.             if ($divide) {
  176.                 log_info('ログイン時に販売種別が異なる商品がカートと結合されました。');
  177.                 return false;
  178.             }
  179.             return true;
  180.         }
  181.         log_info('カートに商品が入っていません。');
  182.         return false;
  183.     }
  184.     /**
  185.      * 注文手続き画面でログインが必要かどうかの判定
  186.      *
  187.      * @return bool
  188.      */
  189.     public function isLoginRequired()
  190.     {
  191.         // フォームログイン済はログイン不要
  192.         if ($this->isGranted('IS_AUTHENTICATED_FULLY')) {
  193.             return false;
  194.         }
  195.         // Remember Meログイン済の場合はフォームからのログインが必要
  196.         if ($this->isGranted('IS_AUTHENTICATED_REMEMBERED')) {
  197.             return true;
  198.         }
  199.         // 未ログインだがお客様情報を入力している場合はログイン不要
  200.         if (!$this->getUser() && $this->getNonMember()) {
  201.             return false;
  202.         }
  203.         return true;
  204.     }
  205.     /**
  206.      * 購入処理中の受注を取得する.
  207.      *
  208.      * @param string|null $preOrderId
  209.      *
  210.      * @return Order|null
  211.      */
  212.     public function getPurchaseProcessingOrder($preOrderId null)
  213.     {
  214.         if (null === $preOrderId) {
  215.             return null;
  216.         }
  217.         return $this->orderRepository->findOneBy([
  218.             'pre_order_id' => $preOrderId,
  219.             'OrderStatus' => OrderStatus::PROCESSING,
  220.         ]);
  221.     }
  222.     /**
  223.      * セッションに保持されている非会員情報を取得する.
  224.      * 非会員購入時に入力されたお客様情報を返す.
  225.      *
  226.      * @param string $session_key
  227.      *
  228.      * @return Customer|null
  229.      */
  230.     public function getNonMember($session_key self::SESSION_NON_MEMBER)
  231.     {
  232.         $data $this->session->get($session_key);
  233.         if (empty($data)) {
  234.             return null;
  235.         }
  236.         $Customer = new Customer();
  237.         $Customer
  238.             ->setName01($data['name01'])
  239.             ->setName02($data['name02'])
  240.             ->setKana01($data['kana01'])
  241.             ->setKana02($data['kana02'])
  242.             ->setCompanyName($data['company_name'])
  243.             ->setEmail($data['email'])
  244.             ->setPhonenumber($data['phone_number'])
  245.             ->setPostalcode($data['postal_code'])
  246.             ->setAddr01($data['addr01'])
  247.             ->setAddr02($data['addr02']);
  248.         if (!empty($data['pref'])) {
  249.             $Pref $this->prefRepository->find($data['pref']);
  250.             $Customer->setPref($Pref);
  251.         }
  252.         return $Customer;
  253.     }
  254.     /**
  255.      * @param Cart $Cart
  256.      * @param Customer $Customer
  257.      *
  258.      * @return Order|null
  259.      */
  260.     public function initializeOrder(Cart $CartCustomer $Customer)
  261.     {
  262.         // 購入処理中の受注情報を取得
  263.         if ($Order $this->getPurchaseProcessingOrder($Cart->getPreOrderId())) {
  264.             return $Order;
  265.         }
  266.         // 受注情報を作成
  267.         $Order $this->createPurchaseProcessingOrder($Cart$Customer);
  268.         $Cart->setPreOrderId($Order->getPreOrderId());
  269.         return $Order;
  270.     }
  271.     public function removeSession()
  272.     {
  273.         $this->session->remove(self::SESSION_ORDER_ID);
  274.         $this->session->remove(self::SESSION_NON_MEMBER);
  275.         $this->session->remove(self::SESSION_NON_MEMBER_ADDRESSES);
  276.     }
  277.     /**
  278.      * 会員情報の更新日時が受注の作成日時よりも新しければ, 受注の注文者情報を更新する.
  279.      *
  280.      * @param Order $Order
  281.      * @param Customer $Customer
  282.      */
  283.     public function updateCustomerInfo(Order $OrderCustomer $Customer)
  284.     {
  285.         if ($Order->getCreateDate() < $Customer->getUpdateDate()) {
  286.             $this->setCustomer($Order$Customer);
  287.         }
  288.     }
  289.     public function createPreOrderId()
  290.     {
  291.         // ランダムなpre_order_idを作成
  292.         do {
  293.             $preOrderId sha1(StringUtil::random(32));
  294.             $Order $this->orderRepository->findOneBy(
  295.                 [
  296.                     'pre_order_id' => $preOrderId,
  297.                 ]
  298.             );
  299.         } while ($Order);
  300.         return $preOrderId;
  301.     }
  302.     protected function setCustomer(Order $OrderCustomer $Customer)
  303.     {
  304.         if ($Customer->getId()) {
  305.             $Order->setCustomer($Customer);
  306.         }
  307.         $Order->copyProperties(
  308.             $Customer,
  309.             [
  310.                 'id',
  311.                 'create_date',
  312.                 'update_date',
  313.                 'del_flg',
  314.             ]
  315.         );
  316.     }
  317.     /**
  318.      * @param Collection|ArrayCollection|CartItem[] $CartItems
  319.      *
  320.      * @return OrderItem[]
  321.      */
  322.     protected function createOrderItemsFromCartItems($CartItems)
  323.     {
  324.         $ProductItemType $this->orderItemTypeRepository->find(OrderItemType::PRODUCT);
  325.         return array_map(function ($item) use ($ProductItemType) {
  326.             /* @var $item CartItem */
  327.             /* @var $ProductClass \Eccube\Entity\ProductClass */
  328.             $ProductClass $item->getProductClass();
  329.             /* @var $Product \Eccube\Entity\Product */
  330.             $Product $ProductClass->getProduct();
  331.             $OrderItem = new OrderItem();
  332.             $OrderItem
  333.                 ->setProduct($Product)
  334.                 ->setProductClass($ProductClass)
  335.                 ->setProductName($Product->getName())
  336.                 ->setProductCode($ProductClass->getCode())
  337.                 ->setPrice($ProductClass->getPrice02())
  338.                 ->setQuantity($item->getQuantity())
  339.                 ->setOrderItemType($ProductItemType);
  340.             $ClassCategory1 $ProductClass->getClassCategory1();
  341.             if (!is_null($ClassCategory1)) {
  342.                 $OrderItem->setClasscategoryName1($ClassCategory1->getName());
  343.                 $OrderItem->setClassName1($ClassCategory1->getClassName()->getName());
  344.             }
  345.             $ClassCategory2 $ProductClass->getClassCategory2();
  346.             if (!is_null($ClassCategory2)) {
  347.                 $OrderItem->setClasscategoryName2($ClassCategory2->getName());
  348.                 $OrderItem->setClassName2($ClassCategory2->getClassName()->getName());
  349.             }
  350.             return $OrderItem;
  351.         }, $CartItems instanceof Collection $CartItems->toArray() : $CartItems);
  352.     }
  353.     /**
  354.      * @param Customer $Customer
  355.      *
  356.      * @return Shipping
  357.      */
  358.     protected function createShippingFromCustomer(Customer $Customer)
  359.     {
  360.         $Shipping = new Shipping();
  361.         $Shipping
  362.             ->setName01($Customer->getName01())
  363.             ->setName02($Customer->getName02())
  364.             ->setKana01($Customer->getKana01())
  365.             ->setKana02($Customer->getKana02())
  366.             ->setCompanyName($Customer->getCompanyName())
  367.             ->setPhoneNumber($Customer->getPhoneNumber())
  368.             ->setPostalCode($Customer->getPostalCode())
  369.             ->setPref($Customer->getPref())
  370.             ->setAddr01($Customer->getAddr01())
  371.             ->setAddr02($Customer->getAddr02());
  372.         return $Shipping;
  373.     }
  374.     /**
  375.      * @param Shipping $Shipping
  376.      */
  377.     protected function setDefaultDelivery(Shipping $Shipping)
  378.     {
  379.         // 配送商品に含まれる販売種別を抽出.
  380.         $OrderItems $Shipping->getOrderItems();
  381.         $SaleTypes = [];
  382.         /** @var OrderItem $OrderItem */
  383.         foreach ($OrderItems as $OrderItem) {
  384.             $ProductClass $OrderItem->getProductClass();
  385.             $SaleType $ProductClass->getSaleType();
  386.             $SaleTypes[$SaleType->getId()] = $SaleType;
  387.         }
  388.         // 販売種別に紐づく配送業者を取得.
  389.         $Deliveries $this->deliveryRepository->getDeliveries($SaleTypes);
  390.         // 初期の配送業者を設定
  391.         $Delivery current($Deliveries);
  392.         $Shipping->setDelivery($Delivery);
  393.         $Shipping->setShippingDeliveryName($Delivery->getName());
  394.     }
  395.     /**
  396.      * @param Order $Order
  397.      */
  398.     protected function setDefaultPayment(Order $Order)
  399.     {
  400.         $OrderItems $Order->getOrderItems();
  401.         // 受注明細に含まれる販売種別を抽出.
  402.         $SaleTypes = [];
  403.         /** @var OrderItem $OrderItem */
  404.         foreach ($OrderItems as $OrderItem) {
  405.             $ProductClass $OrderItem->getProductClass();
  406.             if (is_null($ProductClass)) {
  407.                 // 商品明細のみ対象とする. 送料明細等はスキップする.
  408.                 continue;
  409.             }
  410.             $SaleType $ProductClass->getSaleType();
  411.             $SaleTypes[$SaleType->getId()] = $SaleType;
  412.         }
  413.         // 販売種別に紐づく配送業者を抽出
  414.         $Deliveries $this->deliveryRepository->getDeliveries($SaleTypes);
  415.         // 利用可能な支払い方法を抽出.
  416.         // ここでは支払総額が決まっていないため、利用条件に合致しないものも選択対象になる場合がある
  417.         $Payments $this->paymentRepository->findAllowedPayments($Deliveriestrue);
  418.         // 初期の支払い方法を設定.
  419.         $Payment current($Payments);
  420.         if ($Payment) {
  421.             $Order->setPayment($Payment);
  422.             $Order->setPaymentMethod($Payment->getMethod());
  423.         }
  424.     }
  425.     /**
  426.      * @param Order $Order
  427.      * @param Shipping $Shipping
  428.      * @param array $OrderItems
  429.      */
  430.     protected function addOrderItems(Order $OrderShipping $Shipping, array $OrderItems)
  431.     {
  432.         foreach ($OrderItems as $OrderItem) {
  433.             $Shipping->addOrderItem($OrderItem);
  434.             $Order->addOrderItem($OrderItem);
  435.             $OrderItem->setOrder($Order);
  436.             $OrderItem->setShipping($Shipping);
  437.         }
  438.     }
  439.     /**
  440.      * @see Symfony\Bundle\FrameworkBundle\Controller\AbstractController
  441.      */
  442.     private function isGranted($attribute$subject null): bool
  443.     {
  444.         return $this->container->get('security.authorization_checker')->isGranted($attribute$subject);
  445.     }
  446.     /**
  447.      * @see Symfony\Bundle\FrameworkBundle\Controller\AbstractController
  448.      */
  449.     private function getUser(): ?UserInterface
  450.     {
  451.         if (null === $token $this->container->get('security.token_storage')->getToken()) {
  452.             return null;
  453.         }
  454.         if (!\is_object($user $token->getUser())) {
  455.             return null;
  456.         }
  457.         return $user;
  458.     }
  459.     /**
  460.      * 税表示区分を取得する.
  461.      *
  462.      * - 商品: 税抜
  463.      * - 送料: 税込
  464.      * - 値引き: 税抜
  465.      * - 手数料: 税込
  466.      * - ポイント値引き: 税込
  467.      *
  468.      * @param $OrderItemType
  469.      *
  470.      * @return TaxDisplayType
  471.      */
  472.     public function getTaxDisplayType($OrderItemType)
  473.     {
  474.         if ($OrderItemType instanceof OrderItemType) {
  475.             $OrderItemType $OrderItemType->getId();
  476.         }
  477.         switch ($OrderItemType) {
  478.             case OrderItemType::PRODUCT:
  479.                 return $this->entityManager->find(TaxDisplayType::class, TaxDisplayType::EXCLUDED);
  480.             case OrderItemType::DELIVERY_FEE:
  481.                 return $this->entityManager->find(TaxDisplayType::class, TaxDisplayType::INCLUDED);
  482.             case OrderItemType::DISCOUNT:
  483.                 return $this->entityManager->find(TaxDisplayType::class, TaxDisplayType::EXCLUDED);
  484.             case OrderItemType::CHARGE:
  485.                 return $this->entityManager->find(TaxDisplayType::class, TaxDisplayType::INCLUDED);
  486.             case OrderItemType::POINT:
  487.                 return $this->entityManager->find(TaxDisplayType::class, TaxDisplayType::INCLUDED);
  488.             default:
  489.                 return $this->entityManager->find(TaxDisplayType::class, TaxDisplayType::EXCLUDED);
  490.         }
  491.     }
  492. }