Ver código fonte

feat(core): Expose Order.promotions via GraphQL APIs

Relates to #174
Michael Bromley 6 anos atrás
pai
commit
02ebd9c0c9

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

@@ -1484,6 +1484,7 @@ export type Order = Node & {
     /** Order-level adjustments to the order total, such as discounts from promotions */
     /** Order-level adjustments to the order total, such as discounts from promotions */
     adjustments: Array<Adjustment>;
     adjustments: Array<Adjustment>;
     couponCodes: Array<Scalars['String']>;
     couponCodes: Array<Scalars['String']>;
+    promotions: Array<Promotion>;
     payments?: Maybe<Array<Payment>>;
     payments?: Maybe<Array<Payment>>;
     fulfillments?: Maybe<Array<Fulfillment>>;
     fulfillments?: Maybe<Array<Fulfillment>>;
     subTotalBeforeTax: Scalars['Int'];
     subTotalBeforeTax: Scalars['Int'];

+ 1 - 0
packages/common/src/generated-types.ts

@@ -2173,6 +2173,7 @@ export type Order = Node & {
   /** Order-level adjustments to the order total, such as discounts from promotions */
   /** Order-level adjustments to the order total, such as discounts from promotions */
   adjustments: Array<Adjustment>,
   adjustments: Array<Adjustment>,
   couponCodes: Array<Scalars['String']>,
   couponCodes: Array<Scalars['String']>,
+  promotions: Array<Promotion>,
   payments?: Maybe<Array<Payment>>,
   payments?: Maybe<Array<Payment>>,
   fulfillments?: Maybe<Array<Fulfillment>>,
   fulfillments?: Maybe<Array<Fulfillment>>,
   subTotalBeforeTax: Scalars['Int'],
   subTotalBeforeTax: Scalars['Int'],

+ 49 - 48
packages/core/e2e/graphql/generated-e2e-admin-types.ts

@@ -2108,6 +2108,7 @@ export type Order = Node & {
     /** Order-level adjustments to the order total, such as discounts from promotions */
     /** Order-level adjustments to the order total, such as discounts from promotions */
     adjustments: Array<Adjustment>;
     adjustments: Array<Adjustment>;
     couponCodes: Array<Scalars['String']>;
     couponCodes: Array<Scalars['String']>;
+    promotions: Array<Promotion>;
     payments?: Maybe<Array<Payment>>;
     payments?: Maybe<Array<Payment>>;
     fulfillments?: Maybe<Array<Fulfillment>>;
     fulfillments?: Maybe<Array<Fulfillment>>;
     subTotalBeforeTax: Scalars['Int'];
     subTotalBeforeTax: Scalars['Int'];
@@ -4364,6 +4365,33 @@ export type UpdateOptionGroupMutation = { __typename?: 'Mutation' } & {
     updateProductOptionGroup: { __typename?: 'ProductOptionGroup' } & Pick<ProductOptionGroup, 'id'>;
     updateProductOptionGroup: { __typename?: 'ProductOptionGroup' } & Pick<ProductOptionGroup, 'id'>;
 };
 };
 
 
+export type DeletePromotionAdHoc1MutationVariables = {};
+
+export type DeletePromotionAdHoc1Mutation = { __typename?: 'Mutation' } & {
+    deletePromotion: { __typename?: 'DeletionResponse' } & Pick<DeletionResponse, 'result'>;
+};
+
+export type GetPromoProductsQueryVariables = {};
+
+export type GetPromoProductsQuery = { __typename?: 'Query' } & {
+    products: { __typename?: 'ProductList' } & {
+        items: Array<
+            { __typename?: 'Product' } & Pick<Product, 'id' | 'slug'> & {
+                    variants: Array<
+                        { __typename?: 'ProductVariant' } & Pick<
+                            ProductVariant,
+                            'id' | 'price' | 'priceWithTax' | 'sku'
+                        > & {
+                                facetValues: Array<
+                                    { __typename?: 'FacetValue' } & Pick<FacetValue, 'id' | 'code'>
+                                >;
+                            }
+                    >;
+                }
+        >;
+    };
+};
+
 export type GetOrderListQueryVariables = {
 export type GetOrderListQueryVariables = {
     options?: Maybe<OrderListOptions>;
     options?: Maybe<OrderListOptions>;
 };
 };
@@ -4918,33 +4946,6 @@ export type GetCustomerIdsQuery = { __typename?: 'Query' } & {
     };
     };
 };
 };
 
 
-export type DeletePromotionAdHoc1MutationVariables = {};
-
-export type DeletePromotionAdHoc1Mutation = { __typename?: 'Mutation' } & {
-    deletePromotion: { __typename?: 'DeletionResponse' } & Pick<DeletionResponse, 'result'>;
-};
-
-export type GetPromoProductsQueryVariables = {};
-
-export type GetPromoProductsQuery = { __typename?: 'Query' } & {
-    products: { __typename?: 'ProductList' } & {
-        items: Array<
-            { __typename?: 'Product' } & Pick<Product, 'id' | 'slug'> & {
-                    variants: Array<
-                        { __typename?: 'ProductVariant' } & Pick<
-                            ProductVariant,
-                            'id' | 'price' | 'priceWithTax' | 'sku'
-                        > & {
-                                facetValues: Array<
-                                    { __typename?: 'FacetValue' } & Pick<FacetValue, 'id' | 'code'>
-                                >;
-                            }
-                    >;
-                }
-        >;
-    };
-};
-
 export type UpdateStockMutationVariables = {
 export type UpdateStockMutationVariables = {
     input: Array<UpdateProductVariantInput>;
     input: Array<UpdateProductVariantInput>;
 };
 };
@@ -5685,6 +5686,27 @@ export namespace UpdateOptionGroup {
     export type UpdateProductOptionGroup = UpdateOptionGroupMutation['updateProductOptionGroup'];
     export type UpdateProductOptionGroup = UpdateOptionGroupMutation['updateProductOptionGroup'];
 }
 }
 
 
+export namespace DeletePromotionAdHoc1 {
+    export type Variables = DeletePromotionAdHoc1MutationVariables;
+    export type Mutation = DeletePromotionAdHoc1Mutation;
+    export type DeletePromotion = DeletePromotionAdHoc1Mutation['deletePromotion'];
+}
+
+export namespace GetPromoProducts {
+    export type Variables = GetPromoProductsQueryVariables;
+    export type Query = GetPromoProductsQuery;
+    export type Products = GetPromoProductsQuery['products'];
+    export type Items = NonNullable<GetPromoProductsQuery['products']['items'][0]>;
+    export type Variants = NonNullable<
+        (NonNullable<GetPromoProductsQuery['products']['items'][0]>)['variants'][0]
+    >;
+    export type FacetValues = NonNullable<
+        (NonNullable<
+            (NonNullable<GetPromoProductsQuery['products']['items'][0]>)['variants'][0]
+        >)['facetValues'][0]
+    >;
+}
+
 export namespace GetOrderList {
 export namespace GetOrderList {
     export type Variables = GetOrderListQueryVariables;
     export type Variables = GetOrderListQueryVariables;
     export type Query = GetOrderListQuery;
     export type Query = GetOrderListQuery;
@@ -6067,27 +6089,6 @@ export namespace GetCustomerIds {
     export type Items = NonNullable<GetCustomerIdsQuery['customers']['items'][0]>;
     export type Items = NonNullable<GetCustomerIdsQuery['customers']['items'][0]>;
 }
 }
 
 
-export namespace DeletePromotionAdHoc1 {
-    export type Variables = DeletePromotionAdHoc1MutationVariables;
-    export type Mutation = DeletePromotionAdHoc1Mutation;
-    export type DeletePromotion = DeletePromotionAdHoc1Mutation['deletePromotion'];
-}
-
-export namespace GetPromoProducts {
-    export type Variables = GetPromoProductsQueryVariables;
-    export type Query = GetPromoProductsQuery;
-    export type Products = GetPromoProductsQuery['products'];
-    export type Items = NonNullable<GetPromoProductsQuery['products']['items'][0]>;
-    export type Variants = NonNullable<
-        (NonNullable<GetPromoProductsQuery['products']['items'][0]>)['variants'][0]
-    >;
-    export type FacetValues = NonNullable<
-        (NonNullable<
-            (NonNullable<GetPromoProductsQuery['products']['items'][0]>)['variants'][0]
-        >)['facetValues'][0]
-    >;
-}
-
 export namespace UpdateStock {
 export namespace UpdateStock {
     export type Variables = UpdateStockMutationVariables;
     export type Variables = UpdateStockMutationVariables;
     export type Mutation = UpdateStockMutation;
     export type Mutation = UpdateStockMutation;

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

@@ -1484,6 +1484,7 @@ export type Order = Node & {
     /** Order-level adjustments to the order total, such as discounts from promotions */
     /** Order-level adjustments to the order total, such as discounts from promotions */
     adjustments: Array<Adjustment>;
     adjustments: Array<Adjustment>;
     couponCodes: Array<Scalars['String']>;
     couponCodes: Array<Scalars['String']>;
+    promotions: Array<Promotion>;
     payments?: Maybe<Array<Payment>>;
     payments?: Maybe<Array<Payment>>;
     fulfillments?: Maybe<Array<Fulfillment>>;
     fulfillments?: Maybe<Array<Fulfillment>>;
     subTotalBeforeTax: Scalars['Int'];
     subTotalBeforeTax: Scalars['Int'];
@@ -2461,6 +2462,18 @@ export type GetOrderByCodeQuery = { __typename?: 'Query' } & {
     orderByCode: Maybe<{ __typename?: 'Order' } & TestOrderFragmentFragment>;
     orderByCode: Maybe<{ __typename?: 'Order' } & TestOrderFragmentFragment>;
 };
 };
 
 
+export type GetOrderPromotionsByCodeQueryVariables = {
+    code: Scalars['String'];
+};
+
+export type GetOrderPromotionsByCodeQuery = { __typename?: 'Query' } & {
+    orderByCode: Maybe<
+        { __typename?: 'Order' } & {
+            promotions: Array<{ __typename?: 'Promotion' } & Pick<Promotion, 'id' | 'name'>>;
+        } & TestOrderFragmentFragment
+    >;
+};
+
 export type GetAvailableCountriesQueryVariables = {};
 export type GetAvailableCountriesQueryVariables = {};
 
 
 export type GetAvailableCountriesQuery = { __typename?: 'Query' } & {
 export type GetAvailableCountriesQuery = { __typename?: 'Query' } & {
@@ -2727,6 +2740,15 @@ export namespace GetOrderByCode {
     export type OrderByCode = TestOrderFragmentFragment;
     export type OrderByCode = TestOrderFragmentFragment;
 }
 }
 
 
+export namespace GetOrderPromotionsByCode {
+    export type Variables = GetOrderPromotionsByCodeQueryVariables;
+    export type Query = GetOrderPromotionsByCodeQuery;
+    export type OrderByCode = TestOrderFragmentFragment;
+    export type Promotions = NonNullable<
+        (NonNullable<GetOrderPromotionsByCodeQuery['orderByCode']>)['promotions'][0]
+    >;
+}
+
 export namespace GetAvailableCountries {
 export namespace GetAvailableCountries {
     export type Variables = GetAvailableCountriesQueryVariables;
     export type Variables = GetAvailableCountriesQueryVariables;
     export type Query = GetAvailableCountriesQuery;
     export type Query = GetAvailableCountriesQuery;

+ 13 - 0
packages/core/e2e/graphql/shop-definitions.ts

@@ -243,6 +243,19 @@ export const GET_ORDER_BY_CODE = gql`
     ${TEST_ORDER_FRAGMENT}
     ${TEST_ORDER_FRAGMENT}
 `;
 `;
 
 
+export const GET_ORDER_PROMOTIONS_BY_CODE = gql`
+    query GetOrderPromotionsByCode($code: String!) {
+        orderByCode(code: $code) {
+            ...TestOrderFragment
+            promotions {
+                id
+                name
+            }
+        }
+    }
+    ${TEST_ORDER_FRAGMENT}
+`;
+
 export const GET_AVAILABLE_COUNTRIES = gql`
 export const GET_AVAILABLE_COUNTRIES = gql`
     query GetAvailableCountries {
     query GetAvailableCountries {
         availableCountries {
         availableCountries {

+ 18 - 1
packages/core/e2e/shop-promotion.e2e-spec.ts → packages/core/e2e/order-promotion.e2e-spec.ts

@@ -2,6 +2,7 @@
 import gql from 'graphql-tag';
 import gql from 'graphql-tag';
 import path from 'path';
 import path from 'path';
 
 
+import { pick } from '../../common/src/pick';
 import {
 import {
     discountOnItemWithFacets,
     discountOnItemWithFacets,
     orderPercentageDiscount,
     orderPercentageDiscount,
@@ -20,6 +21,7 @@ import {
     AdjustItemQuantity,
     AdjustItemQuantity,
     ApplyCouponCode,
     ApplyCouponCode,
     GetActiveOrder,
     GetActiveOrder,
+    GetOrderPromotionsByCode,
     RemoveCouponCode,
     RemoveCouponCode,
     SetCustomerForOrder,
     SetCustomerForOrder,
 } from './graphql/generated-e2e-shop-types';
 } from './graphql/generated-e2e-shop-types';
@@ -29,6 +31,7 @@ import {
     ADJUST_ITEM_QUANTITY,
     ADJUST_ITEM_QUANTITY,
     APPLY_COUPON_CODE,
     APPLY_COUPON_CODE,
     GET_ACTIVE_ORDER,
     GET_ACTIVE_ORDER,
+    GET_ORDER_PROMOTIONS_BY_CODE,
     REMOVE_COUPON_CODE,
     REMOVE_COUPON_CODE,
     SET_CUSTOMER,
     SET_CUSTOMER,
 } from './graphql/shop-definitions';
 } from './graphql/shop-definitions';
@@ -41,7 +44,7 @@ import {
     testSuccessfulPaymentMethod,
     testSuccessfulPaymentMethod,
 } from './utils/test-order-utils';
 } from './utils/test-order-utils';
 
 
-describe('Shop orders', () => {
+describe('Promotions applied to Orders', () => {
     const adminClient = new TestAdminClient();
     const adminClient = new TestAdminClient();
     const shopClient = new TestShopClient();
     const shopClient = new TestShopClient();
     const server = new TestServer();
     const server = new TestServer();
@@ -397,6 +400,7 @@ describe('Shop orders', () => {
 
 
         describe('guest customer', () => {
         describe('guest customer', () => {
             const GUEST_EMAIL_ADDRESS = 'guest@test.com';
             const GUEST_EMAIL_ADDRESS = 'guest@test.com';
+            let orderCode: string;
 
 
             function addGuestCustomerToOrder() {
             function addGuestCustomerToOrder() {
                 return shopClient.query<SetCustomerForOrder.Mutation, SetCustomerForOrder.Variables>(
                 return shopClient.query<SetCustomerForOrder.Mutation, SetCustomerForOrder.Variables>(
@@ -428,6 +432,19 @@ describe('Shop orders', () => {
                 const order = await addPaymentToOrder(shopClient, testSuccessfulPaymentMethod);
                 const order = await addPaymentToOrder(shopClient, testSuccessfulPaymentMethod);
                 expect(order.state).toBe('PaymentSettled');
                 expect(order.state).toBe('PaymentSettled');
                 expect(order.active).toBe(false);
                 expect(order.active).toBe(false);
+                orderCode = order.code;
+            });
+
+            it('adds Promotions to Order once payment arranged', async () => {
+                const { orderByCode } = await shopClient.query<
+                    GetOrderPromotionsByCode.Query,
+                    GetOrderPromotionsByCode.Variables
+                >(GET_ORDER_PROMOTIONS_BY_CODE, {
+                    code: orderCode,
+                });
+                expect(orderByCode!.promotions.map(pick(['id', 'name']))).toEqual([
+                    { id: 'T_9', name: 'Free with test coupon' },
+                ]);
             });
             });
 
 
             it('throws when usage exceeds limit', async () => {
             it('throws when usage exceeds limit', async () => {

+ 13 - 3
packages/core/src/api/resolvers/entity/order-entity.resolver.ts

@@ -8,9 +8,11 @@ import { ShippingMethodService } from '../../../service/services/shipping-method
 
 
 @Resolver('Order')
 @Resolver('Order')
 export class OrderEntityResolver {
 export class OrderEntityResolver {
-    constructor(private orderService: OrderService,
-                private shippingMethodService: ShippingMethodService,
-                private historyService: HistoryService) {}
+    constructor(
+        private orderService: OrderService,
+        private shippingMethodService: ShippingMethodService,
+        private historyService: HistoryService,
+    ) {}
 
 
     @ResolveProperty()
     @ResolveProperty()
     async payments(@Parent() order: Order) {
     async payments(@Parent() order: Order) {
@@ -41,4 +43,12 @@ export class OrderEntityResolver {
     async history(@Parent() order: Order, @Args() args: OrderHistoryArgs) {
     async history(@Parent() order: Order, @Args() args: OrderHistoryArgs) {
         return this.historyService.getHistoryForOrder(order.id, args.options || undefined);
         return this.historyService.getHistoryForOrder(order.id, args.options || undefined);
     }
     }
+
+    @ResolveProperty()
+    async promotions(@Parent() order: Order) {
+        if (order.promotions) {
+            return order.promotions;
+        }
+        return this.orderService.getOrderPromotions(order.id);
+    }
 }
 }

+ 1 - 0
packages/core/src/api/schema/type/order.type.graphql

@@ -14,6 +14,7 @@ type Order implements Node {
     "Order-level adjustments to the order total, such as discounts from promotions"
     "Order-level adjustments to the order total, such as discounts from promotions"
     adjustments: [Adjustment!]!
     adjustments: [Adjustment!]!
     couponCodes: [String!]!
     couponCodes: [String!]!
+    promotions: [Promotion!]!
     payments: [Payment!]
     payments: [Payment!]
     fulfillments: [Fulfillment!]
     fulfillments: [Fulfillment!]
     subTotalBeforeTax: Int!
     subTotalBeforeTax: Int!

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

@@ -310,6 +310,13 @@ export class OrderService {
         return this.applyPriceAdjustments(ctx, order);
         return this.applyPriceAdjustments(ctx, order);
     }
     }
 
 
+    async getOrderPromotions(orderId: ID): Promise<Promotion[]> {
+        const order = await getEntityOrThrow(this.connection, Order, orderId, {
+            relations: ['promotions'],
+        });
+        return order.promotions || [];
+    }
+
     getNextOrderStates(order: Order): OrderState[] {
     getNextOrderStates(order: Order): OrderState[] {
         return this.orderStateMachine.getNextStates(order);
         return this.orderStateMachine.getNextStates(order);
     }
     }

Diferenças do arquivo suprimidas por serem muito extensas
+ 0 - 0
schema-admin.json


Diferenças do arquivo suprimidas por serem muito extensas
+ 0 - 0
schema-shop.json


Alguns arquivos não foram mostrados porque muitos arquivos mudaram nesse diff