11
11
use Magento \Quote \Api \Data \AddressInterface ;
12
12
use Magento \Quote \Api \Data \ShippingAssignmentInterface ;
13
13
use Magento \Quote \Model \Quote ;
14
+ use Magento \Quote \Model \Quote \Address ;
14
15
use Magento \Quote \Model \Quote \Address \Total ;
15
16
use Magento \Quote \Model \Quote \Address \Total \AbstractTotal ;
16
17
use Magento \Quote \Model \Quote \Item ;
20
21
use Magento \SalesRule \Api \Data \RuleDiscountInterfaceFactory ;
21
22
use Magento \SalesRule \Model \Data \RuleDiscount ;
22
23
use Magento \SalesRule \Model \Discount \PostProcessorFactory ;
24
+ use Magento \SalesRule \Model \Rule ;
23
25
use Magento \SalesRule \Model \Validator ;
24
26
use Magento \Store \Model \StoreManagerInterface ;
27
+ use Magento \SalesRule \Model \RulesApplier ;
25
28
26
29
/**
27
30
* Discount totals calculation model.
@@ -66,21 +69,33 @@ class Discount extends AbstractTotal
66
69
*/
67
70
private $ discountDataInterfaceFactory ;
68
71
72
+ /**
73
+ * @var RulesApplier|null
74
+ */
75
+ private $ rulesApplier ;
76
+
77
+ /**
78
+ * @var array
79
+ */
80
+ private $ addressDiscountAggregator = [];
81
+
69
82
/**
70
83
* @param ManagerInterface $eventManager
71
84
* @param StoreManagerInterface $storeManager
72
85
* @param Validator $validator
73
86
* @param PriceCurrencyInterface $priceCurrency
74
87
* @param RuleDiscountInterfaceFactory|null $discountInterfaceFactory
75
88
* @param DiscountDataInterfaceFactory|null $discountDataInterfaceFactory
89
+ * @param RulesApplier|null $rulesApplier
76
90
*/
77
91
public function __construct (
78
92
ManagerInterface $ eventManager ,
79
93
StoreManagerInterface $ storeManager ,
80
94
Validator $ validator ,
81
95
PriceCurrencyInterface $ priceCurrency ,
82
96
RuleDiscountInterfaceFactory $ discountInterfaceFactory = null ,
83
- DiscountDataInterfaceFactory $ discountDataInterfaceFactory = null
97
+ DiscountDataInterfaceFactory $ discountDataInterfaceFactory = null ,
98
+ RulesApplier $ rulesApplier = null
84
99
) {
85
100
$ this ->setCode (self ::COLLECTOR_TYPE_CODE );
86
101
$ this ->eventManager = $ eventManager ;
@@ -91,6 +106,8 @@ public function __construct(
91
106
?: ObjectManager::getInstance ()->get (RuleDiscountInterfaceFactory::class);
92
107
$ this ->discountDataInterfaceFactory = $ discountDataInterfaceFactory
93
108
?: ObjectManager::getInstance ()->get (DiscountDataInterfaceFactory::class);
109
+ $ this ->rulesApplier = $ rulesApplier
110
+ ?: ObjectManager::getInstance ()->get (RulesApplier::class);
94
111
}
95
112
96
113
/**
@@ -102,88 +119,106 @@ public function __construct(
102
119
* @return $this
103
120
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
104
121
* @SuppressWarnings(PHPMD.NPathComplexity)
122
+ * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
105
123
*/
106
124
public function collect (
107
125
Quote $ quote ,
108
126
ShippingAssignmentInterface $ shippingAssignment ,
109
127
Total $ total
110
128
) {
111
129
parent ::collect ($ quote , $ shippingAssignment , $ total );
112
-
113
130
$ store = $ this ->storeManager ->getStore ($ quote ->getStoreId ());
131
+ /** @var Address $address */
114
132
$ address = $ shippingAssignment ->getShipping ()->getAddress ();
115
-
116
133
if ($ quote ->currentPaymentWasSet ()) {
117
134
$ address ->setPaymentMethod ($ quote ->getPayment ()->getMethod ());
118
135
}
119
-
120
136
$ this ->calculator ->reset ($ address );
121
-
122
- $ items = $ shippingAssignment ->getItems ();
123
- if (!count ($ items )) {
137
+ $ itemsAggregate = [];
138
+ foreach ($ shippingAssignment ->getItems () as $ item ) {
139
+ $ itemId = $ item ->getId ();
140
+ $ itemsAggregate [$ itemId ] = $ item ;
141
+ }
142
+ $ items = [];
143
+ foreach ($ quote ->getAllAddresses () as $ quoteAddress ) {
144
+ foreach ($ quoteAddress ->getAllItems () as $ item ) {
145
+ $ items [] = $ item ;
146
+ }
147
+ }
148
+ if (!$ items || !$ itemsAggregate ) {
124
149
return $ this ;
125
150
}
126
-
127
151
$ eventArgs = [
128
152
'website_id ' => $ store ->getWebsiteId (),
129
153
'customer_group_id ' => $ quote ->getCustomerGroupId (),
130
154
'coupon_code ' => $ quote ->getCouponCode (),
131
155
];
132
-
133
- $ this ->calculator ->init ($ store ->getWebsiteId (), $ quote ->getCustomerGroupId (), $ quote ->getCouponCode ());
134
- $ this ->calculator ->initTotals ($ items , $ address );
135
-
136
156
$ address ->setDiscountDescription ([]);
137
- $ items = $ this ->calculator ->sortItemsByPriority ($ items , $ address );
138
157
$ address ->getExtensionAttributes ()->setDiscounts ([]);
139
- $ addressDiscountAggregator = [];
140
-
141
- /** @var Item $item */
158
+ $ this -> addressDiscountAggregator = [];
159
+ $ address -> setCartFixedRules ([]);
160
+ $ quote -> setCartFixedRules ([]);
142
161
foreach ($ items as $ item ) {
143
- if ($ item ->getNoDiscount () || !$ this ->calculator ->canApplyDiscount ($ item )) {
144
- $ item ->setDiscountAmount (0 );
145
- $ item ->setBaseDiscountAmount (0 );
146
-
147
- // ensure my children are zeroed out
148
- if ($ item ->getHasChildren () && $ item ->isChildrenCalculated ()) {
149
- foreach ($ item ->getChildren () as $ child ) {
150
- $ child ->setDiscountAmount (0 );
151
- $ child ->setBaseDiscountAmount (0 );
152
- }
162
+ $ this ->rulesApplier ->setAppliedRuleIds ($ item , []);
163
+ if ($ item ->getExtensionAttributes ()) {
164
+ $ item ->getExtensionAttributes ()->setDiscounts (null );
165
+ }
166
+ $ item ->setDiscountAmount (0 );
167
+ $ item ->setBaseDiscountAmount (0 );
168
+ $ item ->setDiscountPercent (0 );
169
+ if ($ item ->getChildren () && $ item ->isChildrenCalculated ()) {
170
+ foreach ($ item ->getChildren () as $ child ) {
171
+ $ child ->setDiscountAmount (0 );
172
+ $ child ->setBaseDiscountAmount (0 );
173
+ $ child ->setDiscountPercent (0 );
174
+ }
175
+ }
176
+ }
177
+ $ this ->calculator ->init ($ store ->getWebsiteId (), $ quote ->getCustomerGroupId (), $ quote ->getCouponCode ());
178
+ $ this ->calculator ->initTotals ($ items , $ address );
179
+ $ items = $ this ->calculator ->sortItemsByPriority ($ items , $ address );
180
+ $ rules = $ this ->calculator ->getRules ($ address );
181
+ /** @var Rule $rule */
182
+ foreach ($ rules as $ rule ) {
183
+ /** @var Item $item */
184
+ foreach ($ items as $ item ) {
185
+ if ($ item ->getNoDiscount () || !$ this ->calculator ->canApplyDiscount ($ item ) || $ item ->getParentItem ()) {
186
+ continue ;
153
187
}
188
+ $ eventArgs ['item ' ] = $ item ;
189
+ $ this ->eventManager ->dispatch ('sales_quote_address_discount_item ' , $ eventArgs );
190
+ $ this ->calculator ->process ($ item , $ rule );
191
+ }
192
+ $ appliedRuleIds = $ quote ->getAppliedRuleIds () ? explode (', ' , $ quote ->getAppliedRuleIds ()) : [];
193
+ if ($ rule ->getStopRulesProcessing () && in_array ($ rule ->getId (), $ appliedRuleIds )) {
194
+ break ;
195
+ }
196
+ $ this ->calculator ->initTotals ($ items , $ address );
197
+ }
198
+ foreach ($ items as $ item ) {
199
+ if (!isset ($ itemsAggregate [$ item ->getId ()])) {
154
200
continue ;
155
201
}
156
- // to determine the child item discount, we calculate the parent
157
202
if ($ item ->getParentItem ()) {
158
203
continue ;
159
- }
160
-
161
- $ eventArgs ['item ' ] = $ item ;
162
- $ this ->eventManager ->dispatch ('sales_quote_address_discount_item ' , $ eventArgs );
163
-
164
- if ($ item ->getHasChildren () && $ item ->isChildrenCalculated ()) {
165
- $ this ->calculator ->process ($ item );
204
+ } elseif ($ item ->getHasChildren () && $ item ->isChildrenCalculated ()) {
166
205
foreach ($ item ->getChildren () as $ child ) {
167
206
$ eventArgs ['item ' ] = $ child ;
168
207
$ this ->eventManager ->dispatch ('sales_quote_address_discount_item ' , $ eventArgs );
169
208
$ this ->aggregateItemDiscount ($ child , $ total );
170
209
}
171
- } else {
172
- $ this ->calculator ->process ($ item );
173
- $ this ->aggregateItemDiscount ($ item , $ total );
174
210
}
211
+ $ this ->aggregateItemDiscount ($ item , $ total );
175
212
if ($ item ->getExtensionAttributes ()) {
176
- $ this ->aggregateDiscountPerRule ($ item , $ address, $ addressDiscountAggregator );
213
+ $ this ->aggregateDiscountPerRule ($ item , $ address );
177
214
}
178
215
}
179
-
180
216
$ this ->calculator ->prepareDescription ($ address );
181
217
$ total ->setDiscountDescription ($ address ->getDiscountDescription ());
182
218
$ total ->setSubtotalWithDiscount ($ total ->getSubtotal () + $ total ->getDiscountAmount ());
183
219
$ total ->setBaseSubtotalWithDiscount ($ total ->getBaseSubtotal () + $ total ->getBaseDiscountAmount ());
184
220
$ address ->setDiscountAmount ($ total ->getDiscountAmount ());
185
221
$ address ->setBaseDiscountAmount ($ total ->getBaseDiscountAmount ());
186
-
187
222
return $ this ;
188
223
}
189
224
@@ -273,13 +308,11 @@ public function fetch(Quote $quote, Total $total)
273
308
*
274
309
* @param AbstractItem $item
275
310
* @param AddressInterface $address
276
- * @param array $addressDiscountAggregator
277
311
* @return void
278
312
*/
279
313
private function aggregateDiscountPerRule (
280
314
AbstractItem $ item ,
281
- AddressInterface $ address ,
282
- array &$ addressDiscountAggregator
315
+ AddressInterface $ address
283
316
) {
284
317
$ discountBreakdown = $ item ->getExtensionAttributes ()->getDiscounts ();
285
318
if ($ discountBreakdown ) {
@@ -288,15 +321,17 @@ private function aggregateDiscountPerRule(
288
321
$ discount = $ value ->getDiscountData ();
289
322
$ ruleLabel = $ value ->getRuleLabel ();
290
323
$ ruleID = $ value ->getRuleID ();
291
- if (isset ($ addressDiscountAggregator [$ ruleID ])) {
324
+ if (isset ($ this -> addressDiscountAggregator [$ ruleID ])) {
292
325
/** @var RuleDiscount $cartDiscount */
293
- $ cartDiscount = $ addressDiscountAggregator [$ ruleID ];
326
+ $ cartDiscount = $ this -> addressDiscountAggregator [$ ruleID ];
294
327
$ discountData = $ cartDiscount ->getDiscountData ();
295
- $ discountData ->setBaseAmount ($ discountData ->getBaseAmount ()+$ discount ->getBaseAmount ());
296
- $ discountData ->setAmount ($ discountData ->getAmount ()+$ discount ->getAmount ());
297
- $ discountData ->setOriginalAmount ($ discountData ->getOriginalAmount ()+$ discount ->getOriginalAmount ());
328
+ $ discountData ->setBaseAmount ($ discountData ->getBaseAmount () + $ discount ->getBaseAmount ());
329
+ $ discountData ->setAmount ($ discountData ->getAmount () + $ discount ->getAmount ());
330
+ $ discountData ->setOriginalAmount (
331
+ $ discountData ->getOriginalAmount () + $ discount ->getOriginalAmount ()
332
+ );
298
333
$ discountData ->setBaseOriginalAmount (
299
- $ discountData ->getBaseOriginalAmount ()+ $ discount ->getBaseOriginalAmount ()
334
+ $ discountData ->getBaseOriginalAmount () + $ discount ->getBaseOriginalAmount ()
300
335
);
301
336
} else {
302
337
$ data = [
@@ -313,10 +348,10 @@ private function aggregateDiscountPerRule(
313
348
];
314
349
/** @var RuleDiscount $cartDiscount */
315
350
$ cartDiscount = $ this ->discountInterfaceFactory ->create (['data ' => $ data ]);
316
- $ addressDiscountAggregator [$ ruleID ] = $ cartDiscount ;
351
+ $ this -> addressDiscountAggregator [$ ruleID ] = $ cartDiscount ;
317
352
}
318
353
}
319
354
}
320
- $ address ->getExtensionAttributes ()->setDiscounts (array_values ($ addressDiscountAggregator ));
355
+ $ address ->getExtensionAttributes ()->setDiscounts (array_values ($ this -> addressDiscountAggregator ));
321
356
}
322
357
}
0 commit comments