Skip to content

Commit

Permalink
feat(core): More flexible handling of shipping calculations
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
jonyw4 authored Jul 9, 2020
1 parent 7fd413f commit d166c08
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 21 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ export class ShippingCalculator<T extends ShippingCalculatorArgs = {}> extends C
calculate(
order: Order,
args: ConfigArg[],
): ShippingCalculationResult | Promise<ShippingCalculationResult> {
): ShippingCalculationResult | Promise<ShippingCalculationResult> | undefined {
return this.calculateFn(order, argsArrayToHash(args));
}
}
Expand Down Expand Up @@ -103,4 +103,4 @@ export interface ShippingCalculationResult {
export type CalculateShippingFn<T extends ShippingCalculatorArgs> = (
order: Order,
args: ConfigArgValues<T>,
) => ShippingCalculationResult | Promise<ShippingCalculationResult>;
) => ShippingCalculationResult | Promise<ShippingCalculationResult> | undefined;
Original file line number Diff line number Diff line change
Expand Up @@ -59,12 +59,15 @@ export class ShippingMethod extends VendureEntity implements ChannelAware, SoftD
async apply(order: Order): Promise<ShippingCalculationResult | undefined> {
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,
};
}
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
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';
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) {}
Expand All @@ -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<Array<{ method: ShippingMethod; result: ShippingCalculationResult }>> {
async getEligibleShippingMethods(ctx: RequestContext, order: Order): Promise<EligibleShippingMethod[]> {
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<EligibleShippingMethod | undefined> {
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);
}
}

0 comments on commit d166c08

Please sign in to comment.