Bladeren bron

fix(core): Apply Promotions when calculating modified order total

Relates to #688
Michael Bromley 5 jaren geleden
bovenliggende
commit
c678a216f3

+ 100 - 3
packages/core/e2e/order-modification.e2e-spec.ts

@@ -14,11 +14,17 @@ import path from 'path';
 import { initialData } from '../../../e2e-common/e2e-initial-data';
 import { testConfig, TEST_SETUP_TIMEOUT_MS } from '../../../e2e-common/test-config';
 import { manualFulfillmentHandler } from '../src/config/fulfillment/manual-fulfillment-handler';
+import { orderFixedDiscount } from '../src/config/promotion/actions/order-fixed-discount-action';
 
-import { testSuccessfulPaymentMethod } from './fixtures/test-payment-methods';
+import {
+    failsToSettlePaymentMethod,
+    testFailingPaymentMethod,
+    testSuccessfulPaymentMethod,
+} from './fixtures/test-payment-methods';
 import {
     AddManualPayment,
     AdminTransition,
+    CreatePromotion,
     CreateShippingMethod,
     ErrorCode,
     GetOrder,
@@ -31,10 +37,12 @@ import {
     OrderFragment,
     OrderWithLinesFragment,
     OrderWithModificationsFragment,
+    SettlePayment,
     UpdateProductVariants,
 } from './graphql/generated-e2e-admin-types';
 import {
     AddItemToOrderMutationVariables,
+    ApplyCouponCode,
     SetShippingAddress,
     SetShippingMethod,
     TestOrderWithPaymentsFragment,
@@ -43,12 +51,19 @@ import {
 } from './graphql/generated-e2e-shop-types';
 import {
     ADMIN_TRANSITION_TO_STATE,
+    CREATE_PROMOTION,
     CREATE_SHIPPING_METHOD,
     GET_ORDER,
     GET_ORDER_HISTORY,
+    SETTLE_PAYMENT,
     UPDATE_PRODUCT_VARIANTS,
 } from './graphql/shared-definitions';
-import { SET_SHIPPING_ADDRESS, SET_SHIPPING_METHOD, TRANSITION_TO_STATE } from './graphql/shop-definitions';
+import {
+    APPLY_COUPON_CODE,
+    SET_SHIPPING_ADDRESS,
+    SET_SHIPPING_METHOD,
+    TRANSITION_TO_STATE,
+} from './graphql/shop-definitions';
 import { addPaymentToOrder, proceedToArrangingPayment } from './utils/test-order-utils';
 
 const SHIPPING_GB = 500;
@@ -82,7 +97,14 @@ describe('Order modification', () => {
     const { server, adminClient, shopClient } = createTestEnvironment(
         mergeConfig(testConfig, {
             paymentOptions: {
-                paymentMethodHandlers: [testSuccessfulPaymentMethod],
+                paymentMethodHandlers: [
+                    testSuccessfulPaymentMethod,
+                    failsToSettlePaymentMethod,
+                    testFailingPaymentMethod,
+                ],
+            },
+            promotionOptions: {
+                promotionConditions: [orderFixedDiscount],
             },
             shippingOptions: {
                 shippingCalculators: [defaultShippingCalculator, testCalculator],
@@ -109,6 +131,14 @@ describe('Order modification', () => {
                         name: testSuccessfulPaymentMethod.code,
                         handler: { code: testSuccessfulPaymentMethod.code, arguments: [] },
                     },
+                    {
+                        name: failsToSettlePaymentMethod.code,
+                        handler: { code: failsToSettlePaymentMethod.code, arguments: [] },
+                    },
+                    {
+                        name: testFailingPaymentMethod.code,
+                        handler: { code: testFailingPaymentMethod.code, arguments: [] },
+                    },
                 ],
             },
             productsCsvPath: path.join(__dirname, 'fixtures/e2e-products-full.csv'),
@@ -1255,6 +1285,73 @@ describe('Order modification', () => {
         });
     });
 
+    // https://github.com/vendure-ecommerce/vendure/issues/688 - 4th point
+    it('correct additional payment when discounts applied', async () => {
+        await adminClient.query<CreatePromotion.Mutation, CreatePromotion.Variables>(CREATE_PROMOTION, {
+            input: {
+                name: '$5 off',
+                couponCode: '5OFF',
+                enabled: true,
+                conditions: [],
+                actions: [
+                    {
+                        code: orderFixedDiscount.code,
+                        arguments: [{ name: 'discount', value: '500' }],
+                    },
+                ],
+            },
+        });
+
+        await shopClient.asUserWithCredentials('trevor_donnelly96@hotmail.com', 'test');
+        await shopClient.query(gql(ADD_ITEM_TO_ORDER_WITH_CUSTOM_FIELDS), {
+            productVariantId: 'T_1',
+            quantity: 1,
+        } as any);
+        await shopClient.query<ApplyCouponCode.Mutation, ApplyCouponCode.Variables>(APPLY_COUPON_CODE, {
+            couponCode: '5OFF',
+        });
+        await proceedToArrangingPayment(shopClient);
+        const order = await addPaymentToOrder(shopClient, testSuccessfulPaymentMethod);
+        orderGuard.assertSuccess(order);
+
+        const originalTotalWithTax = order.totalWithTax;
+        const surcharge = 300;
+
+        const { transitionOrderToState } = await adminClient.query<
+            AdminTransition.Mutation,
+            AdminTransition.Variables
+        >(ADMIN_TRANSITION_TO_STATE, {
+            id: order.id,
+            state: 'Modifying',
+        });
+        orderGuard.assertSuccess(transitionOrderToState);
+
+        expect(transitionOrderToState.state).toBe('Modifying');
+
+        const { modifyOrder } = await adminClient.query<ModifyOrder.Mutation, ModifyOrder.Variables>(
+            MODIFY_ORDER,
+            {
+                input: {
+                    dryRun: false,
+                    orderId: order.id,
+                    surcharges: [
+                        {
+                            description: 'extra fee',
+                            sku: '123',
+                            price: surcharge,
+                            priceIncludesTax: true,
+                            taxRate: 20,
+                            taxDescription: 'VAT',
+                        },
+                    ],
+                },
+            },
+        );
+        orderGuard.assertSuccess(modifyOrder);
+
+        expect(modifyOrder.totalWithTax).toBe(originalTotalWithTax + surcharge);
+    });
+
     async function assertOrderIsUnchanged(order: OrderWithLinesFragment) {
         const { order: order2 } = await adminClient.query<GetOrder.Query, GetOrder.Variables>(GET_ORDER, {
             id: order.id,

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

@@ -24,6 +24,7 @@ import { OrderModification } from '../../../entity/order-modification/order-modi
 import { Order } from '../../../entity/order/order.entity';
 import { Payment } from '../../../entity/payment/payment.entity';
 import { ProductVariant } from '../../../entity/product-variant/product-variant.entity';
+import { Promotion } from '../../../entity/promotion/promotion.entity';
 import { ShippingLine } from '../../../entity/shipping-line/shipping-line.entity';
 import { Surcharge } from '../../../entity/surcharge/surcharge.entity';
 import { CountryService } from '../../services/country.service';
@@ -344,7 +345,11 @@ export class OrderModifier {
         }
 
         const updatedOrderLines = order.lines.filter(l => updatedOrderLineIds.includes(l.id));
-        await this.orderCalculator.applyPriceAdjustments(ctx, order, [], updatedOrderLines, {
+        const promotions = await this.connection.getRepository(ctx, Promotion).find({
+            where: { enabled: true, deletedAt: null },
+            order: { priorityScore: 'ASC' },
+        });
+        await this.orderCalculator.applyPriceAdjustments(ctx, order, promotions, updatedOrderLines, {
             recalculateShipping: input.options?.recalculateShipping,
         });
 

+ 1 - 1
packages/core/src/service/services/payment-method.service.ts

@@ -156,7 +156,7 @@ export class PaymentMethodService {
         const initialState = 'Created';
         const payment = await this.connection
             .getRepository(ctx, Payment)
-            .save(new Payment({ ...result, state: initialState }));
+            .save(new Payment({ ...result, method, state: initialState }));
         await this.paymentStateMachine.transition(ctx, order, payment, result.state);
         await this.connection.getRepository(ctx, Payment).save(payment, { reload: false });
         this.eventBus.publish(