-
-
Notifications
You must be signed in to change notification settings - Fork 3.9k
Description
Package.json file
{
"name": "medusa",
"version": "0.0.1",
"description": "A starter for Medusa projects.",
"author": "Medusa (https://medusajs.com)",
"license": "MIT",
"keywords": [
"sqlite",
"postgres",
"typescript",
"ecommerce",
"headless",
"medusa"
],
"scripts": {
"seed": "medusa exec ./src/scripts/seed.ts",
"start": "medusa start",
"dev": "medusa develop",
"predeploy": "npx medusa db:migrate",
"build": "medusa build",
},
"dependencies": {
"@medusajs/admin-sdk": "2.9.0",
"@medusajs/cli": "2.9.0",
"@medusajs/dashboard": "2.9.0",
"@medusajs/framework": "2.9.0",
"@medusajs/medusa": "2.9.0",
"@mikro-orm/core": "6.4.3",
"@mikro-orm/knex": "6.4.3",
"@mikro-orm/migrations": "6.4.3",
"@mikro-orm/postgresql": "6.4.3",
"awilix": "^8.0.1",
"date-fns-tz": "^3.2.0",
"module-alias": "^2.2.3",
"multer": "^1.4.5-lts.2",
"pdfmake": "^0.2.20",
"pg": "^8.13.0",
"react-pdf": "^10.1.0",
"xlsx": "^0.18.5"
},
"devDependencies": {
"@medusajs/test-utils": "2.9.0",
"@mikro-orm/cli": "6.4.3",
"@swc/core": "1.5.7",
"@swc/jest": "^0.2.36",
"@types/jest": "^29.5.13",
"@types/multer": "^1",
"@types/node": "^20.0.0",
"@types/pdfmake": "^0.2.11",
"@types/react": "^18.3.2",
"@types/react-dom": "^18.2.25",
"jest": "^29.7.0",
"prop-types": "^15.8.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"rimraf": "^6.0.1",
"ts-node": "^10.9.2",
"tsc-alias": "^1.8.13",
"typescript": "^5.6.2",
"vite": "^5.2.11",
"yalc": "^1.0.0-pre.53"
},
"engines": {
"node": ">=20"
},
"packageManager": "[email protected]",
}
{
"name": "medusa",
"version": "0.0.1",
"description": "A starter for Medusa projects.",
"author": "Medusa (https://medusajs.com)",
"license": "MIT",
"keywords": [
"sqlite",
"postgres",
"typescript",
"ecommerce",
"headless",
"medusa"
],
"scripts": {
"seed": "medusa exec ./src/scripts/seed.ts",
"start": "medusa start",
"dev": "medusa develop",
"predeploy": "npx medusa db:migrate",
"build": "medusa build",
},
"dependencies": {
"@medusajs/admin-sdk": "2.9.0",
"@medusajs/cli": "2.9.0",
"@medusajs/dashboard": "2.9.0",
"@medusajs/framework": "2.9.0",
"@medusajs/medusa": "2.9.0",
"@mikro-orm/core": "6.4.3",
"@mikro-orm/knex": "6.4.3",
"@mikro-orm/migrations": "6.4.3",
"@mikro-orm/postgresql": "6.4.3",
"awilix": "^8.0.1",
"date-fns-tz": "^3.2.0",
"module-alias": "^2.2.3",
"multer": "^1.4.5-lts.2",
"pdfmake": "^0.2.20",
"pg": "^8.13.0",
"react-pdf": "^10.1.0",
"xlsx": "^0.18.5"
},
"devDependencies": {
"@medusajs/test-utils": "2.9.0",
"@mikro-orm/cli": "6.4.3",
"@swc/core": "1.5.7",
"@swc/jest": "^0.2.36",
"@types/jest": "^29.5.13",
"@types/multer": "^1",
"@types/node": "^20.0.0",
"@types/pdfmake": "^0.2.11",
"@types/react": "^18.3.2",
"@types/react-dom": "^18.2.25",
"jest": "^29.7.0",
"prop-types": "^15.8.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"rimraf": "^6.0.1",
"ts-node": "^10.9.2",
"tsc-alias": "^1.8.13",
"typescript": "^5.6.2",
"vite": "^5.2.11",
"yalc": "^1.0.0-pre.53"
},
"engines": {
"node": ">=20"
},
"packageManager": "[email protected]",
}Node.js version
v20.10.0
Database and its version
Postgres 17
Operating system name and version
MacOs
Browser name
Brave
What happended?
When an item is configured with tax-inclusive pricing, the item totals are calculated correctly — but the refundable totals incorrectly include tax. This results in inflated refundable amounts.
Example
Item data:
{
"is_discountable": false,
"is_tax_inclusive": true,
"is_custom_price": true,
"unit_price": 0.5,
"quantity": 3,
"subtotal": 1.4285714285714286,
"total": 1.5,
"original_total": 1.5,
"discount_total": 0,
"discount_subtotal": 0,
"discount_tax_total": 0,
"tax_total": 0.07142857142857142,
"original_tax_total": 0.07142857142857142,
"refundable_total_per_unit": 0.525,
"refundable_total": 1.575
}In this scenario, the refundable_total should exclude tax when tax is already baked into the price, otherwise refunds return more than the customer actually paid pre-tax.
Code causing issue
The current implementation recalculates tax based on the refundable subtotal:
const refundableSubTotal = MathBN.sub(
MathBN.mult(currentQuantity, item.unit_price),
MathBN.mult(currentQuantity, discountPerUnit)
)
const taxTotal = calculateTaxTotal({
taxLines: item.tax_lines || [],
taxableAmount: refundableSubTotal,
})
const refundableTotal = MathBN.add(refundableSubTotal, taxTotal)This logic assumes the item price is tax-exclusive, which is wrong when is_tax_inclusive is true.
Impact
Refund processes can credit higher amounts than what customers paid, leading to accounting discrepancies.
Expected behavior
When is_tax_inclusive = true:
- Do not add tax back into refundable totals
- Refundable subtotal already includes tax → tax shouldn’t be re-applied
Proposed Fix
Before calculating refundable tax, check is_tax_inclusive:
- If
true→ use unit_price as final price (no added tax) - If
false→ retain existing logic
Actual behavior
Actual Behavior
For a tax-inclusive item:
{
"unit_price": 0.5,
"quantity": 3,
"is_tax_inclusive": true,
"subtotal": 1.4285714285714286,
"total": 1.5,
"tax_total": 0.07142857142857142
}
The item totals are correctly calculated from a tax-inclusive price:
0.50 × 3 = 1.50 (total)
1.50 / 1.05 = 1.428571... (subtotal)
Tax = 1.50 − 1.428571... = 0.071428...
However, the refundable calculation incorrectly re-adds tax:
refundable_subtotal = 3 × 0.50 = 1.50 (already includes tax)
tax_total = 1.50 × 5% = 0.071428...
refundable_total = 1.50 + 0.071428... = 1.571428... (recorded as 1.575)
refundable_total_per_unit = 1.575 / 3 = 0.525
This results in:
| Field | Value |
|---|---|
| refundable_total | 1.575 |
| refundable_total_per_unit | 0.525 |
Refunds end up higher than the paid price, because tax is refunded twice.
Link to reproduction repo
N/A