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();
123 foreach($appliedDiscounts as $discount)
125 $appliedList[$discount[
'ID']] = $discount;
127 unset($discount, $appliedDiscounts);
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']);
141 $giftCollection =
new Collection(array(), $giftData[
'Type']);
142 foreach($giftData[
'GiftValue'] as $value)
144 $giftCollection[] =
new Gift($value);
148 $collections[] = $giftCollection;
155 private function getGiftedProductIdsByAppliedDiscount(array $discount)
157 if(empty($discount[
'RESULT'][
'BASKET']))
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();
216 foreach($appliedDiscounts as $discount)
218 $giftedProductIds = $this->getGiftedProductIdsByAppliedDiscount($discount);
219 $potentialGiftData = array_merge(
221 $this->deleteGiftedProducts(
222 \CSaleActionGiftCtrlGroup::ProvideGiftProductData($discount),
223 \CSaleActionGiftCtrlGroup::ExtendProductIds($giftedProductIds)
229 foreach($discounts as $discount)
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())
447 $discount = $order->getDiscount();
448 $discount->calculate();
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);
505 if(!$result->isSuccess())
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)
531 foreach($appliedDiscounts as $discount)
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);
581 return Analyzer::getInstance()->isContainGiftAction($discount);
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');