Pārlūkot izejas kodu

fix(core): Clear previous line adjustments before testing order item promotions (#3320)

Ben Loveridge 1 gadu atpakaļ
vecāks
revīzija
c970dea62f

+ 65 - 0
packages/core/src/service/helpers/order-calculator/order-calculator.spec.ts

@@ -1182,6 +1182,71 @@ describe('OrderCalculator', () => {
                     expect(order.subTotalWithTax).toBe(5719);
                 });
             });
+
+            it(`clear previous promotion state before testing`, async () => {
+                const noLineDiscountsCondition = new PromotionCondition({
+                    args: {},
+                    code: 'no_other_discounts_condition',
+                    description: [{ languageCode: LanguageCode.en, value: '' }],
+                    check(_ctx, _order) {
+                        const linesToDiscount = _order.lines
+                            .filter(line => !line.adjustments.length)
+                            .map(line => line.id);
+                        return linesToDiscount.length ? { lines: linesToDiscount } : false;
+                    },
+                });
+                const discountMatchedLinesAction = new PromotionItemAction({
+                    code: 'discount_matched_lines_action',
+                    conditions: [noLineDiscountsCondition],
+                    description: [{ languageCode: LanguageCode.en, value: '' }],
+                    args: { discount: { type: 'int' } },
+                    execute(_ctx, orderLine, args, state) {
+                        if (state.no_other_discounts_condition.lines.includes(orderLine.id)) {
+                            return -args.discount;
+                        }
+                        return 0;
+                    },
+                });
+
+                const discountAllUndiscountedItems = new Promotion({
+                    id: 1,
+                    name: 'Discount all undiscounted items',
+                    conditions: [
+                        {
+                            code: noLineDiscountsCondition.code,
+                            args: [],
+                        },
+                    ],
+                    promotionConditions: [noLineDiscountsCondition],
+                    actions: [
+                        {
+                            code: discountMatchedLinesAction.code,
+                            args: [{ name: 'discount', value: '50' }],
+                        },
+                    ],
+                    promotionActions: [discountMatchedLinesAction],
+                });
+
+                const ctx = createRequestContext({ pricesIncludeTax: false });
+                const order = createOrder({
+                    ctx,
+                    lines: [
+                        {
+                            listPrice: 500,
+                            taxCategory: taxCategoryStandard,
+                            quantity: 2,
+                        },
+                    ],
+                });
+
+                await orderCalculator.applyPriceAdjustments(ctx, order, [discountAllUndiscountedItems]);
+                // everything gets discounted by 50
+                expect(order.subTotal).toBe(900);
+                // should still be discounted after changing quantity
+                order.lines[0].quantity = 3;
+                await orderCalculator.applyPriceAdjustments(ctx, order, [discountAllUndiscountedItems]);
+                expect(order.subTotal).toBe(1350);
+            });
         });
     });
 

+ 1 - 1
packages/core/src/service/helpers/order-calculator/order-calculator.ts

@@ -186,8 +186,8 @@ export class OrderCalculator {
         for (const line of order.lines) {
             // Must be re-calculated for each line, since the previous lines may have triggered promotions
             // which affected the order price.
-            const applicablePromotions = await filterAsync(promotions, p => p.test(ctx, order).then(Boolean));
             line.clearAdjustments();
+            const applicablePromotions = await filterAsync(promotions, p => p.test(ctx, order).then(Boolean));
 
             for (const promotion of applicablePromotions) {
                 let priceAdjusted = false;