Procházet zdrojové kódy

fix(core): Re-calculate OrderItem price on all OrderLine changes

Relates to #660
Michael Bromley před 5 roky
rodič
revize
0d8c485923

+ 54 - 18
packages/core/e2e/order-item-price-calculation-strategy.e2e-spec.ts

@@ -43,6 +43,8 @@ describe('custom OrderItemPriceCalculationStrategy', () => {
         await server.destroy();
     });
 
+    let secondOrderLineId: string;
+
     it('does not add surcharge', async () => {
         const variant0 = variants[0];
 
@@ -72,9 +74,46 @@ describe('custom OrderItemPriceCalculationStrategy', () => {
         expect(addItemToOrder.lines[0].unitPrice).toEqual(variantPrice);
         expect(addItemToOrder.lines[1].unitPrice).toEqual(variantPrice + 500);
         expect(addItemToOrder.subTotal).toEqual(variantPrice + variantPrice + 500);
+        secondOrderLineId = addItemToOrder.lines[1].id;
+    });
+
+    it('re-calculates when customFields changes', async () => {
+        const { adjustOrderLine } = await shopClient.query(ADJUST_ORDER_LINE_CUSTOM_FIELDS, {
+            orderLineId: secondOrderLineId,
+            quantity: 1,
+            customFields: {
+                giftWrap: false,
+            },
+        });
+
+        const variantPrice = (variants[0].price as SinglePrice).value as number;
+        expect(adjustOrderLine.lines[0].unitPrice).toEqual(variantPrice);
+        expect(adjustOrderLine.lines[1].unitPrice).toEqual(variantPrice);
+        expect(adjustOrderLine.subTotal).toEqual(variantPrice + variantPrice);
     });
 });
 
+const ORDER_WITH_LINES_AND_ITEMS_FRAGMENT = gql`
+    fragment OrderWithLinesAndItems on Order {
+        id
+        subTotal
+        subTotalWithTax
+        shipping
+        total
+        totalWithTax
+        lines {
+            id
+            quantity
+            unitPrice
+            unitPriceWithTax
+            items {
+                unitPrice
+                unitPriceWithTax
+            }
+        }
+    }
+`;
+
 const ADD_ITEM_TO_ORDER_CUSTOM_FIELDS = gql`
     mutation AddItemToOrderCustomFields(
         $productVariantId: ID!
@@ -86,24 +125,21 @@ const ADD_ITEM_TO_ORDER_CUSTOM_FIELDS = gql`
             quantity: $quantity
             customFields: $customFields
         ) {
-            ... on Order {
-                id
-                subTotal
-                subTotalWithTax
-                shipping
-                total
-                totalWithTax
-                lines {
-                    id
-                    quantity
-                    unitPrice
-                    unitPriceWithTax
-                    items {
-                        unitPrice
-                        unitPriceWithTax
-                    }
-                }
-            }
+            ...OrderWithLinesAndItems
+        }
+    }
+    ${ORDER_WITH_LINES_AND_ITEMS_FRAGMENT}
+`;
+
+const ADJUST_ORDER_LINE_CUSTOM_FIELDS = gql`
+    mutation AdjustOrderLineCustomFields(
+        $orderLineId: ID!
+        $quantity: Int!
+        $customFields: OrderLineCustomFieldsInput
+    ) {
+        adjustOrderLine(orderLineId: $orderLineId, quantity: $quantity, customFields: $customFields) {
+            ...OrderWithLinesAndItems
         }
     }
+    ${ORDER_WITH_LINES_AND_ITEMS_FRAGMENT}
 `;

+ 2 - 2
packages/core/src/entity/order-item/order-item.entity.ts

@@ -33,7 +33,7 @@ export class OrderItem extends VendureEntity {
      * current Channel, may or may not include tax.
      */
     @Column()
-    readonly listPrice: number;
+    listPrice: number;
 
     /**
      * @description
@@ -41,7 +41,7 @@ export class OrderItem extends VendureEntity {
      * of the current Channel.
      */
     @Column()
-    readonly listPriceIncludesTax: boolean;
+    listPriceIncludesTax: boolean;
 
     @Column('simple-json')
     adjustments: Adjustment[];

+ 2 - 10
packages/core/src/service/helpers/order-modifier/order-modifier.ts

@@ -130,24 +130,16 @@ export class OrderModifier {
         order: Order,
     ): Promise<OrderLine> {
         const currentQuantity = orderLine.quantity;
-        const { orderItemPriceCalculationStrategy } = this.configService.orderOptions;
 
         if (currentQuantity < quantity) {
             if (!orderLine.items) {
                 orderLine.items = [];
             }
-            const productVariant = orderLine.productVariant;
-            const { price, priceIncludesTax } = await orderItemPriceCalculationStrategy.calculateUnitPrice(
-                ctx,
-                productVariant,
-                orderLine.customFields || {},
-            );
-            const taxRate = productVariant.taxRateApplied;
             for (let i = currentQuantity; i < quantity; i++) {
                 const orderItem = await this.connection.getRepository(ctx, OrderItem).save(
                     new OrderItem({
-                        listPrice: price,
-                        listPriceIncludesTax: priceIncludesTax,
+                        listPrice: orderLine.productVariant.price,
+                        listPriceIncludesTax: orderLine.productVariant.priceIncludesTax,
                         adjustments: [],
                         taxLines: [],
                         line: orderLine,

+ 12 - 0
packages/core/src/service/services/order.service.ts

@@ -1245,6 +1245,18 @@ export class OrderService {
         order: Order,
         updatedOrderLine?: OrderLine,
     ): Promise<Order> {
+        if (updatedOrderLine) {
+            const { orderItemPriceCalculationStrategy } = this.configService.orderOptions;
+            const { price, priceIncludesTax } = await orderItemPriceCalculationStrategy.calculateUnitPrice(
+                ctx,
+                updatedOrderLine.productVariant,
+                updatedOrderLine.customFields || {},
+            );
+            for (const item of updatedOrderLine.items) {
+                item.listPrice = price;
+                item.listPriceIncludesTax = priceIncludesTax;
+            }
+        }
         const promotions = await this.connection.getRepository(ctx, Promotion).find({
             where: { enabled: true, deletedAt: null },
             order: { priorityScore: 'ASC' },