<?php
/*
* This file is part of EC-CUBE
*
* Copyright(c) EC-CUBE CO.,LTD. All Rights Reserved.
*
* http://www.ec-cube.co.jp/
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Customize\Service;
use Customize\Repository\Master\MtbPrintRepository;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\UnitOfWork;
use Eccube\Entity\Cart;
use Eccube\Entity\CartItem;
use Eccube\Entity\Customer;
use Eccube\Entity\ItemHolderInterface;
use Eccube\Entity\OrderItem;
use Eccube\Entity\ProductClass;
use Eccube\Repository\BaseInfoRepository;
use Eccube\Repository\CartItemRepository;
use Eccube\Repository\CartRepository;
use Eccube\Repository\ClassCategoryRepository;
use Eccube\Repository\ClassNameRepository;
use Eccube\Repository\OrderRepository;
use Eccube\Repository\ProductClassRepository;
use Eccube\Service\Cart\CartItemAllocator;
use Eccube\Service\Cart\CartItemComparator;
use Customize\Service\TaxRuleServiceCustom as TaxRuleService;
use Eccube\Util\StringUtil;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\Session\SessionInterface;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
use Eccube\Repository\ProductRepository;
class CartService
{
/**
* @var Cart[]
*/
protected $carts;
/**
* @var SessionInterface
*/
protected $session;
/**
* @var \Doctrine\ORM\EntityManagerInterface
*/
protected $entityManager;
/**
* @var ItemHolderInterface
*
* @deprecated
*/
protected $cart;
/**
* @var ProductClassRepository
*/
protected $productClassRepository;
/**
* @var CartRepository
*/
protected $cartRepository;
/**
* @var CartItemComparator
*/
protected $cartItemComparator;
/**
* @var CartItemAllocator
*/
protected $cartItemAllocator;
/**
* @var OrderRepository
*/
protected $orderRepository;
/**
* @var TokenStorageInterface
*/
protected $tokenStorage;
/**
* @var AuthorizationCheckerInterface
*/
protected $authorizationChecker;
protected $cartItemRepository;
protected $mtbPrintRepository;
protected $container;
protected $userRate;
protected $taxRuleService;
protected $productRepository;
/**
* CartService constructor.
*/
public function __construct(
SessionInterface $session,
EntityManagerInterface $entityManager,
ProductClassRepository $productClassRepository,
CartRepository $cartRepository,
CartItemComparator $cartItemComparator,
CartItemAllocator $cartItemAllocator,
OrderRepository $orderRepository,
TokenStorageInterface $tokenStorage,
AuthorizationCheckerInterface $authorizationChecker,
CartItemRepository $cartItemRepository,
MtbPrintRepository $mtbPrintRepository,
ContainerInterface $container,
BaseInfoRepository $baseInfoRepository,
TaxRuleService $taxRuleService,
ProductRepository $productRepository
) {
$this->session = $session;
$this->entityManager = $entityManager;
$this->productClassRepository = $productClassRepository;
$this->cartRepository = $cartRepository;
$this->cartItemComparator = $cartItemComparator;
$this->cartItemAllocator = $cartItemAllocator;
$this->orderRepository = $orderRepository;
$this->tokenStorage = $tokenStorage;
$this->authorizationChecker = $authorizationChecker;
$this->cartItemRepository = $cartItemRepository;
$this->mtbPrintRepository = $mtbPrintRepository;
$this->container = $container;
$this->userRate = $baseInfoRepository->get()->getOptionUserRate();
$this->taxRuleService = $taxRuleService;
$this->productRepository = $productRepository;
}
/**
* 現在のカートの配列を取得する.
*
* 本サービスのインスタンスのメンバーが空の場合は、DBまたはセッションからカートを取得する
*
* @param bool $empty_delete true の場合、商品明細が空のカートが存在した場合は削除する
*
* @return Cart[]
*/
public function getCarts($empty_delete = false)
{
if (null !== $this->carts) {
if ($empty_delete) {
$cartKeys = [];
foreach (array_keys($this->carts) as $index) {
$Cart = $this->carts[$index];
if ($Cart->getItems()->count() > 0) {
$cartKeys[] = $Cart->getCartKey();
} else {
$this->entityManager->remove($this->carts[$index]);
$this->entityManager->flush();
unset($this->carts[$index]);
}
}
$this->session->set('cart_keys', $cartKeys);
}
return $this->carts;
}
if ($this->getUser()) {
$this->carts = $this->getPersistedCarts();
} else {
$this->carts = $this->getSessionCarts();
}
return $this->carts;
}
/**
* 永続化されたカートを返す
*
* @return Cart[]
*/
public function getPersistedCarts()
{
return $this->cartRepository->findBy(['Customer' => $this->getUser()]);
}
/**
* セッションにあるカートを返す
*
* @return Cart[]
*/
public function getSessionCarts()
{
$cartKeys = $this->session->get('cart_keys', []);
if (empty($cartKeys)) {
return [];
}
return $this->cartRepository->findBy(['cart_key' => $cartKeys], ['id' => 'ASC']);
}
/**
* 会員が保持する永続化されたカートと、非会員時のカートをマージする.
*/
public function mergeFromPersistedCart()
{
$persistedCarts = $this->getPersistedCarts();
$sessionCarts = $this->getSessionCarts();
$CartItems = [];
// 永続化されたカートとセッションのカートが同一の場合はマージしない #4574
$cartKeys = $this->session->get('cart_keys', []);
if ((count($persistedCarts) > 0) && !in_array($persistedCarts[0]->getCartKey(), $cartKeys, true)) {
foreach ($persistedCarts as $Cart) {
$CartItems = $this->mergeCartItems($Cart->getCartItems(), $CartItems);
}
}
// セッションにある非会員カートとDBから取得した会員カートをマージする.
foreach ($sessionCarts as $Cart) {
$CartItems = $this->mergeCartItems($Cart->getCartItems(), $CartItems);
}
$this->restoreCarts($CartItems);
}
/**
* @return Cart|null
*/
public function getCart()
{
$Carts = $this->getCarts();
if (empty($Carts)) {
return null;
}
$cartKeys = $this->session->get('cart_keys', []);
$Cart = null;
if (count($cartKeys) > 0) {
foreach ($Carts as $cart) {
if ($cart->getCartKey() === current($cartKeys)) {
$Cart = $cart;
break;
}
}
} else {
$Cart = $Carts[0];
}
return $Cart;
}
/**
* @param CartItem[] $cartItems
*
* @return CartItem[]
*/
protected function mergeAllCartItems($cartItems = [])
{
/** @var CartItem[] $allCartItems */
$allCartItems = [];
foreach ($this->getCarts() as $Cart) {
$allCartItems = $this->mergeCartItems($Cart->getCartItems(), $allCartItems);
}
return $this->mergeCartItems($cartItems, $allCartItems);
}
/**
* @param $cartItems
* @param $allCartItems
*
* @return array
*/
protected function mergeCartItems($cartItems, $allCartItems)
{
foreach ($cartItems as $item) {
$itemExists = false;
$idProduct = $item->getProductClass()->getProduct()->getId();
$product = $this->productRepository->find($idProduct);
foreach ($allCartItems as $itemInArray) {
// 同じ明細があればマージする
if ($this->cartItemComparator->compare($item, $itemInArray)) {
$itemInArray->setQuantity($itemInArray->getQuantity() + $item->getQuantity());
$itemInArray->setProductPrintType($item->getProductPrintType());
$itemInArray->setProductPrintFeeType($item->getProductPrintFeeType());
$itemInArray->setProductPrintFeePrice($item->getProductPrintFeePrice());
$itemInArray->setProductPlateTypePrint($item->getProductPlateTypePrint());
$itemInArray->setProductPrintColor($item->getProductPrintColor());
$itemInArray->setIsPrint($item->getIsPrint());
$itemInArray->setIsRepurchase($item->getIsRepurchase());
$itemInArray->setProductCodeByColor($item->getProductCodeByColor());
$itemExists = true;
break;
}
}
if (!$itemExists) {
$allCartItems[] = $item;
}
}
return $allCartItems;
}
protected function restoreCarts($cartItems)
{
foreach ($this->getCarts() as $Cart) {
foreach ($Cart->getCartItems() as $i) {
$this->entityManager->remove($i);
$this->entityManager->flush();
}
$this->entityManager->remove($Cart);
$this->entityManager->flush();
}
$this->carts = [];
/** @var Cart[] $Carts */
$Carts = [];
foreach ($cartItems as $item) {
$allocatedId = $this->cartItemAllocator->allocate($item);
$cartKey = $this->createCartKey($allocatedId, $this->getUser());
if (isset($Carts[$cartKey])) {
$Cart = $Carts[$cartKey];
$Cart->addCartItem($item);
$item->setCart($Cart);
} else {
/** @var Cart $Cart */
$Cart = $this->cartRepository->findOneBy(['cart_key' => $cartKey]);
if ($Cart) {
foreach ($Cart->getCartItems() as $i) {
$this->entityManager->remove($i);
$this->entityManager->flush();
}
$this->entityManager->remove($Cart);
$this->entityManager->flush();
}
$Cart = new Cart();
$Cart->setCartKey($cartKey);
$Cart->addCartItem($item);
$item->setCart($Cart);
$Carts[$cartKey] = $Cart;
}
}
$this->carts = array_values($Carts);
}
protected function isGranted($attribute, $subject = null): bool
{
if (!$this->container->has('security.authorization_checker')) {
throw new \LogicException(
'The SecurityBundle is not registered in your application. Try running "composer require symfony/security-bundle".'
);
}
return $this->container->get('security.authorization_checker')->isGranted($attribute, $subject);
}
public function getTaxRuleService()
{
return $this->taxRuleService;
}
/**
* カートに商品を追加します.
*
* @param $ProductClass ProductClass 商品規格
* @param $quantity int 数量
*
* @return bool 商品を追加できた場合はtrue
*/
public function addProduct($ProductClass, $quantity = 1, $print = [])
{
if (!$ProductClass instanceof ProductClass) {
$ProductClassId = $ProductClass;
$ProductClass = $this->entityManager
->getRepository(ProductClass::class)
->find($ProductClassId);
if (is_null($ProductClass)) {
return false;
}
}
$ClassCategory1 = $ProductClass->getClassCategory1();
if ($ClassCategory1 && !$ClassCategory1->isVisible()) {
return false;
}
$ClassCategory2 = $ProductClass->getClassCategory2();
if ($ClassCategory2 && !$ClassCategory2->isVisible()) {
return false;
}
$newItem = new CartItem();
$newItem->setQuantity($quantity);
$price = 0;
// if($this->isGranted('ROLE_USER') == true) {
// $rate = $this->userRate/100;
// $price = floor($ProductClass->getPrice02() - round($ProductClass->getPrice02() * $rate));
// $priceTax = $this->taxRuleService->getTax($price, $ProductClass->getProduct(), $ProductClass);
// $price = round($price + $priceTax);
// } else {
// $price = $ProductClass->getPrice02IncTax();
// }
$price = $ProductClass->getPrice02();
$newItem->setPrice($price);
$newItem->setProductClass($ProductClass);
if (count($print) > 0) {
if (isset($print['update_quantity']) && $print['update_quantity']) {
if(isset($print['cartItemId']) && $print['cartItemId'] > 0) {
$dataCartItem = $this->cartItemRepository->findOneBy(
['Cart' => $this->getCart(), 'ProductClass' => $ProductClass, 'id' => $print['cartItemId']]
);
} else {
$dataCartItem = $this->cartItemRepository->findOneBy(
['Cart' => $this->getCart(), 'ProductClass' => $ProductClass]
);
}
if ($dataCartItem) {
$print = [
'product_print_type' => $dataCartItem['product_print_type'],
'product_print_fee_type' => $dataCartItem['product_print_fee_type'],
'product_print_fee_price' => $dataCartItem['product_print_fee_price'],
'product_plate_type_print' => $dataCartItem['product_plate_type_print'],
'product_print_color' => $dataCartItem['product_print_color'],
'is_print' => $dataCartItem['is_print'],
'is_repurchase' => $dataCartItem['is_repurchase'],
'quantity' => $dataCartItem['quantity'],
];
}
} else {
$dataCartItem = $this->cartItemRepository->findOneBy(
['Cart' => $this->getCart(), 'ProductClass' => $ProductClass, 'product_print_color' => $print['product_print_color']]
);
if($dataCartItem) {
$quantity = $quantity + (int)$dataCartItem->getQuantity();
}
}
$product_print_fee_price = $print['product_print_fee_price'];
if ($this->getCart()) {
$newQuantity = (isset($print['quantity']) && $print['quantity']) ? $print['quantity'] + $quantity : $quantity;
if ($print['product_print_fee_type'] == 1) {
$dataMtbPrint = $this->mtbPrintRepository->findBy(
[
'product_print_fee_type' => $print['product_print_fee_type'],
'discriminator_type' => 'fee_print_name'
]
);
foreach ($dataMtbPrint as $value) {
if ($value['product_print_fee_type_max'] > 0) {
if ($newQuantity >= $value['product_print_fee_type_min'] && $newQuantity <= $value['product_print_fee_type_max']) {
$product_print_fee_price = $value['price'];
break;
}
} else {
$product_print_fee_price = $value['price'];
}
}
} elseif ($print['product_print_fee_type'] == 3) {
$dataMtbPrint = $this->mtbPrintRepository->findBy(
[
'product_print_fee_type' => $print['product_print_fee_type'],
'discriminator_type' => 'fee_print_name'
]
);
foreach ($dataMtbPrint as $value) {
if ($value['product_print_fee_type_max'] > 0) {
$product_print_fee_price = 50;
} else {
if ($newQuantity >= $value['product_print_fee_type_min']) {
$product_print_fee_price = $value['price'];
break;
}
}
}
}
}
$newItem->setProductPrintType($print['product_print_type']);
$newItem->setProductPrintFeeType($print['product_print_fee_type']);
$newItem->setProductPrintFeePrice($product_print_fee_price);
$newItem->setProductPlateTypePrint($print['product_plate_type_print']);
$newItem->setProductPrintColor($print['product_print_color']);
$newItem->setIsPrint($print['is_print']);
$newItem->setIsRepurchase($print['is_repurchase']);
$newItem->setProductCodeByColor(
(isset($print['product_code_by_color'])) ? $print['product_code_by_color'] : ''
);
}
$allCartItems = $this->mergeAllCartItems([$newItem]);
$this->restoreCarts($allCartItems);
return true;
}
public function removeProduct($ProductClass, $cartItemId = 0)
{
if (!$ProductClass instanceof ProductClass) {
$ProductClassId = $ProductClass;
$ProductClass = $this->entityManager
->getRepository(ProductClass::class)
->find($ProductClassId);
if (is_null($ProductClass)) {
return false;
}
}
if($cartItemId == 0) {
$removeItem = new CartItem();
$removeItem->setPrice($ProductClass->getPrice02IncTax());
$removeItem->setProductClass($ProductClass);
}
$allCartItems = $this->mergeAllCartItems();
$foundIndex = -1;
foreach ($allCartItems as $index => $itemInCart) {
if($cartItemId == 0) {
$cartProductClassId = $itemInCart->getProductClass()->getId();
$removeProductClassId = $removeItem->getProductClass()->getId();
// if ($this->cartItemComparator->compare($itemInCart, $removeItem)) { caohv remove because not working
if ($cartProductClassId == $removeProductClassId) {
$foundIndex = $index;
break;
}
} else {
if ($itemInCart->getId() == $cartItemId) {
$foundIndex = $index;
break;
}
}
}
array_splice($allCartItems, $foundIndex, 1);
$this->restoreCarts($allCartItems);
return true;
}
public function save()
{
$cartKeys = [];
$data_fee_print_all_price = $this->mtbPrintRepository->findOneBy(
['product_print_fee_type' => 4, 'discriminator_type' => 'fee_print_all']
);
if($this->carts) {
foreach ($this->carts as &$Cart) {
$totalPrice = 0;
$fee_print_all_price = 0;
$platePrint = [];
$product_print_fee_price = 0;
foreach ($Cart->getCartItems() as $cartItem) {
$pricePrint = 0;
if ($cartItem->getIsPrint() == 1) {
if ($cartItem->getIsRepurchase() == 0) {
$platePrint[$cartItem->getProductClass()->getId() . $cartItem->getProductPrintColor()] = 1;
}
$newQuantity = $cartItem->getQuantity();
if ($cartItem->getProductPrintFeeType() == 1) {
$dataMtbPrint = $this->mtbPrintRepository->findBy(
[
'product_print_fee_type' => $cartItem->getProductPrintFeeType(),
'discriminator_type' => 'fee_print_name'
]
);
foreach ($dataMtbPrint as $value) {
if ($value['product_print_fee_type_max'] > 0) {
if ($newQuantity >= $value['product_print_fee_type_min'] && $newQuantity <= $value['product_print_fee_type_max']) {
$product_print_fee_price = $value['price'];
break;
}
} else {
$product_print_fee_price = $value['price'];
}
}
} elseif ($cartItem->getProductPrintFeeType() == 3) {
$dataMtbPrint = $this->mtbPrintRepository->findBy(
[
'product_print_fee_type' => $cartItem->getProductPrintFeeType(),
'discriminator_type' => 'fee_print_name'
]
);
foreach ($dataMtbPrint as $value) {
if ($value['product_print_fee_type_max'] > 0) {
$product_print_fee_price = 50;
} else {
if ($newQuantity >= $value['product_print_fee_type_min']) {
$product_print_fee_price = $value['price'];
break;
}
}
}
} else {
if($cartItem->getProductClass()) {
$product_print_fee_price = $cartItem->getProductClass()->getProduct()->getProductPrintFeePrice();
}
}
$cartItem->setProductPrintFeePrice($product_print_fee_price);
$pricePrint = $product_print_fee_price * $cartItem->getQuantity();
}
$totalPrice = $totalPrice + ($cartItem->getTotalPrice() + $pricePrint);
}
if (count($platePrint) > 0) {
$fee_print_all_price = env('FEE_PRINT_PRICE', 8000) * count($platePrint);
if ($data_fee_print_all_price) {
$fee_print_all_price = (int)$data_fee_print_all_price->getPrice() * count($platePrint);
}
}
$Cart->setFeePrintAllQuantity(count($platePrint));
$Cart->setFeePrintAllPrice($fee_print_all_price);
$Cart->setTotalPrice($totalPrice + $fee_print_all_price);
$Cart->setDeliveryFeeTotal(0);
$Cart->setCustomer($this->getUser());
$this->entityManager->persist($Cart);
foreach ($Cart->getCartItems() as $item) {
$this->entityManager->persist($item);
}
$this->entityManager->flush();
$cartKeys[] = $Cart->getCartKey();
}
$this->session->set('cart_keys', $cartKeys);
}
return;
}
/**
* @param string $pre_order_id
*
* @return \Eccube\Service\CartService
*/
public function setPreOrderId($pre_order_id)
{
$this->getCart()->setPreOrderId($pre_order_id);
return $this;
}
/**
* @return string|null
*/
public function getPreOrderId()
{
$Cart = $this->getCart();
if (!empty($Cart)) {
return $Cart->getPreOrderId();
}
return null;
}
/**
* @return \Eccube\Service\CartService
*/
public function clear()
{
$Carts = $this->getCarts();
if (!empty($Carts)) {
$removed = $this->getCart();
if ($removed && UnitOfWork::STATE_MANAGED === $this->entityManager->getUnitOfWork()->getEntityState(
$removed
)) {
$this->entityManager->remove($removed);
$this->entityManager->flush();
$cartKeys = [];
foreach ($Carts as $key => $Cart) {
// テーブルから削除されたカートを除外する
if ($Cart == $removed) {
unset($Carts[$key]);
}
$cartKeys[] = $Cart->getCartKey();
}
$this->session->set('cart_keys', $cartKeys);
// 注文完了のカートキーをセッションから削除する
$this->session->remove('cart_key');
$this->carts = $this->cartRepository->findBy(['cart_key' => $cartKeys], ['id' => 'ASC']);
}
}
return $this;
}
/**
* @param CartItemComparator $cartItemComparator
*/
public function setCartItemComparator($cartItemComparator)
{
$this->cartItemComparator = $cartItemComparator;
}
/**
* カートキーで指定したインデックスにあるカートを優先にする
*
* @param string $cartKey カートキー
*/
public function setPrimary($cartKey)
{
$Carts = $this->getCarts();
$primary = $Carts[0];
$index = 0;
foreach ($Carts as $key => $Cart) {
if ($Cart->getCartKey() === $cartKey) {
$index = $key;
$primary = $Carts[$index];
break;
}
}
$prev = $Carts[0];
array_splice($Carts, 0, 1, [$primary]);
array_splice($Carts, $index, 1, [$prev]);
$this->carts = $Carts;
$this->save();
}
protected function getUser()
{
if (null === $token = $this->tokenStorage->getToken()) {
return;
}
if (!is_object($user = $token->getUser())) {
// e.g. anonymous authentication
return;
}
return $user;
}
/**
* @param string $allocatedId
*/
protected function createCartKey($allocatedId, Customer $Customer = null)
{
if ($Customer instanceof Customer) {
return $Customer->getId() . '_' . $allocatedId;
}
if ($this->session->has('cart_key_prefix')) {
return $this->session->get('cart_key_prefix') . '_' . $allocatedId;
}
do {
$random = StringUtil::random(32);
$cartKey = $random . '_' . $allocatedId;
$Cart = $this->cartRepository->findOneBy(['cart_key' => $cartKey]);
} while ($Cart);
$this->session->set('cart_key_prefix', $random);
return $cartKey;
}
}