Browse Source

feat(core): Implement `setOrderCustomFields` in Shop API

Relates to #404
Michael Bromley 5 năm trước cách đây
mục cha
commit
3a12dc5da9

+ 14 - 0
packages/common/src/generated-shop-types.ts

@@ -1338,6 +1338,7 @@ export type Mutation = {
      * entity, a third argument 'customFields' will be available.
      */
     addItemToOrder?: Maybe<Order>;
+    /** Remove an OrderLine from the Order */
     removeOrderLine?: Maybe<Order>;
     /**
      * Adjusts an OrderLine. If custom fields are defined on the OrderLine entity, a
@@ -1353,9 +1354,13 @@ export type Mutation = {
     setOrderShippingAddress?: Maybe<Order>;
     /** Sets the billing address for this order */
     setOrderBillingAddress?: Maybe<Order>;
+    /** Allows any custom fields to be set for the active order */
+    setOrderCustomFields?: Maybe<Order>;
     /** Sets the shipping method by id, which can be obtained with the `eligibleShippingMethods` query */
     setOrderShippingMethod?: Maybe<Order>;
+    /** Add a Payment to the Order */
     addPaymentToOrder?: Maybe<Order>;
+    /** Set the Customer for the Order. Required only if the Customer is not currently logged in */
     setCustomerForOrder?: Maybe<Order>;
     /**
      * Authenticates the user using the native authentication strategy. This mutation
@@ -1364,6 +1369,7 @@ export type Mutation = {
     login: LoginResult;
     /** Authenticates the user using a named authentication strategy */
     authenticate: LoginResult;
+    /** End the current authenticated session */
     logout: Scalars['Boolean'];
     /**
      * Regenerate and send a verification token for a new Customer registration. Only
@@ -1439,6 +1445,10 @@ export type MutationSetOrderBillingAddressArgs = {
     input: CreateAddressInput;
 };
 
+export type MutationSetOrderCustomFieldsArgs = {
+    input: UpdateOrderInput;
+};
+
 export type MutationSetOrderShippingMethodArgs = {
     shippingMethodId: Scalars['ID'];
 };
@@ -2291,6 +2301,10 @@ export type UpdateCustomerInput = {
     customFields?: Maybe<Scalars['JSON']>;
 };
 
+export type UpdateOrderInput = {
+    customFields?: Maybe<Scalars['JSON']>;
+};
+
 export type User = Node & {
     __typename?: 'User';
     id: Scalars['ID'];

+ 14 - 0
packages/core/e2e/graphql/generated-e2e-shop-types.ts

@@ -1338,6 +1338,7 @@ export type Mutation = {
      * entity, a third argument 'customFields' will be available.
      */
     addItemToOrder?: Maybe<Order>;
+    /** Remove an OrderLine from the Order */
     removeOrderLine?: Maybe<Order>;
     /**
      * Adjusts an OrderLine. If custom fields are defined on the OrderLine entity, a
@@ -1353,9 +1354,13 @@ export type Mutation = {
     setOrderShippingAddress?: Maybe<Order>;
     /** Sets the billing address for this order */
     setOrderBillingAddress?: Maybe<Order>;
+    /** Allows any custom fields to be set for the active order */
+    setOrderCustomFields?: Maybe<Order>;
     /** Sets the shipping method by id, which can be obtained with the `eligibleShippingMethods` query */
     setOrderShippingMethod?: Maybe<Order>;
+    /** Add a Payment to the Order */
     addPaymentToOrder?: Maybe<Order>;
+    /** Set the Customer for the Order. Required only if the Customer is not currently logged in */
     setCustomerForOrder?: Maybe<Order>;
     /**
      * Authenticates the user using the native authentication strategy. This mutation
@@ -1364,6 +1369,7 @@ export type Mutation = {
     login: LoginResult;
     /** Authenticates the user using a named authentication strategy */
     authenticate: LoginResult;
+    /** End the current authenticated session */
     logout: Scalars['Boolean'];
     /**
      * Regenerate and send a verification token for a new Customer registration. Only
@@ -1439,6 +1445,10 @@ export type MutationSetOrderBillingAddressArgs = {
     input: CreateAddressInput;
 };
 
+export type MutationSetOrderCustomFieldsArgs = {
+    input: UpdateOrderInput;
+};
+
 export type MutationSetOrderShippingMethodArgs = {
     shippingMethodId: Scalars['ID'];
 };
@@ -2291,6 +2301,10 @@ export type UpdateCustomerInput = {
     customFields?: Maybe<Scalars['JSON']>;
 };
 
+export type UpdateOrderInput = {
+    customFields?: Maybe<Scalars['JSON']>;
+};
+
 export type User = Node & {
     __typename?: 'User';
     id: Scalars['ID'];

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

@@ -1,6 +1,7 @@
 /* tslint:disable:no-non-null-assertion */
 import { mergeConfig } from '@vendure/core';
 import { createTestEnvironment } from '@vendure/testing';
+import gql from 'graphql-tag';
 import path from 'path';
 
 import { initialData } from '../../../e2e-common/e2e-initial-data';
@@ -76,6 +77,9 @@ describe('Shop orders', () => {
                     testErrorPaymentMethod,
                 ],
             },
+            customFields: {
+                Order: [{ name: 'giftWrap', type: 'boolean', defaultValue: false }],
+            },
             orderOptions: {
                 orderItemsLimit: 99,
             },
@@ -1119,4 +1123,59 @@ describe('Shop orders', () => {
             expect(activeOrder!.customer!.orders.items).toEqual([]);
         });
     });
+
+    describe('order custom fields', () => {
+        it('custom fields added to type', async () => {
+            await shopClient.asAnonymousUser();
+            await shopClient.query<AddItemToOrder.Mutation, AddItemToOrder.Variables>(ADD_ITEM_TO_ORDER, {
+                productVariantId: 'T_1',
+                quantity: 1,
+            });
+            const { activeOrder } = await shopClient.query(GET_ORDER_CUSTOM_FIELDS);
+
+            expect(activeOrder?.customFields).toEqual({
+                giftWrap: false,
+            });
+        });
+
+        it('setting order custom fields', async () => {
+            const { setOrderCustomFields } = await shopClient.query(SET_ORDER_CUSTOM_FIELDS, {
+                input: {
+                    customFields: { giftWrap: true },
+                },
+            });
+
+            expect(setOrderCustomFields?.customFields).toEqual({
+                giftWrap: true,
+            });
+
+            const { activeOrder } = await shopClient.query(GET_ORDER_CUSTOM_FIELDS);
+
+            expect(activeOrder?.customFields).toEqual({
+                giftWrap: true,
+            });
+        });
+    });
 });
+
+const GET_ORDER_CUSTOM_FIELDS = gql`
+    query GetOrderCustomFields {
+        activeOrder {
+            id
+            customFields {
+                giftWrap
+            }
+        }
+    }
+`;
+
+const SET_ORDER_CUSTOM_FIELDS = gql`
+    mutation SetOrderCustomFields($input: UpdateOrderInput!) {
+        setOrderCustomFields(input: $input) {
+            id
+            customFields {
+                giftWrap
+            }
+        }
+    }
+`;

+ 15 - 0
packages/core/src/api/resolvers/shop/shop-order.resolver.ts

@@ -7,6 +7,7 @@ import {
     MutationRemoveOrderLineArgs,
     MutationSetCustomerForOrderArgs,
     MutationSetOrderBillingAddressArgs,
+    MutationSetOrderCustomFieldsArgs,
     MutationSetOrderShippingAddressArgs,
     MutationSetOrderShippingMethodArgs,
     MutationTransitionOrderToStateArgs,
@@ -179,6 +180,20 @@ export class ShopOrderResolver {
         }
     }
 
+    @Mutation()
+    @Allow(Permission.Owner)
+    async setOrderCustomFields(
+        @Ctx() ctx: RequestContext,
+        @Args() args: MutationSetOrderCustomFieldsArgs,
+    ): Promise<Order | undefined> {
+        if (ctx.authorizedAsOwnerOnly) {
+            const sessionOrder = await this.getOrderFromContext(ctx);
+            if (sessionOrder) {
+                return this.orderService.updateCustomFields(ctx, sessionOrder.id, args.input.customFields);
+            }
+        }
+    }
+
     @Query()
     @Allow(Permission.Owner)
     async nextOrderStates(@Ctx() ctx: RequestContext): Promise<string[]> {

+ 9 - 1
packages/core/src/api/schema/shop-api/shop.api.graphql

@@ -19,6 +19,7 @@ type Query {
 type Mutation {
     "Adds an item to the order. If custom fields are defined on the OrderLine entity, a third argument 'customFields' will be available."
     addItemToOrder(productVariantId: ID!, quantity: Int!): Order
+    "Remove an OrderLine from the Order"
     removeOrderLine(orderLineId: ID!): Order
     "Adjusts an OrderLine. If custom fields are defined on the OrderLine entity, a third argument 'customFields' of type `OrderLineCustomFieldsInput` will be available."
     adjustOrderLine(orderLineId: ID!, quantity: Int): Order
@@ -31,14 +32,19 @@ type Mutation {
     setOrderShippingAddress(input: CreateAddressInput!): Order
     "Sets the billing address for this order"
     setOrderBillingAddress(input: CreateAddressInput!): Order
+    "Allows any custom fields to be set for the active order"
+    setOrderCustomFields(input: UpdateOrderInput!): Order
     "Sets the shipping method by id, which can be obtained with the `eligibleShippingMethods` query"
     setOrderShippingMethod(shippingMethodId: ID!): Order
+    "Add a Payment to the Order"
     addPaymentToOrder(input: PaymentInput!): Order
+    "Set the Customer for the Order. Required only if the Customer is not currently logged in"
     setCustomerForOrder(input: CreateCustomerInput!): Order
     "Authenticates the user using the native authentication strategy. This mutation is an alias for `authenticate({ native: { ... }})`"
     login(username: String!, password: String!, rememberMe: Boolean): LoginResult!
     "Authenticates the user using a named authentication strategy"
     authenticate(input: AuthenticationInput!, rememberMe: Boolean): LoginResult!
+    "End the current authenticated session"
     logout: Boolean!
     "Regenerate and send a verification token for a new Customer registration. Only applicable if `authOptions.requireVerification` is set to true."
     refreshCustomerVerification(emailAddress: String!): Boolean!
@@ -93,6 +99,9 @@ input UpdateCustomerInput {
     phoneNumber: String
 }
 
+# Populated with any custom fields at run-time
+input UpdateOrderInput
+
 """
 Passed as input to the `addPaymentToOrder` mutation.
 """
@@ -117,4 +126,3 @@ input OrderListOptions
 
 # generated by generateListOptions function
 input ProductListOptions
-

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

@@ -60,6 +60,7 @@ import {
     orderItemsAreFulfilled,
     orderTotalIsCovered,
 } from '../helpers/utils/order-utils';
+import { patchEntity } from '../helpers/utils/patch-entity';
 import { translateDeep } from '../helpers/utils/translate-entity';
 
 import { CountryService } from './country.service';
@@ -241,6 +242,12 @@ export class OrderService {
         return this.connection.getRepository(Order).save(newOrder);
     }
 
+    async updateCustomFields(ctx: RequestContext, orderId: ID, customFields: any) {
+        let order = await this.getOrderOrThrow(ctx, orderId);
+        order = patchEntity(order, { customFields });
+        return this.connection.getRepository(Order).save(order);
+    }
+
     async addItemToOrder(
         ctx: RequestContext,
         orderId: ID,

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 0 - 0
schema-shop.json


+ 1 - 1
scripts/codegen/generate-graphql-types.ts

@@ -14,7 +14,7 @@ const CLIENT_QUERY_FILES = path.join(
 );
 const E2E_ADMIN_QUERY_FILES = path.join(
     __dirname,
-    '../../packages/core/e2e/**/!(import.e2e-spec|plugin.e2e-spec|shop-definitions|custom-fields.e2e-spec|price-calculation-strategy.e2e-spec|list-query-builder.e2e-spec).ts',
+    '../../packages/core/e2e/**/!(import.e2e-spec|plugin.e2e-spec|shop-definitions|custom-fields.e2e-spec|price-calculation-strategy.e2e-spec|list-query-builder.e2e-spec|shop-order.e2e-spec).ts',
 );
 const E2E_SHOP_QUERY_FILES = [path.join(__dirname, '../../packages/core/e2e/graphql/shop-definitions.ts')];
 const E2E_ELASTICSEARCH_PLUGIN_QUERY_FILES = path.join(

Một số tệp đã không được hiển thị bởi vì quá nhiều tập tin thay đổi trong này khác