<?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 Doctrine\ORM\EntityManagerInterface;
use Eccube\Entity\Cart;
use Eccube\Entity\CartItem;
use Eccube\Entity\ProductClass;
use Eccube\Repository\CartRepository;
use Eccube\Repository\CartItemRepository;
use Eccube\Repository\OrderRepository;
use Eccube\Repository\ProductClassRepository;
use Eccube\Service\Cart\CartItemAllocator;
use Eccube\Service\Cart\CartItemComparator;
use Customize\Service\OrderHelper;
use Eccube\Util\StringUtil;
use Lm\Engine\EC\Entity\GoodsExtended;
use Lm\Entity\Sku;
use Lm\Service\Db\SqlService;
use Symfony\Component\HttpFoundation\Session\SessionInterface;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Eccube\Common\EccubeConfig;
class CartService extends \Eccube\Service\CartService
{
const CartTypeNormal = 1; #通常
const CartTypeEstimate = 2; #見積シミュレーション
const CartTypeSample = 3; #サンプル
const CartTypeCatalog = 4; #カタログ
const CartTypeComposite = 9; #複合
const Estimate_Type_Print = 2; #プリント
const Estimate_Type_Susoage = 1; #裾上げ
const Session_ExclusionControlFlg = 'Session_ExclusionControlFlg';
const Matrix_name = 'product_matrix';
const DummyEstimateId = 'xx';
const CartTypeRepeat = '101'; #リピート時 カートに商品がある
const RepeatError01 = 'RepeatError01';
const RepeatError02 = 'RepeatError02';
const RepeatError03 = 'RepeatError03';
const SaveCartType = 'Session_SaveCartType';
/**
* ルーティング名 - 「カートに入れる」関連
*/
const ROUTE_ADD_NORMAL = 'add_Normal';
const ROUTE_VALID_ESTIMATE = 'valid_estimate';
const ROUTE_ADD_ESTIMATE = 'add_estimate';
const ROUTE_ADD_SAMPLE = 'add_sample';
const ROUTE_ADD_CATALOG = 'add_catalog';
const ROUTE_ADD_LINE = 'add_line';
const ROUTE_ADD_HYBRID = 'add_hybrid';
const ROUTE_ADD_REPEAT = 'add_repeat';
/**
* Case can mix susoage and print:
* Option 1:
* 伝票1 BILL_1 = Type 1 (normal) + Kyoei (type 1 normal) + Type 1 (reservation) + Kyoei (type 1 reservation) + susoage (normal + reservation)
* 伝票2 BILL_2 = Print (type 2 normal + reservation)
* 伝票3 BILL_3 = Kyoei (type 2 normal + reservation)
* Option 2:
* 伝票1 BILL_1 = Type 1 (normal) + Kyoei (type 1 normal)
* 伝票2 BILL_2 = Print (type 2 normal + reservation)
* 伝票3 BILL_3 = Kyoei (type 2 normal + reservation)
* 伝票4 BILL_4 = Type 1 (reservation) + Kyoei (type 1 reservation) + susoage (normal + reservation)
*/
const BILL_1 = "BILL_1";
const BILL_2 = "BILL_2";
const BILL_3 = "BILL_3";
const BILL_4 = "BILL_4";
const GROUP_NORMAL = 'GROUP_1_NORMAL';
const GROUP_RESERVATION = 'GROUP_2_RESERVATION';
const GROUP_KYOUEI_WITH_NAIRE_PRINT = 'GROUP_3_KYOUEI';
const SESSION_BULK_CHECKOUT_ENABLED = 'cart.bulk_checkout.enabled';
protected $GoodsService;
protected $orderHelper;
protected $CartType = 0;
protected $Quantitys;
protected $EstimateId = 0; #見積ID
protected $Container;
protected $MergeFlg = true; #商品が追加された場合 マージか アッドか?
protected $CartItemRepository;
protected $ProductClass = [];
protected $NewItems = [];
protected $ValidationData = [];
protected $CartItemIds = [];
protected $Estimates;
protected $EstimateOption = [];
protected $EccubeConfig;
/**
* @var array
*/
protected $_buffer;
public function __construct(
SessionInterface $session,
EntityManagerInterface $entityManager,
ProductClassRepository $productClassRepository,
CartRepository $cartRepository,
CartItemComparator $cartItemComparator,
CartItemAllocator $cartItemAllocator,
OrderRepository $orderRepository,
TokenStorageInterface $tokenStorage,
AuthorizationCheckerInterface $authorizationChecker,
ContainerInterface $Container,
CartItemRepository $CartItemRepository,
EccubeConfig $EccubeConfig,
GoodsService $GoodsService,
OrderHelper $orderHelper
)
{
//
parent::__construct($session, $entityManager, $productClassRepository, $cartRepository, $cartItemComparator, $cartItemAllocator, $orderRepository, $tokenStorage, $authorizationChecker);
//
$this->Container = $Container;
$this->CartItemRepository = $CartItemRepository;
$this->EccubeConfig = $EccubeConfig;
$this->orderHelper = $orderHelper;
}
/**
* カートに商品を追加します.
* @param int $ProductClass 商品規格
* @param int $quantity 数量
* @param false|bool $noOptions
* @return bool 商品を追加できた場合はtrue
*/
public function addProduct($ProductClass, $quantity = 1, $noOptions = false)
{
if (!$ProductClass instanceof ProductClass) {
$ProductClassId = $ProductClass;
$ProductClass = $this->entityManager
->getRepository(ProductClass::class)
->find($ProductClassId);
if (is_null($ProductClass)) {
return false;
}
}
// use logic calculator in cart, and set for new Order
$ClassCategory1 = $ProductClass->getClassCategory1();
$Patan = $this->EccubeConfig['ESTIMATE_WHOIT_ONLY'];
if (!preg_match($Patan, $ClassCategory1->getBackendname()) && !empty($this->Estimates)) {
$optionObject = json_decode($this->Estimates,true);
$optionObject["white_only"] = 2;
$this->SetEstimates($optionObject);
}
if ($ClassCategory1 && !$ClassCategory1->isVisible()) {
return false;
}
$ClassCategory2 = $ProductClass->getClassCategory2();
if ($ClassCategory2 && !$ClassCategory2->isVisible()) {
return false;
}
$newItem = new CartItem();
$newItem->setQuantity($quantity);
$newItem->setPrice($ProductClass->getPrice02IncTax());
$newItem->setProductClass($ProductClass);
//
if (!$noOptions) {
$newItem->setOptions($this->Estimates);
}
#見積もりIDの追加
$this->SetEstimateId();
$newItem->setEstimateId($this->EstimateId);
$allCartItems = $this->mergeAllCartItems_2([$newItem]);
$this->restoreCarts($allCartItems);
return true;
}
/**
* @param CartItem[] $cartItems
*
* @return CartItem[]
*
* mergeCartItemsを2回読んでいるが
* 1度目は $allCartItems が空の配列なので Cart->getCartItems()を$allCartItems へ置き換えているだけ
* 2度目は $allCartItems== Cart->getCartItems() で 2度目で始めたマージしている
* クーロンすれば ?
*/
protected function mergeAllCartItems_2($cartItems = [])
{
/** @var CartItem[] $allCartItems */
//$allCartItems=[];
/**
* @var Object $allCartItems
*/
$allCartItems = count($this->getCarts()) > 0 ? [] : (object)$cartItems;
foreach ($this->getCarts() as $Cart) {
// $allCartItems = $this->mergeCartItems($Cart->getCartItems(), $allCartItems);
$allCartItems = $this->mergeCartItems_2($cartItems, $Cart->getCartItems());
}
return clone $allCartItems;
// return $this->mergeCartItems($cartItems, $allCartItems);
}
/**
* @param $cartItems
* @param $allCartItems
*
* @return array
*/
protected function mergeCartItems_2($cartItems, $allCartItems)
{
foreach ($cartItems as $item) {
$itemExists = false;
foreach ($allCartItems as $i => $itemInArray) {
if (0 != $itemInArray->getEstimateId()) {
continue;
}
// 同じ明細があればマージする
if ($this->cartItemComparator->compare($item, $itemInArray) && $this->MergeFlg) {
$itemInArray->setQuantity($itemInArray->getQuantity() + $item->getQuantity());
$itemExists = true;
break;
}
}
if (!$itemExists) {
$allCartItems[] = $item;
}
}
return $allCartItems;
}
/**
* カートを更新します。
*
* @param $CartItemId int CartItem ID
* @param $ProductClass ProductClass 商品規格
* @param $quantity int 数量
* @param $options text オプション(見積りシミュレーションの結果、など)
*
* @return bool 商品を追加できた場合はtrue
*/
public function updateCartItem($CartItemId, $ProductClass, $quantity = 1, $options = "")
{
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);
$newItem->setPrice($ProductClass->getPrice02IncTax());
$newItem->setProductClass($ProductClass);
$newItem->setOptions($options);
$allCartItems = $this->mergeAllCartItems([$newItem]);
$this->restoreCarts($allCartItems);
return true;
}
/**
* EC-CUBEのカートデータを旧UTのカートデータに変換する
*
* @return array
* [
* 'cart' => [],
* 'tmp_cart' => [],
* ]
*/
public function convertToLmCart()
{
$carts = $this->getCart();
$lmCart = [];
foreach ($carts as $key => $value) {
if ($key === 'hoge') {
$lmCart['cart']['piyo'] = $value;
} else if ($key === 'piyo') {
$lmCart['tmp_cart']['piyo'] = $value;
}
}
return $lmCart;
}
public function save()
{
$cartKeys = [];
foreach ($this->carts as $Cart) {
$Tatal = 0;
$Cart->setCustomer($this->getUser());
if (is_null($Cart->getDeliveryFeeTotal())) {
$Cart->setDeliveryFeeTotal(0);
}
#2022/10/20 カートタイプを登録する 修正
if ($this->CartType) {
$CartType = $this->CartType == self::CartTypeComposite ? self::CartTypeEstimate : $this->CartType;
if ($Cart->getCartType() != $CartType) {
$Cart->setCartType($CartType);
}
}
$this->entityManager->persist($Cart);
foreach ($Cart->getCartItems() as $item) {
$Tatal += $item->getPrice() * $item->getQuantity();
$this->entityManager->persist($item);
}
if (is_null($Cart->getTotalPrice())) {
$Cart->setTotalPrice($Tatal);
}
try {
if (empty($Cart->CartType) || $Cart->CartType == 'null'){
log_debug("[LM]Create Cart empty cart_type: CartInfo", [
"Cart" => $Cart,
"CartItem" => $Cart->getCartItems()
]);
}
} catch (\Exception $exception){
log_error("[LM]Create Cart EMPTY cart_type ERROR- " . $exception->getMessage());
}
$this->entityManager->flush();
$cartKeys[] = $Cart->getCartKey();
}
$this->session->set('cart_keys', $cartKeys);
return;
}
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);
#2022/03/28 カートタイプを登録する 4/7修正
# if($this->CartType){
# $Cart->setCartType($this->CartType);
# }
$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);
#2022/03/28 カートタイプを登録する 4/7修正
# if($this->CartType){
# $Cart->setCartType($this->CartType);
# }
$item->setCart($Cart);
$Carts[$cartKey] = $Cart;
}
}
$this->carts = array_values($Carts);
}
/**
* 2022/06/16 tkgoya
*
* @return int|void
*/
public function GetCartType($Flg = false)
{
//
//return $this->CartHelper->GetCartType($Flg);
$Carts = $this->getCarts();
if (count($Carts) < 1) {
return $Flg ?? $this->session->get(self::SaveCartType) ?? 0;
}
foreach ($Carts as $Cart) {
$this->session->set(self::SaveCartType, $Cart->getCartType());
return $Cart->getCartType();
}
}
/**
* 2022/03/28 Kakeru
*
* @param int $CartType
*
*/
public function SetCartType($CartType)
{
if ($this->CartType == $CartType) {
return;
}
$this->CartType = $CartType;
/*foreach ($this->getCarts() as $Cart) {
$Cart->setCartType($CartType);
$this->entityManager->persist($Cart);
$this->entityManager->flush();
}*/
}
/** 20220409
* 会員が保持する永続化されたカートと、非会員時のカートをマージする.
* 2022/07 カートに商品がある場合は前回の商品はマージしない
*/
public function mergeFromPersistedCart()
{
$sessionCarts = $this->getSessionCarts();
$persistedCarts = [];
if (count($sessionCarts) < 1) {
$persistedCarts = $this->getPersistedCarts();
}
$CartItems = [];
// 永続化されたカートとセッションのカートが同一の場合はマージしない #4574
$cartKeys = $this->session->get('cart_keys', []);
if ((count($persistedCarts) > 0) && !in_array($persistedCarts[0]->getCartKey(), $cartKeys, true)) {
foreach ($persistedCarts as $Cart) {
$this->CartType = $Cart->getCartType();
$CartItems = $this->mergeCartItems($Cart->getCartItems(), $CartItems);
}
}
// セッションにある非会員カートとDBから取得した会員カートをマージする.
foreach ($sessionCarts as $Cart) {
$this->CartType = $Cart->getCartType();
$CartItems = $this->mergeCartItems($Cart->getCartItems(), $CartItems);
}
$this->restoreCarts($CartItems);
}
/**
* カートの合計数を ClassId で取得する
*
* @param int $ClassId
*
* @return int $Quantity
*/
public function getQuantitys($ClassId)
{
if (!$this->Quantitys) {
if (!$Carts = $this->getCarts()) {
return 0;
};
foreach ($Carts as $Cart) {
if (!$Items = $Cart->getItems()) {
return 0;
}
foreach ($Items as $Item) {
if (!$Item->isProduct()) {
continue;
}
$Class = $Item->getProductClass();
$Id = $Class->getId();
$this->Quantitys[$Id] = $this->Quantitys[$Id] ?? 0;
$this->Quantitys[$Id] += $Item->getQuantity();
}
}
}
return $this->Quantitys[$ClassId] ?? 0;
}
/**
* EstimateIdの設定
*
*
*/
public function SetEstimateId($Id = null)
{
if ($Id) {
$this->EstimateId = $Id;
return;
}
# 1 通常と加工の混在
if ($this->CartType == self::CartTypeComposite) {
# 10/20 $this->CartType = self::CartTypeNormal;
$this->EstimateId = 0;
return;
}
#加工でなければ
if ($this->CartType != self::CartTypeEstimate) {
return;
}
#3 既に設定している
if ($this->EstimateId !== 0) {
return;
}
#4EstimateIdの作成
$this->MergeFlg = false;
$this->EstimateId = $this->getMaxEstimateId() + 1;
return;
}
public function getMaxEstimateId()
{
$em = $this->Container->get('doctrine.orm.entity_manager');
$Qb = $em->createQueryBuilder();
$MaxEstimateId = $Qb
->select('COALESCE(MAX(CI.EstimateId), 0)')
->from("Eccube\\Entity\\CartItem", 'CI')
->getQuery()
->getSingleResult();
return $MaxEstimateId[1] ?? 0;
}
/**
* GetEstimateId を返す
* @return int $this->EstimateId;
*/
public function GetEstimateId()
{
return $this->EstimateId;
}
public function getLmCartItems()
{
#カートが空なら
if (count($this->carts) < 1) {
return [];
}
$Cart = $this->carts[0];
#カタログなら
if ($Cart->getCartType() == self::CartTypeCatalog) {
return [];
}
$em = $this->Container->get('doctrine.orm.entity_manager');
$Qb = $em->createQueryBuilder();
$Items = $Qb
->select('CI')
->from("Eccube\\Entity\\CartItem", 'CI')
->innerJoin('CI.ProductClass', 'pc')
->orderBy('pc.Product', 'ASC')
->addOrderBy('CI.EstimateId', 'ASC')
->addOrderBy('CI.id', 'ASC')
->where('CI.Cart = :cart')
->setParameter('cart', $Cart)
->getQuery()
->getResult();
$Cart->setCartItems($Items);
return;
}
public function GetProductClass($ProductClassId)
{
if (isset($this->ProductClass[$ProductClassId])) {
return $this->ProductClass[$ProductClassId];
}
$this->ProductClass[$ProductClassId] = $this->entityManager
->getRepository(ProductClass::class)
->find($ProductClassId);
return $this->ProductClass[$ProductClassId];
}
/**
* @param int $CartItemId
* @return $this
*/
public function RemoveItem($CartItemId)
{
$this->CartType = $this->GetCartType();
$CartItems = [];
$Flg = true;
$productClassIdDeleted = '';
$estimateIdDeleted = '';
foreach ($this->getCarts() as $Cart) {
foreach ($Cart->getCartItems() as $CartItem) {
if ($CartItemId == $CartItem->getId()) {
$productClassIdDeleted = $CartItem->getProductClass()->getId()??'';
$estimateIdDeleted = $CartItem->getEstimateId();
}
}
foreach ($Cart->getCartItems() as $CartItem) {
if ($CartItemId == $CartItem->getId()) {
continue;
}
$cartItemOptions = $CartItem->getOptions();
$cartItemOptions = json_decode($cartItemOptions,true);
if($CartItem->getEstimateId() == $estimateIdDeleted && isset($cartItemOptions['susoage']) && is_array($cartItemOptions['susoage'])){
if(isset($cartItemOptions['susoage'][$productClassIdDeleted]) && is_array($cartItemOptions['susoage'][$productClassIdDeleted])){
foreach ($cartItemOptions['susoage'][$productClassIdDeleted] as &$item){
$item['do'] = 0;
}
}
}
$cartItemOptions = $cartItemOptions ? json_encode($cartItemOptions) : null;
if (!empty($cartItemOptions)) {
$this->SetEstimateOption($CartItem->getEstimateId(), $CartItem->getProductClass(), $CartItem->getQuantity(), $cartItemOptions);
}
$CartItems[] = clone $CartItem;
if ($CartItem->getEstimateId()) {
$Flg = false;
}
}
}
#加工と 通常混在の場合 加工を削除すると
if ($this->CartType == self::CartTypeEstimate && $Flg) {
$this->CartType = self::CartTypeNormal;
}
$this->restoreCarts($CartItems);
$this->save();
return $this;
}
/**
* カートにてDATaの追加変更を行う
* @param $Datas
*/
public function AddCartLine($Datas)
{
$Items = [];
$Options = [];
foreach ($this->getCarts() as $Cart) {
$this->CartType = $Cart->getCartType();
foreach ($Cart->getCartItems() as $Item) {
$Items[$Item->getId()] = $Item;
// $Options[$Item->getEstimateId()] = $Item->getOptions();
}
}
$Errors = [];
$AddLineFlg = false;
foreach ($Datas as $EstimateId => $Data) {
$Options = null;
foreach ($Data as $ItemId => $Product) {
$ProductClass = null;
if (is_numeric($ItemId)) {
$Item = $Items[$ItemId] ?? null; # もしエラーなら
if($Item != null){
if ($ProductClass = $Item->getProductClass()) { #もしえらーなら 下記もエラー
$ClassCategory1 = $ProductClass->getClassCategory1();
$ClassCategory2 = $ProductClass->getClassCategory2();
}
$Options = $Item->getOptions();
} else {
$Options = null;
}
switch (true) {
case !$Item || !$ProductClass:
$Errors[0] = 13;
break;
#内容が同じなら
case $ClassCategory1->getId() == $Product['color']
&& $ClassCategory2->getId() == $Product['size']
&& $Item->getQuantity() == $Product['quantity']:
$this->AddValidationData($ProductClass, $Product['quantity']);
$this->NewItems[] = clone $Item;
break;
default :
$AddLineFlg = true;
if (0 == $Product['quantity']) {
$Errors[$ProductClass->getId()] = 8;
}
$ProductClass = $this->AddNewItem($Product, $EstimateId, $Options);
break;
}
#新規套路
} else {
if ($Product['quantity']) {
if (is_numeric($Product['quantity'])) {
$Ids = explode('-', $ItemId);
$Product['product'] = $Ids[1] ?? null;
$AddLineFlg = true;
$ProductClass = $this->AddNewItem($Product, $EstimateId, $Options, $ItemId);
} else {
$Errors[$ItemId] = 4;
}
}
}
#2022/09/09 見積シミュレーション options 内容変更
if (!empty($Options)) {
$this->SetEstimateOption($EstimateId, $ProductClass, $Product['quantity'], $Options);
}
}
}
if (!$AddLineFlg) {
$Errors[0] = 14;
}
return [$this->ValidationData, $Errors];
}
protected function AddNewItem($Product, $EstimateId, $Options, $ItemId = null)
{
$ProductId = $Product['product'];
$ClassCategoryId1 = $Product['color'];
$ClassCategoryId2 = $Product['size'];
$Quantity = $Product['quantity'];
$ProductClass = $this->productClassRepository->findOneBy(['Product' => $ProductId,
'ClassCategory1' => $ClassCategoryId1,
'ClassCategory2' => $ClassCategoryId2,
]);
# echo $ProductId.':'. $ClassCategoryId1 .';'. $ClassCategoryId2;
# echo gettype($ProductClass);
#キャッシュとバリデーションDATA 保存
if ($ProductClass) {
$this->AddValidationData($ProductClass, $Product['quantity']);
}
#追加アイテムの保存
if ($ItemId) {
$this->CartItemIds[$ProductClass->getId()][] = $ItemId;
}
$newItem = new CartItem();
$newItem->setQuantity($Quantity)
->setPrice($ProductClass->getPrice02IncTax())
->setProductClass($ProductClass)
->setOptions($Options)
->setEstimateId($EstimateId);
$this->NewItems[] = $newItem;
return $ProductClass;
}
/*
* 行の追加で 同じEstimateIde で 同じProductId で 同じ ProductClassId の場合マージする
*
*/
protected function MergeNewItem()
{
$NewItems = [];
foreach ($this->NewItems as $Item) {
$ProductClass = $Item->getProductClass();
$Product = $ProductClass->getProduct();
$EstimateId = $Item->getEstimateId();
$ProductId = $Product->getId();
$ProductClassId = $ProductClass->getId();
if (isset($NewItems[$EstimateId][$ProductId][$ProductClassId])) {
$Quantity = $NewItems[$EstimateId][$ProductId][$ProductClassId]->getQuantity() + $Item->getQuantity();
$NewItems[$EstimateId][$ProductId][$ProductClassId]->setQuantity($Quantity);
} else {
$NewItems[$EstimateId][$ProductId][$ProductClassId] = $Item;
}
}
$ReNewItem = [];
foreach ($NewItems as $EstimateId => $Product) {
foreach ($Product as $ProductId => $ProductClass) {
foreach ($ProductClass as $ProductClassId => $Item)
$ReNewItem[] = $Item;
}
}
$goodsColorKeys = array_map(function ($item) {
/**
* @var CartItem $item
*/
return $item->getProductClass()->getJancode()->getGoodsColor()->getGclDisplay();
}, $ReNewItem);
$goodsSizeKeys = array_map(function ($item) {
/**
* @var CartItem $item
*/
return $item->getProductClass()->getJancode()->getGoodsPrice()->getGpDisplay();
}, $ReNewItem);
array_multisort($goodsColorKeys, SORT_ASC, SORT_NUMERIC,
$goodsSizeKeys, SORT_ASC, SORT_NUMERIC,
$ReNewItem
);
return $ReNewItem;
}
public function MakeValidationData()
{
$CartType = null;
foreach ($this->getCarts() as $Cart) {
$CartType = $Cart->getCartType();
foreach ($Cart->getCartItems() as $Item) {
$ProductClass = $Item->getProductClass();
if ($ProductClass) {
$this->AddValidationData($ProductClass, $Item->getQuantity());
}
}
}
return [$CartType, $this->ValidationData];
}
protected function AddValidationData($ProductClass, $Quantity)
{
#キャッシュ
$this->ProductClass[$ProductClass->getId()] = $ProductClass;
$ClassId = $ProductClass->getId();
if (isset($this->ValidationData[$ClassId])) {
$this->ValidationData[$ClassId] += $Quantity;
} else {
$this->ValidationData[$ClassId] = $Quantity;
}
}
/**
* マトリックスからのDATを コンバートする
*
*
*/
public function CartItemConv($Products)
{
if (!$Products) {
return null;
}
$ReProducts = [];
foreach ($Products as $ClassId => $Quantity) {
if (!$Quantity) {
continue;
}
#ここでDATAのコンバートをする
#1 2バイト文字をIバイト文字に変換
$Quantity = mb_convert_kana($Quantity, 'n');
$ReProducts[$ClassId] = $Quantity;
}
return $ReProducts;
}
public function convertProductsForSetPurchase($Products)
{
//
$janIdList = array_keys($Products);
//
$janIdListCsv = implode(',', $janIdList);
$sql = "SELECT
T1.jan_id
, T.goods_id
, T.goods_set_purchase_flg
, GROUP_CONCAT(DISTINCT T6.jan_id ORDER BY T2.gsp_type SEPARATOR ',') AS `child_jan_id_list`
FROM goods_table AS T
INNER Join jancode_table AS T1 ON T.goods_id = T1.jan_goods
LEFT JOIN goods_set_purchase_table AS T2 ON T.goods_id = T2.gsp_goods_parent
LEFT JOIN goods_table AS T3 ON T3.goods_id = T2.gsp_goods_child
LEFT JOIN gsp_gcl_table AS T4 ON T4.gsp_gcl_parent = T1.jan_color
LEFT JOIN gsp_gp_table AS T5 ON T5.gsp_gp_parent = T1.jan_price
LEFT JOIN jancode_table AS T6 ON T3.goods_id = T6.jan_goods AND (T6.jan_color, T6.jan_price) IN ((T4.gsp_gcl_main, T5.gsp_gp_main), (T4.gsp_gcl_sub, T5.gsp_gp_sub), (T4.gsp_gcl_other, T5.gsp_gp_other))
WHERE T1.jan_id IN ($janIdListCsv)
GROUP By T.goods_id, T1.jan_id
ORDER By T.goods_id, T1.jan_id
";
//
$result = (new SqlService())
->Sql($sql)
->FetchAll();
//
$_Products = [];
//
foreach ($result as $jan) {
//
$parentJanId = $jan['jan_id'];
$quantity = $Products[$parentJanId];
//
if ($jan['goods_set_purchase_flg'] == 1 && ($childJanIdList = explode(',', $jan['child_jan_id_list']))) {
//
foreach ($childJanIdList as $childJanId) {
//
$_Products[$childJanId] = ($_Products[$childJanId] ?? 0) + $quantity;
}
} else {
$_Products[$parentJanId] = ($_Products[$parentJanId] ?? 0) + $quantity;
}
}
//
return $_Products;
}
/**
*
*
*/
public function AddProducts()
{
$NewItems = $this->MergeNewItem();
$this->restoreCarts($NewItems);
}
/**
* AddLine で 追加分のDATAを返す
* @param int $ProductClassId
*
* @return array()
*/
public function GetAddlines($ProductClassId)
{
if (!$this->CartItemIds) {
return null;
} #不要?
return $this->CartItemIds[$ProductClassId] ?? null;
}
/**
* $Estimates 見積DATAを格納する
* @param $Estimates
*
*/
public function SetEstimates($Estimates)
{
if ($Estimates) {
$this->Estimates = json_encode($Estimates);
}
}
/**
* 見積もりシミュレーション ハイブリット 戻り値の登録
*
*/
public function SetHybrid($CartItemId)
{
$CasrtItemIds = explode(',', $CartItemId);
/**
* @var CartItem[] $CartItems
*/
$CartItems = $this->CartItemRepository->findBy(['id' => $CasrtItemIds]);
foreach ($CartItems as $CartItem) {
//
$noOptions = $this->isProductNoOptions($CartItem->getProductClass()->getProduct()->getId());
//
$Cart = $CartItem->getCart();
if ($Cart->getCartType() != self::CartTypeEstimate) {
$Cart->setCartType(self::CartTypeEstimate);
$CartItem->setCart($Cart);
}
//
if (!$noOptions) {
$CartItem->setOptions($this->Estimates);
}
if (!$CartItem->getEstimateId()) {
$this->SetEstimateId();
$CartItem->setEstimateId($this->EstimateId);
}
$this->entityManager->persist($CartItem);
$this->entityManager->flush();
}
}
public function resetEstimateOptions()
{
$this->EstimateOption = [];
}
public function checkExistOption($estimateOptions, $estimateId, $optionName)
{
foreach ($estimateOptions as $options) {
if(isset($options[$estimateId][$optionName])) {
return true;
}
}
return false;
}
/**
* @param object $Item
*
*/
public function GetEstimateOptionData($Items, $Page = 'cart')
{
foreach ($Items as $Item) {
if (!$Item->getOptions()) {
continue;
}
#OrderItemの時 不要かな?
if ('order' == $Page) {
if (1 != $Item->getOrderItemTypeId()) {
continue;
}
}
$EstimateId = $Item->getEstimateId();
$Quantity = $Item->getQuantity();
$ProductClass = $Item->getProductClass();
$this->SetEstimateOption($EstimateId, $ProductClass, $Quantity);
}
return $this->GetEstimateOption();
}
/**
* 見積もりシミュレーション合計値を計算する
* 金額は金額モジュールより
*
* @param int $EstimateId
* @param object $ProductClass
* @param string $Option
*/
public function SetEstimateOption($EstimateId, $ProductClass, $Quantity, $Options = null)
{
#加工なし
if (!$EstimateId) {
return;
}
#数量設定なし
if (!$Quantity) {
return;
}
#Option の登録
if (!isset($this->EstimateOption[$EstimateId]['option']) && $Options) {
$this->EstimateOption[$EstimateId]['option'] = $Options;
}
#合計金額の算出
if (isset($this->EstimateOption[$EstimateId]['product_total'])) {
$this->EstimateOption[$EstimateId]['product_total'] += $Quantity * $ProductClass->getPrice02IncTax();
} else {
$this->EstimateOption[$EstimateId]['product_total'] = $Quantity * $ProductClass->getPrice02IncTax();
}
#数量の算出
if (isset($this->EstimateOption[$EstimateId]['quantity'])) {
$this->EstimateOption[$EstimateId]['quantity'] += $Quantity;
} else {
$this->EstimateOption[$EstimateId]['quantity'] = $Quantity;
}
if (!isset($this->EstimateOption[$EstimateId]['white_only'])) {
$this->EstimateOption[$EstimateId]['white_only'] = 1;
}
$ClassCategory1 = $ProductClass->getClassCategory1();
$Patan = $this->EccubeConfig['ESTIMATE_WHOIT_ONLY'];
if (!preg_match($Patan, $ClassCategory1->getBackendname())) {
$this->EstimateOption[$EstimateId]['white_only'] = 2;
}
return;
}
public function GetEstimateOption()
{
return $this->EstimateOption[self::DummyEstimateId] ?? $this->EstimateOption;
}
public function UpEstimateOption()
{
if (count($this->EstimateOption) < 1) {
return;
}
$Columns = ['product_total', 'quantity', 'white_only'];
foreach ($this->EstimateOption as $EstimateId => $Data) {
$Flg = false;
if (empty($Data['option'])) continue;
$Options = json_decode($Data['option'], true);
foreach ($Columns as $Column) {
if (($Options[$Column] ?? null) != $Data[$Column]) {
$Flg = true;
$Options[$Column] = $Data[$Column];
}
}
if ($Flg) {
$this->RunEstimateOptions($EstimateId, json_encode($Options));
}
}
}
public function UpRepeatEstimateOption()
{
if (!$this->EstimateOption) {
return;
}
$this->RunEstimateOptions($this->EstimateId, $this->Estimates);
}
protected function RunEstimateOptions($EstimateId, $Options)
{
foreach ($this->getCarts() as $cart) {
$this->CartItemRepository
->createQueryBuilder('ci')
->update()
->set('ci.options', ':Options')
->andWhere('ci.Cart = :CartId')
->andWhere('ci.EstimateId = :EstimateId')
->andWhere('ci.options IS NOT NULL')
->setParameter('Options', $Options)
->setParameter('CartId', $cart->getId())
->setParameter('EstimateId', $EstimateId)
->getQuery()
->execute();
}
}
/**
* 分割処理により
* 加工
* プリント =2 裾上げ =1 を返す
*
* @return inr
*/
public function getEstimateType()
{
foreach ($this->getCarts() as $i => $Cart) {
foreach ($Cart->getCartItems() as $Items) {
if (!$Options = $Items->getOptions()) {
continue;
}
$Option = json_decode($Options, true);
return $Option['type'] ?? 1;
}
}
}
/**
* 2022/10/22 カートに 商品を追加する
*
*
*/
public function AddCartProduct($Products)
{
//
$this->clearBuffer('isProductNoOptions');
//
foreach ($Products as $ClassId => $Quantity) {
if (!$Quantity) {
continue;
}
/**
* @var ProductClass $ProductClass
*/
$ProductClass = $this->GetProductClass($ClassId) ?? $ClassId;
//
$noOptions = $this->isProductNoOptions($ProductClass->getProduct()->getId());
//
$this->addProduct($ProductClass, $Quantity, $noOptions);
}
$this->save();
}
public function InitiarizeEstimate()
{
$this->Estimates = null;
$this->EstimateId = null;
}
/**
* @param string $name
* @return void
*/
public function clearBuffer($name = null)
{
if ($name === null) {
//
$this->_buffer = [];
} else {
//
unset($this->_buffer[$name]);
}
}
/**
* @param int $productId
* @return bool
*/
public function isProductNoOptions($productId)
{
//
$result = false;
//
if (!isset($this->_buffer['isProductNoOptions'])) {
//
$this->_buffer['isProductNoOptions'] = $productId;
} else {
//
$result = ($this->_buffer['isProductNoOptions'] != $productId);
}
//
return $result;
}
/**
* @return ProductClass[]
*/
public function getAllProductClasses()
{
/**
* @var ProductClass[] $ProductClasses
*/
$ProductClasses = [];
//
foreach ($this->getCarts() as $Cart) {
//
foreach ($Cart->getCartItems() as $CartItem) {
//
if ($CartItem->isProduct()) {
//
$ProductClasses[] = $CartItem->getProductClass();
}
}
}
//
return $ProductClasses;
}
/**
* @return ProductClass[]
*/
public function getEstimateProductClasses()
{
/**
* @var ProductClass[] $ProductClasses
*/
$ProductClasses = [];
//
foreach ($this->getCarts() as $Cart) {
//
foreach ($Cart->getCartItems() as $CartItem) {
//
if ($CartItem->isProduct() && !empty($CartItem->getOptions())) {
//
$ProductClasses[] = $CartItem->getProductClass();
}
}
}
//
return $ProductClasses;
}
public function hasSusoage()
{
//
return GoodsService::isSusoageExistInJanIdList(array_map(function ($ProductClass) {
//
return $ProductClass->getId();
}, $this->getEstimateProductClasses()));
}
public function hasNairePrint()
{
//
return GoodsService::isNairePrintExistInJanIdList(array_map(function ($ProductClass) {
//
return $ProductClass->getId();
}, $this->getEstimateProductClasses()));
}
public function hasKyouei()
{
//
return GoodsService::isKyoueiExistInJanIdList(array_map(function ($ProductClass) {
//
return $ProductClass->getId();
}, $this->getAllProductClasses()));
}
public function hasNairePrintWithKyouei()
//
{
return GoodsService::isNairePrintWithKyoueiExistInJanIdList(array_map(function ($ProductClass) {
//
return $ProductClass->getId();
}, $this->getEstimateProductClasses()));
}
public function hasNairePrintWithoutKyouei()
//
{
return GoodsService::isNairePrintWithoutKyoueiExistInJanIdList(array_map(function ($ProductClass) {
//
return $ProductClass->getId();
}, $this->getEstimateProductClasses()));
}
public function detectCartTypeByRouteName($routeName)
{
switch ($routeName) {
case self::ROUTE_ADD_NORMAL:
case self::ROUTE_ADD_LINE:
//
return self::CartTypeNormal;
break;
case self::ROUTE_VALID_ESTIMATE:
case self::ROUTE_ADD_ESTIMATE:
case self::ROUTE_ADD_HYBRID:
//
return self::CartTypeEstimate;
break;
case self::ROUTE_ADD_SAMPLE:
//
return self::CartTypeSample;
break;
case self::ROUTE_ADD_CATALOG:
//
return self::CartTypeCatalog;
break;
case self::ROUTE_ADD_REPEAT:
// TODO: リピート注文の排他制御対応
return $this->GetCartType();
break;
default:
//
throw new NotFoundHttpException();
}
}
/**
* @param string $routeName
* @param array $janIdList
* @param int|null $currentCartType
* @return int[]|true
*/
public function checkMixCart($routeName, array $janIdList, $pendingCartType = null, $currentCartType = null)
{
//
$result = [];
//
if ($pendingCartType === null) {
//
$pendingCartType = $this->detectCartTypeByRouteName($routeName);
}
//
if ($currentCartType === null) {
//
$currentCartType = $this->GetCartType();
}
//
if ($currentCartType === CartService::CartTypeNormal) {
//
if ($pendingCartType === CartService::CartTypeSample) {
// 購入(加工なし) × 貸出サンプル
return [
CartService::CartTypeNormal,
CartService::CartTypeSample,
];
} else if ($pendingCartType === CartService::CartTypeCatalog) {
// 購入(加工なし) × カタログ請求
return [
CartService::CartTypeNormal,
CartService::CartTypeCatalog,
];
}
} else if ($currentCartType === CartService::CartTypeEstimate) {
$canMixPrintAndSusoage = $this->EccubeConfig['MIX_PRINT_AND_SUSOAGE']['Enabled'] ?? false;
//
if ($pendingCartType === CartService::CartTypeSample) {
// 購入(加工あり) × 貸出サンプル
return [
CartService::CartTypeEstimate,
CartService::CartTypeSample,
];
} else if ($pendingCartType === CartService::CartTypeCatalog) {
// 購入(加工あり) × カタログ請求
return [
CartService::CartTypeEstimate,
CartService::CartTypeCatalog,
];
} else if ($pendingCartType === CartService::CartTypeEstimate) {
// 購入(加工あり) × 購入(加工あり)
if ($this->hasSusoage()) {
//
if (GoodsService::isNairePrintExistInJanIdList($janIdList) && !$canMixPrintAndSusoage) {
// 購入(加工あり)(裾上げ) × 購入(名入れ/プリント)
return [
CartService::CartTypeEstimate,
CartService::CartTypeEstimate,
\Lm\Entity\Estimate::TYPE_SUSOAGE,
\Lm\Entity\Estimate::TYPE_NAIRE_PRINT,
];
}
} else if ($this->hasNairePrint()) {
//
if (GoodsService::isSusoageExistInJanIdList($janIdList) && !$canMixPrintAndSusoage) {
// 購入(名入れ/プリント) × 購入(加工あり)(裾上げ)
return [
CartService::CartTypeEstimate,
CartService::CartTypeEstimate,
\Lm\Entity\Estimate::TYPE_NAIRE_PRINT,
\Lm\Entity\Estimate::TYPE_SUSOAGE,
];
} else if ($this->hasKyouei()) {
//
if (GoodsService::isNairePrintWithoutKyoueiExistInJanIdList($janIdList) && !$canMixPrintAndSusoage) {
// 購入(名入れ/プリント)(共栄) × 購入(名入れ/プリント)(共栄以外)
return [
CartService::CartTypeEstimate,
CartService::CartTypeEstimate,
\Lm\Entity\Estimate::TYPE_NAIRE_PRINT_KYOUEI,
\Lm\Entity\Estimate::TYPE_NAIRE_PRINT,
];
}
} else if (GoodsService::isNairePrintWithKyoueiExistInJanIdList($janIdList) && !$canMixPrintAndSusoage) {
// 購入(名入れ/プリント)(共栄以外) × 購入(名入れ/プリント)(共栄)
return [
CartService::CartTypeEstimate,
CartService::CartTypeEstimate,
\Lm\Entity\Estimate::TYPE_NAIRE_PRINT,
\Lm\Entity\Estimate::TYPE_NAIRE_PRINT_KYOUEI,
];
}
}
}
} else if ($currentCartType === CartService::CartTypeSample) {
//
if ($pendingCartType === self::CartTypeNormal) {
// 貸出サンプル × 購入(加工なし)
return [
CartService::CartTypeSample,
CartService::CartTypeNormal,
];
} else if ($pendingCartType === self::CartTypeEstimate) {
// 貸出サンプル × 購入(加工あり)
return [
CartService::CartTypeSample,
CartService::CartTypeEstimate,
];
} else if ($pendingCartType === self::CartTypeCatalog) {
// 貸出サンプル × カタログ請求
return [
CartService::CartTypeSample,
CartService::CartTypeCatalog,
];
}
} else if ($currentCartType === CartService::CartTypeCatalog) {
// カタログの場合、カタログ以外を入れようとすると上書きするように
}
//
return $result ?: true;
}
function createCommonCartKey()
{
if ($currentCustomer = $this->getUser()) {
return $currentCustomer->getId() . '_type_%s';
}
if ($this->session->has('cart_key_prefix')) {
return $this->session->get('cart_key_prefix') . '_type_%s';
}
do {
$random = StringUtil::random(32);
$cartKey = $random . '_type_%s';
$cart = $this->cartRepository->findOneBy(['cart_key' => $cartKey]);
} while ($cart);
$this->session->set('cart_key_prefix', $random);
return $cartKey;
}
function removeCart($cart)
{
foreach ($cart->getCartItems() as $i) {
$this->entityManager->remove($i);
$this->entityManager->flush();
}
$preOrderId = $cart->getPreOrderId();
$Order = $this->orderHelper->getPurchaseProcessingOrder($preOrderId);
if ($Order) {
$this->entityManager->remove($Order);
}
$this->entityManager->remove($cart);
$this->entityManager->flush();
}
/**
* @return CartItem[]
*/
function getAllCartsItems()
{
//
return array_merge(...(array_map(function ($cart) {
return is_array(($cartItems = $cart->getCartItems())) ? $cartItems : $cartItems->toArray();
}, $this->getCarts()) ?: [[]]));
}
public function removeCartItems($cartItemIds)
{
$cartItems = $this->getAllCartsItems();
foreach ($cartItems as $item) {
if (in_array($item->getId(), $cartItemIds)) {
$this->entityManager->remove($item);
}
}
$this->entityManager->flush();
}
/**
* @param bool|null $enabled
* @return bool|void
*/
public function bulkCheckoutEnabled($enabled = null)
{
if ($enabled === null) {
return $this->session->get(self::SESSION_BULK_CHECKOUT_ENABLED);
} else {
$this->session->set(self::SESSION_BULK_CHECKOUT_ENABLED, $enabled);
}
}
/**
* 在庫切れの商品が含まれていないかを確認する
* @return bool
* @throws \Exception
*/
public function isItemsStockAvailable()
{
//
foreach ($this->getCarts() as $cart) {
foreach ($cart->getCartItems() as $cartItem) {
if ($skuInfo = $cartItem->getProductClass()->getSkuInfo()) {
if ($skuInfo->getBackOrder() === Sku::BACK_ORDER_UNAVAILABLE && $skuInfo->getStockAvailability() === Sku::STOCK_AVL_OUT_OF_STOCK) {
// 入荷予定: なし
// 在庫状況: 在庫切れ
return false;
}
}
}
}
//
return true;
}
/**
* check cart has error Susoage has warning when change size, color, qty
* @return bool
* @throws \Exception
*/
public function listSusoageChange()
{
$listOrder = [];
foreach ($this->getCarts() as $cart) {
foreach ($cart->getCartItems() as $cartItem) {
$qty = 0;
$qtyItem = intval($cartItem->getQuantity());
$options = $cartItem->getOptions();
$options = json_decode($options, true);
if (isset($options['susoage']) and is_array($options['susoage'])) {
$productClass = $cartItem->getProductClass();
if ($productClass) {
if (!isset($options['susoage'][$productClass->getId()])) {
$listOrder[$cartItem->getEstimateId()] = $cartItem->getEstimateId();
}
}
foreach ($options['susoage'] as $classId =>$susoage) {
if($classId == $productClass->getId()){
$qty += count($susoage);
}
}
if ($qty != $qtyItem) {
$listOrder[$cartItem->getEstimateId()] = $cartItem->getEstimateId();
}
}
}
}
//
return $listOrder;
}
}