[Bug]: Product import cannot read back the region price columns that product export writes
Package.json file
{
"dependencies": {
"@medusajs/framework": "2.21.0",
"@medusajs/medusa": "2.21.0"
}
}Reproduced on develop at da9be14fbb (@medusajs/utils 2.21.0); the code path is the same in the published 2.21.0.
Node.js version
v24.2.0
Database and its version
Not needed for the reproduction below: it runs the import normalizer directly. (The end-to-end import was not run against a database.)
Operating system name and version
macOS 15 (arm64)
Browser name
No response
What happended?
A product export writes a region-scoped price as a column named Variant Price <Region Name> [<CURRENCY>]. integration-tests/http/__tests__/product/admin/product-export.spec.ts:732 asserts exactly that column: "Variant Price Test Region [USD]": 45.
The product import cannot read that column back. Both current import workflows (importProductsWorkflow through normalizeCsvStep, and importProductsAsChunksWorkflow through normalizeCsvToChunksStep) use CSVNormalizer. Its variant price processor keeps only the last space-separated word of the column name as the currency (packages/core/utils/src/product/csv-normalizer.ts:49-65, used at :324). It also drops the region that parseVariantPriceColumn extracts. So:
Variant Price Test Region [USD]becomes a price withcurrency_code: "[usd]"and no region rule;Variant Price [Europe] EUR, the format that the error message in the same function gives as its example, becomes a plaineurprice. The region is silently dropped, so a region price is imported as a store-wide price.
The older path in packages/core/core-flows/src/product/helpers/normalize-for-import.ts:312-338 did handle the export's format. It looked the region up by name, set currency_code from the region and added rules: { region_id }. The CSVNormalizer path has no equivalent, so an export followed by an import no longer round-trips region prices.
Reproduction (no project needed):
// node repro.js, with @medusajs/utils 2.21.0 resolvable
const { CSVNormalizer } = require("@medusajs/utils")
const row = {
"Product Handle": "t-shirt",
"Product Title": "T-Shirt",
"Variant Title": "S",
"Variant Price USD": 40,
"Variant Price Test Region [USD]": 45, // what product export writes
"Variant Price [Europe] EUR": 30, // the format the import error message suggests
}
const normalizer = new CSVNormalizer([CSVNormalizer.preProcess(row, 1)])
const { toCreate } = normalizer.proccess()
console.log(JSON.stringify(toCreate["t-shirt"].variants[0].prices, null, 2))Output:
[
{ "currency_code": "usd", "amount": 40 },
{ "currency_code": "[usd]", "amount": 45 },
{ "currency_code": "eur", "amount": 30 }
]Expected behavior
A column the export writes can be imported again. Variant Price Test Region [USD] should become a USD price with a region_id rule for the region named "Test Region", as the older normalizer did. A region name that does not exist should be refused with an error, not stored.
Actual behavior
The export's region price column is imported as a price with the currency code [usd] and no region rule. With the format from the error message, the region is dropped and the price is imported as a store-wide price in that currency. Neither case raises an error.
Link to reproduction repo
Self-contained reproduction above; it needs only @medusajs/utils.
If you agree on the expected behaviour, I would like to send a fix. parseVariantPriceColumn would accept the export's <Region Name> [<CURRENCY>] shape, and the region would be resolved the way normalize-for-import.ts resolves it, with tests for both import workflows. One question first: should Variant Price [Region] CUR, the shape the error message names, keep working as a second accepted spelling, or should the message change to the export's shape?
Source: medusajs/medusa