rule = $rule; $this->ruleUsedStock = $ruleUsedStock; /** @var FreeCartItemChoicesSuitability $freeCartItemChoicesSuitability */ $this->autoAddCartItemChoicesSuitability = Factory::get("Core_RuleProcessor_AutoAddCartItemChoicesSuitability"); } public function canAutoAdd() { return method_exists($this->rule, 'getAutoAdds') && boolval($this->rule->getAutoAdds()); } public function canItemAutoAdds() { return method_exists($this->rule, 'getAutoAddsCollection') && boolval($this->rule->getAutoAddsCollection()->asArray()); } /** * TODO implement! * Not requires without frontend implementation * * @param Cart $cart */ public function addAutoAdds(&$cart) { $rule = $this->rule; $gifts = $rule->getAutoAdds(); } /** * @param Cart $cart * @param CartItemsCollection $collection */ public function addCartItemAutoAdds(&$cart, $collection) { /** @var SingleItemRule $rule */ $rule = $this->rule; $totalQty = floatval(0); /** * @var array $itemIndexes * Cheap solution to fetch product with which we add free product. * Needed for gifting products from collection. * * ItemIndexes is a list with items and indexes. Index in nutshell is number of attempt at which we begin to use item. * For example: * We have 'single item' rule with collection 3 apple and 2 bananas and 1 orange. * So, itemIndexes will be * array( * array( 'index' => 1, 'item' => apple ), * array( 'index' => 4 (1 + qty of apple), 'item' => banana ), * array( 'index' => 6 (1 + qty of apple + qty of bananas ), 'item' => orange ), * ) * When we try to iterate on attempts, we get an item * Attempt count | item * 1 | apple * 2 | apple * 3 | apple * 4 | banana * 5 | banana * 6 | orange */ $itemIndexes = array(); foreach ($collection->get_items() as $item) { $itemIndexes[] = array( 'index' => $totalQty + 1, 'item' => $item, ); $totalQty += $item->getQty(); } $attemptCount = 0; if ($rule->getAutoAddStrategy() === $rule::BASED_ON_LIMIT_STRATEGY) { $attemptCount = min($totalQty, $rule->getAutoAddLimit()); } elseif ( $rule->getAutoAddStrategy() === $rule::BASED_ON_SUBTOTAL_EXCL_TAX_STRATEGY || $rule->getAutoAddStrategy() === $rule::BASED_ON_SUBTOTAL_INCL_TAX_STRATEGY ) { if ($rule->getAutoAddSubtotalDivider()) { $inclTax = $rule->getAutoAddStrategy() === $rule::BASED_ON_SUBTOTAL_INCL_TAX_STRATEGY; $tmpCart = clone $cart; foreach ($collection->get_items() as $item) { $tmpCart->addToCart($item); } $itemsSubtotals = (new CartTotals($tmpCart))->getSubtotal($inclTax); $attemptCount = intval($itemsSubtotals / $rule->getAutoAddSubtotalDivider()); } } /** @var array> $autoAddCartItemsByHash */ $autoAddCartItemsByHash = array(); $index = 0; while ($index < $attemptCount) { $index++; $item = null; foreach ($itemIndexes as $key => $data) { if ($data['index'] <= $index) { $item = $data['item']; } } if (!$item) { continue; } $giftIndex = 0; /** @var BasicCartItem $item */ foreach ($rule->getAutoAddsCollection()->asArray() as $autoAdd) { if ($autoAdd->getQty() <= 0) { continue; } $autoAddCartItemChoices = $this->convertAutoAddToAutoAddCartItemChoices($autoAdd, array($item)); $hash = $autoAddCartItemChoices->generateHash($rule, $giftIndex, $autoAdd); $this->processAutoAddItem($autoAddCartItemsByHash, $hash, $cart, $autoAddCartItemChoices); $autoAddCartItemChoices[$hash]['auto_add'] = $autoAdd; $giftIndex++; } } $customer = $cart->getContext()->getCustomer(); foreach ($autoAddCartItemsByHash as $hash => $autoAddArray) { $removedAutoAddItems = $customer->getRemovedAutoAddItems($hash); /** * @var $autoAdd AutoAdd */ $autoAdd = $autoAddArray['auto_add']; $discount = $autoAdd->getDiscount(); $productAdjustment = new SingleItemRule\ProductsAdjustment($discount); /** @var PriceCalculator $priceCalculator */ $priceCalculator = Factory::get( "Core_RuleProcessor_PriceCalculator", $this->rule, $productAdjustment->getDiscount() ); /** @var $autoAddCartItem AutoAddCartItem */ foreach ($autoAddArray['auto_add_cart_items'] as $autoAddCartItem) { $deletedQty = $removedAutoAddItems->get($autoAddCartItem->hash()); if($autoAddCartItem->getQty() <= $deletedQty) { $deletedQty = $autoAddCartItem->getQty(); $autoAddCartItem->setQty(0); } else { $autoAddCartItem->setQty($autoAddCartItem->getQty() - $deletedQty); } $removedAutoAddItems->set($autoAddCartItem->hash(), $deletedQty); $newPrice = $priceCalculator->calculateSinglePrice($autoAddCartItem->getPrice()); $autoAddCartItem->setPrice($newPrice); $cart->addToCart($autoAddCartItem); } } } /** * @param AutoAdd $autoAdd * @param array $items * * @return AutoAddCartItemChoices */ protected function convertAutoAddToAutoAddCartItemChoices($autoAdd, $items) { $newAutoAddChoices = array(); foreach ($autoAdd->getChoices() as $autoAddChoice) { if ($autoAddChoice->getType()->getValue() === AutoAddChoiceTypeEnum::CLONE_ADJUSTED) { $newAutoAddChoice = clone $autoAddChoice; $newAutoAddChoice->setType(new AutoAddChoiceTypeEnum(AutoAddChoiceTypeEnum::PRODUCT)); $values = array(); foreach ($items as $item) { $values[] = $item->getWcItem()->getProduct()->get_id(); } $newAutoAddChoice->setValues($values); $newAutoAddChoice->setMethod(new AutoAddChoiceMethodEnum(AutoAddChoiceMethodEnum::IN_LIST)); $newAutoAddChoices = array($newAutoAddChoice); break; } $newAutoAddChoices[] = $autoAddChoice; } $autoAddCartItemChoices = new AutoAddCartItemChoices(); $autoAddCartItemChoices->setChoices($newAutoAddChoices); $autoAddCartItemChoices->setRequiredQty($autoAdd->getQty()); return $autoAddCartItemChoices; } /** * @param Cart $cart * @param CartSetCollection $collection */ public function addCartSetAutoAdds(&$cart, $collection) { /** @var PackageRule $rule */ $rule = $this->rule; $totalQty = floatval(0); $setIndexes = array(); foreach ($collection->getSets() as $set) { $setIndexes[] = array( 'index' => $totalQty + 1, 'set' => $set, ); $totalQty += $set->getQty(); } $attemptCount = 0; if ($rule->getAutoAddStrategy() === $rule::BASED_ON_LIMIT_STRATEGY) { $attemptCount = min($totalQty, $rule->getItemGiftLimit()); } elseif ( $rule->getAutoAddStrategy() === $rule::BASED_ON_SUBTOTAL_EXCL_TAX_STRATEGY || $rule->getAutoAddStrategy() === $rule::BASED_ON_SUBTOTAL_INCL_TAX_STRATEGY ) { if ($rule->getAutoAddSubtotalDivider()) { $inclTax = $rule->getAutoAddStrategy() === $rule::BASED_ON_SUBTOTAL_INCL_TAX_STRATEGY; $tmpCart = clone $cart; foreach ($collection->getSets() as $set) { foreach ($set->getItems() as $item) { $tmpCart->addToCart($item); } } $itemsSubtotals = (new CartTotals($tmpCart))->getSubtotal($inclTax); $attemptCount = intval($itemsSubtotals / $rule->getAutoAddSubtotalDivider()); } } /** @var AutoAddCartItem[][] $autoAddCartItemsByHash */ $autoAddCartItemsByHash = array(); $index = 0; while ($index < $attemptCount) { $index++; $set = null; foreach ($setIndexes as $key => $data) { if ($data['index'] <= $index) { $set = $data['set']; } } if (!$set) { continue; } $giftIndex = 0; /** @var CartSet $set */ foreach ($rule->getAutoAddsCollection()->asArray() as $autoAdd) { if ($autoAdd->getQty() <= 0) { continue; } $autoAddCartItemChoices = $this->convertAutoAddToAutoAddCartItemChoices($autoAdd, $set->getItems()); $hash = $autoAddCartItemChoices->generateHash($rule, $giftIndex, $autoAdd); $this->processAutoAddItem($autoAddCartItemsByHash, $hash, $cart, $autoAddCartItemChoices); $autoAddCartItemChoices[$hash]['auto_add'] = $autoAdd; $giftIndex++; } } $customer = $cart->getContext()->getCustomer(); foreach ($autoAddCartItemsByHash as $hash => $autoAddArray) { $removedAutoAddItems = $customer->getRemovedAutoAddItems($hash); /** * @var $autoAdd AutoAdd */ $autoAdd = $autoAddArray['auto_add']; $discount = $autoAdd->getDiscount(); $productAdjustment = new SingleItemRule\ProductsAdjustment($discount); /** @var PriceCalculator $priceCalculator */ $priceCalculator = Factory::get( "Core_RuleProcessor_PriceCalculator", $this->rule, $productAdjustment->getDiscount() ); /** @var $autoAddCartItem AutoAddCartItem */ foreach ($autoAddArray['auto_add_cart_items'] as $autoAddCartItem) { $deletedQty = $removedAutoAddItems->get($autoAddCartItem->hash()); if($autoAddCartItem->getQty() <= $deletedQty) { $deletedQty = $autoAddCartItem->getQty(); $autoAddCartItem->setQty(0); } else { $autoAddCartItem->setQty($autoAddCartItem->getQty() - $deletedQty); } $removedAutoAddItems->set($autoAddCartItem->hash(), $deletedQty); $newPrice = $priceCalculator->calculateSinglePrice($autoAddCartItem->getPrice()); $autoAddCartItem->setPrice($newPrice); $cart->addToCart($autoAddCartItem); } } } /** * @param Cart $cart * @param int $productId * @param float $qty * @param string $associatedHash * @param array $variation * @param array $cartItemData * * @return AutoAddCartItem|false */ protected function prepareAutoAddCartItem( $cart, $productId, $qty, $associatedHash, $variation = array(), $cartItemData = array() ) { if (!($cart instanceof Cart && is_numeric($productId) && is_numeric($qty))) { return false; } if (!$this->canItemAutoAdds()) { return false; } /** @var SingleItemRule|PackageRule $rule */ $rule = $this->rule; $productId = intval($productId); $product = CacheHelper::getWcProduct($productId); $qty = floatval($qty); if ($qty < floatval(0)) { return false; } if ($qty === floatval(0)) { return false; } $isReplace = $rule->isReplaceAutoAdds(); $replaceCode = $rule->getReplaceAutoAddsCode(); $canBeRemoved = !$rule->getAutoAddRemoveDisable(); try { $autoAddItem = new AutoAddCartItem($product, $qty, $this->rule->getId(), $associatedHash); } catch (\Exception $e) { return false; } if (count($variation) > 0) { $autoAddItem->setVariation($variation); } $autoAddItem->setCartItemData($cartItemData); if ($isReplace && $replaceCode) { $autoAddItem->setReplaceWithCoupon($isReplace); $autoAddItem->setReplaceCouponCode($replaceCode); } $autoAddItem->setCanBeRemoved($canBeRemoved); $autoAddItem->setIsRecommended($rule->getAutoAddShowAsRecommended()); return $autoAddItem; } /** * @param array> $autoAddCartItemsByHash * @param string $hash * @param Cart $cart * @param AutoAddCartItemChoices $autoAddCartItemChoices * @param float $autoAddedCount */ protected function processAutoAddItem( &$autoAddCartItemsByHash, $hash, $cart, $autoAddCartItemChoices, $autoAddedCount = 0.0 ) { $readyList = $this->autoAddCartItemChoicesSuitability->getProductsSuitableToAutoAdd($autoAddCartItemChoices, $this->ruleUsedStock, $autoAddedCount); if (!isset($autoAddCartItemsByHash[$hash]['auto_add_cart_items'])) { $autoAddCartItemsByHash[$hash]['auto_add_cart_items'] = array(); } /** @var AutoAddCartItem[] $autoAddCartItems */ $autoAddCartItems = $autoAddCartItemsByHash[$hash]['auto_add_cart_items']; foreach ($readyList as $value) { list($productId, $qty) = $value; if (!($autoAddCartItem = $this->prepareAutoAddCartItem($cart, $productId, $qty, $hash))) { continue; } $calculatedHash = $autoAddCartItem->hash(); if (isset($autoAddCartItems[$calculatedHash])) { $autoAddCartItems[$calculatedHash]->setQty( $autoAddCartItems[$calculatedHash]->getQty() + $autoAddCartItem->getQty() ); } else { $autoAddCartItems[$calculatedHash] = clone $autoAddCartItem; } $this->ruleUsedStock->add( $autoAddCartItem->getProduct()->get_id(), $autoAddCartItem->getQty(), $autoAddCartItem->getProduct()->get_parent_id(), $autoAddCartItem->getVariation(), $autoAddCartItem->getCartItemData() ); } $autoAddCartItemsByHash[$hash]['auto_add_cart_items'] = $autoAddCartItems; } }