From d0166a2b79eaf1756d2fd4286bf2a3dd7860c03c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BCrg=20Hunziker?= Date: Mon, 22 Apr 2024 11:18:32 +0200 Subject: [PATCH] fix(core): Add surcharge taxLines to taxSummary (#2798) --- .../src/entity/order/order.entity.spec.ts | 74 ++++++++++++++++++- .../core/src/entity/order/order.entity.ts | 19 ++++- packages/core/src/testing/order-test-utils.ts | 6 +- 3 files changed, 93 insertions(+), 6 deletions(-) diff --git a/packages/core/src/entity/order/order.entity.spec.ts b/packages/core/src/entity/order/order.entity.spec.ts index 30cf05fceb..0dfc9c3322 100644 --- a/packages/core/src/entity/order/order.entity.spec.ts +++ b/packages/core/src/entity/order/order.entity.spec.ts @@ -5,6 +5,7 @@ import { beforeAll, describe, expect, it } from 'vitest'; import { ensureConfigLoaded } from '../../config/config-helpers'; import { createOrder, createRequestContext, taxCategoryStandard } from '../../testing/order-test-utils'; import { ShippingLine } from '../shipping-line/shipping-line.entity'; +import { Surcharge } from '../surcharge/surcharge.entity'; import { Order } from './order.entity'; @@ -324,6 +325,73 @@ describe('Order entity methods', () => { ]); assertOrderTaxesAddsUp(order); }); + + it('with surcharge', () => { + const ctx = createRequestContext({ pricesIncludeTax: false }); + const order = createOrder({ + ctx, + lines: [ + { + listPrice: 300, + taxCategory: taxCategoryStandard, + quantity: 2, + }, + { + listPrice: 1000, + taxCategory: taxCategoryStandard, + quantity: 1, + }, + ], + surcharges: [ + new Surcharge({ + description: 'Special surcharge', + listPrice: 400, + listPriceIncludesTax: ctx.channel.pricesIncludeTax, + taxLines: [ + { description: 'Special surcharge tax', taxRate: 50 }, + { description: 'Special surcharge second tax', taxRate: 20 }, + ], + sku: 'special-surcharge', + }), + new Surcharge({ + description: 'Other surcharge', + listPrice: 500, + listPriceIncludesTax: ctx.channel.pricesIncludeTax, + taxLines: [{ description: 'Other surcharge tax', taxRate: 0 }], + sku: 'other-surcharge', + }), + ], + }); + order.lines.forEach(i => (i.taxLines = [{ taxRate: 5, description: 'tax a' }])); + + expect(order.taxSummary).toEqual([ + { + description: 'tax a', + taxRate: 5, + taxBase: 1600, + taxTotal: 80, + }, + { + description: 'Special surcharge tax', + taxRate: 50, + taxBase: 400, + taxTotal: 200, + }, + { + description: 'Special surcharge second tax', + taxRate: 20, + taxBase: 400, + taxTotal: 80, + }, + { + description: 'Other surcharge tax', + taxRate: 0, + taxBase: 500, + taxTotal: 0, + }, + ]); + assertOrderTaxesAddsUp(order); + }); }); }); @@ -332,5 +400,9 @@ function assertOrderTaxesAddsUp(order: Order) { const lineTotal = summate(order.lines, 'proratedLinePrice'); const lineTotalWithTax = summate(order.lines, 'proratedLinePriceWithTax'); const shippingTax = (order.shippingWithTax ?? 0) - (order.shipping ?? 0); - expect(lineTotalWithTax - lineTotal + shippingTax).toBe(summaryTaxTotal); + const surchargesTotal = summate(order.surcharges, 'price'); + const surchargesTotalWithTax = summate(order.surcharges, 'priceWithTax'); + expect(lineTotalWithTax - lineTotal + shippingTax + (surchargesTotalWithTax - surchargesTotal)).toBe( + summaryTaxTotal, + ); } diff --git a/packages/core/src/entity/order/order.entity.ts b/packages/core/src/entity/order/order.entity.ts index 3dccbbfce6..a4f10f230c 100644 --- a/packages/core/src/entity/order/order.entity.ts +++ b/packages/core/src/entity/order/order.entity.ts @@ -299,7 +299,11 @@ export class Order extends VendureEntity implements ChannelAware, HasCustomField { rate: number; base: number; tax: number; description: string } >(); const taxId = (taxLine: TaxLine): string => `${taxLine.description}:${taxLine.taxRate}`; - const taxableLines = [...(this.lines ?? []), ...(this.shippingLines ?? [])]; + const taxableLines = [ + ...(this.lines ?? []), + ...(this.shippingLines ?? []), + ...(this.surcharges ?? []), + ]; for (const line of taxableLines) { const taxRateTotal = summate(line.taxLines, 'taxRate'); for (const taxLine of line.taxLines) { @@ -307,9 +311,18 @@ export class Order extends VendureEntity implements ChannelAware, HasCustomField const row = taxRateMap.get(id); const proportionOfTotalRate = 0 < taxLine.taxRate ? taxLine.taxRate / taxRateTotal : 0; - const lineBase = line instanceof OrderLine ? line.proratedLinePrice : line.discountedPrice; + const lineBase = + line instanceof OrderLine + ? line.proratedLinePrice + : line instanceof Surcharge + ? line.price + : line.discountedPrice; const lineWithTax = - line instanceof OrderLine ? line.proratedLinePriceWithTax : line.discountedPriceWithTax; + line instanceof OrderLine + ? line.proratedLinePriceWithTax + : line instanceof Surcharge + ? line.priceWithTax + : line.discountedPriceWithTax; const amount = Math.round((lineWithTax - lineBase) * proportionOfTotalRate); if (row) { row.tax += amount; diff --git a/packages/core/src/testing/order-test-utils.ts b/packages/core/src/testing/order-test-utils.ts index f664946f83..3d3c38a5f5 100644 --- a/packages/core/src/testing/order-test-utils.ts +++ b/packages/core/src/testing/order-test-utils.ts @@ -3,6 +3,7 @@ import { Omit } from '@vendure/common/lib/omit'; import { ID } from '@vendure/common/lib/shared-types'; import { RequestContext } from '../api/common/request-context'; +import { Surcharge } from '../entity'; import { Channel } from '../entity/channel/channel.entity'; import { Order } from '../entity/order/order.entity'; import { OrderLine } from '../entity/order-line/order-line.entity'; @@ -130,13 +131,14 @@ export class MockTaxRateService { } export function createOrder( - orderConfig: Partial> & { + orderConfig: Partial> & { ctx: RequestContext; lines: Array<{ listPrice: number; taxCategory: TaxCategory; quantity: number; }>; + surcharges?: Surcharge[]; }, ): Order { const lines = orderConfig.lines.map( @@ -156,7 +158,7 @@ export function createOrder( couponCodes: [], lines, shippingLines: [], - surcharges: [], + surcharges: orderConfig.surcharges || [], modifications: [], }); }