![]() Server : Apache System : Linux server2.corals.io 4.18.0-348.2.1.el8_5.x86_64 #1 SMP Mon Nov 15 09:17:08 EST 2021 x86_64 User : corals ( 1002) PHP Version : 7.4.33 Disable Function : exec,passthru,shell_exec,system Directory : /home/corals/old/vendor/magento/module-sales-rule/Model/ |
<?php /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ namespace Magento\SalesRule\Model; use Magento\Quote\Model\Quote\Address; use Magento\Quote\Model\Quote\Item\AbstractItem; use Magento\SalesRule\Model\Data\RuleDiscount; use Magento\SalesRule\Model\Quote\ChildrenValidationLocator; use Magento\Framework\App\ObjectManager; use Magento\SalesRule\Model\Rule\Action\Discount\CalculatorFactory; use Magento\SalesRule\Model\Rule\Action\Discount\Data; use Magento\SalesRule\Model\Rule\Action\Discount\DataFactory; use Magento\SalesRule\Api\Data\RuleDiscountInterfaceFactory; use Magento\SalesRule\Api\Data\DiscountDataInterfaceFactory; /** * Rule applier model * * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ class RulesApplier { /** * Application Event Dispatcher * * @var \Magento\Framework\Event\ManagerInterface */ protected $_eventManager; /** * @var \Magento\SalesRule\Model\Utility */ protected $validatorUtility; /** * @var ChildrenValidationLocator */ private $childrenValidationLocator; /** * @var CalculatorFactory */ private $calculatorFactory; /** * @var \Magento\SalesRule\Model\Rule\Action\Discount\DataFactory */ protected $discountFactory; /** * @var RuleDiscountInterfaceFactory */ private $discountInterfaceFactory; /** * @var DiscountDataInterfaceFactory */ private $discountDataInterfaceFactory; /** * @var array */ private $discountAggregator; /** * RulesApplier constructor. * @param CalculatorFactory $calculatorFactory * @param \Magento\Framework\Event\ManagerInterface $eventManager * @param Utility $utility * @param ChildrenValidationLocator|null $childrenValidationLocator * @param DataFactory|null $discountDataFactory * @param RuleDiscountInterfaceFactory|null $discountInterfaceFactory * @param DiscountDataInterfaceFactory|null $discountDataInterfaceFactory */ public function __construct( \Magento\SalesRule\Model\Rule\Action\Discount\CalculatorFactory $calculatorFactory, \Magento\Framework\Event\ManagerInterface $eventManager, \Magento\SalesRule\Model\Utility $utility, ChildrenValidationLocator $childrenValidationLocator = null, DataFactory $discountDataFactory = null, RuleDiscountInterfaceFactory $discountInterfaceFactory = null, DiscountDataInterfaceFactory $discountDataInterfaceFactory = null ) { $this->calculatorFactory = $calculatorFactory; $this->validatorUtility = $utility; $this->_eventManager = $eventManager; $this->childrenValidationLocator = $childrenValidationLocator ?: ObjectManager::getInstance()->get(ChildrenValidationLocator::class); $this->discountFactory = $discountDataFactory ?: ObjectManager::getInstance()->get(DataFactory::class); $this->discountInterfaceFactory = $discountInterfaceFactory ?: ObjectManager::getInstance()->get(RuleDiscountInterfaceFactory::class); $this->discountDataInterfaceFactory = $discountDataInterfaceFactory ?: ObjectManager::getInstance()->get(DiscountDataInterfaceFactory::class); } /** * Apply rules to current order item * * @param AbstractItem $item * @param array $rules * @param bool $skipValidation * @param mixed $couponCode * @return array * @SuppressWarnings(PHPMD.CyclomaticComplexity) */ public function applyRules($item, $rules, $skipValidation, $couponCode) { $address = $item->getAddress(); $appliedRuleIds = []; /* @var $rule Rule */ foreach ($rules as $rule) { if (!$this->validatorUtility->canProcessRule($rule, $address)) { continue; } if (!$skipValidation && !$rule->getActions()->validate($item)) { if (!$this->childrenValidationLocator->isChildrenValidationRequired($item)) { continue; } $childItems = $item->getChildren(); $isContinue = true; if (!empty($childItems)) { foreach ($childItems as $childItem) { if ($rule->getActions()->validate($childItem)) { $isContinue = false; } } } if ($isContinue) { continue; } } $this->applyRule($item, $rule, $address, $couponCode); $appliedRuleIds[$rule->getRuleId()] = $rule->getRuleId(); } return $appliedRuleIds; } /** * Add rule discount description label to address object * * @param Address $address * @param Rule $rule * @return $this */ public function addDiscountDescription($address, $rule) { $description = $address->getDiscountDescriptionArray(); $ruleLabel = $rule->getStoreLabel($address->getQuote()->getStore()); $label = ''; if ($ruleLabel) { $label = $ruleLabel; } else { if ($address->getCouponCode() !== null && strlen($address->getCouponCode())) { $label = $address->getCouponCode(); if ($rule->getDescription()) { $label = $rule->getDescription(); } } } if (strlen($label)) { $description[$rule->getId()] = $label; } $address->setDiscountDescriptionArray($description); return $this; } /** * Apply Rule * * @param AbstractItem $item * @param Rule $rule * @param \Magento\Quote\Model\Quote\Address $address * @param mixed $couponCode * @return $this */ protected function applyRule($item, $rule, $address, $couponCode) { if ($item->getChildren() && $item->isChildrenCalculated()) { $cloneItem = clone $item; /** * validate without children */ $applyAll = $rule->getActions()->validate($cloneItem); foreach ($item->getChildren() as $childItem) { if ($applyAll || $rule->getActions()->validate($childItem)) { $discountData = $this->getDiscountData($childItem, $rule, $address); $this->setDiscountData($discountData, $childItem); } } } else { $discountData = $this->getDiscountData($item, $rule, $address); $this->setDiscountData($discountData, $item); } $this->maintainAddressCouponCode($address, $rule, $couponCode); $this->addDiscountDescription($address, $rule); return $this; } /** * Get discount Data * * @param AbstractItem $item * @param \Magento\SalesRule\Model\Rule $rule * @param \Magento\Quote\Model\Quote\Address $address * @return Data */ protected function getDiscountData($item, $rule, $address) { $qty = $this->validatorUtility->getItemQty($item, $rule); $discountCalculator = $this->calculatorFactory->create($rule->getSimpleAction()); $qty = $discountCalculator->fixQuantity($qty, $rule); $discountData = $discountCalculator->calculate($rule, $item, $qty); $this->eventFix($discountData, $item, $rule, $qty); $this->validatorUtility->deltaRoundingFix($discountData, $item); $this->setDiscountBreakdown($discountData, $item, $rule, $address); /** * We can't use row total here because row total not include tax * Discount can be applied on price included tax */ $this->validatorUtility->minFix($discountData, $item, $qty); return $discountData; } /** * Set Discount Breakdown * * @param Data $discountData * @param \Magento\Quote\Model\Quote\Item\AbstractItem $item * @param \Magento\SalesRule\Model\Rule $rule * @param \Magento\Quote\Model\Quote\Address $address * @return $this */ private function setDiscountBreakdown($discountData, $item, $rule, $address) { if ($discountData->getAmount() > 0 && $item->getExtensionAttributes()) { $data = [ 'amount' => $discountData->getAmount(), 'base_amount' => $discountData->getBaseAmount(), 'original_amount' => $discountData->getOriginalAmount(), 'base_original_amount' => $discountData->getBaseOriginalAmount() ]; $itemDiscount = $this->discountDataInterfaceFactory->create(['data' => $data]); $ruleLabel = $rule->getStoreLabel($address->getQuote()->getStore()) ?: __('Discount'); $data = [ 'discount' => $itemDiscount, 'rule' => $ruleLabel, 'rule_id' => $rule->getId(), ]; /** @var RuleDiscount $itemDiscount */ $ruleDiscount = $this->discountInterfaceFactory->create(['data' => $data]); $this->discountAggregator[$item->getId()][$rule->getId()] = $ruleDiscount; $item->getExtensionAttributes()->setDiscounts(array_values($this->discountAggregator[$item->getId()])); $parentItem = $item->getParentItem(); if ($parentItem && $parentItem->getExtensionAttributes()) { $this->aggregateDiscountBreakdown($discountData, $parentItem, $rule, $address); } } return $this; } /** * Reset discount aggregator */ public function resetDiscountAggregator() { $this->discountAggregator = []; } /** * Add Discount Breakdown to existing discount data * * @param Data $discountData * @param AbstractItem $item * @param Rule $rule * @param Address $address */ private function aggregateDiscountBreakdown( Data $discountData, AbstractItem $item, Rule $rule, Address $address ): void { $ruleLabel = $rule->getStoreLabel($address->getQuote()->getStore()) ?: __('Discount'); /** @var RuleDiscount[] $discounts */ $discounts = []; foreach ((array) $item->getExtensionAttributes()->getDiscounts() as $discount) { $discounts[$discount->getRuleID()] = $discount; } $data = [ 'amount' => $discountData->getAmount(), 'base_amount' => $discountData->getBaseAmount(), 'original_amount' => $discountData->getOriginalAmount(), 'base_original_amount' => $discountData->getBaseOriginalAmount() ]; $discount = $discounts[$rule->getId()] ?? null; if (isset($discount)) { $data['amount'] += $discount->getDiscountData()->getAmount(); $data['base_amount'] += $discount->getDiscountData()->getBaseAmount(); $data['original_amount'] += $discount->getDiscountData()->getOriginalAmount(); $data['base_original_amount'] += $discount->getDiscountData()->getBaseOriginalAmount(); } $discounts[$rule->getId()] = $this->discountInterfaceFactory->create( [ 'data' => [ 'discount' => $this->discountDataInterfaceFactory->create(['data' => $data]), 'rule' => $ruleLabel, 'rule_id' => $rule->getId(), ] ] ); $item->getExtensionAttributes()->setDiscounts(array_values($discounts)); } /** * Set Discount data * * @param Data $discountData * @param AbstractItem $item * @return $this */ protected function setDiscountData($discountData, $item) { $item->setDiscountAmount($discountData->getAmount()); $item->setBaseDiscountAmount($discountData->getBaseAmount()); $item->setOriginalDiscountAmount($discountData->getOriginalAmount()); $item->setBaseOriginalDiscountAmount($discountData->getBaseOriginalAmount()); return $this; } /** * Set coupon code to address if $rule contains validated coupon * * @param Address $address * @param Rule $rule * @param mixed $couponCode * @return $this */ public function maintainAddressCouponCode($address, $rule, $couponCode) { /* Rule is a part of rules collection, which includes only rules with 'No Coupon' type or with validated coupon. As a result, if rule uses coupon code(s) ('Specific' or 'Auto' Coupon Type), it always contains validated coupon */ if ($rule->getCouponType() != Rule::COUPON_TYPE_NO_COUPON) { $address->setCouponCode($couponCode); } return $this; } /** * Fire event to allow overwriting of discount amounts * * @param Data $discountData * @param AbstractItem $item * @param Rule $rule * @param float $qty * @return $this */ protected function eventFix( Data $discountData, AbstractItem $item, Rule $rule, $qty ) { $quote = $item->getQuote(); $address = $item->getAddress(); $this->_eventManager->dispatch( 'salesrule_validator_process', [ 'rule' => $rule, 'item' => $item, 'address' => $address, 'quote' => $quote, 'qty' => $qty, 'result' => $discountData ] ); return $this; } /** * Set Applied Rule Ids * * @param AbstractItem $item * @param int[] $appliedRuleIds * @return $this */ public function setAppliedRuleIds(AbstractItem $item, array $appliedRuleIds) { $address = $item->getAddress(); $quote = $item->getQuote(); $item->setAppliedRuleIds($this->validatorUtility->mergeIds($item->getAppliedRuleIds(), $appliedRuleIds)); $address->setAppliedRuleIds($this->validatorUtility->mergeIds($address->getAppliedRuleIds(), $appliedRuleIds)); $quote->setAppliedRuleIds($this->validatorUtility->mergeIds($quote->getAppliedRuleIds(), $appliedRuleIds)); return $this; } }