feat: Add skeleton for supporting product imports in BE (#8232)

This commit is contained in:
Stevche Radevski
2024-07-23 11:16:14 +02:00
committed by GitHub
parent 55b55b6a92
commit 4b09be3a88
17 changed files with 204 additions and 1178 deletions

View File

@@ -1,165 +0,0 @@
const fs = require("fs")
const path = require("path")
const { useApi } = require("../../../../environment-helpers/use-api")
const { useDb } = require("../../../../environment-helpers/use-db")
const adminSeeder = require("../../../../helpers/admin-seeder")
const userSeeder = require("../../../../helpers/user-seeder")
const { simpleProductCategoryFactory } = require("../../../../factories")
const batchJobSeeder = require("../../../../helpers/batch-job-seeder")
const {
simpleProductCollectionFactory,
} = require("../../../../factories/simple-product-collection-factory")
const startServerWithEnvironment =
require("../../../../environment-helpers/start-server-with-environment").default
jest.setTimeout(30000)
function getImportFile() {
return path.resolve(
"__tests__",
"batch-jobs",
"product",
"product-import-pc.csv"
)
}
function copyTemplateFile() {
const csvTemplate = path.resolve(
"__tests__",
"batch-jobs",
"product",
"product-import-pc-template.csv"
)
const destination = getImportFile()
fs.copyFileSync(csvTemplate, destination)
}
const adminReqConfig = {
headers: {
"x-medusa-access-token": "test_token",
},
}
function cleanTempData() {
// cleanup tmp ops files
const opsFiles = path.resolve("__tests__", "batch-jobs", "product", "imports")
fs.rmSync(opsFiles, { recursive: true, force: true })
}
describe("Product import - Product Category", () => {
let cat
let dbConnection
let medusaProcess
const collectionHandle1 = "test-collection1"
beforeAll(async () => {
const cwd = path.resolve(path.join(__dirname, "..", "..", ".."))
cleanTempData()
const [process, connection] = await startServerWithEnvironment({
cwd,
env: { MEDUSA_FF_PRODUCT_CATEGORIES: true },
uploadDir: __dirname,
})
dbConnection = connection
medusaProcess = process
})
afterAll(async () => {
const db = useDb()
await db.shutdown()
cleanTempData()
medusaProcess.kill()
})
beforeEach(async () => {
try {
await batchJobSeeder(dbConnection)
await adminSeeder(dbConnection)
await userSeeder(dbConnection)
await simpleProductCategoryFactory(dbConnection, {
name: "category",
handle: "import-category-1",
})
await simpleProductCollectionFactory(dbConnection, {
handle: collectionHandle1,
})
} catch (e) {
console.log(e)
throw e
}
})
afterEach(async () => {
const db = useDb()
return await db.teardown()
})
it("Import products with an existing product category", async () => {
jest.setTimeout(1000000)
const api = useApi()
copyTemplateFile()
const response = await api.post(
"/admin/batch-jobs",
{
type: "product-import",
context: {
fileKey: "product-import-pc.csv",
},
},
adminReqConfig
)
const batchJobId = response.data.batch_job.id
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 productsResponse = await api.get(
"/admin/products?expand=categories",
adminReqConfig
)
expect(productsResponse.data.count).toBe(1)
expect(productsResponse.data.products).toEqual([
expect.objectContaining({
title: "Test product",
handle: "test-product-product-1",
categories: [
expect.objectContaining({
handle: "import-category-1",
}),
],
}),
])
})
})

View File

@@ -1,178 +0,0 @@
const fs = require("fs")
const path = require("path")
const { useApi } = require("../../../../environment-helpers/use-api")
const { useDb } = require("../../../../environment-helpers/use-db")
const adminSeeder = require("../../../../helpers/admin-seeder")
const userSeeder = require("../../../../helpers/user-seeder")
const { simpleSalesChannelFactory } = require("../../../../factories")
const batchJobSeeder = require("../../../../helpers/batch-job-seeder")
const {
simpleProductCollectionFactory,
} = require("../../../../factories/simple-product-collection-factory")
const startServerWithEnvironment =
require("../../../../environment-helpers/start-server-with-environment").default
jest.setTimeout(30000)
function getImportFile() {
return path.resolve(
"__tests__",
"batch-jobs",
"product",
"product-import-ss.csv"
)
}
function copyTemplateFile() {
const csvTemplate = path.resolve(
"__tests__",
"batch-jobs",
"product",
"product-import-ss-template.csv"
)
const destination = getImportFile()
fs.copyFileSync(csvTemplate, destination)
}
const adminReqConfig = {
headers: {
"x-medusa-access-token": "test_token",
},
}
function cleanTempData() {
// cleanup tmp ops files
const opsFiles = path.resolve("__tests__", "batch-jobs", "product", "imports")
fs.rmSync(opsFiles, { recursive: true, force: true })
}
describe("Product import - Sales Channel", () => {
let dbConnection
let medusaProcess
const collectionHandle1 = "test-collection1"
beforeAll(async () => {
const cwd = path.resolve(path.join(__dirname, "..", "..", ".."))
cleanTempData()
const [process, connection] = await startServerWithEnvironment({
cwd,
env: { MEDUSA_FF_SALES_CHANNELS: true },
uploadDir: __dirname,
})
dbConnection = connection
medusaProcess = process
})
afterAll(async () => {
const db = useDb()
await db.shutdown()
cleanTempData()
medusaProcess.kill()
})
beforeEach(async () => {
try {
await batchJobSeeder(dbConnection)
await adminSeeder(dbConnection)
await userSeeder(dbConnection)
await simpleSalesChannelFactory(dbConnection, {
name: "Import Sales Channel 1",
})
await simpleSalesChannelFactory(dbConnection, {
name: "Import Sales Channel 2",
})
await simpleProductCollectionFactory(dbConnection, {
handle: collectionHandle1,
})
} catch (e) {
console.log(e)
throw e
}
})
afterEach(async () => {
const db = useDb()
return await db.teardown()
})
it("Import products to an existing sales channel", async () => {
jest.setTimeout(1000000)
const api = useApi()
copyTemplateFile()
const response = await api.post(
"/admin/batch-jobs",
{
type: "product-import",
context: {
fileKey: "product-import-ss.csv",
},
},
adminReqConfig
)
const batchJobId = response.data.batch_job.id
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 productsResponse = await api.get("/admin/products", adminReqConfig)
expect(productsResponse.data.count).toBe(1)
expect(productsResponse.data.products).toEqual([
expect.objectContaining({
title: "Test product",
description:
"Hopper Stripes Bedding, available as duvet cover, pillow sham and sheet.\\n100% organic cotton, soft and crisp to the touch. Made in Portugal.",
handle: "test-product-product-1",
variants: [
expect.objectContaining({
title: "Test variant",
sku: "test-sku-1",
}),
],
sales_channels: [
expect.objectContaining({
name: "Import Sales Channel 1",
is_disabled: false,
}),
expect.objectContaining({
name: "Import Sales Channel 2",
is_disabled: false,
}),
],
collection: expect.objectContaining({
handle: collectionHandle1,
}),
}),
])
})
})

View File

@@ -1,397 +0,0 @@
const fs = require("fs")
const path = require("path")
const setupServer = require("../../../../environment-helpers/setup-server")
const { useApi } = require("../../../../environment-helpers/use-api")
const { initDb, useDb } = require("../../../../environment-helpers/use-db")
const adminSeeder = require("../../../../helpers/admin-seeder")
const batchJobSeeder = require("../../../../helpers/batch-job-seeder")
const userSeeder = require("../../../../helpers/user-seeder")
const { simpleProductFactory } = require("../../../../factories")
const {
simpleProductCollectionFactory,
} = require("../../../../factories/simple-product-collection-factory")
const adminReqConfig = {
headers: {
"x-medusa-access-token": "test_token",
},
}
function getImportFile() {
return path.resolve(
"__tests__",
"batch-jobs",
"product",
"product-import.csv"
)
}
function copyTemplateFile() {
const csvTemplate = path.resolve(
"__tests__",
"batch-jobs",
"product",
"product-import-template.csv"
)
const destination = getImportFile()
fs.copyFileSync(csvTemplate, destination)
}
jest.setTimeout(1000000)
function cleanTempData() {
// cleanup tmp ops files
const opsFiles = path.resolve("__tests__", "batch-jobs", "product", "imports")
fs.rmSync(opsFiles, { recursive: true, force: true })
}
describe("Product import batch job", () => {
let medusaProcess
let dbConnection
const collectionHandle1 = "test-collection1"
const collectionHandle2 = "test-collection2"
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,
uploadDir: __dirname,
})
})
afterAll(async () => {
const db = useDb()
await db.shutdown()
cleanTempData()
medusaProcess.kill()
})
beforeEach(async () => {
await batchJobSeeder(dbConnection)
await adminSeeder(dbConnection)
await userSeeder(dbConnection)
await simpleProductCollectionFactory(dbConnection, [
{
handle: collectionHandle1,
},
{
handle: collectionHandle2,
},
])
})
afterEach(async () => {
const db = useDb()
await db.teardown()
})
it("should import a csv file", async () => {
jest.setTimeout(1000000)
const api = useApi()
copyTemplateFile()
const existingProductToBeUpdated = await simpleProductFactory(
dbConnection,
{
id: "existing-product-id",
title: "Test product",
options: [{ id: "opt-1-id", title: "Size" }],
variants: [
{
id: "existing-variant-id",
title: "Initial tile",
sku: "test-sku-4",
barde: "test-barcode-4",
options: [
{
option_id: "opt-1-id",
value: "Large",
},
],
},
],
}
)
const response = await api.post(
"/admin/batch-jobs",
{
type: "product-import",
context: {
fileKey: "product-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 productsResponse = await api.get("/admin/products", adminReqConfig)
expect(productsResponse.data.count).toBe(3)
expect(productsResponse.data.products).toEqual(
expect.arrayContaining([
// NEW PRODUCT
expect.objectContaining({
title: "Test product",
description:
"Hopper Stripes Bedding, available as duvet cover, pillow sham and sheet.\\n100% organic cotton, soft and crisp to the touch. Made in Portugal.",
handle: "test-product-product-1",
is_giftcard: false,
status: "draft",
thumbnail: "test-image.png",
variants: [
// NEW VARIANT
expect.objectContaining({
title: "Test variant",
sku: "test-sku-1",
barcode: "test-barcode-1",
ean: null,
upc: null,
inventory_quantity: 10,
prices: expect.arrayContaining([
expect.objectContaining({
currency_code: "eur",
amount: 100,
region_id: "region-product-import-0",
}),
expect.objectContaining({
currency_code: "usd",
amount: 110,
}),
expect.objectContaining({
currency_code: "dkk",
amount: 130,
region_id: "region-product-import-1",
}),
]),
options: expect.arrayContaining([
expect.objectContaining({
value: "option 1 value red",
}),
expect.objectContaining({
value: "option 2 value 1",
}),
]),
}),
],
type: null,
images: expect.arrayContaining([
expect.objectContaining({
url: "test-image.png",
}),
]),
options: expect.arrayContaining([
expect.objectContaining({
title: "test-option-1",
}),
expect.objectContaining({
title: "test-option-2",
}),
]),
tags: expect.arrayContaining([
expect.objectContaining({
value: "123_1",
}),
]),
collection: expect.objectContaining({
handle: collectionHandle1,
}),
}),
expect.objectContaining({
title: "Test product",
description:
"Hopper Stripes Bedding, available as duvet cover, pillow sham and sheet.\\n100% organic cotton, soft and crisp to the touch. Made in Portugal.",
handle: "test-product-product-1-1",
is_giftcard: false,
status: "draft",
thumbnail: "test-image.png",
variants: [
// NEW VARIANT
expect.objectContaining({
title: "Test variant",
sku: "test-sku-1-1",
barcode: "test-barcode-1-1",
ean: null,
upc: null,
inventory_quantity: 10,
prices: expect.arrayContaining([
expect.objectContaining({
currency_code: "eur",
amount: 100,
region_id: "region-product-import-0",
}),
expect.objectContaining({
currency_code: "usd",
amount: 110,
}),
expect.objectContaining({
currency_code: "dkk",
amount: 130,
region_id: "region-product-import-1",
}),
]),
options: expect.arrayContaining([
expect.objectContaining({
value: "option 1 value red",
}),
expect.objectContaining({
value: "option 2 value 1",
}),
]),
}),
],
type: null,
images: expect.arrayContaining([
expect.objectContaining({
url: "test-image.png",
}),
]),
options: expect.arrayContaining([
expect.objectContaining({
title: "test-option-1",
}),
expect.objectContaining({
title: "test-option-2",
}),
]),
tags: [],
collection: expect.objectContaining({
handle: collectionHandle1,
}),
}),
// UPDATED PRODUCT
expect.objectContaining({
id: existingProductToBeUpdated.id,
title: "Test product",
description: "test-product-description",
handle: "test-product-product-2",
is_giftcard: false,
status: "draft",
thumbnail: "test-image.png",
profile_id: expect.any(String),
variants: expect.arrayContaining([
// UPDATED VARIANT
expect.objectContaining({
id: "existing-variant-id",
title: "Test variant changed",
sku: "test-sku-4",
barcode: "test-barcode-4",
options: [
expect.objectContaining({
value: "Large",
option_id: "opt-1-id",
}),
],
}),
// CREATED VARIANT
expect.objectContaining({
title: "Test variant",
product_id: existingProductToBeUpdated.id,
sku: "test-sku-2",
barcode: "test-barcode-2",
ean: null,
upc: null,
inventory_quantity: 10,
allow_backorder: false,
manage_inventory: true,
prices: [
expect.objectContaining({
currency_code: "dkk",
amount: 110,
region_id: "region-product-import-2",
}),
],
options: [
expect.objectContaining({
value: "Small",
option_id: "opt-1-id",
}),
],
}),
// CREATED VARIANT
expect.objectContaining({
title: "Test variant",
product_id: existingProductToBeUpdated.id,
sku: "test-sku-3",
barcode: "test-barcode-3",
ean: null,
upc: null,
inventory_quantity: 10,
allow_backorder: false,
manage_inventory: true,
prices: [
expect.objectContaining({
currency_code: "usd",
amount: 120,
region_id: null,
}),
],
options: [
expect.objectContaining({
value: "Medium",
option_id: "opt-1-id",
}),
],
}),
]),
images: [
expect.objectContaining({
url: "test-image.png",
}),
],
options: [
expect.objectContaining({
product_id: existingProductToBeUpdated.id,
id: "opt-1-id",
title: "Size",
}),
],
type: expect.objectContaining({ value: "test-type" }),
tags: [
expect.objectContaining({
value: "123",
}),
],
collection: expect.objectContaining({
handle: collectionHandle2,
}),
}),
])
)
})
})

View File

@@ -1,2 +0,0 @@
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,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,Product Category 1 Handle
,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,,,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-category-1
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 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 Product Category 1 Handle
2 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 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-category-1

View File

@@ -1,2 +0,0 @@
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,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
,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,,,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,,
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 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 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 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

View File

@@ -1,6 +0,0 @@
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,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
,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,,123_1,TRUE,,,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
,test-product-product-1-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,,,TRUE,,,Test variant,test-sku-1-1,test-barcode-1-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
existing-product-id,test-product-product-2,Test product,,test-product-description,draft,test-image.png,,,,,,,,,Test collection,test-collection2,test-type,123,TRUE,,,Test variant,test-sku-2,test-barcode-2,10,FALSE,TRUE,,,,,,,,,,,,1.10,Size,Small,,,test-image.png
existing-product-id,test-product-product-2,Test product,,test-product-description,draft,,,,,,,,,,Test collection,test-collection2,test-type,123,TRUE,,,Test variant,test-sku-3,test-barcode-3,10,FALSE,TRUE,,,,,,,,,,1.20,,,Size,Medium,,,test-image.png
existing-product-id,test-product-product-2,Test product,,test-product-description,draft,,,,,,,,,,Test collection,test-collection2,test-type,123,TRUE,,existing-variant-id,Test variant changed,test-sku-4,test-barcode-4,10,FALSE,TRUE,,,,,,,,,,,,,Size,Large,,,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 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 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 123_1 TRUE 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
3 test-product-product-1-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 TRUE Test variant test-sku-1-1 test-barcode-1-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
4 existing-product-id test-product-product-2 Test product test-product-description draft test-image.png Test collection test-collection2 test-type 123 TRUE Test variant test-sku-2 test-barcode-2 10 FALSE TRUE 1.10 Size Small test-image.png
5 existing-product-id test-product-product-2 Test product test-product-description draft Test collection test-collection2 test-type 123 TRUE Test variant test-sku-3 test-barcode-3 10 FALSE TRUE 1.20 Size Medium test-image.png
6 existing-product-id test-product-product-2 Test product test-product-description draft Test collection test-collection2 test-type 123 TRUE existing-variant-id Test variant changed test-sku-4 test-barcode-4 10 FALSE TRUE Size Large test-image.png