diff --git a/vendor/magento/module-offline-shipping/Model/SalesRule/Calculator.php b/vendor/magento/module-offline-shipping/Model/SalesRule/Calculator.php index dfc22896d25..ee37b1a7c79 100644 --- a/vendor/magento/module-offline-shipping/Model/SalesRule/Calculator.php +++ b/vendor/magento/module-offline-shipping/Model/SalesRule/Calculator.php @@ -4,14 +4,12 @@ * See COPYING.txt for license details. */ -/** - * Shopping Cart Rule data model - * - * @author Magento Core Team - */ namespace Magento\OfflineShipping\Model\SalesRule; +use Magento\Quote\Model\Quote\Address; +use Magento\Quote\Model\Quote\Item\AbstractItem; use Magento\SalesRule\Model\Validator; +use \Magento\SalesRule\Model\Rule as SalesRule; /** * @api @@ -24,38 +22,110 @@ class Calculator extends Validator * This process not affect information about applied rules, coupon code etc. * This information will be added during discount amounts processing * - * @param \Magento\Quote\Model\Quote\Item\AbstractItem $item + * @param AbstractItem $item + * * @return \Magento\OfflineShipping\Model\SalesRule\Calculator + * + * @throws \Zend_Db_Select_Exception */ - public function processFreeShipping(\Magento\Quote\Model\Quote\Item\AbstractItem $item) + public function processFreeShipping(AbstractItem $item) { $address = $item->getAddress(); - $item->setFreeShipping(false); + $this->resetFreeShipping($item); + /* @var $rule SalesRule */ foreach ($this->getRules($address) as $rule) { - /* @var $rule \Magento\SalesRule\Model\Rule */ - if (!$this->validatorUtility->canProcessRule($rule, $address)) { + if (!$this->canApplyRuleToItem($rule, $address, $item)) { continue; } - if (!$rule->getActions()->validate($item)) { - continue; - } + $this->applyFreeShippingRule($rule, $address, $item); - switch ($rule->getSimpleFreeShipping()) { - case Rule::FREE_SHIPPING_ITEM: - $item->setFreeShipping($rule->getDiscountQty() ? $rule->getDiscountQty() : true); - $item->setFreeShippingMethod($item->getAddress()->getShippingMethod()); - break; - - case Rule::FREE_SHIPPING_ADDRESS: - $address->setFreeShipping(true); - break; - } if ($rule->getStopRulesProcessing()) { break; } } + return $this; } + + /** + * Validates rule for item + * + * @param SalesRule $rule + * @param Address $address + * @param AbstractItem $item + * + * @return bool + */ + private function canApplyRuleToItem(SalesRule $rule, Address $address, AbstractItem $item): bool + { + if (!$this->validatorUtility->canProcessRule($rule, $address)) { + return false; + } + + return (bool) $rule->getActions()->validate($item); + } + + /** + * Apply free shipping rule for cart item + * + * @param SalesRule $rule + * @param Address $address + * @param AbstractItem $item + * + * @return void + */ + private function applyFreeShippingRule(SalesRule $rule, Address $address, AbstractItem $item): void + { + $type = (int) $rule->getSimpleFreeShipping(); + + if ($type === Rule::FREE_SHIPPING_ITEM) { + $this->applyItemFreeShipping($rule, $item); + return; + } + + if ($type === Rule::FREE_SHIPPING_ADDRESS) { + $address->setFreeShipping(true); + } + } + + /** + * Free shipping can be applied to parent or child items + * + * @param SalesRule $rule + * @param AbstractItem $item + * + * @return void + */ + private function applyItemFreeShipping(SalesRule $rule, AbstractItem $item): void + { + $method = $item->getAddress()->getShippingMethod(); + $item->setFreeShipping($rule->getDiscountQty() ? $rule->getDiscountQty() : true); + $item->setFreeShippingMethod($method); + + if ($item->getHasChildren() && $item->isShipSeparately()) { + foreach ($item->getChildren() as $child) { + $child->setFreeShipping($rule->getDiscountQty() ? $rule->getDiscountQty() : true); + $child->setFreeShippingMethod($method); + } + } + } + + /** + * Reset free shipping for item + * + * @param AbstractItem $item + * + * @return void + */ + private function resetFreeShipping(AbstractItem $item): void + { + $item->setFreeShipping(false); + if ($item->getHasChildren() && $item->isShipSeparately()) { + foreach ($item->getChildren() as $child) { + $child->setFreeShipping(false); + } + } + } }