소스 검색

feat(core): Loosen constraints on adding payment to Order

Closes #963
Michael Bromley 3 년 전
부모
커밋
7a42b01b71
2개의 변경된 파일72개의 추가작업 그리고 2개의 파일을 삭제
  1. 50 1
      packages/core/e2e/order-process.e2e-spec.ts
  2. 22 1
      packages/core/src/service/services/order.service.ts

+ 50 - 1
packages/core/e2e/order-process.e2e-spec.ts

@@ -18,6 +18,8 @@ import {
     SetShippingMethod,
     TestOrderFragmentFragment,
     TransitionToState,
+    TransitionToStateMutation,
+    TransitionToStateMutationVariables,
 } from './graphql/generated-e2e-shop-types';
 import { ADMIN_TRANSITION_TO_STATE, GET_ORDER } from './graphql/shared-definitions';
 import {
@@ -40,7 +42,7 @@ const transitionErrorSpy = jest.fn();
 
 describe('Order process', () => {
     const VALIDATION_ERROR_MESSAGE = 'Customer must have a company email address';
-    const customOrderProcess: CustomOrderProcess<'ValidatingCustomer'> = {
+    const customOrderProcess: CustomOrderProcess<'ValidatingCustomer' | 'PaymentProcessing'> = {
         init(injector) {
             initSpy(injector.get(TransactionalConnection).rawConnection.name);
         },
@@ -52,6 +54,12 @@ describe('Order process', () => {
             ValidatingCustomer: {
                 to: ['ArrangingPayment', 'AddingItems'],
             },
+            ArrangingPayment: {
+                to: ['PaymentProcessing'],
+            },
+            PaymentProcessing: {
+                to: ['PaymentAuthorized', 'PaymentSettled'],
+            },
         },
         onTransitionStart(fromState, toState, data) {
             transitionStartSpy(fromState, toState, data);
@@ -261,6 +269,47 @@ describe('Order process', () => {
                 'AddingItems',
             ]);
         });
+
+        // https://github.com/vendure-ecommerce/vendure/issues/963
+        it('allows addPaymentToOrder from a custom state', async () => {
+            await shopClient.query<SetShippingMethod.Mutation, SetShippingMethod.Variables>(
+                SET_SHIPPING_METHOD,
+                { id: 'T_1' },
+            );
+            const result0 = await shopClient.query<
+                TransitionToStateMutation,
+                TransitionToStateMutationVariables
+            >(TRANSITION_TO_STATE, {
+                state: 'ValidatingCustomer',
+            });
+            orderErrorGuard.assertSuccess(result0.transitionOrderToState);
+            const result1 = await shopClient.query<
+                TransitionToStateMutation,
+                TransitionToStateMutationVariables
+            >(TRANSITION_TO_STATE, {
+                state: 'ArrangingPayment',
+            });
+            orderErrorGuard.assertSuccess(result1.transitionOrderToState);
+            const result2 = await shopClient.query<
+                TransitionToStateMutation,
+                TransitionToStateMutationVariables
+            >(TRANSITION_TO_STATE, {
+                state: 'PaymentProcessing',
+            });
+            orderErrorGuard.assertSuccess(result2.transitionOrderToState);
+            expect(result2.transitionOrderToState.state).toBe('PaymentProcessing');
+            const { addPaymentToOrder } = await shopClient.query<
+                AddPaymentToOrder.Mutation,
+                AddPaymentToOrder.Variables
+            >(ADD_PAYMENT, {
+                input: {
+                    method: testSuccessfulPaymentMethod.code,
+                    metadata: {},
+                },
+            });
+            orderErrorGuard.assertSuccess(addPaymentToOrder);
+            expect(addPaymentToOrder.state).toBe('PaymentSettled');
+        });
     });
 
     describe('Admin API transition constraints', () => {

+ 22 - 1
packages/core/src/service/services/order.service.ts

@@ -959,7 +959,7 @@ export class OrderService {
         input: PaymentInput,
     ): Promise<ErrorResultUnion<AddPaymentToOrderResult, Order>> {
         const order = await this.getOrderOrThrow(ctx, orderId);
-        if (order.state !== 'ArrangingPayment') {
+        if (!this.canAddPaymentToOrder(order)) {
             return new OrderPaymentStateError();
         }
         order.payments = await this.getOrderPayments(ctx, order.id);
@@ -990,6 +990,27 @@ export class OrderService {
         return this.transitionOrderIfTotalIsCovered(ctx, order);
     }
 
+    /**
+     * @description
+     * We can add a Payment to the order if:
+     * 1. the Order is in the `ArrangingPayment` state or
+     * 2. the Order's current state can transition to `PaymentAuthorized` and `PaymentSettled`
+     */
+    private canAddPaymentToOrder(order: Order): boolean {
+        if (order.state === 'ArrangingPayment') {
+            return true;
+        }
+        const canTransitionToPaymentAuthorized = this.orderStateMachine.canTransition(
+            order.state,
+            'PaymentAuthorized',
+        );
+        const canTransitionToPaymentSettled = this.orderStateMachine.canTransition(
+            order.state,
+            'PaymentSettled',
+        );
+        return canTransitionToPaymentAuthorized && canTransitionToPaymentSettled;
+    }
+
     private async transitionOrderIfTotalIsCovered(
         ctx: RequestContext,
         order: Order,