Skip to content

Commit

Permalink
feat(core): Add testEligibleShippingMethods query
Browse files Browse the repository at this point in the history
Allows testing mock orders against existing shipping methods, to see what options storefront customer would have for a given order and destination.
  • Loading branch information
michaelbromley committed Aug 9, 2019
1 parent 4027325 commit bc860e0
Show file tree
Hide file tree
Showing 7 changed files with 204 additions and 1 deletion.
11 changes: 11 additions & 0 deletions packages/common/src/generated-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2658,6 +2658,7 @@ export type Query = {
shippingEligibilityCheckers: Array<ConfigurableOperationDefinition>,
shippingCalculators: Array<ConfigurableOperationDefinition>,
testShippingMethod: TestShippingMethodResult,
testEligibleShippingMethods: Array<ShippingMethodQuote>,
taxCategories: Array<TaxCategory>,
taxCategory?: Maybe<TaxCategory>,
taxRates: TaxRateList,
Expand Down Expand Up @@ -2828,6 +2829,11 @@ export type QueryTestShippingMethodArgs = {
};


export type QueryTestEligibleShippingMethodsArgs = {
input: TestEligibleShippingMethodsInput
};


export type QueryTaxCategoryArgs = {
id: Scalars['ID']
};
Expand Down Expand Up @@ -3173,6 +3179,11 @@ export type TaxRateSortParameter = {
value?: Maybe<SortOrder>,
};

export type TestEligibleShippingMethodsInput = {
shippingAddress: CreateAddressInput,
lines: Array<TestShippingMethodOrderLineInput>,
};

export type TestShippingMethodInput = {
checker: ConfigurableOperationInput,
calculator: ConfigurableOperationInput,
Expand Down
49 changes: 49 additions & 0 deletions packages/core/e2e/graphql/generated-e2e-admin-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2591,6 +2591,7 @@ export type Query = {
shippingEligibilityCheckers: Array<ConfigurableOperationDefinition>;
shippingCalculators: Array<ConfigurableOperationDefinition>;
testShippingMethod: TestShippingMethodResult;
testEligibleShippingMethods: Array<ShippingMethodQuote>;
taxCategories: Array<TaxCategory>;
taxCategory?: Maybe<TaxCategory>;
taxRates: TaxRateList;
Expand Down Expand Up @@ -2728,6 +2729,10 @@ export type QueryTestShippingMethodArgs = {
input: TestShippingMethodInput;
};

export type QueryTestEligibleShippingMethodsArgs = {
input: TestEligibleShippingMethodsInput;
};

export type QueryTaxCategoryArgs = {
id: Scalars['ID'];
};
Expand Down Expand Up @@ -3073,6 +3078,11 @@ export type TaxRateSortParameter = {
value?: Maybe<SortOrder>;
};

export type TestEligibleShippingMethodsInput = {
shippingAddress: CreateAddressInput;
lines: Array<TestShippingMethodOrderLineInput>;
};

export type TestShippingMethodInput = {
checker: ConfigurableOperationInput;
calculator: ConfigurableOperationInput;
Expand Down Expand Up @@ -4744,6 +4754,30 @@ export type GetCalculatorsQuery = { __typename?: 'Query' } & {
>;
};

export type TestShippingMethodQueryVariables = {
input: TestShippingMethodInput;
};

export type TestShippingMethodQuery = { __typename?: 'Query' } & {
testShippingMethod: { __typename?: 'TestShippingMethodResult' } & Pick<
TestShippingMethodResult,
'eligible'
> & { price: Maybe<{ __typename?: 'ShippingPrice' } & Pick<ShippingPrice, 'price' | 'priceWithTax'>> };
};

export type TestEligibleMethodsQueryVariables = {
input: TestEligibleShippingMethodsInput;
};

export type TestEligibleMethodsQuery = { __typename?: 'Query' } & {
testEligibleShippingMethods: Array<
{ __typename?: 'ShippingMethodQuote' } & Pick<
ShippingMethodQuote,
'id' | 'description' | 'price' | 'priceWithTax'
>
>;
};

export type GetMeQueryVariables = {};

export type GetMeQuery = { __typename?: 'Query' } & {
Expand Down Expand Up @@ -5910,6 +5944,21 @@ export namespace GetCalculators {
export type Args = NonNullable<(NonNullable<GetCalculatorsQuery['shippingCalculators'][0]>)['args'][0]>;
}

export namespace TestShippingMethod {
export type Variables = TestShippingMethodQueryVariables;
export type Query = TestShippingMethodQuery;
export type TestShippingMethod = TestShippingMethodQuery['testShippingMethod'];
export type Price = NonNullable<TestShippingMethodQuery['testShippingMethod']['price']>;
}

export namespace TestEligibleMethods {
export type Variables = TestEligibleMethodsQueryVariables;
export type Query = TestEligibleMethodsQuery;
export type TestEligibleShippingMethods = NonNullable<
TestEligibleMethodsQuery['testEligibleShippingMethods'][0]
>;
}

export namespace GetMe {
export type Variables = GetMeQueryVariables;
export type Query = GetMeQuery;
Expand Down
103 changes: 103 additions & 0 deletions packages/core/e2e/shipping-method.e2e-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ import {
GetEligibilityCheckers,
GetShippingMethod,
GetShippingMethodList,
TestEligibleMethods,
TestShippingMethod,
UpdateShippingMethod,
} from './graphql/generated-e2e-admin-types';
import { TestAdminClient, TestShopClient } from './test-client';
Expand Down Expand Up @@ -176,6 +178,84 @@ describe('ShippingMethod resolver', () => {
const listResult2 = await adminClient.query<GetShippingMethodList.Query>(GET_SHIPPING_METHOD_LIST);
expect(listResult2.shippingMethods.items.map(i => i.id)).toEqual(['T_1', 'T_2']);
});

it('testShippingMethod', async () => {
const { testShippingMethod } = await adminClient.query<
TestShippingMethod.Query,
TestShippingMethod.Variables
>(TEST_SHIPPING_METHOD, {
input: {
calculator: {
code: defaultShippingCalculator.code,
arguments: [
{
name: 'rate',
type: 'int',
value: '1000',
},
{
name: 'taxRate',
type: 'int',
value: '20',
},
],
},
checker: {
code: defaultShippingEligibilityChecker.code,
arguments: [
{
name: 'orderMinimum',
type: 'int',
value: '0',
},
],
},
lines: [{ productVariantId: 'T_1', quantity: 1 }],
shippingAddress: {
streetLine1: '',
countryCode: 'GB',
},
},
});

expect(testShippingMethod).toEqual({
eligible: true,
price: {
price: 1000,
priceWithTax: 1200,
},
});
});

it('testEligibleShippingMethods', async () => {
const { testEligibleShippingMethods } = await adminClient.query<
TestEligibleMethods.Query,
TestEligibleMethods.Variables
>(TEST_ELIGIBLE_SHIPPING_METHODS, {
input: {
lines: [{ productVariantId: 'T_1', quantity: 1 }],
shippingAddress: {
streetLine1: '',
countryCode: 'GB',
},
},
});

expect(testEligibleShippingMethods).toEqual([
{
id: 'T_1',
description: 'Standard Shipping',
price: 500,
priceWithTax: 500,
},
{
id: 'T_2',
description: 'Express Shipping',
price: 1000,
priceWithTax: 1000,
},
]);
});
});

const SHIPPING_METHOD_FRAGMENT = gql`
Expand Down Expand Up @@ -271,3 +351,26 @@ const GET_CALCULATORS = gql`
}
}
`;

const TEST_SHIPPING_METHOD = gql`
query TestShippingMethod($input: TestShippingMethodInput!) {
testShippingMethod(input: $input) {
eligible
price {
price
priceWithTax
}
}
}
`;

export const TEST_ELIGIBLE_SHIPPING_METHODS = gql`
query TestEligibleMethods($input: TestEligibleShippingMethodsInput!) {
testEligibleShippingMethods(input: $input) {
id
description
price
priceWithTax
}
}
`;
11 changes: 11 additions & 0 deletions packages/core/src/api/resolvers/admin/shipping-method.resolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
Permission,
QueryShippingMethodArgs,
QueryShippingMethodsArgs,
QueryTestEligibleShippingMethodsArgs,
QueryTestShippingMethodArgs,
} from '@vendure/common/lib/generated-types';
import { PaginatedList } from '@vendure/common/lib/shared-types';
Expand Down Expand Up @@ -77,4 +78,14 @@ export class ShippingMethodResolver {
const { input } = args;
return this.orderTestingService.testShippingMethod(ctx, input);
}

@Query()
@Allow(Permission.ReadSettings)
testEligibleShippingMethods(
@Ctx() ctx: RequestContext,
@Args() args: QueryTestEligibleShippingMethodsArgs,
) {
const { input } = args;
return this.orderTestingService.testEligibleShippingMethods(ctx, input);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ type Query {
shippingEligibilityCheckers: [ConfigurableOperationDefinition!]!
shippingCalculators: [ConfigurableOperationDefinition!]!
testShippingMethod(input: TestShippingMethodInput!): TestShippingMethodResult!
testEligibleShippingMethods(input: TestEligibleShippingMethodsInput!): [ShippingMethodQuote!]!
}

type Mutation {
Expand Down Expand Up @@ -40,6 +41,11 @@ input TestShippingMethodInput {
lines: [TestShippingMethodOrderLineInput!]!
}

input TestEligibleShippingMethodsInput {
shippingAddress: CreateAddressInput!
lines: [TestShippingMethodOrderLineInput!]!
}

input TestShippingMethodOrderLineInput {
productVariantId: ID!
quantity: Int!
Expand Down
23 changes: 23 additions & 0 deletions packages/core/src/service/services/order-testing.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import { Injectable } from '@nestjs/common';
import { InjectConnection } from '@nestjs/typeorm';
import {
CreateAddressInput,
ShippingMethodQuote,
TestEligibleShippingMethodsInput,
TestShippingMethodInput,
TestShippingMethodResult,
} from '@vendure/common/lib/generated-types';
Expand All @@ -15,6 +17,7 @@ import { Order } from '../../entity/order/order.entity';
import { ProductVariant } from '../../entity/product-variant/product-variant.entity';
import { ShippingMethod } from '../../entity/shipping-method/shipping-method.entity';
import { OrderCalculator } from '../helpers/order-calculator/order-calculator';
import { ShippingCalculator } from '../helpers/shipping-calculator/shipping-calculator';
import { ShippingConfiguration } from '../helpers/shipping-configuration/shipping-configuration';
import { getEntityOrThrow } from '../helpers/utils/get-entity-or-throw';

Expand All @@ -27,6 +30,7 @@ export class OrderTestingService {
constructor(
@InjectConnection() private connection: Connection,
private orderCalculator: OrderCalculator,
private shippingCalculator: ShippingCalculator,
private shippingConfiguration: ShippingConfiguration,
) {}

Expand All @@ -50,6 +54,25 @@ export class OrderTestingService {
price,
};
}

/**
* Tests all available ShippingMethods against a mock Order and return those whic hare eligible. This
* is intended to simulate a call to the `eligibleShippingMethods` query of the Shop API.
*/
async testEligibleShippingMethods(
ctx: RequestContext,
input: TestEligibleShippingMethodsInput,
): Promise<ShippingMethodQuote[]> {
const mockOrder = await this.buildMockOrder(ctx, input.shippingAddress, input.lines);
const eligibleMethods = await this.shippingCalculator.getEligibleShippingMethods(ctx, mockOrder);
return eligibleMethods.map(result => ({
id: result.method.id as string,
price: result.price.price,
priceWithTax: result.price.priceWithTax,
description: result.method.description,
}));
}

private async buildMockOrder(
ctx: RequestContext,
shippingAddress: CreateAddressInput,
Expand Down
2 changes: 1 addition & 1 deletion schema-admin.json

Large diffs are not rendered by default.

0 comments on commit bc860e0

Please sign in to comment.