www/apps/resources/app/commerce-modules/promotion/promotion-taxes/page.mdx
export const metadata = {
title: Tax-Inclusive Promotions,
}
In this guide, you’ll learn how taxes are applied to promotions in a cart.
<Note>This feature is available from Medusa v2.8.5.
</Note>By default, promotions are tax-exclusive, meaning that the discount amount is applied as-is to the cart before taxes are calculated and applied to the cart total.
A tax-inclusive promotion is a promotion for which taxes are calculated from the discount amount entered by the merchant.
When a promotion is tax-inclusive, the discount amount is reduced by the calculated tax amount based on the tax region's rate. The reduced discount amount is then applied to the cart total.
<Note>Tax-inclusiveness doesn't apply to Buy X Get Y promotions.
</Note>Tax-inclusive promotions are most useful when using tax-inclusive prices for items in the cart.
In this scenario, Medusa applies taxes consistently across the cart, ensuring that the total price reflects the taxes and promotions correctly.
You can see this in action in the examples below.
The Promotion data model has an is_tax_inclusive property that determines whether the promotion is tax-inclusive.
If is_tax_inclusive is disabled (which is the default), the promotion's discount amount will be applied as-is to the cart, before taxes are calculated. See an example in the Tax-Exclusive Promotion Example section.
If is_tax_inclusive is enabled, the promotion's discount amount will first be reduced by the calculated tax amount (based on the tax region's rate). The reduced discount amount is then applied to the cart total. See an example in the Tax-Inclusive Promotion Example section.
You can enable tax-inclusiveness for a promotion when creating it in the Medusa Admin.
</Note>You can set the is_tax_inclusive property when creating a promotion by using either the Promotion workflows or the Promotion Module's service.
For most use cases, it's recommended to use workflows instead of directly using the module's service, as they implement the necessary rollback mechanisms in case of errors.
</Note>For example, if you're creating a promotion with the createPromotionsWorkflow in an API route:
import type {
MedusaRequest,
MedusaResponse,
} from "@medusajs/framework/http"
import { createPromotionsWorkflow } from "@medusajs/medusa/core-flows"
export async function POST(
req: MedusaRequest,
res: MedusaResponse
) {
const { result } = await createPromotionsWorkflow(req.scope)
.run({
input: {
promotionsData: [{
code: "10OFF",
// ...
is_tax_inclusive: true,
}],
},
})
res.send(result)
}
In the above example, you set the is_tax_inclusive property to true when creating the promotion, making it tax-inclusive.
A promotion's tax-inclusiveness cannot be updated after it has been created. If you need to change a promotion's tax-inclusiveness, you must delete the existing promotion and create a new one with the desired is_tax_inclusive value.
The following sections provide examples of how tax-inclusive promotions work in different scenarios, including both tax-exclusive and tax-inclusive promotions.
These examples will help you understand how tax-inclusive promotions affect the cart total, allowing you to decide when to use them effectively.
Consider the following scenario:
$10 discount on the cart's total.25% tax rate.$100.The result:
$10 discount to cart total: $100 - $10 = $90$90 x 25% = $22.50$90 + $22.50 = $112.50Consider the following scenario:
$10 discount on the cart's total.25% tax rate.$100.The result:
$10 ÷ 1.25 = $8$100 - $8 = $92$92 x 25% = $23$92 + $23 = $115Consider the following scenario:
$10 discount on the cart's total.25% tax rate.$100.The result:
$10 ÷ 1.25 = $8$100 ÷ 1.25 = $80$80 - $8 = $72$72 x 1.25 = $90The final total is $90, which correctly applies both the tax-inclusive promotion and tax-inclusive pricing.