ソースを参照

fix(core): Fix relation constraints in OrderModification

The OneToOne relations prevented the correct handling
of payments/refunds that apply to multiple modifications.
Michael Bromley 6 ヶ月 前
コミット
87fc9296ba

+ 87 - 2
packages/core/e2e/order-modification.e2e-spec.ts

@@ -149,7 +149,7 @@ describe('Order modification', () => {
     let testShippingMethodId: string;
     let testExpressShippingMethodId: string;
     const orderGuard: ErrorResultGuard<
-        UpdatedOrderFragment | OrderWithModificationsFragment | OrderFragment
+        UpdatedOrderFragment | OrderWithModificationsFragment | OrderFragment | TestOrderWithPaymentsFragment
     > = createErrorResultGuard(input => !!input.id);
 
     beforeAll(async () => {
@@ -1963,7 +1963,7 @@ describe('Order modification', () => {
             order = modifyOrder;
         });
 
-        it('creates a Refund with the correct amount', async () => {
+        it('creates a Refund with the correct amount', () => {
             expect(order.payments?.[0].refunds[0].total).toBe(SHIPPING_OTHER - SHIPPING_GB);
         });
 
@@ -2535,6 +2535,91 @@ describe('Order modification', () => {
         });
     });
 
+    describe('payment handling with multiple modifications  ', () => {
+        let orderId3: string;
+
+        it('should handle manual payment after multiple modifications', async () => {
+            // 1. Create an order
+            const order = await createOrderAndTransitionToModifyingState([
+                {
+                    productVariantId: 'T_1',
+                    quantity: 1,
+                },
+            ]);
+
+            // 2. First modification - add an item
+            const { modifyOrder: firstModification } = await adminClient.query<
+                Codegen.ModifyOrderMutation,
+                Codegen.ModifyOrderMutationVariables
+            >(MODIFY_ORDER, {
+                input: {
+                    dryRun: false,
+                    orderId: order.id,
+                    addItems: [{ productVariantId: 'T_2', quantity: 1 }],
+                },
+            });
+            orderGuard.assertSuccess(firstModification);
+
+            // 3. Second modification - add another item
+            const { modifyOrder: secondModification } = await adminClient.query<
+                Codegen.ModifyOrderMutation,
+                Codegen.ModifyOrderMutationVariables
+            >(MODIFY_ORDER, {
+                input: {
+                    dryRun: false,
+                    orderId: order.id,
+                    addItems: [{ productVariantId: 'T_3', quantity: 1 }],
+                },
+            });
+            orderGuard.assertSuccess(secondModification);
+
+            // 4. Transition to ArrangingAdditionalPayment state
+            const transitionResult = await adminTransitionOrderToState(
+                order.id,
+                'ArrangingAdditionalPayment',
+            );
+            orderGuard.assertSuccess(transitionResult);
+            expect(transitionResult.state).toBe('ArrangingAdditionalPayment');
+
+            // 5. Add manual payment - this should currently fail due to a bug
+            const { addManualPaymentToOrder } = await adminClient.query<
+                Codegen.AddManualPaymentMutation,
+                Codegen.AddManualPaymentMutationVariables
+            >(ADD_MANUAL_PAYMENT, {
+                input: {
+                    orderId: order.id,
+                    method: 'test',
+                    transactionId: 'MULTI_MOD_123',
+                    metadata: {
+                        test: 'multiple modifications',
+                    },
+                },
+            });
+
+            // This should fail due to the bug, but we expect it to succeed after the fix
+            orderGuard.assertSuccess(addManualPaymentToOrder);
+
+            // Verify the payment was added correctly
+            expect(addManualPaymentToOrder.payments?.length).toBe(2);
+            expect(addManualPaymentToOrder.payments?.[1]).toEqual({
+                id: expect.any(String),
+                transactionId: 'MULTI_MOD_123',
+                state: 'Settled',
+                amount: expect.any(Number),
+                method: 'test',
+                metadata: {
+                    test: 'multiple modifications',
+                },
+                refunds: [],
+            });
+
+            // Verify the modifications are properly settled
+            expect(addManualPaymentToOrder.modifications.length).toBe(2);
+            expect(addManualPaymentToOrder.modifications[0].isSettled).toBe(true);
+            expect(addManualPaymentToOrder.modifications[1].isSettled).toBe(true);
+        });
+    });
+
     async function adminTransitionOrderToState(id: string, state: string) {
         const result = await adminClient.query<
             Codegen.AdminTransitionMutation,

+ 4 - 4
packages/core/src/entity/order-modification/order-modification.entity.ts

@@ -1,12 +1,12 @@
 import { OrderAddress } from '@vendure/common/lib/generated-types';
 import { DeepPartial } from '@vendure/common/lib/shared-types';
-import { Column, Entity, Index, JoinColumn, ManyToOne, OneToMany, OneToOne } from 'typeorm';
+import { Column, Entity, Index, JoinColumn, ManyToOne, OneToMany } from 'typeorm';
 
 import { Calculated } from '../../common/calculated-decorator';
 import { VendureEntity } from '../base/base.entity';
 import { Money } from '../money.decorator';
-import { Order } from '../order/order.entity';
 import { OrderModificationLine } from '../order-line-reference/order-modification-line.entity';
+import { Order } from '../order/order.entity';
 import { Payment } from '../payment/payment.entity';
 import { Refund } from '../refund/refund.entity';
 import { Surcharge } from '../surcharge/surcharge.entity';
@@ -40,11 +40,11 @@ export class OrderModification extends VendureEntity {
     @Money()
     priceChange: number;
 
-    @OneToOne(type => Payment)
+    @ManyToOne(type => Payment)
     @JoinColumn()
     payment?: Payment;
 
-    @OneToOne(type => Refund)
+    @ManyToOne(type => Refund)
     @JoinColumn()
     refund?: Refund;