@@ -107,12 +107,15 @@ protected function mapAssociatedEntities($entityType, $objectField)
107
107
108
108
$ associatedEntities = $ this ->getConnection ()->fetchAll ($ select );
109
109
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 );
110
+ array_map (
111
+ function ($ associatedEntity ) use ($ entityInfo , $ ruleIdField , $ objectField ) {
112
+ $ item = $ this ->getItemByColumnValue ($ ruleIdField , $ associatedEntity [$ ruleIdField ]);
113
+ $ itemAssociatedValue = $ item ->getData ($ objectField ) === null ? [] : $ item ->getData ($ objectField );
114
+ $ itemAssociatedValue [] = $ associatedEntity [$ entityInfo ['entity_id_field ' ]];
115
+ $ item ->setData ($ objectField , $ itemAssociatedValue );
116
+ },
117
+ $ associatedEntities
118
+ );
116
119
}
117
120
118
121
/**
@@ -144,6 +147,7 @@ protected function _afterLoad()
144
147
* @use $this->addWebsiteGroupDateFilter()
145
148
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
146
149
* @return $this
150
+ * @throws \Zend_Db_Select_Exception
147
151
*/
148
152
public function setValidationFilter (
149
153
$ websiteId ,
@@ -153,32 +157,21 @@ public function setValidationFilter(
153
157
Address $ address = null
154
158
) {
155
159
if (!$ this ->getFlag ('validation_filter ' )) {
156
- /* We need to overwrite joinLeft if coupon is applied */
157
- $ this ->getSelect ()->reset ();
158
- parent ::_initSelect ();
159
160
160
- $ this ->addWebsiteGroupDateFilter ($ websiteId , $ customerGroupId , $ now );
161
- $ select = $ this ->getSelect ();
161
+ $ this ->prepareSelect ($ websiteId , $ customerGroupId , $ now );
162
162
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
- );
163
+ $ noCouponRules = $ this ->getNoCouponCodeSelect ();
164
+
165
+ if ($ couponCode ) {
166
+ $ couponRules = $ this ->getCouponCodeSelect ($ couponCode );
167
+ $ allAllowedRules = $ this ->getConnection ()->select ();
168
+ $ allAllowedRules ->union ([$ noCouponRules , $ couponRules ], \Zend_Db_Select::SQL_UNION_ALL );
169
+
170
+ $ this ->_select = $ allAllowedRules ;
176
171
} else {
177
- $ this ->addFieldToFilter (
178
- 'main_table.coupon_type ' ,
179
- \Magento \SalesRule \Model \Rule::COUPON_TYPE_NO_COUPON
180
- );
172
+ $ this ->_select = $ noCouponRules ;
181
173
}
174
+
182
175
$ this ->setOrder ('sort_order ' , self ::SORT_ORDER_ASC );
183
176
$ this ->setFlag ('validation_filter ' , true );
184
177
}
@@ -187,72 +180,96 @@ public function setValidationFilter(
187
180
}
188
181
189
182
/**
190
- * Get rules ids related to coupon code
183
+ * Recreate the default select object for specific needs of salesrule evaluation with coupon codes.
191
184
*
192
- * @param string $couponCode
193
- * @return array
185
+ * @param $websiteId
186
+ * @param $customerGroupId
187
+ * @param $now
194
188
*/
195
- private function getCouponRelatedRuleIds ( string $ couponCode ): array
189
+ private function prepareSelect ( $ websiteId , $ customerGroupId , $ now )
196
190
{
197
- $ connection = $ this ->getConnection ();
198
- $ select = $ connection ->select ()->from (
199
- ['main_table ' => $ this ->getTable ('salesrule ' )],
200
- 'rule_id '
191
+ $ this ->getSelect ()->reset ();
192
+ parent ::_initSelect ();
193
+
194
+ $ this ->addWebsiteGroupDateFilter ($ websiteId , $ customerGroupId , $ now );
195
+ }
196
+
197
+ /**
198
+ * Return select object to determine all active rules not needing a coupon code.
199
+ *
200
+ * @return Select
201
+ */
202
+ private function getNoCouponCodeSelect ()
203
+ {
204
+ $ noCouponSelect = clone $ this ->getSelect ();
205
+
206
+ $ noCouponSelect ->where (
207
+ 'main_table.coupon_type = ? ' ,
208
+ Rule::COUPON_TYPE_NO_COUPON
201
209
);
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
- )
210
+
211
+ $ noCouponSelect ->columns ([Coupon::KEY_CODE => new \Zend_Db_Expr ('NULL ' )]);
212
+
213
+ return $ noCouponSelect ;
214
+ }
215
+
216
+ /**
217
+ * Determine all active rules that are valid for the given coupon code.
218
+ *
219
+ * @param $couponCode
220
+ * @return Select
221
+ */
222
+ private function getCouponCodeSelect ($ couponCode )
223
+ {
224
+ $ couponSelect = clone $ this ->getSelect ();
225
+
226
+ $ this ->joinCouponTable ($ couponCode , $ couponSelect );
227
+
228
+ $ notExpired = $ this ->getConnection ()->quoteInto (
229
+ '(rule_coupons.expiration_date IS NULL OR rule_coupons.expiration_date >= ?) ' ,
230
+ $ this ->_date ->date ()->format ('Y-m-d ' )
209
231
);
210
232
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 ,
233
+ $ isAutogeneratedCoupon =
234
+ $ this ->getConnection ()->quoteInto ('main_table.coupon_type = ? ' , Rule::COUPON_TYPE_AUTO )
235
+ . ' AND ' .
236
+ $ this ->getConnection ()->quoteInto ('rule_coupons.type = ? ' , CouponInterface::TYPE_GENERATED );
237
+
238
+ $ isValidSpecificCoupon =
239
+ $ this ->getConnection ()->quoteInto ('(main_table.coupon_type = ?) ' , Rule::COUPON_TYPE_SPECIFIC )
240
+ . ' AND ( ' .
241
+ '(main_table.use_auto_generation = 1 AND rule_coupons.type = 1) '
242
+ . ' OR ' .
243
+ '(main_table.use_auto_generation = 0 AND rule_coupons.type = 0) '
244
+ . ') ' ;
245
+
246
+ $ couponSelect ->where (
247
+ "$ notExpired AND ( $ isAutogeneratedCoupon OR $ isValidSpecificCoupon) " ,
250
248
null ,
251
249
Select::TYPE_CONDITION
252
250
);
253
- $ select ->group ('main_table.rule_id ' );
254
251
255
- return $ connection ->fetchCol ($ select );
252
+ return $ couponSelect ;
253
+ }
254
+
255
+ /**
256
+ * @param $couponCode
257
+ * @param Select $couponSelect
258
+ */
259
+ private function joinCouponTable ($ couponCode , Select $ couponSelect )
260
+ {
261
+ $ couponJoinCondition =
262
+ 'main_table.rule_id = rule_coupons.rule_id '
263
+ . ' AND ' .
264
+ $ this ->getConnection ()->quoteInto ('main_table.coupon_type <> ? ' , Rule::COUPON_TYPE_NO_COUPON )
265
+ . ' AND ' .
266
+ $ this ->getConnection ()->quoteInto ('rule_coupons.code = ? ' , $ couponCode );
267
+
268
+ $ couponSelect ->joinInner (
269
+ ['rule_coupons ' => $ this ->getTable ('salesrule_coupon ' )],
270
+ $ couponJoinCondition ,
271
+ [Coupon::KEY_CODE ]
272
+ );
256
273
}
257
274
258
275
/**
0 commit comments