UNPKG

@vendure/core

Version:

A modern, headless ecommerce framework

119 lines 4.76 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.OrderLevelTaxCalculationStrategy = void 0; const tax_utils_1 = require("../../common/tax-utils"); /** * @description * An {@link OrderTaxCalculationStrategy} that groups net subtotals by tax rate * and rounds once per group. This eliminates per-line rounding accumulation errors * present in the {@link DefaultOrderTaxCalculationStrategy}. * * This approach is required by certain jurisdictions and ERP systems that expect * tax to be calculated on the subtotal per tax rate rather than per line. * * Note that when using this strategy, the `taxTotal` in the tax summary may differ * by ±1 minor unit from the sum of individual line-level `proratedLineTax` values. * This is expected and is the intended behaviour. * * @example * ```ts * import { OrderLevelTaxCalculationStrategy, VendureConfig } from '\@vendure/core'; * * export const config: VendureConfig = { * taxOptions: { * orderTaxCalculationStrategy: new OrderLevelTaxCalculationStrategy(), * }, * }; * ``` * * @docsCategory tax * @docsPage OrderTaxCalculationStrategy * @since 3.6.0 */ class OrderLevelTaxCalculationStrategy { calculateOrderTotals(order) { const { subTotal, subTotalGroups, shipping, shippingGroups } = this.groupOrder(order); let subTotalTax = 0; for (const [, group] of subTotalGroups) { subTotalTax += Math.round((0, tax_utils_1.taxPayableOn)(group.netBase, group.rate)); } let shippingTax = 0; for (const [, group] of shippingGroups) { shippingTax += Math.round((0, tax_utils_1.taxPayableOn)(group.netBase, group.rate)); } return { subTotal, subTotalWithTax: subTotal + subTotalTax, shipping, shippingWithTax: shipping + shippingTax, }; } calculateTaxSummary(order) { const { subTotalGroups, shippingGroups } = this.groupOrder(order); const merged = new Map(); for (const groups of [subTotalGroups, shippingGroups]) { for (const [key, group] of groups) { const roundedTax = Math.round((0, tax_utils_1.taxPayableOn)(group.netBase, group.rate)); const existing = merged.get(key); if (existing) { existing.netBase += group.netBase; existing.tax += roundedTax; } else { merged.set(key, Object.assign(Object.assign({}, group), { tax: roundedTax })); } } } const taxSummary = []; for (const [, group] of merged) { taxSummary.push({ taxRate: group.rate, description: group.description, taxBase: group.netBase, taxTotal: group.tax, }); } return taxSummary; } groupOrder(order) { var _a, _b, _c; let subTotal = 0; let shipping = 0; const subTotalGroups = new Map(); const shippingGroups = new Map(); for (const line of (_a = order.lines) !== null && _a !== void 0 ? _a : []) { subTotal += line.proratedLinePrice; this.accumulateIntoGroups(subTotalGroups, line.taxLines, line.proratedLinePrice); } for (const surcharge of (_b = order.surcharges) !== null && _b !== void 0 ? _b : []) { subTotal += surcharge.price; this.accumulateIntoGroups(subTotalGroups, surcharge.taxLines, surcharge.price); } for (const shippingLine of (_c = order.shippingLines) !== null && _c !== void 0 ? _c : []) { shipping += shippingLine.discountedPrice; this.accumulateIntoGroups(shippingGroups, shippingLine.taxLines, shippingLine.discountedPrice); } return { subTotal, subTotalGroups, shipping, shippingGroups }; } accumulateIntoGroups(groups, taxLines, lineNetBase) { if (!(taxLines === null || taxLines === void 0 ? void 0 : taxLines.length)) { return; } for (const taxLine of taxLines) { const key = `${taxLine.description}:${taxLine.taxRate}`; const existing = groups.get(key); if (existing) { existing.netBase += lineNetBase; } else { groups.set(key, { rate: taxLine.taxRate, description: taxLine.description, netBase: lineNetBase, }); } } } } exports.OrderLevelTaxCalculationStrategy = OrderLevelTaxCalculationStrategy; //# sourceMappingURL=order-level-tax-calculation-strategy.js.map