src/Eccube/Service/OrderHelper.php line 232

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