28 private static $instance;
32 private function __construct()
35 $this->basketCloneCache =
new SplObjectStorage;
36 $this->basketAddedProduct =
new SplObjectStorage;
44 private function getBasketCopy(
Basket $basket)
46 if(!$this->basketCloneCache->contains($basket))
48 $this->basketCloneCache[$basket] = $basket->copy();
51 if($this->basketAddedProduct->contains($this->basketCloneCache[$basket]))
53 foreach($this->basketAddedProduct[$this->basketCloneCache[$basket]] as $product)
55 $this->deleteProductFromBasket($this->basketCloneCache[$basket], $product);
57 $this->basketAddedProduct->detach($this->basketCloneCache[$basket]);
60 return $this->basketCloneCache[$basket];
77 $this->userId = $userId;
82 private function __clone()
91 if (!isset(self::$instance))
93 self::$instance =
new self;
96 return self::$instance;
110 $this->errorCollection->clear();
117 if($discounts ===
null || $appliedDiscounts ===
null)
119 list($discounts, $appliedDiscounts) = $this->getDiscounts($basket);
122 $appliedList =
array();
134 $potentialGiftData = $this->getPotentialGiftData($discounts, $appliedList);
136 $collections =
array();
137 foreach($potentialGiftData as $giftData)
139 $giftData[
'GiftValue'] = is_array($giftData[
'GiftValue'])? $giftData[
'GiftValue'] :
array($giftData[
'GiftValue']);
142 foreach($giftData[
'GiftValue'] as $value)
144 $giftCollection[] =
new Gift($value);
148 $collections[] = $giftCollection;
155 private function getGiftedProductIdsByAppliedDiscount(
array $discount)
161 $giftedProducts =
array();
162 foreach(
$discount[
'RESULT'][
'BASKET'] as $item)
164 if(empty($item[
'VALUE_PERCENT']) || $item[
'VALUE_PERCENT'] != 100)
170 if(empty($item[
'MODULE']) || $item[
'MODULE'] !==
'catalog')
174 $giftedProducts[] = $item[
'PRODUCT_ID'];
178 return $giftedProducts;
181 private function deleteGiftedProducts(
array $gifts,
array $giftedProductIds)
183 foreach($gifts as
$i => &$giftItem)
185 if($giftItem[
'Type'] === CSaleDiscountActionApply::GIFT_SELECT_TYPE_ONE)
187 if(array_intersect($giftedProductIds, (
array)$giftItem[
'GiftValue']))
193 elseif($giftItem[
'Type'] === CSaleDiscountActionApply::GIFT_SELECT_TYPE_ALL)
195 $giftItem[
'GiftValue'] = array_diff((
array)$giftItem[
'GiftValue'], $giftedProductIds);
196 if(!$giftItem[
'GiftValue'])
208 private function getPotentialGiftData(
array $discounts,
array $appliedDiscounts =
array())
215 $potentialGiftData =
array();
218 $giftedProductIds = $this->getGiftedProductIdsByAppliedDiscount(
$discount);
219 $potentialGiftData = array_merge(
221 $this->deleteGiftedProducts(
231 if(isset($appliedDiscounts[
$discount[
'ID']]))
236 $data = \CSaleActionGiftCtrlGroup::ProvideGiftProductData(
$discount);
241 $potentialGiftData = array_merge($potentialGiftData,
$data);
245 return $potentialGiftData;
248 private function isValidProduct(
array $product)
250 if(empty($product[
'ID']))
252 $this->errorCollection[] =
new Error(
'Product array has to have ID');
254 if(empty($product[
'MODULE']))
256 $this->errorCollection[] =
new Error(
'Product array has to have MODULE');
258 if(empty($product[
'PRODUCT_PROVIDER_CLASS']))
260 $this->errorCollection[] =
new Error(
'Product array has to have PRODUCT_PROVIDER_CLASS');
262 if(empty($product[
'QUANTITY']))
264 $this->errorCollection[] =
new Error(
'Product array has to have QUANTITY');
266 if($this->errorCollection->count())
286 $this->errorCollection->clear();
293 if(!$this->isValidProduct($product))
298 $pseudoBasket = $this->getBasketCopy($basket);
299 $checkProductInBasket = $this->checkProductInBasket($product, $pseudoBasket);
300 if($checkProductInBasket)
302 $this->deleteProductFromBasket($pseudoBasket, $product,
false);
306 $this->addProductToBasket($pseudoBasket, $product);
312 if(!$this->hasDifference($collectionsByBasket, $collectionsByPseudoBasket))
317 return $checkProductInBasket? $collectionsByBasket : $collectionsByPseudoBasket;
320 private function hasDifference(
array $collectionsA,
array $collectionsB)
322 foreach($collectionsA as
$i => $collectionA)
325 foreach($collectionsB as $j => $collectionB)
327 if($this->isEqual($collectionA, $collectionB))
330 unset($collectionsA[
$i]);
331 unset($collectionsB[$j]);
345 return (
bool)$collectionsB;
348 private function isEqual(Collection $collectionA, Collection $collectionB)
350 $productIdsFromCollectionA = $this->getProductIdsFromCollection($collectionA);
351 $productIdsFromCollectionB = $this->getProductIdsFromCollection($collectionB);
354 !array_diff($productIdsFromCollectionA, $productIdsFromCollectionB) &&
355 !array_diff($productIdsFromCollectionB, $productIdsFromCollectionA)
359 private function getProductIdsFromCollection(Collection $collection)
362 foreach($collection as $gift)
365 $idsFrom[$gift->getProductId()] = $gift->getProductId();
381 private function getAffectedReformattedBasketItemsInDiscount(Basket $basket,
array $discountData,
array $calcResults)
384 foreach($calcResults[
'PRICES'][
'BASKET'] as $basketCode => $priceData)
386 if(empty($priceData[
'DISCOUNT']))
390 if(!empty($priceData[
'PRICE']))
394 if(empty($calcResults[
'RESULT'][
'BASKET'][$basketCode]))
400 foreach($calcResults[
'RESULT'][
'BASKET'][$basketCode] as
$data)
402 if(
$data[
'DISCOUNT_ID'] == $discountData[
'ID'])
414 $basketItem = $basket->getItemByBasketCode($basketCode);
415 if(!$basketItem || $basketItem->getField(
'MODULE') !=
'catalog')
421 'PRODUCT_ID' => $basketItem->getProductId(),
422 'VALUE_PERCENT' =>
'100',
423 'MODULE' =>
'catalog',
431 private function getDiscounts(Basket $basket)
433 if($basket->getOrder())
435 throw new SystemException(
'Could not get discounts by basket which has order.');
440 $orderClass = $registry->getOrderClassName();
442 $order = $orderClass::create($basket->getSiteId(), $this->userId);
443 if(!
$order->setBasket($basket)->isSuccess())
449 $calcResults =
$discount->getApplyResult(
true);
452 $appliedDiscounts =
array();
453 foreach($calcResults[
'DISCOUNT_LIST'] as $discountData)
455 if(isset($calcResults[
'FULL_DISCOUNT_LIST'][$discountData[
'REAL_DISCOUNT_ID']]))
457 $appliedDiscounts[$discountData[
'REAL_DISCOUNT_ID']] = $calcResults[
'FULL_DISCOUNT_LIST'][$discountData[
'REAL_DISCOUNT_ID']];
458 if(empty($appliedDiscounts[$discountData[
'REAL_DISCOUNT_ID']][
'RESULT'][
'BASKET']))
460 $appliedDiscounts[$discountData[
'REAL_DISCOUNT_ID']][
'RESULT'][
'BASKET'] =
array();
463 $appliedDiscounts[$discountData[
'REAL_DISCOUNT_ID']][
'RESULT'][
'BASKET'] = array_merge(
464 $appliedDiscounts[$discountData[
'REAL_DISCOUNT_ID']][
'RESULT'][
'BASKET'],
465 $this->getAffectedReformattedBasketItemsInDiscount($basket, $discountData, $calcResults)
469 unset($discountData);
472 $calcResults[
'FULL_DISCOUNT_LIST'],
477 private function checkProductInBasket(
array $product, Basket $basket)
479 return (
bool)$this->getItemFromBasket($product, $basket);
482 private function getItemFromBasket(
array $product, Basket $basket)
484 foreach($basket as $item)
488 $item->getProductId() == $product[
'ID'] &&
489 $item->getField(
'MODULE') === $product[
'MODULE']
499 private function addProductToBasket(Basket $basket,
array $product)
501 $basketItem = $basket->createItem($product[
'MODULE'], $product[
'ID']);
502 unset($product[
'MODULE'], $product[
'ID']);
504 $result = $basketItem->setFields($product);
510 if(!$this->basketAddedProduct->contains($basket))
512 $this->basketAddedProduct[$basket] =
array($product);
516 $this->basketAddedProduct[$basket][] = $product;
520 private function deleteProductFromBasket(Basket $basket,
array $product,
bool $checkQuantity =
true)
522 $item = $this->getItemFromBasket($product, $basket);
523 if($item && (!$checkQuantity || $item->getQuantity() == $product[
'QUANTITY']))
529 private function existProductInAppliedDiscounts(
array $product,
array $appliedDiscounts)
533 if(array_search($product[
'ID'], $this->getGiftedProductIdsByAppliedDiscount(
$discount)) !==
false)
551 $this->errorCollection->clear();
558 if(!$this->isValidProduct($product))
563 if(!$this->checkProductInBasket($product, $basket))
565 $basket = $this->getBasketCopy($basket);
566 $this->addProductToBasket($basket, $product);
568 list(, $appliedDiscounts) = $this->getDiscounts($basket);
570 return $this->existProductInAppliedDiscounts($product, $appliedDiscounts);
591 return Option::get(
'sale',
'exists_discounts_with_gift',
'N') ===
'Y';
600 Option::set(
'sale',
'exists_discounts_with_gift',
'N');
609 Option::set(
'sale',
'exists_discounts_with_gift',
'Y');
if( $daysToExpire >=0 &&$daysToExpire< 60 elseif)( $daysToExpire< 0)