feat(core-flows,types,utils,medusa): Translate tax lines (#14359)

* Include locale field for traslations on tax line workflows

* Translate tax lines in getItemTaxLinesStep with new util

* Update tax calculation context, so that we pass locale to third party tax providers if they want to return translated tax rates

* Apply translations to tax lines on product and variant tax middlewares

* Cart management translations tests

* Update tax lines when order locale gets updated

* Add changeset

* Get tranlsated tax lines step

* Fix wording

* Mutate ref directly

* Update order tax lines translations upon order locale change

* Claims translations tests

* Update tax lines upon draft order locale update

* Exchange tests for tax lines translations

* Order edits test for tax line translation

* Add tests for shipping methods tax line translations on various order flows

* Returns shipping method translations tests

* Execute update in parallel

* Use TranslationFeatureFlag.key

* Fix feature flag import

* Add @medusajs/medusa dependency for feature flag usage

* Revert "Add @medusajs/medusa dependency for feature flag usage"

This reverts commit e8897aed0a88f83c1034ac73e817e4222250a2c9.

* Use feature flag string directly

* Fix test

* Parallelize tax line translations application
This commit is contained in:
Nicolas Gorga
2026-01-13 15:12:42 -03:00
committed by GitHub
parent 28fae96cee
commit cec8b8e428
23 changed files with 2032 additions and 164 deletions

View File

@@ -36,13 +36,16 @@ medusaIntegrationTestRunner({
let returnShippingOption: { id: string }
let outboundShippingOption: { id: string }
let inventoryItem: { id: string }
let taxRate: { id: string; name: string }
beforeAll(async () => {
appContainer = getContainer()
})
beforeEach(async () => {
await setupTaxStructure(appContainer.resolve(Modules.TAX))
const taxStructure = await setupTaxStructure(
appContainer.resolve(Modules.TAX)
)
await createAdminUser(dbConnection, adminHeaders, appContainer)
const publishableKey = await generatePublishableKey(appContainer)
storeHeaders = generateStoreHeaders({ publishableKey })
@@ -255,7 +258,16 @@ medusaIntegrationTestRunner({
)
).data.shipping_option
// Create translations for product, variants, and shipping options
const taxRatesResponse = await api.get(
`/admin/tax-rates?tax_region_id=${taxStructure.us.children.cal.province.id}`,
adminHeaders
)
taxRate = taxRatesResponse.data.tax_rates.find(
(rate: { is_default: boolean; code: string }) =>
rate.is_default && rate.code === "CADEFAULT"
)
// Create translations for product and variants
await api.post(
"/admin/translations/batch",
{
@@ -318,6 +330,22 @@ medusaIntegrationTestRunner({
name: "Test-Versandoption",
},
},
{
reference_id: taxRate.id,
reference: "tax_rate",
locale_code: "fr-FR",
translations: {
name: "Taux par défaut CA",
},
},
{
reference_id: taxRate.id,
reference: "tax_rate",
locale_code: "de-DE",
translations: {
name: "CA Standardsteuersatz",
},
},
],
},
adminHeaders
@@ -521,6 +549,119 @@ medusaIntegrationTestRunner({
)
})
})
describe("Tax line translations", () => {
it("should translate tax line descriptions when order locale is updated", async () => {
// Create order with French locale
const order = await createOrderFromCart("fr-FR")
// Verify tax lines exist and have French translation
expect(order.items[0].tax_lines).toBeDefined()
expect(order.items[0].tax_lines.length).toBe(1)
expect(order.items[0].tax_lines[0]).toEqual(
expect.objectContaining({
description: "Taux par défaut CA",
rate: 5,
code: "CADEFAULT",
})
)
// Update order locale to German
await api.post(
`/admin/orders/${order.id}`,
{ locale: "de-DE" },
adminHeaders
)
// Fetch updated order
const updatedOrder = (
await api.get(`/admin/orders/${order.id}`, adminHeaders)
).data.order
// Verify tax lines are translated to German
expect(updatedOrder.items[0].tax_lines.length).toBe(1)
expect(updatedOrder.items[0].tax_lines[0]).toEqual(
expect.objectContaining({
description: "CA Standardsteuersatz",
rate: 5,
code: "CADEFAULT",
})
)
})
it("should preserve tax line translations when order is created with locale", async () => {
// Create order with French locale
const order = await createOrderFromCart("fr-FR")
// Verify tax lines are translated from the start
expect(order.items[0].tax_lines).toBeDefined()
expect(order.items[0].tax_lines.length).toBeGreaterThan(0)
expect(order.items[0].tax_lines[0]).toEqual(
expect.objectContaining({
description: "Taux par défaut CA",
rate: 5,
code: "CADEFAULT",
})
)
})
it("should use original tax line description when order has no locale", async () => {
// Create order without locale
const order = await createOrderFromCart()
// Verify tax lines use original description
expect(order.items[0].tax_lines).toBeDefined()
expect(order.items[0].tax_lines.length).toBeGreaterThan(0)
expect(order.items[0].tax_lines[0]).toEqual(
expect.objectContaining({
description: "CA Default Rate",
rate: 5,
code: "CADEFAULT",
})
)
})
it("should translate shipping method tax lines when order locale is updated", async () => {
// Create order with French locale
const order = await createOrderFromCart("fr-FR")
// Verify shipping method tax lines exist and are translated
expect(order.shipping_methods).toBeDefined()
expect(order.shipping_methods.length).toBeGreaterThan(0)
if (order.shipping_methods[0].tax_lines?.length > 0) {
expect(order.shipping_methods[0].tax_lines[0]).toEqual(
expect.objectContaining({
description: "Taux par défaut CA",
rate: 5,
code: "CADEFAULT",
})
)
// Update order locale to German
await api.post(
`/admin/orders/${order.id}`,
{ locale: "de-DE" },
adminHeaders
)
// Fetch updated order
const updatedOrder = (
await api.get(`/admin/orders/${order.id}`, adminHeaders)
).data.order
// Verify shipping method tax lines are translated
if (updatedOrder.shipping_methods[0].tax_lines?.length > 0) {
expect(updatedOrder.shipping_methods[0].tax_lines[0]).toEqual(
expect.objectContaining({
description: "CA Standardsteuersatz",
rate: 5,
code: "CADEFAULT",
})
)
}
}
})
})
})
},
})