-
-
Notifications
You must be signed in to change notification settings - Fork 1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(core): Implement testShippingMethod query
Relates to #133
- Loading branch information
1 parent
554357f
commit a3a9931
Showing
9 changed files
with
267 additions
and
55 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
65 changes: 65 additions & 0 deletions
65
packages/core/src/service/helpers/shipping-configuration/shipping-configuration.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
import { Injectable } from '@nestjs/common'; | ||
import { ConfigurableOperationInput } from '@vendure/common/lib/generated-types'; | ||
|
||
import { ConfigurableOperation } from '../../../../../common/lib/generated-types'; | ||
import { UserInputError } from '../../../common/error/errors'; | ||
import { ConfigService } from '../../../config/config.service'; | ||
import { ShippingCalculator } from '../../../config/shipping-method/shipping-calculator'; | ||
import { ShippingEligibilityChecker } from '../../../config/shipping-method/shipping-eligibility-checker'; | ||
|
||
/** | ||
* This helper class provides methods relating to ShippingMethod configurable operations (eligibility checkers | ||
* and calculators). | ||
*/ | ||
@Injectable() | ||
export class ShippingConfiguration { | ||
readonly shippingEligibilityCheckers: ShippingEligibilityChecker[]; | ||
readonly shippingCalculators: ShippingCalculator[]; | ||
|
||
constructor(private configService: ConfigService) { | ||
this.shippingEligibilityCheckers = | ||
this.configService.shippingOptions.shippingEligibilityCheckers || []; | ||
this.shippingCalculators = this.configService.shippingOptions.shippingCalculators || []; | ||
} | ||
|
||
parseCheckerInput(input: ConfigurableOperationInput): ConfigurableOperation { | ||
const checker = this.getChecker(input.code); | ||
return this.parseOperationArgs(input, checker); | ||
} | ||
|
||
parseCalculatorInput(input: ConfigurableOperationInput): ConfigurableOperation { | ||
const calculator = this.getCalculator(input.code); | ||
return this.parseOperationArgs(input, calculator); | ||
} | ||
|
||
/** | ||
* Converts the input values of the "create" and "update" mutations into the format expected by the ShippingMethod entity. | ||
*/ | ||
private parseOperationArgs( | ||
input: ConfigurableOperationInput, | ||
checkerOrCalculator: ShippingEligibilityChecker | ShippingCalculator, | ||
): ConfigurableOperation { | ||
const output: ConfigurableOperation = { | ||
code: input.code, | ||
description: checkerOrCalculator.description, | ||
args: input.arguments, | ||
}; | ||
return output; | ||
} | ||
|
||
private getChecker(code: string): ShippingEligibilityChecker { | ||
const match = this.shippingEligibilityCheckers.find(a => a.code === code); | ||
if (!match) { | ||
throw new UserInputError(`error.shipping-eligibility-checker-with-code-not-found`, { code }); | ||
} | ||
return match; | ||
} | ||
|
||
private getCalculator(code: string): ShippingCalculator { | ||
const match = this.shippingCalculators.find(a => a.code === code); | ||
if (!match) { | ||
throw new UserInputError(`error.shipping-calculator-with-code-not-found`, { code }); | ||
} | ||
return match; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
89 changes: 89 additions & 0 deletions
89
packages/core/src/service/services/order-testing.service.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
import { Injectable } from '@nestjs/common'; | ||
import { InjectConnection } from '@nestjs/typeorm'; | ||
import { | ||
CreateAddressInput, | ||
TestShippingMethodInput, | ||
TestShippingMethodResult, | ||
} from '@vendure/common/lib/generated-types'; | ||
import { Connection } from 'typeorm'; | ||
|
||
import { ID } from '../../../../common/lib/shared-types'; | ||
import { RequestContext } from '../../api/common/request-context'; | ||
import { OrderItem } from '../../entity/order-item/order-item.entity'; | ||
import { OrderLine } from '../../entity/order-line/order-line.entity'; | ||
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 { ShippingConfiguration } from '../helpers/shipping-configuration/shipping-configuration'; | ||
import { getEntityOrThrow } from '../helpers/utils/get-entity-or-throw'; | ||
|
||
/** | ||
* This service is responsible for creating temporary mock Orders against which tests can be run, such as | ||
* testing a ShippingMethod or Promotion. | ||
*/ | ||
@Injectable() | ||
export class OrderTestingService { | ||
constructor( | ||
@InjectConnection() private connection: Connection, | ||
private orderCalculator: OrderCalculator, | ||
private shippingConfiguration: ShippingConfiguration, | ||
) {} | ||
|
||
/** | ||
* Runs a given ShippingMethod configuration against a mock Order to test for eligibility and resulting | ||
* price. | ||
*/ | ||
async testShippingMethod( | ||
ctx: RequestContext, | ||
input: TestShippingMethodInput, | ||
): Promise<TestShippingMethodResult> { | ||
const shippingMethod = new ShippingMethod({ | ||
checker: this.shippingConfiguration.parseCheckerInput(input.checker), | ||
calculator: this.shippingConfiguration.parseCalculatorInput(input.calculator), | ||
}); | ||
const mockOrder = await this.buildMockOrder(ctx, input.shippingAddress, input.lines); | ||
const eligible = await shippingMethod.test(mockOrder); | ||
const price = eligible ? await shippingMethod.apply(mockOrder) : undefined; | ||
return { | ||
eligible, | ||
price, | ||
}; | ||
} | ||
private async buildMockOrder( | ||
ctx: RequestContext, | ||
shippingAddress: CreateAddressInput, | ||
lines: Array<{ productVariantId: ID; quantity: number }>, | ||
): Promise<Order> { | ||
const mockOrder = new Order({ | ||
lines: [], | ||
}); | ||
mockOrder.shippingAddress = shippingAddress; | ||
for (const line of lines) { | ||
const productVariant = await getEntityOrThrow( | ||
this.connection, | ||
ProductVariant, | ||
line.productVariantId, | ||
{ relations: ['taxCategory'] }, | ||
); | ||
const orderLine = new OrderLine({ | ||
productVariant, | ||
items: [], | ||
taxCategory: productVariant.taxCategory, | ||
}); | ||
mockOrder.lines.push(orderLine); | ||
|
||
for (let i = 0; i < line.quantity; i++) { | ||
const orderItem = new OrderItem({ | ||
unitPrice: productVariant.price, | ||
pendingAdjustments: [], | ||
unitPriceIncludesTax: productVariant.priceIncludesTax, | ||
taxRate: productVariant.priceIncludesTax ? productVariant.taxRateApplied.value : 0, | ||
}); | ||
orderLine.items.push(orderItem); | ||
} | ||
} | ||
await this.orderCalculator.applyPriceAdjustments(ctx, mockOrder, []); | ||
return mockOrder; | ||
} | ||
} |
Oops, something went wrong.