ソースを参照

fix(core): Correct order totals in order modification preview

Fixes #872
Michael Bromley 4 年 前
コミット
1795f487c8

+ 18 - 3
packages/admin-ui/src/lib/core/src/common/generated-types.ts

@@ -2116,7 +2116,7 @@ export type ProductVariant = Node & {
   options: Array<ProductOption>;
   facetValues: Array<FacetValue>;
   translations: Array<ProductVariantTranslation>;
-  customFields?: Maybe<Scalars['JSON']>;
+  customFields?: Maybe<ProductVariantCustomFields>;
 };
 
 
@@ -2257,7 +2257,7 @@ export type CreateProductVariantInput = {
   outOfStockThreshold?: Maybe<Scalars['Int']>;
   useGlobalOutOfStockThreshold?: Maybe<Scalars['Boolean']>;
   trackInventory?: Maybe<GlobalFlag>;
-  customFields?: Maybe<Scalars['JSON']>;
+  customFields?: Maybe<CreateProductVariantCustomFieldsInput>;
 };
 
 export type UpdateProductVariantInput = {
@@ -2274,7 +2274,7 @@ export type UpdateProductVariantInput = {
   outOfStockThreshold?: Maybe<Scalars['Int']>;
   useGlobalOutOfStockThreshold?: Maybe<Scalars['Boolean']>;
   trackInventory?: Maybe<GlobalFlag>;
-  customFields?: Maybe<Scalars['JSON']>;
+  customFields?: Maybe<UpdateProductVariantCustomFieldsInput>;
 };
 
 export type AssignProductsToChannelInput = {
@@ -4836,6 +4836,7 @@ export type ProductVariantFilterParameter = {
   currencyCode?: Maybe<StringOperators>;
   priceWithTax?: Maybe<NumberOperators>;
   stockLevel?: Maybe<StringOperators>;
+  discountPrice?: Maybe<NumberOperators>;
 };
 
 export type ProductVariantSortParameter = {
@@ -4851,6 +4852,7 @@ export type ProductVariantSortParameter = {
   price?: Maybe<SortOrder>;
   priceWithTax?: Maybe<SortOrder>;
   stockLevel?: Maybe<SortOrder>;
+  discountPrice?: Maybe<SortOrder>;
 };
 
 export type PromotionFilterParameter = {
@@ -4951,6 +4953,19 @@ export type HistoryEntrySortParameter = {
   updatedAt?: Maybe<SortOrder>;
 };
 
+export type ProductVariantCustomFields = {
+  __typename?: 'ProductVariantCustomFields';
+  discountPrice?: Maybe<Scalars['Int']>;
+};
+
+export type CreateProductVariantCustomFieldsInput = {
+  discountPrice?: Maybe<Scalars['Int']>;
+};
+
+export type UpdateProductVariantCustomFieldsInput = {
+  discountPrice?: Maybe<Scalars['Int']>;
+};
+
 export type AuthenticationInput = {
   native?: Maybe<NativeAuthInput>;
 };

+ 17 - 3
packages/asset-server-plugin/e2e/graphql/generated-e2e-asset-server-plugin-types.ts

@@ -1912,7 +1912,7 @@ export type ProductVariant = Node & {
     options: Array<ProductOption>;
     facetValues: Array<FacetValue>;
     translations: Array<ProductVariantTranslation>;
-    customFields?: Maybe<Scalars['JSON']>;
+    customFields?: Maybe<ProductVariantCustomFields>;
 };
 
 export type ProductVariantStockMovementsArgs = {
@@ -2051,7 +2051,7 @@ export type CreateProductVariantInput = {
     outOfStockThreshold?: Maybe<Scalars['Int']>;
     useGlobalOutOfStockThreshold?: Maybe<Scalars['Boolean']>;
     trackInventory?: Maybe<GlobalFlag>;
-    customFields?: Maybe<Scalars['JSON']>;
+    customFields?: Maybe<CreateProductVariantCustomFieldsInput>;
 };
 
 export type UpdateProductVariantInput = {
@@ -2068,7 +2068,7 @@ export type UpdateProductVariantInput = {
     outOfStockThreshold?: Maybe<Scalars['Int']>;
     useGlobalOutOfStockThreshold?: Maybe<Scalars['Boolean']>;
     trackInventory?: Maybe<GlobalFlag>;
-    customFields?: Maybe<Scalars['JSON']>;
+    customFields?: Maybe<UpdateProductVariantCustomFieldsInput>;
 };
 
 export type AssignProductsToChannelInput = {
@@ -4544,6 +4544,7 @@ export type ProductVariantFilterParameter = {
     currencyCode?: Maybe<StringOperators>;
     priceWithTax?: Maybe<NumberOperators>;
     stockLevel?: Maybe<StringOperators>;
+    discountPrice?: Maybe<NumberOperators>;
 };
 
 export type ProductVariantSortParameter = {
@@ -4559,6 +4560,7 @@ export type ProductVariantSortParameter = {
     price?: Maybe<SortOrder>;
     priceWithTax?: Maybe<SortOrder>;
     stockLevel?: Maybe<SortOrder>;
+    discountPrice?: Maybe<SortOrder>;
 };
 
 export type PromotionFilterParameter = {
@@ -4659,6 +4661,18 @@ export type HistoryEntrySortParameter = {
     updatedAt?: Maybe<SortOrder>;
 };
 
+export type ProductVariantCustomFields = {
+    discountPrice?: Maybe<Scalars['Int']>;
+};
+
+export type CreateProductVariantCustomFieldsInput = {
+    discountPrice?: Maybe<Scalars['Int']>;
+};
+
+export type UpdateProductVariantCustomFieldsInput = {
+    discountPrice?: Maybe<Scalars['Int']>;
+};
+
 export type AuthenticationInput = {
     native?: Maybe<NativeAuthInput>;
 };

+ 8 - 1
packages/common/src/generated-shop-types.ts

@@ -2320,7 +2320,7 @@ export type ProductVariant = Node & {
     options: Array<ProductOption>;
     facetValues: Array<FacetValue>;
     translations: Array<ProductVariantTranslation>;
-    customFields?: Maybe<Scalars['JSON']>;
+    customFields?: Maybe<ProductVariantCustomFields>;
 };
 
 export type ProductVariantTranslation = {
@@ -2845,6 +2845,7 @@ export type ProductVariantFilterParameter = {
     currencyCode?: Maybe<StringOperators>;
     priceWithTax?: Maybe<NumberOperators>;
     stockLevel?: Maybe<StringOperators>;
+    discountPrice?: Maybe<NumberOperators>;
 };
 
 export type ProductVariantSortParameter = {
@@ -2857,6 +2858,7 @@ export type ProductVariantSortParameter = {
     price?: Maybe<SortOrder>;
     priceWithTax?: Maybe<SortOrder>;
     stockLevel?: Maybe<SortOrder>;
+    discountPrice?: Maybe<SortOrder>;
 };
 
 export type CustomerFilterParameter = {
@@ -2929,6 +2931,11 @@ export type UpdateOrderInput = {
     customFields?: Maybe<Scalars['JSON']>;
 };
 
+export type ProductVariantCustomFields = {
+    __typename?: 'ProductVariantCustomFields';
+    discountPrice?: Maybe<Scalars['Int']>;
+};
+
 export type AuthenticationInput = {
     native?: Maybe<NativeAuthInput>;
 };

+ 18 - 3
packages/common/src/generated-types.ts

@@ -2079,7 +2079,7 @@ export type ProductVariant = Node & {
   options: Array<ProductOption>;
   facetValues: Array<FacetValue>;
   translations: Array<ProductVariantTranslation>;
-  customFields?: Maybe<Scalars['JSON']>;
+  customFields?: Maybe<ProductVariantCustomFields>;
 };
 
 
@@ -2220,7 +2220,7 @@ export type CreateProductVariantInput = {
   outOfStockThreshold?: Maybe<Scalars['Int']>;
   useGlobalOutOfStockThreshold?: Maybe<Scalars['Boolean']>;
   trackInventory?: Maybe<GlobalFlag>;
-  customFields?: Maybe<Scalars['JSON']>;
+  customFields?: Maybe<CreateProductVariantCustomFieldsInput>;
 };
 
 export type UpdateProductVariantInput = {
@@ -2237,7 +2237,7 @@ export type UpdateProductVariantInput = {
   outOfStockThreshold?: Maybe<Scalars['Int']>;
   useGlobalOutOfStockThreshold?: Maybe<Scalars['Boolean']>;
   trackInventory?: Maybe<GlobalFlag>;
-  customFields?: Maybe<Scalars['JSON']>;
+  customFields?: Maybe<UpdateProductVariantCustomFieldsInput>;
 };
 
 export type AssignProductsToChannelInput = {
@@ -4798,6 +4798,7 @@ export type ProductVariantFilterParameter = {
   currencyCode?: Maybe<StringOperators>;
   priceWithTax?: Maybe<NumberOperators>;
   stockLevel?: Maybe<StringOperators>;
+  discountPrice?: Maybe<NumberOperators>;
 };
 
 export type ProductVariantSortParameter = {
@@ -4813,6 +4814,7 @@ export type ProductVariantSortParameter = {
   price?: Maybe<SortOrder>;
   priceWithTax?: Maybe<SortOrder>;
   stockLevel?: Maybe<SortOrder>;
+  discountPrice?: Maybe<SortOrder>;
 };
 
 export type PromotionFilterParameter = {
@@ -4913,6 +4915,19 @@ export type HistoryEntrySortParameter = {
   updatedAt?: Maybe<SortOrder>;
 };
 
+export type ProductVariantCustomFields = {
+  __typename?: 'ProductVariantCustomFields';
+  discountPrice?: Maybe<Scalars['Int']>;
+};
+
+export type CreateProductVariantCustomFieldsInput = {
+  discountPrice?: Maybe<Scalars['Int']>;
+};
+
+export type UpdateProductVariantCustomFieldsInput = {
+  discountPrice?: Maybe<Scalars['Int']>;
+};
+
 export type AuthenticationInput = {
   native?: Maybe<NativeAuthInput>;
 };

+ 21 - 4
packages/core/e2e/graphql/generated-e2e-admin-types.ts

@@ -1912,7 +1912,7 @@ export type ProductVariant = Node & {
     options: Array<ProductOption>;
     facetValues: Array<FacetValue>;
     translations: Array<ProductVariantTranslation>;
-    customFields?: Maybe<Scalars['JSON']>;
+    customFields?: Maybe<ProductVariantCustomFields>;
 };
 
 export type ProductVariantStockMovementsArgs = {
@@ -2051,7 +2051,7 @@ export type CreateProductVariantInput = {
     outOfStockThreshold?: Maybe<Scalars['Int']>;
     useGlobalOutOfStockThreshold?: Maybe<Scalars['Boolean']>;
     trackInventory?: Maybe<GlobalFlag>;
-    customFields?: Maybe<Scalars['JSON']>;
+    customFields?: Maybe<CreateProductVariantCustomFieldsInput>;
 };
 
 export type UpdateProductVariantInput = {
@@ -2068,7 +2068,7 @@ export type UpdateProductVariantInput = {
     outOfStockThreshold?: Maybe<Scalars['Int']>;
     useGlobalOutOfStockThreshold?: Maybe<Scalars['Boolean']>;
     trackInventory?: Maybe<GlobalFlag>;
-    customFields?: Maybe<Scalars['JSON']>;
+    customFields?: Maybe<UpdateProductVariantCustomFieldsInput>;
 };
 
 export type AssignProductsToChannelInput = {
@@ -4544,6 +4544,7 @@ export type ProductVariantFilterParameter = {
     currencyCode?: Maybe<StringOperators>;
     priceWithTax?: Maybe<NumberOperators>;
     stockLevel?: Maybe<StringOperators>;
+    discountPrice?: Maybe<NumberOperators>;
 };
 
 export type ProductVariantSortParameter = {
@@ -4559,6 +4560,7 @@ export type ProductVariantSortParameter = {
     price?: Maybe<SortOrder>;
     priceWithTax?: Maybe<SortOrder>;
     stockLevel?: Maybe<SortOrder>;
+    discountPrice?: Maybe<SortOrder>;
 };
 
 export type PromotionFilterParameter = {
@@ -4659,6 +4661,18 @@ export type HistoryEntrySortParameter = {
     updatedAt?: Maybe<SortOrder>;
 };
 
+export type ProductVariantCustomFields = {
+    discountPrice?: Maybe<Scalars['Int']>;
+};
+
+export type CreateProductVariantCustomFieldsInput = {
+    discountPrice?: Maybe<Scalars['Int']>;
+};
+
+export type UpdateProductVariantCustomFieldsInput = {
+    discountPrice?: Maybe<Scalars['Int']>;
+};
+
 export type AuthenticationInput = {
     native?: Maybe<NativeAuthInput>;
 };
@@ -6130,7 +6144,10 @@ export type GetFulfillmentHandlersQuery = {
 
 export type OrderWithModificationsFragment = Pick<Order, 'id' | 'state' | 'total' | 'totalWithTax'> & {
     lines: Array<
-        Pick<OrderLine, 'id' | 'quantity' | 'linePrice' | 'linePriceWithTax'> & {
+        Pick<
+            OrderLine,
+            'id' | 'quantity' | 'linePrice' | 'linePriceWithTax' | 'discountedLinePriceWithTax'
+        > & {
             productVariant: Pick<ProductVariant, 'id' | 'name'>;
             items: Array<Pick<OrderItem, 'id' | 'createdAt' | 'updatedAt' | 'cancelled' | 'unitPrice'>>;
         }

+ 7 - 1
packages/core/e2e/graphql/generated-e2e-shop-types.ts

@@ -2240,7 +2240,7 @@ export type ProductVariant = Node & {
     options: Array<ProductOption>;
     facetValues: Array<FacetValue>;
     translations: Array<ProductVariantTranslation>;
-    customFields?: Maybe<Scalars['JSON']>;
+    customFields?: Maybe<ProductVariantCustomFields>;
 };
 
 export type ProductVariantTranslation = {
@@ -2729,6 +2729,7 @@ export type ProductVariantFilterParameter = {
     currencyCode?: Maybe<StringOperators>;
     priceWithTax?: Maybe<NumberOperators>;
     stockLevel?: Maybe<StringOperators>;
+    discountPrice?: Maybe<NumberOperators>;
 };
 
 export type ProductVariantSortParameter = {
@@ -2741,6 +2742,7 @@ export type ProductVariantSortParameter = {
     price?: Maybe<SortOrder>;
     priceWithTax?: Maybe<SortOrder>;
     stockLevel?: Maybe<SortOrder>;
+    discountPrice?: Maybe<SortOrder>;
 };
 
 export type CustomerFilterParameter = {
@@ -2813,6 +2815,10 @@ export type UpdateOrderInput = {
     customFields?: Maybe<Scalars['JSON']>;
 };
 
+export type ProductVariantCustomFields = {
+    discountPrice?: Maybe<Scalars['Int']>;
+};
+
 export type AuthenticationInput = {
     native?: Maybe<NativeAuthInput>;
 };

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

@@ -5,6 +5,7 @@ import {
     defaultShippingCalculator,
     defaultShippingEligibilityChecker,
     mergeConfig,
+    productsPercentageDiscount,
     ShippingCalculator,
 } from '@vendure/core';
 import { createErrorResultGuard, createTestEnvironment, ErrorResultGuard } from '@vendure/testing';
@@ -37,7 +38,7 @@ import {
     OrderFragment,
     OrderWithLinesFragment,
     OrderWithModificationsFragment,
-    SettlePayment,
+    UpdateChannel,
     UpdateProductVariants,
 } from './graphql/generated-e2e-admin-types';
 import {
@@ -55,7 +56,7 @@ import {
     CREATE_SHIPPING_METHOD,
     GET_ORDER,
     GET_ORDER_HISTORY,
-    SETTLE_PAYMENT,
+    UPDATE_CHANNEL,
     UPDATE_PRODUCT_VARIANTS,
 } from './graphql/shared-definitions';
 import {
@@ -1352,6 +1353,96 @@ describe('Order modification', () => {
         expect(modifyOrder.totalWithTax).toBe(originalTotalWithTax + surcharge);
     });
 
+    // https://github.com/vendure-ecommerce/vendure/issues/872
+    describe('correct price calculations when prices include tax', () => {
+        async function modifyOrderLineQuantity(order: TestOrderWithPaymentsFragment) {
+            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: true,
+                        orderId: order.id,
+                        adjustOrderLines: [{ orderLineId: order!.lines[0].id, quantity: 2 }],
+                    },
+                },
+            );
+            orderGuard.assertSuccess(modifyOrder);
+            return modifyOrder;
+        }
+
+        beforeAll(async () => {
+            await adminClient.query<UpdateChannel.Mutation, UpdateChannel.Variables>(UPDATE_CHANNEL, {
+                input: {
+                    id: 'T_1',
+                    pricesIncludeTax: true,
+                },
+            });
+        });
+
+        it('without promotion', async () => {
+            await shopClient.asUserWithCredentials('hayden.zieme12@hotmail.com', 'test');
+            await shopClient.query(gql(ADD_ITEM_TO_ORDER_WITH_CUSTOM_FIELDS), {
+                productVariantId: 'T_1',
+                quantity: 1,
+            } as any);
+            await proceedToArrangingPayment(shopClient);
+            const order = await addPaymentToOrder(shopClient, testSuccessfulPaymentMethod);
+            orderGuard.assertSuccess(order);
+
+            const modifyOrder = await modifyOrderLineQuantity(order);
+            expect(modifyOrder.lines[0].linePriceWithTax).toBe(order.lines[0].linePriceWithTax * 2);
+        });
+
+        it('with promotion', async () => {
+            await adminClient.query<CreatePromotion.Mutation, CreatePromotion.Variables>(CREATE_PROMOTION, {
+                input: {
+                    name: 'half price',
+                    couponCode: 'HALF',
+                    enabled: true,
+                    conditions: [],
+                    actions: [
+                        {
+                            code: productsPercentageDiscount.code,
+                            arguments: [
+                                { name: 'discount', value: '50' },
+                                { name: 'productVariantIds', value: JSON.stringify(['T_1']) },
+                            ],
+                        },
+                    ],
+                },
+            });
+            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: 'HALF',
+            });
+            await proceedToArrangingPayment(shopClient);
+            const order = await addPaymentToOrder(shopClient, testSuccessfulPaymentMethod);
+            orderGuard.assertSuccess(order);
+
+            const modifyOrder = await modifyOrderLineQuantity(order);
+
+            expect(modifyOrder.lines[0].discountedLinePriceWithTax).toBe(
+                modifyOrder.lines[0].linePriceWithTax / 2,
+            );
+            expect(modifyOrder.lines[0].linePriceWithTax).toBe(order.lines[0].linePriceWithTax * 2);
+        });
+    });
+
     async function assertOrderIsUnchanged(order: OrderWithLinesFragment) {
         const { order: order2 } = await adminClient.query<GetOrder.Query, GetOrder.Variables>(GET_ORDER, {
             id: order.id,
@@ -1416,6 +1507,7 @@ export const ORDER_WITH_MODIFICATION_FRAGMENT = gql`
             quantity
             linePrice
             linePriceWithTax
+            discountedLinePriceWithTax
             productVariant {
                 id
                 name

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

@@ -159,7 +159,7 @@ export class OrderModifier {
             for (let i = currentQuantity; i < quantity; i++) {
                 newOrderItems.push(
                     new OrderItem({
-                        listPrice: orderLine.productVariant.price,
+                        listPrice: orderLine.productVariant.listPrice,
                         listPriceIncludesTax: orderLine.productVariant.listPriceIncludesTax,
                         adjustments: [],
                         taxLines: [],

+ 1 - 0
packages/dev-server/dev-config.ts

@@ -101,6 +101,7 @@ export const devConfig: VendureConfig = {
     },
     customFields: {
         /*Asset: [{ name: 'description', type: 'string' }],*/
+        ProductVariant: [{ name: 'discountPrice', type: 'int' }],
     },
     logger: new DefaultLogger({ level: LogLevel.Info }),
     importExportOptions: {

+ 17 - 3
packages/elasticsearch-plugin/e2e/graphql/generated-e2e-elasticsearch-plugin-types.ts

@@ -1912,7 +1912,7 @@ export type ProductVariant = Node & {
     options: Array<ProductOption>;
     facetValues: Array<FacetValue>;
     translations: Array<ProductVariantTranslation>;
-    customFields?: Maybe<Scalars['JSON']>;
+    customFields?: Maybe<ProductVariantCustomFields>;
 };
 
 export type ProductVariantStockMovementsArgs = {
@@ -2051,7 +2051,7 @@ export type CreateProductVariantInput = {
     outOfStockThreshold?: Maybe<Scalars['Int']>;
     useGlobalOutOfStockThreshold?: Maybe<Scalars['Boolean']>;
     trackInventory?: Maybe<GlobalFlag>;
-    customFields?: Maybe<Scalars['JSON']>;
+    customFields?: Maybe<CreateProductVariantCustomFieldsInput>;
 };
 
 export type UpdateProductVariantInput = {
@@ -2068,7 +2068,7 @@ export type UpdateProductVariantInput = {
     outOfStockThreshold?: Maybe<Scalars['Int']>;
     useGlobalOutOfStockThreshold?: Maybe<Scalars['Boolean']>;
     trackInventory?: Maybe<GlobalFlag>;
-    customFields?: Maybe<Scalars['JSON']>;
+    customFields?: Maybe<UpdateProductVariantCustomFieldsInput>;
 };
 
 export type AssignProductsToChannelInput = {
@@ -4544,6 +4544,7 @@ export type ProductVariantFilterParameter = {
     currencyCode?: Maybe<StringOperators>;
     priceWithTax?: Maybe<NumberOperators>;
     stockLevel?: Maybe<StringOperators>;
+    discountPrice?: Maybe<NumberOperators>;
 };
 
 export type ProductVariantSortParameter = {
@@ -4559,6 +4560,7 @@ export type ProductVariantSortParameter = {
     price?: Maybe<SortOrder>;
     priceWithTax?: Maybe<SortOrder>;
     stockLevel?: Maybe<SortOrder>;
+    discountPrice?: Maybe<SortOrder>;
 };
 
 export type PromotionFilterParameter = {
@@ -4659,6 +4661,18 @@ export type HistoryEntrySortParameter = {
     updatedAt?: Maybe<SortOrder>;
 };
 
+export type ProductVariantCustomFields = {
+    discountPrice?: Maybe<Scalars['Int']>;
+};
+
+export type CreateProductVariantCustomFieldsInput = {
+    discountPrice?: Maybe<Scalars['Int']>;
+};
+
+export type UpdateProductVariantCustomFieldsInput = {
+    discountPrice?: Maybe<Scalars['Int']>;
+};
+
 export type AuthenticationInput = {
     native?: Maybe<NativeAuthInput>;
 };

ファイルの差分が大きいため隠しています
+ 0 - 0
schema-admin.json


ファイルの差分が大きいため隠しています
+ 0 - 0
schema-shop.json


この差分においてかなりの量のファイルが変更されているため、一部のファイルを表示していません