src/Eccube/Service/OrderHelper.php line 521

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