feat(medusa): PriceList import strategy (#2210)

This commit is contained in:
Sebastian Rindom
2022-09-28 15:30:15 +02:00
committed by GitHub
parent 884f36e8a8
commit 7dc8d3a0c9
17 changed files with 1129 additions and 21 deletions

View File

@@ -0,0 +1,290 @@
const fs = require("fs")
const path = require("path")
const setupServer = require("../../../../helpers/setup-server")
const { useApi } = require("../../../../helpers/use-api")
const { initDb, useDb } = require("../../../../helpers/use-db")
const adminSeeder = require("../../../helpers/admin-seeder")
const {
simpleRegionFactory,
simplePriceListFactory,
simpleProductFactory,
} = require("../../../factories")
const adminReqConfig = {
headers: {
Authorization: "Bearer test_token",
},
}
jest.setTimeout(1000000)
function cleanTempData() {
// cleanup tmp ops files
const opsFiles = path.resolve(
"__tests__",
"batch-jobs",
"price-list",
"imports"
)
fs.rmSync(opsFiles, { recursive: true, force: true })
}
function getImportFile() {
return path.resolve(
"__tests__",
"batch-jobs",
"price-list",
"price-list-import.csv"
)
}
function copyTemplateFile() {
const csvTemplate = path.resolve(
"__tests__",
"batch-jobs",
"price-list",
"price-list-import-template.csv"
)
const destination = getImportFile()
fs.copyFileSync(csvTemplate, destination)
}
describe("Price list import batch job", () => {
let medusaProcess
let dbConnection
beforeAll(async () => {
const cwd = path.resolve(path.join(__dirname, "..", "..", ".."))
dbConnection = await initDb({ cwd })
cleanTempData() // cleanup if previous process didn't manage to do it
medusaProcess = await setupServer({
cwd,
redisUrl: "redis://127.0.0.1:6379",
uploadDir: __dirname,
verbose: false,
})
})
afterAll(async () => {
const db = useDb()
await db.shutdown()
cleanTempData()
medusaProcess.kill()
})
beforeEach(async () => {
await adminSeeder(dbConnection)
})
afterEach(async () => {
const db = useDb()
await db.teardown()
})
it("should import a csv file", async () => {
jest.setTimeout(1000000)
const api = useApi()
copyTemplateFile()
const product = await simpleProductFactory(dbConnection, {
variants: [
{
id: "test-pl-variant",
},
{
id: "test-pl-sku-variant",
sku: "pl-sku",
},
],
})
await simpleRegionFactory(dbConnection, {
id: "test-pl-region",
name: "PL Region",
currency_code: "eur",
})
const priceList = await simplePriceListFactory(dbConnection, {
id: "pl_my_price_list",
name: "Test price list",
prices: [
{
variant_id: product.variants[0].id,
currency_code: "usd",
amount: 1000,
},
{
variant_id: product.variants[0].id,
currency_code: "eur",
amount: 2080,
},
],
})
const response = await api.post(
"/admin/batch-jobs",
{
type: "price-list-import",
context: {
price_list_id: priceList.id,
fileKey: "price-list-import.csv",
},
},
adminReqConfig
)
const batchJobId = response.data.batch_job.id
expect(batchJobId).toBeTruthy()
// Pull to check the status until it is completed
let batchJob
let shouldContinuePulling = true
while (shouldContinuePulling) {
const res = await api.get(
`/admin/batch-jobs/${batchJobId}`,
adminReqConfig
)
await new Promise((resolve, _) => {
setTimeout(resolve, 1000)
})
batchJob = res.data.batch_job
shouldContinuePulling = !(
batchJob.status === "completed" || batchJob.status === "failed"
)
}
expect(batchJob.status).toBe("completed")
const priceListRes = await api.get(
"/admin/price-lists/pl_my_price_list",
adminReqConfig
)
// Verify that file service deleted file
const importFilePath = getImportFile()
expect(fs.existsSync(importFilePath)).toBe(false)
expect(priceListRes.data.price_list.prices.length).toEqual(5)
expect(priceListRes.data.price_list.prices).toEqual(
expect.arrayContaining([
expect.objectContaining({
variant_id: "test-pl-variant",
currency_code: "usd",
amount: 1111,
}),
expect.objectContaining({
variant_id: "test-pl-variant",
currency_code: "eur",
region_id: "test-pl-region",
amount: 2222,
}),
expect.objectContaining({
variant_id: "test-pl-variant",
currency_code: "jpy",
amount: 3333,
}),
expect.objectContaining({
variant_id: "test-pl-sku-variant",
currency_code: "usd",
amount: 4444,
}),
expect.objectContaining({
variant_id: "test-pl-sku-variant",
currency_code: "eur",
region_id: "test-pl-region",
amount: 5555,
}),
])
)
})
it("should fail with invalid import format", async () => {
jest.setTimeout(1000000)
const api = useApi()
const product = await simpleProductFactory(dbConnection, {
variants: [
{ id: "test-pl-variant" },
{ id: "test-pl-sku-variant", sku: "pl-sku" },
],
})
await simpleRegionFactory(dbConnection, {
id: "test-pl-region",
name: "PL Region",
currency_code: "eur",
})
const priceList = await simplePriceListFactory(dbConnection, {
id: "pl_my_price_list",
name: "Test price list",
prices: [
{
variant_id: product.variants[0].id,
currency_code: "usd",
amount: 1000,
},
{
variant_id: product.variants[0].id,
currency_code: "eur",
amount: 2080,
},
],
})
const response = await api.post(
"/admin/batch-jobs",
{
type: "price-list-import",
context: {
price_list_id: priceList.id,
fileKey: "invalid-format.csv",
},
},
adminReqConfig
)
const batchJobId = response.data.batch_job.id
expect(batchJobId).toBeTruthy()
// Pull to check the status until it is completed
let batchJob
let shouldContinuePulling = true
while (shouldContinuePulling) {
const res = await api.get(
`/admin/batch-jobs/${batchJobId}`,
adminReqConfig
)
await new Promise((resolve, _) => {
setTimeout(resolve, 1000)
})
batchJob = res.data.batch_job
shouldContinuePulling = !(
batchJob.status === "completed" || batchJob.status === "failed"
)
}
expect(batchJob.status).toBe("failed")
expect(batchJob.result).toEqual({
errors: [
"The csv file parsing failed due to: Unable to treat column non-descript-column from the csv file. No target column found in the provided schema",
],
})
})
})

View File

@@ -0,0 +1,3 @@
non-descript-column,SKU,Price USD,Price PL Region [EUR], Price JPY
test-pl-variant,,11.11,22.22,3333
,pl-sku,44.441,55.55,
1 non-descript-column SKU Price USD Price PL Region [EUR] Price JPY
2 test-pl-variant 11.11 22.22 3333
3 pl-sku 44.441 55.55

View File

@@ -0,0 +1,3 @@
Product Variant ID,SKU,Price USD,Price PL Region [EUR], Price JPY
test-pl-variant,,11.11,22.22,3333
,pl-sku,44.441,55.55,
1 Product Variant ID SKU Price USD Price PL Region [EUR] Price JPY
2 test-pl-variant 11.11 22.22 3333
3 pl-sku 44.441 55.55

View File

@@ -1,4 +1,4 @@
Product id,Product Handle,Product Title,Product Subtitle,Product Description,Product Status,Product Thumbnail,Product Weight,Product Length,Product Width,Product Height,Product HS Code,Product Origin Country,Product MID Code,Product Material,Product Collection Title,Product Collection Handle,Product Type,Product Tags,Product Discountable,Product External ID,Product Profile Name,Product Profile Type,Variant id,Variant Title,Variant SKU,Variant Barcode,Variant Inventory Quantity,Variant Allow backorder,Variant Manage inventory,Variant Weight,Variant Length,Variant Width,Variant Height,Variant HS Code,Variant Origin Country,Variant MID Code,Variant Material,Price ImportLand [EUR],Price USD,Price denmark [DKK],Price Denmark [DKK],Option 1 Name,Option 1 Value,Option 2 Name,Option 2 Value,Image 1 Url,Sales Channel 1 Name,Sales Channel 2 Name,Sales Channel 1 Id,Sales Channel 2 Id
O6S1YQ6mKm,test-product-product-1,Test product,,test-product-description-1,draft,,,,,,,,,,Test collection 1,test-collection1,test-type-1,123_1,TRUE,,profile_1,profile_type_1,,Test variant,test-sku-1,test-barcode-1,10,FALSE,TRUE,,,,,,,,,100,110,130,,test-option-1,option 1 value red,test-option-2,option 2 value 1,test-image.png,Import Sales Channel 1,Import Sales Channel 2,,
5VxiEkmnPV,test-product-product-2,Test product,,test-product-description,draft,,,,,,,,,,Test collection,test-collection2,test-type,123,TRUE,,profile_2,profile_type_2,,Test variant,test-sku-2,test-barcode-2,10,FALSE,TRUE,,,,,,,,,,,,110,test-option,Option 1 value 1,,,test-image.png,,,,
5VxiEkmnPV,test-product-product-2,Test product,,test-product-description,draft,,,,,,,,,,Test collection,test-collection2,test-type,123,TRUE,,profile_2,profile_type_2,,Test variant,test-sku-3,test-barcode-3,10,FALSE,TRUE,,,,,,,,,,120,,,test-option,Option 1 Value blue,,,test-image.png,,,,
O6S1YQ6mKm,test-product-product-1,Test product,,test-product-description-1,draft,,,,,,,,,,Test collection 1,test-collection1,test-type-1,123_1,TRUE,,profile_1,profile_type_1,,Test variant,test-sku-1,test-barcode-1,10,FALSE,TRUE,,,,,,,,,1.00,1.10,1.30,,test-option-1,option 1 value red,test-option-2,option 2 value 1,test-image.png,Import Sales Channel 1,Import Sales Channel 2,,
5VxiEkmnPV,test-product-product-2,Test product,,test-product-description,draft,,,,,,,,,,Test collection,test-collection2,test-type,123,TRUE,,profile_2,profile_type_2,,Test variant,test-sku-2,test-barcode-2,10,FALSE,TRUE,,,,,,,,,,,,1.10,test-option,Option 1 value 1,,,test-image.png,,,,
5VxiEkmnPV,test-product-product-2,Test product,,test-product-description,draft,,,,,,,,,,Test collection,test-collection2,test-type,123,TRUE,,profile_2,profile_type_2,,Test variant,test-sku-3,test-barcode-3,10,FALSE,TRUE,,,,,,,,,,1.20,,,test-option,Option 1 Value blue,,,test-image.png,,,,
1 Product id Product Handle Product Title Product Subtitle Product Description Product Status Product Thumbnail Product Weight Product Length Product Width Product Height Product HS Code Product Origin Country Product MID Code Product Material Product Collection Title Product Collection Handle Product Type Product Tags Product Discountable Product External ID Product Profile Name Product Profile Type Variant id Variant Title Variant SKU Variant Barcode Variant Inventory Quantity Variant Allow backorder Variant Manage inventory Variant Weight Variant Length Variant Width Variant Height Variant HS Code Variant Origin Country Variant MID Code Variant Material Price ImportLand [EUR] Price USD Price denmark [DKK] Price Denmark [DKK] Option 1 Name Option 1 Value Option 2 Name Option 2 Value Image 1 Url Sales Channel 1 Name Sales Channel 2 Name Sales Channel 1 Id Sales Channel 2 Id
2 O6S1YQ6mKm test-product-product-1 Test product test-product-description-1 draft Test collection 1 test-collection1 test-type-1 123_1 TRUE profile_1 profile_type_1 Test variant test-sku-1 test-barcode-1 10 FALSE TRUE 100 1.00 110 1.10 130 1.30 test-option-1 option 1 value red test-option-2 option 2 value 1 test-image.png Import Sales Channel 1 Import Sales Channel 2
3 5VxiEkmnPV test-product-product-2 Test product test-product-description draft Test collection test-collection2 test-type 123 TRUE profile_2 profile_type_2 Test variant test-sku-2 test-barcode-2 10 FALSE TRUE 110 1.10 test-option Option 1 value 1 test-image.png
4 5VxiEkmnPV test-product-product-2 Test product test-product-description draft Test collection test-collection2 test-type 123 TRUE profile_2 profile_type_2 Test variant test-sku-3 test-barcode-3 10 FALSE TRUE 120 1.20 test-option Option 1 Value blue test-image.png

View File

@@ -1,4 +1,4 @@
Product id,Product Handle,Product Title,Product Subtitle,Product Description,Product Status,Product Thumbnail,Product Weight,Product Length,Product Width,Product Height,Product HS Code,Product Origin Country,Product MID Code,Product Material,Product Collection Title,Product Collection Handle,Product Type,Product Tags,Product Discountable,Product External ID,Product Profile Name,Product Profile Type,Variant id,Variant Title,Variant SKU,Variant Barcode,Variant Inventory Quantity,Variant Allow backorder,Variant Manage inventory,Variant Weight,Variant Length,Variant Width,Variant Height,Variant HS Code,Variant Origin Country,Variant MID Code,Variant Material,Price ImportLand [EUR],Price USD,Price denmark [DKK],Price Denmark [DKK],Option 1 Name,Option 1 Value,Option 2 Name,Option 2 Value,Image 1 Url
O6S1YQ6mKm,test-product-product-1,Test product,,"Hopper Stripes Bedding, available as duvet cover, pillow sham and sheet.\n100% organic cotton, soft and crisp to the touch. Made in Portugal.",draft,,,,,,,,,,Test collection 1,test-collection1,test-type-1,123_1,TRUE,,profile_1,profile_type_1,,Test variant,test-sku-1,test-barcode-1,10,FALSE,TRUE,,,,,,,,,100,110,130,,test-option-1,option 1 value red,test-option-2,option 2 value 1,test-image.png
5VxiEkmnPV,test-product-product-2,Test product,,test-product-description,draft,,,,,,,,,,Test collection,test-collection2,test-type,123,TRUE,,profile_2,profile_type_2,,Test variant,test-sku-2,test-barcode-2,10,FALSE,TRUE,,,,,,,,,,,,110,test-option,Option 1 value 1,,,test-image.png
5VxiEkmnPV,test-product-product-2,Test product,,test-product-description,draft,,,,,,,,,,Test collection,test-collection2,test-type,123,TRUE,,profile_2,profile_type_2,,Test variant,test-sku-3,test-barcode-3,10,FALSE,TRUE,,,,,,,,,,120,,,test-option,Option 1 Value blue,,,test-image.png
O6S1YQ6mKm,test-product-product-1,Test product,,"Hopper Stripes Bedding, available as duvet cover, pillow sham and sheet.\n100% organic cotton, soft and crisp to the touch. Made in Portugal.",draft,,,,,,,,,,Test collection 1,test-collection1,test-type-1,123_1,TRUE,,profile_1,profile_type_1,,Test variant,test-sku-1,test-barcode-1,10,FALSE,TRUE,,,,,,,,,1.00,1.10,1.30,,test-option-1,option 1 value red,test-option-2,option 2 value 1,test-image.png
5VxiEkmnPV,test-product-product-2,Test product,,test-product-description,draft,,,,,,,,,,Test collection,test-collection2,test-type,123,TRUE,,profile_2,profile_type_2,,Test variant,test-sku-2,test-barcode-2,10,FALSE,TRUE,,,,,,,,,,,,1.10,test-option,Option 1 value 1,,,test-image.png
5VxiEkmnPV,test-product-product-2,Test product,,test-product-description,draft,,,,,,,,,,Test collection,test-collection2,test-type,123,TRUE,,profile_2,profile_type_2,,Test variant,test-sku-3,test-barcode-3,10,FALSE,TRUE,,,,,,,,,,1.20,,,test-option,Option 1 Value blue,,,test-image.png
1 Product id Product Handle Product Title Product Subtitle Product Description Product Status Product Thumbnail Product Weight Product Length Product Width Product Height Product HS Code Product Origin Country Product MID Code Product Material Product Collection Title Product Collection Handle Product Type Product Tags Product Discountable Product External ID Product Profile Name Product Profile Type Variant id Variant Title Variant SKU Variant Barcode Variant Inventory Quantity Variant Allow backorder Variant Manage inventory Variant Weight Variant Length Variant Width Variant Height Variant HS Code Variant Origin Country Variant MID Code Variant Material Price ImportLand [EUR] Price USD Price denmark [DKK] Price Denmark [DKK] Option 1 Name Option 1 Value Option 2 Name Option 2 Value Image 1 Url
2 O6S1YQ6mKm test-product-product-1 Test product Hopper Stripes Bedding, available as duvet cover, pillow sham and sheet.\n100% organic cotton, soft and crisp to the touch. Made in Portugal. draft Test collection 1 test-collection1 test-type-1 123_1 TRUE profile_1 profile_type_1 Test variant test-sku-1 test-barcode-1 10 FALSE TRUE 100 1.00 110 1.10 130 1.30 test-option-1 option 1 value red test-option-2 option 2 value 1 test-image.png
3 5VxiEkmnPV test-product-product-2 Test product test-product-description draft Test collection test-collection2 test-type 123 TRUE profile_2 profile_type_2 Test variant test-sku-2 test-barcode-2 10 FALSE TRUE 110 1.10 test-option Option 1 value 1 test-image.png
4 5VxiEkmnPV test-product-product-2 Test product test-product-description draft Test collection test-collection2 test-type 123 TRUE profile_2 profile_type_2 Test variant test-sku-3 test-barcode-3 10 FALSE TRUE 120 1.20 test-option Option 1 Value blue test-image.png

View File

@@ -10,6 +10,7 @@ export type ProductVariantFactoryData = {
product_id: string
id?: string
is_giftcard?: boolean
sku?: string
inventory_quantity?: number
title?: string
options?: { option_id: string; value: string }[]
@@ -31,6 +32,7 @@ export const simpleProductVariantFactory = async (
const toSave = manager.create(ProductVariant, {
id,
product_id: data.product_id,
sku: data.sku ?? null,
inventory_quantity:
typeof data.inventory_quantity !== "undefined"
? data.inventory_quantity