Skip to content

Commit 11e5397

Browse files
committed
Merge branch 'fuehrd-2.3-develop' into 2.3-develop
2 parents 91fecf7 + 5ca9dbd commit 11e5397

File tree

1 file changed

+108
-84
lines changed

1 file changed

+108
-84
lines changed

app/code/Magento/SalesRule/Model/ResourceModel/Rule/Collection.php

Lines changed: 108 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@
99
use Magento\Framework\DB\Select;
1010
use Magento\Framework\Serialize\Serializer\Json;
1111
use Magento\Quote\Model\Quote\Address;
12+
use Magento\SalesRule\Api\Data\CouponInterface;
13+
use Magento\SalesRule\Model\Coupon;
14+
use Magento\SalesRule\Model\Rule;
1215

1316
/**
1417
* Sales Rules resource collection model.
@@ -107,12 +110,15 @@ protected function mapAssociatedEntities($entityType, $objectField)
107110

108111
$associatedEntities = $this->getConnection()->fetchAll($select);
109112

110-
array_map(function ($associatedEntity) use ($entityInfo, $ruleIdField, $objectField) {
111-
$item = $this->getItemByColumnValue($ruleIdField, $associatedEntity[$ruleIdField]);
112-
$itemAssociatedValue = $item->getData($objectField) === null ? [] : $item->getData($objectField);
113-
$itemAssociatedValue[] = $associatedEntity[$entityInfo['entity_id_field']];
114-
$item->setData($objectField, $itemAssociatedValue);
115-
}, $associatedEntities);
113+
array_map(
114+
function ($associatedEntity) use ($entityInfo, $ruleIdField, $objectField) {
115+
$item = $this->getItemByColumnValue($ruleIdField, $associatedEntity[$ruleIdField]);
116+
$itemAssociatedValue = $item->getData($objectField) ?? [];
117+
$itemAssociatedValue[] = $associatedEntity[$entityInfo['entity_id_field']];
118+
$item->setData($objectField, $itemAssociatedValue);
119+
},
120+
$associatedEntities
121+
);
116122
}
117123

118124
/**
@@ -141,6 +147,7 @@ protected function _afterLoad()
141147
* @param string $couponCode
142148
* @param string|null $now
143149
* @param Address $address allow extensions to further filter out rules based on quote address
150+
* @throws \Zend_Db_Select_Exception
144151
* @use $this->addWebsiteGroupDateFilter()
145152
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
146153
* @return $this
@@ -153,32 +160,25 @@ public function setValidationFilter(
153160
Address $address = null
154161
) {
155162
if (!$this->getFlag('validation_filter')) {
156-
/* We need to overwrite joinLeft if coupon is applied */
157-
$this->getSelect()->reset();
158-
parent::_initSelect();
159163

160-
$this->addWebsiteGroupDateFilter($websiteId, $customerGroupId, $now);
161-
$select = $this->getSelect();
164+
$this->prepareSelect($websiteId, $customerGroupId, $now);
162165

163-
$connection = $this->getConnection();
164-
if (strlen($couponCode)) {
165-
$noCouponWhereCondition = $connection->quoteInto(
166-
'main_table.coupon_type = ?',
167-
\Magento\SalesRule\Model\Rule::COUPON_TYPE_NO_COUPON
168-
);
169-
$relatedRulesIds = $this->getCouponRelatedRuleIds($couponCode);
170-
171-
$select->where(
172-
$noCouponWhereCondition . ' OR main_table.rule_id IN (?)',
173-
$relatedRulesIds,
174-
Select::TYPE_CONDITION
175-
);
166+
$noCouponRules = $this->getNoCouponCodeSelect();
167+
168+
if ($couponCode) {
169+
$couponRules = $this->getCouponCodeSelect($couponCode);
170+
171+
$allAllowedRules = $this->getConnection()->select();
172+
$allAllowedRules->union([$noCouponRules, $couponRules], \Zend_Db_Select::SQL_UNION_ALL);
173+
174+
$wrapper = $this->getConnection()->select();
175+
$wrapper->from($allAllowedRules);
176+
177+
$this->_select = $wrapper;
176178
} else {
177-
$this->addFieldToFilter(
178-
'main_table.coupon_type',
179-
\Magento\SalesRule\Model\Rule::COUPON_TYPE_NO_COUPON
180-
);
179+
$this->_select = $noCouponRules;
181180
}
181+
182182
$this->setOrder('sort_order', self::SORT_ORDER_ASC);
183183
$this->setFlag('validation_filter', true);
184184
}
@@ -187,72 +187,96 @@ public function setValidationFilter(
187187
}
188188

189189
/**
190-
* Get rules ids related to coupon code
190+
* Recreate the default select object for specific needs of salesrule evaluation with coupon codes.
191191
*
192-
* @param string $couponCode
193-
* @return array
192+
* @param $websiteId
193+
* @param $customerGroupId
194+
* @param $now
194195
*/
195-
private function getCouponRelatedRuleIds(string $couponCode): array
196+
private function prepareSelect($websiteId, $customerGroupId, $now)
196197
{
197-
$connection = $this->getConnection();
198-
$select = $connection->select()->from(
199-
['main_table' => $this->getTable('salesrule')],
200-
'rule_id'
198+
$this->getSelect()->reset();
199+
parent::_initSelect();
200+
201+
$this->addWebsiteGroupDateFilter($websiteId, $customerGroupId, $now);
202+
}
203+
204+
/**
205+
* Return select object to determine all active rules not needing a coupon code.
206+
*
207+
* @return Select
208+
*/
209+
private function getNoCouponCodeSelect()
210+
{
211+
$noCouponSelect = clone $this->getSelect();
212+
213+
$noCouponSelect->where(
214+
'main_table.coupon_type = ?',
215+
Rule::COUPON_TYPE_NO_COUPON
201216
);
202-
$select->joinLeft(
203-
['rule_coupons' => $this->getTable('salesrule_coupon')],
204-
$connection->quoteInto(
205-
'main_table.rule_id = rule_coupons.rule_id AND main_table.coupon_type != ?',
206-
\Magento\SalesRule\Model\Rule::COUPON_TYPE_NO_COUPON,
207-
null
208-
)
217+
218+
$noCouponSelect->columns([Coupon::KEY_CODE => new \Zend_Db_Expr('NULL')]);
219+
220+
return $noCouponSelect;
221+
}
222+
223+
/**
224+
* Determine all active rules that are valid for the given coupon code.
225+
*
226+
* @param $couponCode
227+
* @return Select
228+
*/
229+
private function getCouponCodeSelect($couponCode)
230+
{
231+
$couponSelect = clone $this->getSelect();
232+
233+
$this->joinCouponTable($couponCode, $couponSelect);
234+
235+
$notExpired = $this->getConnection()->quoteInto(
236+
'(rule_coupons.expiration_date IS NULL OR rule_coupons.expiration_date >= ?)',
237+
$this->_date->date()->format('Y-m-d')
209238
);
210239

211-
$autoGeneratedCouponCondition = [
212-
$connection->quoteInto(
213-
"main_table.coupon_type = ?",
214-
\Magento\SalesRule\Model\Rule::COUPON_TYPE_AUTO
215-
),
216-
$connection->quoteInto(
217-
"rule_coupons.type = ?",
218-
\Magento\SalesRule\Api\Data\CouponInterface::TYPE_GENERATED
219-
),
220-
];
221-
222-
$orWhereConditions = [
223-
"(" . implode($autoGeneratedCouponCondition, " AND ") . ")",
224-
$connection->quoteInto(
225-
'(main_table.coupon_type = ? AND main_table.use_auto_generation = 1 AND rule_coupons.type = 1)',
226-
\Magento\SalesRule\Model\Rule::COUPON_TYPE_SPECIFIC
227-
),
228-
$connection->quoteInto(
229-
'(main_table.coupon_type = ? AND main_table.use_auto_generation = 0 AND rule_coupons.type = 0)',
230-
\Magento\SalesRule\Model\Rule::COUPON_TYPE_SPECIFIC
231-
),
232-
];
233-
234-
$andWhereConditions = [
235-
$connection->quoteInto(
236-
'rule_coupons.code = ?',
237-
$couponCode
238-
),
239-
$connection->quoteInto(
240-
'(rule_coupons.expiration_date IS NULL OR rule_coupons.expiration_date >= ?)',
241-
$this->_date->date()->format('Y-m-d')
242-
),
243-
];
244-
245-
$orWhereCondition = implode(' OR ', $orWhereConditions);
246-
$andWhereCondition = implode(' AND ', $andWhereConditions);
247-
248-
$select->where(
249-
'(' . $orWhereCondition . ') AND ' . $andWhereCondition,
240+
$isAutogenerated =
241+
$this->getConnection()->quoteInto('main_table.coupon_type = ?', Rule::COUPON_TYPE_AUTO)
242+
. ' AND ' .
243+
$this->getConnection()->quoteInto('rule_coupons.type = ?', CouponInterface::TYPE_GENERATED);
244+
245+
$isValidSpecific =
246+
$this->getConnection()->quoteInto('(main_table.coupon_type = ?)', Rule::COUPON_TYPE_SPECIFIC)
247+
. ' AND (' .
248+
'(main_table.use_auto_generation = 1 AND rule_coupons.type = 1)'
249+
. ' OR ' .
250+
'(main_table.use_auto_generation = 0 AND rule_coupons.type = 0)'
251+
. ')';
252+
253+
$couponSelect->where(
254+
"$notExpired AND ($isAutogenerated OR $isValidSpecific)",
250255
null,
251256
Select::TYPE_CONDITION
252257
);
253-
$select->group('main_table.rule_id');
254258

255-
return $connection->fetchCol($select);
259+
return $couponSelect;
260+
}
261+
262+
/**
263+
* @param $couponCode
264+
* @param Select $couponSelect
265+
*/
266+
private function joinCouponTable($couponCode, Select $couponSelect)
267+
{
268+
$couponJoinCondition =
269+
'main_table.rule_id = rule_coupons.rule_id'
270+
. ' AND ' .
271+
$this->getConnection()->quoteInto('main_table.coupon_type <> ?', Rule::COUPON_TYPE_NO_COUPON)
272+
. ' AND ' .
273+
$this->getConnection()->quoteInto('rule_coupons.code = ?', $couponCode);
274+
275+
$couponSelect->joinInner(
276+
['rule_coupons' => $this->getTable('salesrule_coupon')],
277+
$couponJoinCondition,
278+
[Coupon::KEY_CODE]
279+
);
256280
}
257281

258282
/**

0 commit comments

Comments
 (0)