From d166c08963d60551a6918bb930a2c0d42dd843d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonathan=20C=C3=A9lio?= Date: Thu, 9 Jul 2020 15:37:39 -0300 Subject: [PATCH] feat(core): More flexible handling of shipping calculations * feat(core): Accept empty as response in shipping calculator * feat(core): Await all promises at same time in ShippingCalculator * refactor(core): Update filter undefined shipping calculator Closes #397, closes #398 --- .../shipping-method/shipping-calculator.ts | 4 +- .../shipping-method/shipping-method.entity.ts | 15 +++++--- .../shipping-calculator.ts | 38 ++++++++++++------- 3 files changed, 36 insertions(+), 21 deletions(-) diff --git a/packages/core/src/config/shipping-method/shipping-calculator.ts b/packages/core/src/config/shipping-method/shipping-calculator.ts index ee98b5dc03..c73d2dd558 100644 --- a/packages/core/src/config/shipping-method/shipping-calculator.ts +++ b/packages/core/src/config/shipping-method/shipping-calculator.ts @@ -59,7 +59,7 @@ export class ShippingCalculator extends C calculate( order: Order, args: ConfigArg[], - ): ShippingCalculationResult | Promise { + ): ShippingCalculationResult | Promise | undefined { return this.calculateFn(order, argsArrayToHash(args)); } } @@ -103,4 +103,4 @@ export interface ShippingCalculationResult { export type CalculateShippingFn = ( order: Order, args: ConfigArgValues, -) => ShippingCalculationResult | Promise; +) => ShippingCalculationResult | Promise | undefined; diff --git a/packages/core/src/entity/shipping-method/shipping-method.entity.ts b/packages/core/src/entity/shipping-method/shipping-method.entity.ts index 5f98e15145..0a03fd1f3f 100644 --- a/packages/core/src/entity/shipping-method/shipping-method.entity.ts +++ b/packages/core/src/entity/shipping-method/shipping-method.entity.ts @@ -59,12 +59,15 @@ export class ShippingMethod extends VendureEntity implements ChannelAware, SoftD async apply(order: Order): Promise { const calculator = this.allCalculators[this.calculator.code]; if (calculator) { - const { price, priceWithTax, metadata } = await calculator.calculate(order, this.calculator.args); - return { - price: Math.round(price), - priceWithTax: Math.round(priceWithTax), - metadata, - }; + const response = await calculator.calculate(order, this.calculator.args); + if (response) { + const { price, priceWithTax, metadata } = response; + return { + price: Math.round(price), + priceWithTax: Math.round(priceWithTax), + metadata, + }; + } } } diff --git a/packages/core/src/service/helpers/shipping-calculator/shipping-calculator.ts b/packages/core/src/service/helpers/shipping-calculator/shipping-calculator.ts index 9adfc5c76b..a308db2a06 100644 --- a/packages/core/src/service/helpers/shipping-calculator/shipping-calculator.ts +++ b/packages/core/src/service/helpers/shipping-calculator/shipping-calculator.ts @@ -1,4 +1,5 @@ import { Injectable } from '@nestjs/common'; +import { notNullOrUndefined } from '@vendure/common/lib/shared-utils'; import { RequestContext } from '../../../api/common/request-context'; import { ShippingCalculationResult } from '../../../config/shipping-method/shipping-calculator'; @@ -6,6 +7,11 @@ import { Order } from '../../../entity/order/order.entity'; import { ShippingMethod } from '../../../entity/shipping-method/shipping-method.entity'; import { ShippingMethodService } from '../../services/shipping-method.service'; +type EligibleShippingMethod = { + method: ShippingMethod; + result: ShippingCalculationResult; +}; + @Injectable() export class ShippingCalculator { constructor(private shippingMethodService: ShippingMethodService) {} @@ -14,21 +20,27 @@ export class ShippingCalculator { * Returns an array of each eligible ShippingMethod for the given Order and sorts them by * price, with the cheapest first. */ - async getEligibleShippingMethods( - ctx: RequestContext, - order: Order, - ): Promise> { + async getEligibleShippingMethods(ctx: RequestContext, order: Order): Promise { const shippingMethods = this.shippingMethodService.getActiveShippingMethods(ctx.channel); - const eligibleMethods: Array<{ method: ShippingMethod; result: ShippingCalculationResult }> = []; - for (const method of shippingMethods) { - const eligible = await method.test(order); - if (eligible) { - const result = await method.apply(order); - if (result) { - eligibleMethods.push({ method, result }); - } + + const checkEligibilityPromises = shippingMethods.map((method) => + this.checkEligibilityByShippingMethod(order, method), + ); + const eligibleMethods = await Promise.all(checkEligibilityPromises); + + return eligibleMethods.filter(notNullOrUndefined).sort((a, b) => a.result.price - b.result.price); + } + + private async checkEligibilityByShippingMethod( + order: Order, + method: ShippingMethod, + ): Promise { + const eligible = await method.test(order); + if (eligible) { + const result = await method.apply(order); + if (result) { + return { method, result }; } } - return eligibleMethods.sort((a, b) => a.result.price - b.result.price); } }