feat(promotion, dashboard, core-flows, cart, types, utils, medusa): tax inclusive promotions (#12412)

* feat: tax inclusive promotions

* feat: add a totals test case

* feat: add integration test

* chore: changeset

* fix: typo

* chore: refactor

* fix: tests

* fix: rest of buyget action tests

* fix: cart spec

* chore: expand integration test with item level totals

* feat: add a few more test cases

---------

Co-authored-by: Oli Juhl <59018053+olivermrbl@users.noreply.github.com>
This commit is contained in:
Frane Polić
2025-06-12 15:07:11 +02:00
committed by GitHub
parent 08de1f54e4
commit 2621f00bb0
29 changed files with 1091 additions and 24 deletions
@@ -557,6 +557,96 @@ describe("Total calculation", function () {
})
})
it("should calculate tax inclusive carts with items + taxes with tax inclusive adjustments", function () {
/**
* TAX INCLUSIVE CART
*
* Total price -> 120 tax inclusive
* Fixed discount -> 10 tax inclusive
* Tax rate -> 20%
*/
const cart = {
items: [
{
unit_price: 60,
quantity: 2,
is_tax_inclusive: true,
adjustments: [
{
amount: 10,
is_tax_inclusive: true,
},
],
tax_lines: [
{
rate: 20,
},
],
},
],
}
const serialized = JSON.parse(JSON.stringify(decorateCartTotals(cart)))
expect(serialized).toEqual({
items: [
{
unit_price: 60,
quantity: 2,
subtotal: 100,
tax_total: 18.333333333333332,
total: 110,
is_tax_inclusive: true,
original_total: 120,
original_tax_total: 20,
discount_subtotal: 8.333333333333334,
discount_tax_total: 1.6666666666666667,
discount_total: 10,
tax_lines: [
{
rate: 20,
total: 18.333333333333332,
subtotal: 20,
},
],
adjustments: [
{
is_tax_inclusive: true,
amount: 10, // <- amount is tax inclusive so it's equal to total
subtotal: 8.333333333333334,
total: 10,
},
],
},
],
subtotal: 100,
tax_total: 18.333333333333332,
total: 110, // total is 120 - 10 tax inclusive discount
original_item_subtotal: 100,
original_item_tax_total: 20,
original_item_total: 120,
original_tax_total: 20,
original_total: 120,
discount_subtotal: 8.333333333333334,
discount_tax_total: 1.6666666666666667,
discount_total: 10,
item_subtotal: 100,
item_tax_total: 18.333333333333332,
item_total: 110,
credit_line_subtotal: 0,
credit_line_tax_total: 0,
credit_line_total: 0,
})
})
it("should calculate carts with items + taxes + adjustments + shipping methods", function () {
const cart = {
items: [
@@ -8,7 +8,7 @@ export function calculateAdjustmentTotal({
includesTax,
taxRate,
}: {
adjustments: Pick<AdjustmentLineDTO, "amount">[]
adjustments: Pick<AdjustmentLineDTO, "amount" | "is_tax_inclusive">[]
includesTax?: boolean
taxRate?: BigNumberInput
}) {
@@ -25,7 +25,15 @@ export function calculateAdjustmentTotal({
}
const adjustmentAmount = MathBN.convert(adj.amount)
adjustmentsSubtotal = MathBN.add(adjustmentsSubtotal, adjustmentAmount)
if (adj.is_tax_inclusive && isDefined(taxRate)) {
adjustmentsSubtotal = MathBN.add(
adjustmentsSubtotal,
MathBN.div(adjustmentAmount, MathBN.add(1, taxRate))
)
} else {
adjustmentsSubtotal = MathBN.add(adjustmentsSubtotal, adjustmentAmount)
}
if (isDefined(taxRate)) {
const adjustmentSubtotal = includesTax
+1 -1
View File
@@ -22,7 +22,7 @@ export interface DecorateCartLikeInputDTO {
unit_price: BigNumberInput
is_tax_inclusive?: boolean
quantity: BigNumberInput
adjustments?: { amount: BigNumberInput }[]
adjustments?: { amount: BigNumberInput; is_tax_inclusive?: boolean }[]
tax_lines?: {
rate: BigNumberInput
}[]