diff --git a/vendor/magento/module-sales-rule/Model/Rule/Condition/Product/Subselect.php b/vendor/magento/module-sales-rule/Model/Rule/Condition/Product/Subselect.php index 1c6d534bf0700..fc56e35d450fa 100644 --- a/vendor/magento/module-sales-rule/Model/Rule/Condition/Product/Subselect.php +++ b/vendor/magento/module-sales-rule/Model/Rule/Condition/Product/Subselect.php @@ -1,29 +1,33 @@ setType(\Magento\SalesRule\Model\Rule\Condition\Product\Subselect::class)->setValue(null); + $this->setType(Subselect::class)->setValue(null); } /** @@ -137,43 +141,97 @@ public function asHtml() } /** - * Validate + * Validate subSelect conditions, base_row_total and attribute * - * @param \Magento\Framework\Model\AbstractModel $model + * @param AbstractModel $model * @return bool * @SuppressWarnings(PHPMD.CyclomaticComplexity) */ - public function validate(\Magento\Framework\Model\AbstractModel $model) + public function validate(AbstractModel $model) { + $subSelectConditionsFlag = true; if (!$this->getConditions()) { return false; } $attr = $this->getAttribute(); $total = 0; - foreach ($model->getQuote()->getAllVisibleItems() as $item) { - $hasValidChild = false; - $useChildrenTotal = ($item->getProductType() == \Magento\Catalog\Model\Product\Type::TYPE_BUNDLE); - $childrenAttrTotal = 0; - $children = $item->getChildren(); - if (!empty($children)) { - foreach ($children as $child) { - if (parent::validate($child)) { - $hasValidChild = true; - if ($useChildrenTotal) { - $childrenAttrTotal += $child->getData($attr); - } - } - } + $isMultiShipping = (bool) $model->getQuote()->getIsMultiShipping(); + $items = $isMultiShipping ? $model->getAllItems() : $model->getQuote()->getAllVisibleItems(); + foreach ($items as $item) { + if ($isMultiShipping) { + $subSelectConditionsFlag = $this->validateSubSelectConditions($item); } - if ($attr !== TotalsItemInterface::KEY_BASE_ROW_TOTAL) { - $childrenAttrTotal *= $item->getQty(); + $total = $this->getBaseRowTotalForChildrenProduct($item, $attr, $total); + if ($subSelectConditionsFlag && $this->validateAttribute($total)) { + return true; } - if ($hasValidChild || parent::validate($item)) { - $total += ($hasValidChild && $useChildrenTotal && $childrenAttrTotal > 0) - ? $childrenAttrTotal - : $item->getData($attr); + } + return $subSelectConditionsFlag && $this->validateAttribute($total); + } + + /** + * Check subSelect conditions to verify if they are met + * + * @param mixed $item + * @return bool + */ + private function validateSubSelectConditions(mixed $item): bool + { + $subSelectConditionsFlag = true; + $all = $this->getAggregator() === 'all'; + $true = (bool)$this->getValue(); + $conditions = $this->getConditions(); + if (!empty($conditions)) { + foreach ($conditions as $cond) { + if ($item instanceof AbstractModel) { + $validated = $cond->validate($item); + } else { + $validated = $cond->validateByEntityId($item); + } + if ($all && $validated !== $true) { + $subSelectConditionsFlag = false; + break; + } elseif (!$all && $validated === $true) { + continue; + } } } - return $this->validateAttribute($total); + return $subSelectConditionsFlag; + } + + /** + * Get base row total for children product for bundle and configurable product + * + * @param mixed $item + * @param mixed $attr + * @param float $total + * @return float + * @SuppressWarnings(PHPMD.CyclomaticComplexity) + */ + private function getBaseRowTotalForChildrenProduct(mixed $item, mixed $attr, float $total): float + { + $hasValidChild = false; + $useChildrenTotal = ($item->getProductType() == Type::TYPE_BUNDLE); + $childrenAttrTotal = 0; + $children = $item->getChildren(); + if (!empty($children)) { + foreach ($children as $child) { + if (parent::validate($child)) { + $hasValidChild = true; + if ($useChildrenTotal) { + $childrenAttrTotal += $child->getData($attr); + } + } + } + } + if ($attr !== TotalsItemInterface::KEY_BASE_ROW_TOTAL) { + $childrenAttrTotal *= $item->getQty(); + } + if ($hasValidChild || parent::validate($item)) { + $total += ($hasValidChild && $useChildrenTotal && $childrenAttrTotal > 0) + ? $childrenAttrTotal + : $item->getData($attr); + } + return $total; } }