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:
@@ -31,6 +31,8 @@ medusaIntegrationTestRunner({
|
||||
let product: { id: string; variants: { id: string; title: string }[] }
|
||||
let salesChannel: { id: string }
|
||||
let shippingProfile: { id: string }
|
||||
let taxRegion: { id: string }
|
||||
let taxRate: { id: string; name: string }
|
||||
|
||||
beforeAll(async () => {
|
||||
appContainer = getContainer()
|
||||
@@ -85,6 +87,59 @@ medusaIntegrationTestRunner({
|
||||
)
|
||||
).data.region
|
||||
|
||||
// Create tax region and tax rate for tax line translations
|
||||
taxRegion = (
|
||||
await api.post(
|
||||
"/admin/tax-regions",
|
||||
{
|
||||
country_code: "us",
|
||||
provider_id: "tp_system",
|
||||
},
|
||||
adminHeaders
|
||||
)
|
||||
).data.tax_region
|
||||
|
||||
// Create the default tax rate
|
||||
taxRate = (
|
||||
await api.post(
|
||||
"/admin/tax-rates",
|
||||
{
|
||||
tax_region_id: taxRegion.id,
|
||||
name: "US Sales Tax",
|
||||
rate: 5,
|
||||
code: "US_SALES_TAX",
|
||||
is_default: true,
|
||||
},
|
||||
adminHeaders
|
||||
)
|
||||
).data.tax_rate
|
||||
|
||||
// Create translations for tax rate name
|
||||
await api.post(
|
||||
"/admin/translations/batch",
|
||||
{
|
||||
create: [
|
||||
{
|
||||
reference_id: taxRate.id,
|
||||
reference: "tax_rate",
|
||||
locale_code: "fr-FR",
|
||||
translations: {
|
||||
name: "Taxe de vente US",
|
||||
},
|
||||
},
|
||||
{
|
||||
reference_id: taxRate.id,
|
||||
reference: "tax_rate",
|
||||
locale_code: "de-DE",
|
||||
translations: {
|
||||
name: "US Umsatzsteuer",
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
adminHeaders
|
||||
)
|
||||
|
||||
// Create product with description for translation
|
||||
product = (
|
||||
await api.post(
|
||||
@@ -516,6 +571,255 @@ medusaIntegrationTestRunner({
|
||||
})
|
||||
})
|
||||
|
||||
describe("Tax line translations", () => {
|
||||
it("should translate tax line descriptions when creating a cart with locale", async () => {
|
||||
const response = await api.post(
|
||||
`/store/carts`,
|
||||
{
|
||||
currency_code: "usd",
|
||||
sales_channel_id: salesChannel.id,
|
||||
region_id: region.id,
|
||||
locale: "fr-FR",
|
||||
shipping_address: shippingAddressData,
|
||||
items: [{ variant_id: product.variants[0].id, quantity: 1 }],
|
||||
},
|
||||
storeHeaders
|
||||
)
|
||||
|
||||
expect(response.status).toEqual(200)
|
||||
expect(response.data.cart.items[0]).toEqual(
|
||||
expect.objectContaining({
|
||||
tax_lines: expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
description: "Taxe de vente US",
|
||||
rate: 5,
|
||||
}),
|
||||
]),
|
||||
})
|
||||
)
|
||||
})
|
||||
|
||||
it("should use original tax line description when no locale is provided", async () => {
|
||||
const response = await api.post(
|
||||
`/store/carts`,
|
||||
{
|
||||
currency_code: "usd",
|
||||
sales_channel_id: salesChannel.id,
|
||||
region_id: region.id,
|
||||
shipping_address: shippingAddressData,
|
||||
items: [{ variant_id: product.variants[0].id, quantity: 1 }],
|
||||
},
|
||||
storeHeaders
|
||||
)
|
||||
|
||||
expect(response.status).toEqual(200)
|
||||
expect(response.data.cart.items[0]).toEqual(
|
||||
expect.objectContaining({
|
||||
tax_lines: expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
description: "US Sales Tax",
|
||||
rate: 5,
|
||||
}),
|
||||
]),
|
||||
})
|
||||
)
|
||||
})
|
||||
|
||||
it("should translate tax line descriptions when adding items to cart with locale", async () => {
|
||||
const cartResponse = await api.post(
|
||||
`/store/carts`,
|
||||
{
|
||||
currency_code: "usd",
|
||||
sales_channel_id: salesChannel.id,
|
||||
region_id: region.id,
|
||||
locale: "de-DE",
|
||||
shipping_address: shippingAddressData,
|
||||
},
|
||||
storeHeaders
|
||||
)
|
||||
|
||||
const cart = cartResponse.data.cart
|
||||
|
||||
const addItemResponse = await api.post(
|
||||
`/store/carts/${cart.id}/line-items`,
|
||||
{
|
||||
variant_id: product.variants[0].id,
|
||||
quantity: 1,
|
||||
},
|
||||
storeHeaders
|
||||
)
|
||||
|
||||
expect(addItemResponse.status).toEqual(200)
|
||||
expect(addItemResponse.data.cart.items[0]).toEqual(
|
||||
expect.objectContaining({
|
||||
tax_lines: expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
description: "US Umsatzsteuer",
|
||||
rate: 5,
|
||||
}),
|
||||
]),
|
||||
})
|
||||
)
|
||||
})
|
||||
|
||||
it("should re-translate tax line descriptions when cart locale is updated", async () => {
|
||||
const cartResponse = await api.post(
|
||||
`/store/carts`,
|
||||
{
|
||||
currency_code: "usd",
|
||||
sales_channel_id: salesChannel.id,
|
||||
region_id: region.id,
|
||||
locale: "fr-FR",
|
||||
shipping_address: shippingAddressData,
|
||||
items: [{ variant_id: product.variants[0].id, quantity: 1 }],
|
||||
},
|
||||
storeHeaders
|
||||
)
|
||||
|
||||
const cart = cartResponse.data.cart
|
||||
|
||||
// Verify French translation
|
||||
expect(cart.items[0].tax_lines[0].description).toEqual(
|
||||
"Taxe de vente US"
|
||||
)
|
||||
|
||||
// Update locale to German
|
||||
const updateResponse = await api.post(
|
||||
`/store/carts/${cart.id}`,
|
||||
{
|
||||
locale: "de-DE",
|
||||
},
|
||||
storeHeaders
|
||||
)
|
||||
|
||||
expect(updateResponse.status).toEqual(200)
|
||||
|
||||
// Fetch updated cart
|
||||
const updatedCartResponse = await api.get(
|
||||
`/store/carts/${cart.id}`,
|
||||
storeHeaders
|
||||
)
|
||||
|
||||
const updatedCart = updatedCartResponse.data.cart
|
||||
|
||||
// Verify German translation
|
||||
expect(updatedCart.items[0]).toEqual(
|
||||
expect.objectContaining({
|
||||
tax_lines: expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
description: "US Umsatzsteuer",
|
||||
rate: 5,
|
||||
}),
|
||||
]),
|
||||
})
|
||||
)
|
||||
})
|
||||
|
||||
it("should revert to original tax line description when locale has no translation", async () => {
|
||||
const cartResponse = await api.post(
|
||||
`/store/carts`,
|
||||
{
|
||||
currency_code: "usd",
|
||||
sales_channel_id: salesChannel.id,
|
||||
region_id: region.id,
|
||||
locale: "fr-FR",
|
||||
shipping_address: shippingAddressData,
|
||||
items: [{ variant_id: product.variants[0].id, quantity: 1 }],
|
||||
},
|
||||
storeHeaders
|
||||
)
|
||||
|
||||
const cart = cartResponse.data.cart
|
||||
|
||||
// Verify French translation exists
|
||||
expect(cart.items[0].tax_lines[0].description).toEqual(
|
||||
"Taxe de vente US"
|
||||
)
|
||||
|
||||
// Update to locale without translation
|
||||
const updateResponse = await api.post(
|
||||
`/store/carts/${cart.id}`,
|
||||
{
|
||||
locale: "ja-JP",
|
||||
},
|
||||
storeHeaders
|
||||
)
|
||||
|
||||
expect(updateResponse.status).toEqual(200)
|
||||
|
||||
// Fetch updated cart
|
||||
const updatedCartResponse = await api.get(
|
||||
`/store/carts/${cart.id}`,
|
||||
storeHeaders
|
||||
)
|
||||
|
||||
const updatedCart = updatedCartResponse.data.cart
|
||||
|
||||
// Should revert to original description
|
||||
expect(updatedCart.items[0]).toEqual(
|
||||
expect.objectContaining({
|
||||
tax_lines: expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
description: "US Sales Tax",
|
||||
rate: 5,
|
||||
}),
|
||||
]),
|
||||
})
|
||||
)
|
||||
})
|
||||
|
||||
it("should translate tax lines for all items when multiple items are added", async () => {
|
||||
const cartResponse = await api.post(
|
||||
`/store/carts`,
|
||||
{
|
||||
currency_code: "usd",
|
||||
sales_channel_id: salesChannel.id,
|
||||
region_id: region.id,
|
||||
locale: "fr-FR",
|
||||
shipping_address: shippingAddressData,
|
||||
},
|
||||
storeHeaders
|
||||
)
|
||||
|
||||
const cart = cartResponse.data.cart
|
||||
|
||||
// Add first item
|
||||
await api.post(
|
||||
`/store/carts/${cart.id}/line-items`,
|
||||
{
|
||||
variant_id: product.variants[0].id,
|
||||
quantity: 1,
|
||||
},
|
||||
storeHeaders
|
||||
)
|
||||
|
||||
// Add second item
|
||||
const response = await api.post(
|
||||
`/store/carts/${cart.id}/line-items`,
|
||||
{
|
||||
variant_id: product.variants[1].id,
|
||||
quantity: 1,
|
||||
},
|
||||
storeHeaders
|
||||
)
|
||||
|
||||
expect(response.status).toEqual(200)
|
||||
expect(response.data.cart.items).toHaveLength(2)
|
||||
|
||||
// Both items should have translated tax lines
|
||||
response.data.cart.items.forEach((item: any) => {
|
||||
expect(item.tax_lines).toEqual(
|
||||
expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
description: "Taxe de vente US",
|
||||
rate: 5,
|
||||
}),
|
||||
])
|
||||
)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe("POST /store/carts/:id/shipping-methods (shipping method translation)", () => {
|
||||
let shippingOption
|
||||
|
||||
|
||||
Reference in New Issue
Block a user