Skip to content

Commit 67499a8

Browse files
authored
fix(currency,payment,pricing,region,order,store,cart,core-flows,medusa,utils): repo wide currency_code normalization (#13975)
* Unified utility normalizeCurrencyCode function * Use new utility function to replace current isolated currency code normalization * Update arg type * Add missing currency code normalization in pricing module * New util function tests * Update previous pricing module tests to include lowercased currency codes * Add changeset * Update arg type and throw if something else is provided * Migration script v1 * Include in transaction for compensation * Remove unnecessary workflow, execute knex directly inside script * Review fixes * Add missing currency_code normalization to modules * Avoid overriding currency_code when not provided * Update tests * Updated changeset * Update script to normalize all potentially affected tables * Keep one changeset * Update tests * Update test * Migration to normalize prices ingested by index module
1 parent 905440a commit 67499a8

File tree

23 files changed

+370
-221
lines changed

23 files changed

+370
-221
lines changed

.changeset/free-rings-happen.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
---
2+
"@medusajs/currency": patch
3+
"@medusajs/core-flows": patch
4+
"@medusajs/payment": patch
5+
"@medusajs/pricing": patch
6+
"@medusajs/region": patch
7+
"@medusajs/order": patch
8+
"@medusajs/store": patch
9+
"@medusajs/cart": patch
10+
"@medusajs/utils": patch
11+
"@medusajs/medusa": patch
12+
---
13+
14+
fix(currency,payment,pricing,region,order,store,cart,core-flows,medusa,utils): repo wide currency_code normalization

integration-tests/modules/__tests__/index/query-index.spec.ts

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -270,12 +270,12 @@ medusaIntegrationTestRunner({
270270
],
271271
prices: expect.arrayContaining([
272272
{
273-
currency_code: "CAD",
273+
currency_code: "cad",
274274
amount: 20,
275275
id: expect.any(String),
276276
},
277277
{
278-
currency_code: "USD",
278+
currency_code: "usd",
279279
amount: 80,
280280
id: expect.any(String),
281281
},
@@ -294,12 +294,12 @@ medusaIntegrationTestRunner({
294294
prices: expect.arrayContaining([
295295
{
296296
amount: 20,
297-
currency_code: "CAD",
297+
currency_code: "cad",
298298
id: expect.any(String),
299299
},
300300
{
301301
amount: 80,
302-
currency_code: "USD",
302+
currency_code: "usd",
303303
id: expect.any(String),
304304
},
305305
]),
@@ -337,12 +337,12 @@ medusaIntegrationTestRunner({
337337
prices: expect.arrayContaining([
338338
{
339339
amount: 30,
340-
currency_code: "USD",
340+
currency_code: "usd",
341341
id: expect.any(String),
342342
},
343343
{
344344
amount: 50,
345-
currency_code: "EUR",
345+
currency_code: "eur",
346346
id: expect.any(String),
347347
},
348348
]),
@@ -400,7 +400,7 @@ medusaIntegrationTestRunner({
400400
"variants.prices.currency_code",
401401
],
402402
filters: {
403-
"variants.prices.currency_code": "USD",
403+
"variants.prices.currency_code": "usd",
404404
},
405405
pagination: {
406406
take: 1,
@@ -422,12 +422,12 @@ medusaIntegrationTestRunner({
422422
prices: expect.arrayContaining([
423423
{
424424
amount: 20,
425-
currency_code: "CAD",
425+
currency_code: "cad",
426426
id: expect.any(String),
427427
},
428428
{
429429
amount: 80,
430-
currency_code: "USD",
430+
currency_code: "usd",
431431
id: expect.any(String),
432432
},
433433
]),
@@ -448,7 +448,7 @@ medusaIntegrationTestRunner({
448448
filters: {
449449
variants: {
450450
prices: {
451-
currency_code: "USD",
451+
currency_code: "usd",
452452
},
453453
},
454454
},
@@ -476,12 +476,12 @@ medusaIntegrationTestRunner({
476476
prices: expect.arrayContaining([
477477
{
478478
amount: 30,
479-
currency_code: "USD",
479+
currency_code: "usd",
480480
id: expect.any(String),
481481
},
482482
{
483483
amount: 50,
484-
currency_code: "EUR",
484+
currency_code: "eur",
485485
id: expect.any(String),
486486
},
487487
]),

integration-tests/modules/__tests__/index/search.spec.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ medusaIntegrationTestRunner({
150150
variants: {
151151
prices: {
152152
amount: { $gt: 50 },
153-
currency_code: { $eq: "AUD" },
153+
currency_code: { $eq: "aud" },
154154
},
155155
},
156156
},
@@ -179,7 +179,7 @@ medusaIntegrationTestRunner({
179179
for (const variant of variants) {
180180
expect(variant.prices.length).toBe(1)
181181
expect(variant.prices[0].amount).toBeGreaterThan(50)
182-
expect(variant.prices[0].currency_code).toBe("AUD")
182+
expect(variant.prices[0].currency_code).toBe("aud")
183183
}
184184
})
185185

packages/core/core-flows/src/product/helpers/normalize-for-import.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import type { ProductTypes } from "@medusajs/framework/types"
22
import type { HttpTypes, RegionTypes } from "@medusajs/framework/types"
3-
import { MedusaError, lowerCaseFirst } from "@medusajs/framework/utils"
3+
import { MedusaError, lowerCaseFirst, normalizeCurrencyCode } from "@medusajs/framework/utils"
44

55
// We want to convert the csv data format to a standard DTO format.
66
export const normalizeForImport = (
@@ -183,7 +183,7 @@ const normalizeVariantForImport = (
183183
if (!priceKey.endsWith("]")) {
184184
response["prices"] = [
185185
...(response["prices"] || []),
186-
{ currency_code: priceKey.toLowerCase(), amount: normalizedValue },
186+
{ currency_code: normalizeCurrencyCode(priceKey), amount: normalizedValue },
187187
]
188188
} else {
189189
const regionName = priceKey.split("_").slice(0, -1).join(" ")
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import { normalizeCurrencyCode } from "../normalize-currency-code"
2+
3+
describe("normalizeCurrencyCode", () => {
4+
it("returns lowercased currency code", () => {
5+
const uppercased = "USD"
6+
const result = normalizeCurrencyCode(uppercased)
7+
8+
expect(result).toEqual("usd")
9+
})
10+
11+
it("throws when value is not a string", () => {
12+
const errorMessage = "Currency code needs to be a string"
13+
14+
expect(() => {
15+
normalizeCurrencyCode(1 as unknown as string)
16+
}).toThrow(errorMessage)
17+
expect(() => {
18+
normalizeCurrencyCode(undefined as unknown as string)
19+
}).toThrow(errorMessage)
20+
})
21+
})

packages/core/utils/src/common/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ export * from "./medusa-container"
5353
export * from "./merge-metadata"
5454
export * from "./merge-plugin-modules"
5555
export * from "./normalize-csv-value"
56+
export * from "./normalize-currency-code"
5657
export * from "./normalize-import-path-with-source"
5758
export * from "./normalize-locale"
5859
export * from "./object-from-string-path"
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import { MedusaError, MedusaErrorTypes } from "./errors"
2+
import { isString } from "./is-string"
3+
4+
/**
5+
* Normalizes `currencyCode` by transforming it to lowercase
6+
*/
7+
export function normalizeCurrencyCode(currencyCode: string) {
8+
if (!isString(currencyCode)) {
9+
throw new MedusaError(MedusaErrorTypes.INVALID_ARGUMENT, "Currency code needs to be a string")
10+
}
11+
12+
return currencyCode.toLowerCase()
13+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import { ContainerRegistrationKeys } from "@medusajs/framework/utils"
2+
import { ExecArgs } from "@medusajs/types"
3+
4+
export default async function migrateNormalizeCurrencyCodes({
5+
container,
6+
}: ExecArgs) {
7+
const knex = container.resolve(ContainerRegistrationKeys.PG_CONNECTION)
8+
9+
await knex.transaction(async (trx) => {
10+
const tables = [
11+
"cart",
12+
"payment_collection",
13+
"payment_session",
14+
"payment",
15+
"order",
16+
"order_transaction",
17+
"price",
18+
"region",
19+
"store_currency",
20+
]
21+
22+
for (const table of tables) {
23+
await trx(table)
24+
.whereNotNull("currency_code")
25+
.update({
26+
currency_code: knex.raw("LOWER(currency_code)"),
27+
})
28+
}
29+
30+
await trx.raw(`
31+
UPDATE index_data
32+
SET data = jsonb_set(data, '{currency_code}', to_jsonb(LOWER(data->>'currency_code')))
33+
WHERE name = 'Price'
34+
AND data->>'currency_code' IS NOT NULL
35+
AND data->>'currency_code' <> LOWER(data->>'currency_code')
36+
`)
37+
})
38+
}

packages/modules/cart/src/services/cart-module.ts

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import {
2323
MedusaError,
2424
ModulesSdkUtils,
2525
promiseAll,
26+
normalizeCurrencyCode,
2627
} from "@medusajs/framework/utils"
2728
import {
2829
Address,
@@ -297,7 +298,13 @@ export default class CartModuleService
297298
const cartsWithItems = data.map(({ items, ...cart }) => {
298299
const cartId = generateEntityId((cart as any).id, "cart")
299300
return {
300-
cart: { ...cart, id: cartId },
301+
cart: {
302+
...cart,
303+
currency_code: cart.currency_code
304+
? normalizeCurrencyCode(cart.currency_code)
305+
: cart.currency_code,
306+
id: cartId,
307+
},
301308
items: items || [],
302309
}
303310
})
@@ -395,10 +402,18 @@ export default class CartModuleService
395402
{
396403
id: dataOrIdOrSelector,
397404
...data,
405+
...(data?.currency_code
406+
? { currency_code: normalizeCurrencyCode(data.currency_code) }
407+
: {}),
398408
},
399409
]
400410
} else if (Array.isArray(dataOrIdOrSelector)) {
401-
toUpdate = dataOrIdOrSelector
411+
toUpdate = dataOrIdOrSelector.map((d) => ({
412+
...d,
413+
...(d.currency_code
414+
? { currency_code: normalizeCurrencyCode(d.currency_code) }
415+
: {}),
416+
}))
402417
} else {
403418
const carts = await this.cartService_.list(
404419
{ ...dataOrIdOrSelector },
@@ -410,6 +425,9 @@ export default class CartModuleService
410425
return {
411426
...data,
412427
id: cart.id,
428+
...(data?.currency_code
429+
? { currency_code: normalizeCurrencyCode(data.currency_code) }
430+
: {}),
413431
}
414432
})
415433
}

packages/modules/currency/src/services/currency-module-service.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import {
1010
ModulesSdkTypes,
1111
} from "@medusajs/framework/types"
1212

13-
import { MedusaService } from "@medusajs/framework/utils"
13+
import { MedusaService, normalizeCurrencyCode } from "@medusajs/framework/utils"
1414
import { Currency } from "@models"
1515

1616
type InjectedDependencies = {
@@ -86,7 +86,7 @@ export default class CurrencyModuleService
8686
FilterableCurrencyProps
8787
>(filters, (fieldName, value) => {
8888
if (fieldName === "code" && !!value) {
89-
return value.toLowerCase()
89+
return normalizeCurrencyCode(value)
9090
}
9191

9292
return value

0 commit comments

Comments
 (0)