Просмотр исходного кода

fix(core): Fix race condition when updating order addresses in parallel

Michael Bromley 3 лет назад
Родитель
Сommit
d436ea9ff9

+ 69 - 0
packages/core/e2e/shop-order.e2e-spec.ts

@@ -2203,6 +2203,75 @@ describe('Shop orders', () => {
             expect(removeAllOrderLines.shippingWithTax).toBe(0);
         });
     });
+
+    describe('edge cases', () => {
+        it('calling setShippingMethod and setBillingMethod in parallel does not introduce race condition', async () => {
+            const shippingAddress: CreateAddressInput = {
+                fullName: 'name',
+                company: 'company',
+                streetLine1: '12 Shipping Street',
+                streetLine2: null,
+                city: 'foo',
+                province: 'bar',
+                postalCode: '123456',
+                countryCode: 'US',
+                phoneNumber: '4444444',
+            };
+            const billingAddress: CreateAddressInput = {
+                fullName: 'name',
+                company: 'company',
+                streetLine1: '22 Billing Avenue',
+                streetLine2: null,
+                city: 'foo',
+                province: 'bar',
+                postalCode: '123456',
+                countryCode: 'US',
+                phoneNumber: '4444444',
+            };
+
+            await Promise.all([
+                shopClient.query<SetBillingAddress.Mutation, SetBillingAddress.Variables>(
+                    SET_BILLING_ADDRESS,
+                    {
+                        input: billingAddress,
+                    },
+                ),
+                shopClient.query<SetShippingAddress.Mutation, SetShippingAddress.Variables>(
+                    SET_SHIPPING_ADDRESS,
+                    {
+                        input: shippingAddress,
+                    },
+                ),
+            ]);
+
+            const { activeOrder } = await shopClient.query(gql`
+                query {
+                    activeOrder {
+                        shippingAddress {
+                            ...OrderAddress
+                        }
+                        billingAddress {
+                            ...OrderAddress
+                        }
+                    }
+                }
+                fragment OrderAddress on OrderAddress {
+                    fullName
+                    company
+                    streetLine1
+                    streetLine2
+                    city
+                    province
+                    postalCode
+                    countryCode
+                    phoneNumber
+                }
+            `);
+
+            expect(activeOrder.shippingAddress).toEqual(shippingAddress);
+            expect(activeOrder.billingAddress).toEqual(billingAddress);
+        });
+    });
 });
 
 const GET_ORDER_CUSTOM_FIELDS = gql`

+ 19 - 7
packages/core/src/service/services/order.service.ts

@@ -751,10 +751,16 @@ export class OrderService {
     async setShippingAddress(ctx: RequestContext, orderId: ID, input: CreateAddressInput): Promise<Order> {
         const order = await this.getOrderOrThrow(ctx, orderId);
         const country = await this.countryService.findOneByCode(ctx, input.countryCode);
-        order.shippingAddress = { ...input, countryCode: input.countryCode, country: country.name };
-        await this.connection.getRepository(ctx, Order).save(order);
+        const shippingAddress = { ...input, countryCode: input.countryCode, country: country.name };
+        await this.connection
+            .getRepository(ctx, Order)
+            .createQueryBuilder('order')
+            .update(Order)
+            .set({ shippingAddress })
+            .where('id = :id', { id: order.id });
+        order.shippingAddress = shippingAddress;
         // Since a changed ShippingAddress could alter the activeTaxZone,
-        // we will remove any cached activeTaxZone so it can be re-calculated
+        // we will remove any cached activeTaxZone, so it can be re-calculated
         // as needed.
         this.requestCache.set(ctx, 'activeTaxZone', undefined);
         return this.applyPriceAdjustments(ctx, order, order.lines);
@@ -767,10 +773,16 @@ export class OrderService {
     async setBillingAddress(ctx: RequestContext, orderId: ID, input: CreateAddressInput): Promise<Order> {
         const order = await this.getOrderOrThrow(ctx, orderId);
         const country = await this.countryService.findOneByCode(ctx, input.countryCode);
-        order.billingAddress = { ...input, countryCode: input.countryCode, country: country.name };
-        await this.connection.getRepository(ctx, Order).save(order);
-        // Since a changed ShippingAddress could alter the activeTaxZone,
-        // we will remove any cached activeTaxZone so it can be re-calculated
+        const billingAddress = { ...input, countryCode: input.countryCode, country: country.name };
+        await this.connection
+            .getRepository(ctx, Order)
+            .createQueryBuilder('order')
+            .update(Order)
+            .set({ billingAddress })
+            .where('id = :id', { id: order.id });
+        order.billingAddress = billingAddress;
+        // Since a changed BillingAddress could alter the activeTaxZone,
+        // we will remove any cached activeTaxZone, so it can be re-calculated
         // as needed.
         this.requestCache.set(ctx, 'activeTaxZone', undefined);
         return this.applyPriceAdjustments(ctx, order, order.lines);