* add reservation endpoints * add changeset * initial * add reservations table * add edit-item modal * udpate inventory item attributes * manage locations skeleton * add combi batch endpoint * cleanup * fix manage locations * add adjust inventory * prep for pr * update versions * fix for pr * fix for pr * cleanup * Update packages/core-flows/src/inventory/workflows/bulk-create-delete-levels.ts Co-authored-by: Carlos R. L. Rodrigues <37986729+carlos-r-l-rodrigues@users.noreply.github.com> * Update packages/core-flows/src/inventory/steps/delete-levels-by-item-and-location.ts Co-authored-by: Carlos R. L. Rodrigues <37986729+carlos-r-l-rodrigues@users.noreply.github.com> * rm wack import * fix build --------- Co-authored-by: Carlos R. L. Rodrigues <37986729+carlos-r-l-rodrigues@users.noreply.github.com>
1273 lines
37 KiB
JavaScript
1273 lines
37 KiB
JavaScript
const { ModuleRegistrationName, Modules } = require("@medusajs/modules-sdk")
|
|
const { medusaIntegrationTestRunner } = require("medusa-test-utils")
|
|
const {
|
|
createAdminUser,
|
|
adminHeaders,
|
|
} = require("../../../helpers/create-admin-user")
|
|
const { breaking } = require("../../../helpers/breaking")
|
|
const { ContainerRegistrationKeys } = require("@medusajs/utils")
|
|
|
|
const adminReqConfig = {
|
|
headers: {
|
|
"x-medusa-access-token": "test_token",
|
|
},
|
|
}
|
|
|
|
let { simpleSalesChannelFactory, simpleProductFactory, simpleOrderFactory } = {}
|
|
let { SalesChannel, Product } = {}
|
|
let orderSeeder
|
|
let productSeeder
|
|
|
|
jest.setTimeout(60000)
|
|
|
|
medusaIntegrationTestRunner({
|
|
// env: { MEDUSA_FF_MEDUSA_V2: true },
|
|
testSuite: ({ dbConnection, getContainer, api }) => {
|
|
let container
|
|
let salesChannelService
|
|
let productService
|
|
let remoteQuery
|
|
let remoteLink
|
|
|
|
beforeAll(() => {
|
|
;({
|
|
simpleProductFactory,
|
|
simpleSalesChannelFactory,
|
|
simpleOrderFactory,
|
|
} = require("../../../factories"))
|
|
;({ SalesChannel, Product } = require("@medusajs/medusa"))
|
|
|
|
orderSeeder = require("../../../helpers/order-seeder")
|
|
productSeeder = require("../../../helpers/product-seeder")
|
|
})
|
|
|
|
beforeEach(async () => {
|
|
container = getContainer()
|
|
await createAdminUser(dbConnection, adminReqConfig, container)
|
|
|
|
salesChannelService = container.resolve(
|
|
ModuleRegistrationName.SALES_CHANNEL
|
|
)
|
|
productService = container.resolve(ModuleRegistrationName.PRODUCT)
|
|
remoteQuery = container.resolve(ContainerRegistrationKeys.REMOTE_QUERY)
|
|
remoteLink = container.resolve(ContainerRegistrationKeys.REMOTE_LINK)
|
|
})
|
|
|
|
describe("GET /admin/sales-channels/:id", () => {
|
|
let salesChannel
|
|
|
|
beforeEach(async () => {
|
|
salesChannel = await breaking(
|
|
async () => {
|
|
return await simpleSalesChannelFactory(dbConnection, {
|
|
name: "test name",
|
|
description: "test description",
|
|
})
|
|
},
|
|
async () => {
|
|
return await salesChannelService.create({
|
|
name: "test name",
|
|
description: "test description",
|
|
})
|
|
}
|
|
)
|
|
})
|
|
|
|
it("should retrieve the requested sales channel", async () => {
|
|
const response = await api.get(
|
|
`/admin/sales-channels/${salesChannel.id}`,
|
|
adminReqConfig
|
|
)
|
|
|
|
expect(response.status).toEqual(200)
|
|
expect(response.data.sales_channel).toBeTruthy()
|
|
expect(response.data.sales_channel).toEqual(
|
|
expect.objectContaining({
|
|
id: expect.any(String),
|
|
name: salesChannel.name,
|
|
description: salesChannel.description,
|
|
created_at: expect.any(String),
|
|
updated_at: expect.any(String),
|
|
})
|
|
)
|
|
})
|
|
})
|
|
|
|
describe("GET /admin/sales-channels", () => {
|
|
let salesChannel1
|
|
let salesChannel2
|
|
|
|
beforeEach(async () => {
|
|
salesChannel1 = await breaking(
|
|
async () => {
|
|
return await simpleSalesChannelFactory(dbConnection, {
|
|
name: "test name",
|
|
description: "test description",
|
|
})
|
|
},
|
|
async () => {
|
|
return await salesChannelService.create({
|
|
name: "test name",
|
|
description: "test description",
|
|
})
|
|
}
|
|
)
|
|
|
|
salesChannel2 = await breaking(
|
|
async () => {
|
|
return await simpleSalesChannelFactory(dbConnection, {
|
|
name: "test name 2",
|
|
description: "test description 2",
|
|
})
|
|
},
|
|
async () => {
|
|
return await salesChannelService.create({
|
|
name: "test name 2",
|
|
description: "test description 2",
|
|
})
|
|
}
|
|
)
|
|
})
|
|
|
|
it("should list the sales channel", async () => {
|
|
const response = await api.get(`/admin/sales-channels`, adminReqConfig)
|
|
|
|
expect(response.status).toEqual(200)
|
|
expect(response.data.sales_channels).toBeTruthy()
|
|
expect(response.data.sales_channels.length).toBe(
|
|
breaking(
|
|
() => 3, // Two created + the default one
|
|
() => 2 // This will not be breaking once the default sales channel is created in the new API
|
|
)
|
|
)
|
|
expect(response.data).toEqual(
|
|
expect.objectContaining({
|
|
sales_channels: expect.arrayContaining([
|
|
expect.objectContaining({
|
|
name: salesChannel1.name,
|
|
description: salesChannel1.description,
|
|
}),
|
|
expect.objectContaining({
|
|
name: salesChannel2.name,
|
|
description: salesChannel2.description,
|
|
}),
|
|
]),
|
|
})
|
|
)
|
|
})
|
|
|
|
it("should list the sales channel using filters", async () => {
|
|
const response = await breaking(
|
|
async () => {
|
|
return await api.get(`/admin/sales-channels?q=2`, adminReqConfig)
|
|
},
|
|
() => undefined
|
|
)
|
|
|
|
breaking(
|
|
() => {
|
|
expect(response.status).toEqual(200)
|
|
expect(response.data.sales_channels).toBeTruthy()
|
|
expect(response.data.sales_channels.length).toBe(1)
|
|
expect(response.data).toEqual({
|
|
count: 1,
|
|
limit: 20,
|
|
offset: 0,
|
|
sales_channels: expect.arrayContaining([
|
|
expect.objectContaining({
|
|
id: expect.any(String),
|
|
name: salesChannel2.name,
|
|
description: salesChannel2.description,
|
|
is_disabled: false,
|
|
deleted_at: null,
|
|
created_at: expect.any(String),
|
|
updated_at: expect.any(String),
|
|
}),
|
|
]),
|
|
})
|
|
},
|
|
() => {
|
|
// TODO: Free text search is not supported in the new sales channel API (yet)
|
|
expect(response).toBeUndefined()
|
|
}
|
|
)
|
|
})
|
|
|
|
it("should list the sales channel using properties filters", async () => {
|
|
const response = await api.get(
|
|
`/admin/sales-channels?name=test+name`,
|
|
adminReqConfig
|
|
)
|
|
|
|
expect(response.status).toEqual(200)
|
|
expect(response.data.sales_channels).toBeTruthy()
|
|
expect(response.data.sales_channels.length).toBe(1)
|
|
expect(response.data).toEqual({
|
|
count: 1,
|
|
limit: 20,
|
|
offset: 0,
|
|
sales_channels: expect.arrayContaining([
|
|
expect.objectContaining({
|
|
id: expect.any(String),
|
|
name: salesChannel1.name,
|
|
description: salesChannel1.description,
|
|
is_disabled: false,
|
|
deleted_at: null,
|
|
created_at: expect.any(String),
|
|
updated_at: expect.any(String),
|
|
}),
|
|
]),
|
|
})
|
|
})
|
|
})
|
|
|
|
describe("POST /admin/sales-channels/:id", () => {
|
|
let sc
|
|
|
|
beforeEach(async () => {
|
|
sc = await breaking(
|
|
async () => {
|
|
return await simpleSalesChannelFactory(dbConnection, {
|
|
name: "test name",
|
|
description: "test description",
|
|
})
|
|
},
|
|
async () => {
|
|
return await salesChannelService.create({
|
|
name: "test name",
|
|
description: "test description",
|
|
})
|
|
}
|
|
)
|
|
})
|
|
|
|
it("updates sales channel properties", async () => {
|
|
const payload = {
|
|
name: "updated name",
|
|
description: "updated description",
|
|
is_disabled: true,
|
|
}
|
|
|
|
const response = await api.post(
|
|
`/admin/sales-channels/${sc.id}`,
|
|
payload,
|
|
adminReqConfig
|
|
)
|
|
|
|
expect(response.status).toEqual(200)
|
|
expect(response.data.sales_channel).toEqual(
|
|
expect.objectContaining({
|
|
id: expect.any(String),
|
|
name: payload.name,
|
|
description: payload.description,
|
|
is_disabled: payload.is_disabled,
|
|
created_at: expect.any(String),
|
|
updated_at: expect.any(String),
|
|
})
|
|
)
|
|
})
|
|
})
|
|
|
|
describe("POST /admin/sales-channels", () => {
|
|
beforeEach(async () => {})
|
|
|
|
it("successfully creates a disabled sales channel", async () => {
|
|
const newSalesChannel = {
|
|
name: "sales channel name",
|
|
is_disabled: true,
|
|
}
|
|
|
|
const response = await api
|
|
.post("/admin/sales-channels", newSalesChannel, adminReqConfig)
|
|
.catch((err) => {
|
|
console.log(err)
|
|
})
|
|
|
|
expect(response.status).toEqual(200)
|
|
expect(response.data.sales_channel).toBeTruthy()
|
|
|
|
expect(response.data).toMatchSnapshot({
|
|
sales_channel: expect.objectContaining({
|
|
name: newSalesChannel.name,
|
|
is_disabled: true,
|
|
}),
|
|
})
|
|
})
|
|
|
|
it("successfully creates a sales channel", async () => {
|
|
const newSalesChannel = {
|
|
name: "sales channel name",
|
|
description: "sales channel description",
|
|
}
|
|
|
|
const response = await api
|
|
.post("/admin/sales-channels", newSalesChannel, adminReqConfig)
|
|
.catch((err) => {
|
|
console.log(err)
|
|
})
|
|
|
|
expect(response.status).toEqual(200)
|
|
expect(response.data.sales_channel).toBeTruthy()
|
|
|
|
expect(response.data).toMatchSnapshot({
|
|
sales_channel: expect.objectContaining({
|
|
name: newSalesChannel.name,
|
|
description: newSalesChannel.description,
|
|
is_disabled: false,
|
|
}),
|
|
})
|
|
})
|
|
})
|
|
|
|
describe("DELETE /admin/sales-channels/:id", () => {
|
|
let salesChannel
|
|
|
|
beforeEach(async () => {
|
|
salesChannel = await breaking(
|
|
async () => {
|
|
return await simpleSalesChannelFactory(dbConnection, {
|
|
name: "test name",
|
|
description: "test description",
|
|
})
|
|
},
|
|
async () => {
|
|
return await salesChannelService.create({
|
|
name: "test name",
|
|
description: "test description",
|
|
})
|
|
}
|
|
)
|
|
|
|
await breaking(async () => {
|
|
await simpleSalesChannelFactory(dbConnection, {
|
|
name: "Default channel",
|
|
id: "test-channel",
|
|
is_default: true,
|
|
})
|
|
})
|
|
})
|
|
|
|
it("should delete the requested sales channel", async () => {
|
|
const toDelete = await breaking(
|
|
async () => {
|
|
return await dbConnection.manager.findOne(SalesChannel, {
|
|
where: { id: salesChannel.id },
|
|
})
|
|
},
|
|
async () => {
|
|
return await salesChannelService.retrieve(salesChannel.id)
|
|
}
|
|
)
|
|
|
|
expect(toDelete.id).toEqual(salesChannel.id)
|
|
expect(toDelete.deleted_at).toEqual(null)
|
|
|
|
const response = await api.delete(
|
|
`/admin/sales-channels/${salesChannel.id}`,
|
|
adminReqConfig
|
|
)
|
|
|
|
expect(response.status).toEqual(200)
|
|
expect(response.data).toMatchSnapshot({
|
|
deleted: true,
|
|
id: expect.any(String),
|
|
object: "sales-channel",
|
|
})
|
|
|
|
const deleted = await breaking(
|
|
async () => {
|
|
return await dbConnection.manager.findOne(SalesChannel, {
|
|
where: { id: salesChannel.id },
|
|
withDeleted: true,
|
|
})
|
|
},
|
|
async () => {
|
|
return await salesChannelService.retrieve(salesChannel.id, {
|
|
withDeleted: true,
|
|
})
|
|
}
|
|
)
|
|
|
|
expect(deleted.id).toEqual(salesChannel.id)
|
|
expect(deleted.deleted_at).not.toEqual(null)
|
|
})
|
|
|
|
it("should throw if we attempt to delete default channel", async () => {
|
|
await breaking(async () => {
|
|
expect.assertions(2)
|
|
|
|
const res = await api
|
|
.delete(`/admin/sales-channels/test-channel`, adminReqConfig)
|
|
.catch((err) => err)
|
|
|
|
expect(res.response.status).toEqual(400)
|
|
expect(res.response.data.message).toEqual(
|
|
"You cannot delete the default sales channel"
|
|
)
|
|
})
|
|
})
|
|
|
|
it("should successfully delete channel associations", async () => {
|
|
await breaking(null, async () => {
|
|
const remoteLink = container.resolve(
|
|
ContainerRegistrationKeys.REMOTE_LINK
|
|
)
|
|
|
|
await remoteLink.create([
|
|
{
|
|
[Modules.SALES_CHANNEL]: {
|
|
sales_channel_id: "test-channel",
|
|
},
|
|
[Modules.STOCK_LOCATION]: {
|
|
stock_location_id: "test-location",
|
|
},
|
|
},
|
|
{
|
|
[Modules.SALES_CHANNEL]: {
|
|
sales_channel_id: "test-channel-default",
|
|
},
|
|
[Modules.STOCK_LOCATION]: {
|
|
stock_location_id: "test-location",
|
|
},
|
|
},
|
|
])
|
|
|
|
await api
|
|
.delete(`/admin/sales-channels/test-channel`, adminReqConfig)
|
|
.catch(console.log)
|
|
|
|
const linkService = remoteLink.getLinkModule(
|
|
Modules.SALES_CHANNEL,
|
|
"sales_channel_id",
|
|
Modules.STOCK_LOCATION,
|
|
"stock_location_id"
|
|
)
|
|
|
|
const channelLinks = await linkService.list()
|
|
expect(channelLinks).toHaveLength(1)
|
|
})
|
|
})
|
|
})
|
|
|
|
describe("GET /admin/orders/:id", () => {
|
|
let order
|
|
beforeEach(async () => {
|
|
order = await simpleOrderFactory(dbConnection, {
|
|
sales_channel: {
|
|
name: "test name",
|
|
description: "test description",
|
|
},
|
|
payment_status: "captured",
|
|
fulfillment_status: "fulfilled",
|
|
line_items: [
|
|
{
|
|
id: "line-item",
|
|
quantity: 2,
|
|
},
|
|
],
|
|
})
|
|
})
|
|
|
|
it("expands sales channel for single", async () => {
|
|
const response = await api.get(
|
|
`/admin/orders/${order.id}`,
|
|
adminReqConfig
|
|
)
|
|
|
|
expect(response.data.order.sales_channel).toBeTruthy()
|
|
expect(response.data.order.sales_channel).toEqual(
|
|
expect.objectContaining({
|
|
id: expect.any(String),
|
|
name: "test name",
|
|
description: "test description",
|
|
is_disabled: false,
|
|
created_at: expect.any(String),
|
|
updated_at: expect.any(String),
|
|
})
|
|
)
|
|
})
|
|
|
|
it("creates swap with order sales channel", async () => {
|
|
const product = await simpleProductFactory(dbConnection, {
|
|
variants: [{ id: "test-variant", inventory_quantity: 100 }],
|
|
})
|
|
|
|
const swap = await api.post(
|
|
`/admin/orders/${order.id}/swaps`,
|
|
{
|
|
return_items: [
|
|
{
|
|
item_id: "line-item",
|
|
quantity: 1,
|
|
},
|
|
],
|
|
additional_items: [{ variant_id: "test-variant", quantity: 1 }],
|
|
},
|
|
adminReqConfig
|
|
)
|
|
|
|
expect(swap.status).toEqual(200)
|
|
|
|
const cartId = swap.data.order.swaps[0].cart_id
|
|
|
|
const swapCart = await api.get(`/store/carts/${cartId}`)
|
|
|
|
expect(swapCart.data.cart.sales_channel_id).toEqual(
|
|
order.sales_channel_id
|
|
)
|
|
})
|
|
|
|
it("creates swap with provided sales channel", async () => {
|
|
const sc = await simpleSalesChannelFactory(dbConnection, {})
|
|
|
|
const product = await simpleProductFactory(dbConnection, {
|
|
variants: [{ id: "test-variant", inventory_quantity: 100 }],
|
|
})
|
|
|
|
const swap = await api.post(
|
|
`/admin/orders/${order.id}/swaps`,
|
|
{
|
|
return_items: [
|
|
{
|
|
item_id: "line-item",
|
|
quantity: 1,
|
|
},
|
|
],
|
|
sales_channel_id: sc.id,
|
|
additional_items: [{ variant_id: "test-variant", quantity: 1 }],
|
|
},
|
|
adminReqConfig
|
|
)
|
|
|
|
expect(swap.status).toEqual(200)
|
|
|
|
const cartId = swap.data.order.swaps[0].cart_id
|
|
|
|
const swapCart = await api.get(`/store/carts/${cartId}`)
|
|
|
|
expect(swapCart.data.cart.sales_channel_id).toEqual(sc.id)
|
|
})
|
|
})
|
|
|
|
describe("GET /admin/orders?expand=sales_channels", () => {
|
|
beforeEach(async () => {
|
|
await simpleOrderFactory(dbConnection, {
|
|
sales_channel: {
|
|
name: "test name",
|
|
description: "test description",
|
|
},
|
|
})
|
|
})
|
|
|
|
it("expands sales channel with parameter", async () => {
|
|
const response = await api.get(
|
|
"/admin/orders?expand=sales_channel",
|
|
adminReqConfig
|
|
)
|
|
|
|
expect(response.data.orders[0].sales_channel).toBeTruthy()
|
|
expect(response.data.orders[0].sales_channel).toEqual(
|
|
expect.objectContaining({
|
|
id: expect.any(String),
|
|
name: "test name",
|
|
description: "test description",
|
|
is_disabled: false,
|
|
created_at: expect.any(String),
|
|
updated_at: expect.any(String),
|
|
})
|
|
)
|
|
})
|
|
})
|
|
|
|
describe("GET /admin/product/:id", () => {
|
|
let product
|
|
beforeEach(async () => {
|
|
product = await simpleProductFactory(dbConnection, {
|
|
sales_channels: [
|
|
{
|
|
name: "webshop",
|
|
description: "Webshop sales channel",
|
|
},
|
|
{
|
|
name: "amazon",
|
|
description: "Amazon sales channel",
|
|
},
|
|
],
|
|
})
|
|
})
|
|
|
|
it("returns product with sales channel", async () => {
|
|
const response = await api
|
|
.get(`/admin/products/${product.id}`, adminReqConfig)
|
|
.catch((err) => console.log(err))
|
|
|
|
expect(response.data.product.sales_channels).toBeTruthy()
|
|
expect(response.data.product.sales_channels).toEqual(
|
|
expect.arrayContaining([
|
|
expect.objectContaining({
|
|
name: "webshop",
|
|
description: "Webshop sales channel",
|
|
is_disabled: false,
|
|
}),
|
|
expect.objectContaining({
|
|
name: "amazon",
|
|
description: "Amazon sales channel",
|
|
is_disabled: false,
|
|
}),
|
|
])
|
|
)
|
|
})
|
|
})
|
|
|
|
describe("GET /admin/products?expand[]=sales_channels", () => {
|
|
beforeEach(async () => {
|
|
await simpleProductFactory(dbConnection, {
|
|
sales_channels: [
|
|
{
|
|
name: "webshop",
|
|
description: "Webshop sales channel",
|
|
},
|
|
{
|
|
name: "amazon",
|
|
description: "Amazon sales channel",
|
|
},
|
|
],
|
|
})
|
|
})
|
|
|
|
it("expands sales channel with parameter", async () => {
|
|
const response = await api.get(
|
|
"/admin/products?expand=sales_channels",
|
|
adminReqConfig
|
|
)
|
|
|
|
expect(response.data.products[0].sales_channels).toBeTruthy()
|
|
expect(response.data.products[0].sales_channels).toEqual(
|
|
expect.arrayContaining([
|
|
expect.objectContaining({
|
|
name: "webshop",
|
|
description: "Webshop sales channel",
|
|
is_disabled: false,
|
|
}),
|
|
expect.objectContaining({
|
|
name: "amazon",
|
|
description: "Amazon sales channel",
|
|
is_disabled: false,
|
|
}),
|
|
])
|
|
)
|
|
})
|
|
})
|
|
|
|
describe("DELETE /admin/sales-channels/:id/products/batch", () => {
|
|
// BREAKING CHANGE: Endpoint has changed
|
|
// from: DELETE /admin/sales-channels/:id/products/batch
|
|
// to: POST /admin/sales-channels/:id/products/batch/remove
|
|
|
|
let salesChannel
|
|
let product
|
|
|
|
beforeEach(async () => {
|
|
;({ salesChannel, product } = await breaking(
|
|
async () => {
|
|
const product = await simpleProductFactory(dbConnection, {
|
|
id: "product_1",
|
|
title: "test title",
|
|
})
|
|
const salesChannel = await simpleSalesChannelFactory(dbConnection, {
|
|
name: "test name",
|
|
description: "test description",
|
|
products: [product],
|
|
})
|
|
|
|
return { salesChannel, product }
|
|
},
|
|
async () => {
|
|
const salesChannel = await salesChannelService.create({
|
|
name: "test name",
|
|
description: "test description",
|
|
})
|
|
const product = await productService.create({
|
|
title: "test title",
|
|
})
|
|
|
|
await remoteLink.create({
|
|
[Modules.PRODUCT]: {
|
|
product_id: product.id,
|
|
},
|
|
[Modules.SALES_CHANNEL]: {
|
|
sales_channel_id: salesChannel.id,
|
|
},
|
|
})
|
|
|
|
return { salesChannel, product }
|
|
}
|
|
))
|
|
})
|
|
|
|
it("should remove products from a sales channel", async () => {
|
|
const attachedProduct = await breaking(
|
|
async () => {
|
|
return await dbConnection.manager.findOne(Product, {
|
|
where: { id: product.id },
|
|
relations: ["sales_channels"],
|
|
})
|
|
},
|
|
async () => {
|
|
const [product] = await remoteQuery({
|
|
products: {
|
|
fields: ["id"],
|
|
sales_channels: {
|
|
fields: ["id", "name", "description", "is_disabled"],
|
|
},
|
|
},
|
|
})
|
|
|
|
return product
|
|
}
|
|
)
|
|
|
|
expect(attachedProduct.sales_channels.length).toBe(
|
|
breaking(
|
|
() => 2,
|
|
() => 1 // Comment: The product factory from v1 adds products to the default channel
|
|
)
|
|
)
|
|
expect(attachedProduct.sales_channels).toEqual(
|
|
expect.arrayContaining(
|
|
breaking(
|
|
() => [
|
|
expect.objectContaining({
|
|
id: expect.any(String),
|
|
name: "test name",
|
|
description: "test description",
|
|
is_disabled: false,
|
|
}),
|
|
expect.objectContaining({
|
|
id: expect.any(String),
|
|
is_disabled: false,
|
|
}),
|
|
],
|
|
() => [
|
|
expect.objectContaining({
|
|
id: expect.any(String),
|
|
name: "test name",
|
|
description: "test description",
|
|
is_disabled: false,
|
|
}),
|
|
]
|
|
)
|
|
)
|
|
)
|
|
|
|
const payload = {
|
|
product_ids: breaking(
|
|
() => [{ id: product.id }],
|
|
() => [product.id]
|
|
),
|
|
}
|
|
|
|
const response = await breaking(
|
|
async () => {
|
|
return await api.delete(
|
|
`/admin/sales-channels/${salesChannel.id}/products/batch`,
|
|
{ ...adminReqConfig, data: payload }
|
|
)
|
|
},
|
|
async () => {
|
|
return await api.post(
|
|
`/admin/sales-channels/${salesChannel.id}/products/batch/remove`,
|
|
payload,
|
|
adminReqConfig
|
|
)
|
|
}
|
|
)
|
|
|
|
expect(response.status).toEqual(200)
|
|
expect(response.data.sales_channel).toEqual(
|
|
expect.objectContaining({
|
|
id: expect.any(String),
|
|
name: "test name",
|
|
description: "test description",
|
|
is_disabled: false,
|
|
})
|
|
)
|
|
|
|
const removedProduct = await breaking(
|
|
async () => {
|
|
return await dbConnection.manager.findOne(Product, {
|
|
where: { id: product.id },
|
|
relations: ["sales_channels"],
|
|
})
|
|
},
|
|
async () => {
|
|
const [product] = await remoteQuery({
|
|
products: {
|
|
fields: ["id"],
|
|
sales_channels: {
|
|
fields: ["id", "name", "description", "is_disabled"],
|
|
},
|
|
},
|
|
})
|
|
|
|
return product
|
|
}
|
|
)
|
|
|
|
// default sales channel
|
|
expect(removedProduct.sales_channels.length).toBe(
|
|
breaking(
|
|
() => 1,
|
|
() => 0 // Comment: The product factory from v1 adds products to the default channel
|
|
)
|
|
)
|
|
})
|
|
})
|
|
|
|
describe("POST /admin/sales-channels/:id/products/batch", () => {
|
|
// BREAKING CHANGE: Endpoint has changed
|
|
// from: /admin/sales-channels/:id/products/batch
|
|
// to: /admin/sales-channels/:id/products/batch/add
|
|
|
|
let { salesChannel, product } = {}
|
|
|
|
beforeEach(async () => {
|
|
;({ salesChannel, product } = await breaking(
|
|
async () => {
|
|
const salesChannel = await simpleSalesChannelFactory(dbConnection, {
|
|
name: "test name",
|
|
description: "test description",
|
|
})
|
|
const product = await simpleProductFactory(dbConnection, {
|
|
id: "product_1",
|
|
title: "test title",
|
|
})
|
|
|
|
return { salesChannel, product }
|
|
},
|
|
async () => {
|
|
const salesChannel = await salesChannelService.create({
|
|
name: "test name",
|
|
description: "test description",
|
|
})
|
|
const product = await productService.create({
|
|
title: "test title",
|
|
})
|
|
|
|
return { salesChannel, product }
|
|
}
|
|
))
|
|
})
|
|
|
|
it("should add products to a sales channel", async () => {
|
|
const payload = {
|
|
product_ids: breaking(
|
|
() => [{ id: product.id }],
|
|
() => [product.id]
|
|
),
|
|
}
|
|
|
|
const response = await breaking(
|
|
async () => {
|
|
return await api.post(
|
|
`/admin/sales-channels/${salesChannel.id}/products/batch`,
|
|
payload,
|
|
adminReqConfig
|
|
)
|
|
},
|
|
async () => {
|
|
return await api.post(
|
|
`/admin/sales-channels/${salesChannel.id}/products/batch/add`,
|
|
payload,
|
|
adminReqConfig
|
|
)
|
|
}
|
|
)
|
|
|
|
expect(response.status).toEqual(200)
|
|
expect(response.data.sales_channel).toEqual(
|
|
expect.objectContaining({
|
|
id: expect.any(String),
|
|
name: "test name",
|
|
description: "test description",
|
|
is_disabled: false,
|
|
created_at: expect.any(String),
|
|
updated_at: expect.any(String),
|
|
deleted_at: null,
|
|
})
|
|
)
|
|
|
|
const attachedProduct = await breaking(
|
|
async () => {
|
|
return await dbConnection.manager.findOne(Product, {
|
|
where: { id: product.id },
|
|
relations: ["sales_channels"],
|
|
})
|
|
},
|
|
async () => {
|
|
const [product] = await remoteQuery({
|
|
products: {
|
|
fields: ["id"],
|
|
sales_channels: {
|
|
fields: ["id", "name", "description", "is_disabled"],
|
|
},
|
|
},
|
|
})
|
|
|
|
return product
|
|
}
|
|
)
|
|
|
|
// + default sales channel
|
|
expect(attachedProduct.sales_channels.length).toBe(
|
|
breaking(
|
|
() => 2,
|
|
() => 1 // Comment: The product factory from v1 adds products to the default channel
|
|
)
|
|
)
|
|
expect(attachedProduct.sales_channels).toEqual(
|
|
expect.arrayContaining(
|
|
breaking(
|
|
() => {
|
|
return [
|
|
expect.objectContaining({
|
|
id: expect.any(String),
|
|
name: "test name",
|
|
description: "test description",
|
|
is_disabled: false,
|
|
}),
|
|
expect.objectContaining({
|
|
// Comment: Same as above
|
|
id: expect.any(String),
|
|
is_disabled: false,
|
|
}),
|
|
]
|
|
},
|
|
() => {
|
|
return [
|
|
expect.objectContaining({
|
|
id: expect.any(String),
|
|
name: "test name",
|
|
description: "test description",
|
|
is_disabled: false,
|
|
}),
|
|
]
|
|
}
|
|
)
|
|
)
|
|
)
|
|
})
|
|
})
|
|
|
|
describe("/admin/orders using sales channels", () => {
|
|
describe("GET /admin/orders", () => {
|
|
let order
|
|
|
|
beforeEach(async () => {
|
|
order = await simpleOrderFactory(dbConnection, {
|
|
sales_channel: {
|
|
name: "test name",
|
|
description: "test description",
|
|
},
|
|
})
|
|
await orderSeeder(dbConnection)
|
|
})
|
|
|
|
it("should successfully lists orders that belongs to the requested sales channels", async () => {
|
|
const response = await api.get(
|
|
`/admin/orders?sales_channel_id[]=${order.sales_channel_id}`,
|
|
{
|
|
headers: {
|
|
"x-medusa-access-token": "test_token",
|
|
},
|
|
}
|
|
)
|
|
|
|
expect(response.status).toEqual(200)
|
|
expect(response.data.orders.length).toEqual(1)
|
|
expect(response.data.orders).toEqual(
|
|
expect.arrayContaining([
|
|
expect.objectContaining({
|
|
id: order.id,
|
|
}),
|
|
])
|
|
)
|
|
})
|
|
})
|
|
})
|
|
|
|
describe("/admin/products using sales channels", () => {
|
|
describe("GET /admin/products", () => {
|
|
const productData = {
|
|
id: "product-sales-channel-1",
|
|
title: "test description",
|
|
}
|
|
let salesChannel
|
|
|
|
beforeEach(async () => {
|
|
await productSeeder(dbConnection)
|
|
const product = await simpleProductFactory(dbConnection, productData)
|
|
salesChannel = await simpleSalesChannelFactory(dbConnection, {
|
|
name: "test name",
|
|
description: "test description",
|
|
products: [product],
|
|
})
|
|
})
|
|
|
|
it("should returns a list of products that belongs to the requested sales channels", async () => {
|
|
const response = await api
|
|
.get(`/admin/products?sales_channel_id[]=${salesChannel.id}`, {
|
|
headers: {
|
|
"x-medusa-access-token": "test_token",
|
|
},
|
|
})
|
|
.catch((err) => {
|
|
console.log(err)
|
|
})
|
|
|
|
expect(response.status).toEqual(200)
|
|
expect(response.data.products.length).toEqual(1)
|
|
expect(response.data.products).toEqual(
|
|
expect.arrayContaining([
|
|
expect.objectContaining({
|
|
id: productData.id,
|
|
title: productData.title,
|
|
}),
|
|
])
|
|
)
|
|
})
|
|
})
|
|
|
|
describe("POST /admin/products", () => {
|
|
let salesChannel
|
|
|
|
beforeEach(async () => {
|
|
await productSeeder(dbConnection)
|
|
salesChannel = await simpleSalesChannelFactory(dbConnection, {
|
|
name: "test name",
|
|
description: "test description",
|
|
is_default: true,
|
|
})
|
|
})
|
|
|
|
it("should creates a product that is assigned to a sales_channel", async () => {
|
|
const payload = {
|
|
title: "Test",
|
|
description: "test-product-description",
|
|
type: { value: "test-type" },
|
|
options: [{ title: "size" }, { title: "color" }],
|
|
variants: [
|
|
{
|
|
title: "Test variant",
|
|
inventory_quantity: 10,
|
|
prices: [{ currency_code: "usd", amount: 100 }],
|
|
options: [{ value: "large" }, { value: "green" }],
|
|
},
|
|
],
|
|
sales_channels: [{ id: salesChannel.id }],
|
|
}
|
|
|
|
const response = await api
|
|
.post("/admin/products", payload, {
|
|
headers: {
|
|
"x-medusa-access-token": "test_token",
|
|
},
|
|
})
|
|
.catch((err) => {
|
|
console.log(err)
|
|
})
|
|
|
|
expect(response.status).toEqual(200)
|
|
expect(response.data.product).toEqual(
|
|
expect.objectContaining({
|
|
sales_channels: [
|
|
expect.objectContaining({
|
|
id: salesChannel.id,
|
|
name: salesChannel.name,
|
|
}),
|
|
],
|
|
})
|
|
)
|
|
})
|
|
|
|
it("should assign the default sales channel to a product if none is provided when creating it", async () => {
|
|
const payload = {
|
|
title: "Product-no-saleschannel",
|
|
description: "test-product-description",
|
|
type: { value: "test-type" },
|
|
options: [{ title: "size" }],
|
|
variants: [
|
|
{
|
|
title: "Test variant",
|
|
inventory_quantity: 10,
|
|
prices: [{ currency_code: "usd", amount: 100 }],
|
|
options: [{ value: "large" }],
|
|
},
|
|
],
|
|
}
|
|
|
|
const response = await api
|
|
.post("/admin/products", payload, {
|
|
headers: {
|
|
"x-medusa-access-token": "test_token",
|
|
},
|
|
})
|
|
.catch((err) => {
|
|
console.log(err)
|
|
})
|
|
|
|
expect(response.status).toEqual(200)
|
|
expect(response.data.product).toEqual(
|
|
expect.objectContaining({
|
|
sales_channels: [
|
|
expect.objectContaining({
|
|
id: salesChannel.id,
|
|
name: salesChannel.name,
|
|
}),
|
|
],
|
|
})
|
|
)
|
|
})
|
|
})
|
|
|
|
describe("POST /admin/products/:id", () => {
|
|
let salesChannel
|
|
|
|
beforeEach(async () => {
|
|
await productSeeder(dbConnection)
|
|
salesChannel = await simpleSalesChannelFactory(dbConnection, {
|
|
name: "test name",
|
|
description: "test description",
|
|
})
|
|
})
|
|
|
|
it("should update a product sales channels assignation with either a sales channel, null, [] or undefined", async () => {
|
|
let response = await api
|
|
.post(
|
|
"/admin/products/test-product",
|
|
{
|
|
sales_channels: null,
|
|
},
|
|
{
|
|
headers: {
|
|
"x-medusa-access-token": "test_token",
|
|
},
|
|
}
|
|
)
|
|
.catch((err) => {
|
|
console.log(err)
|
|
})
|
|
|
|
expect(response.status).toEqual(200)
|
|
expect(response.data.product).toEqual(
|
|
expect.objectContaining({
|
|
sales_channels: [],
|
|
})
|
|
)
|
|
|
|
response = await api
|
|
.post(
|
|
"/admin/products/test-product",
|
|
{
|
|
sales_channels: [{ id: salesChannel.id }],
|
|
},
|
|
{
|
|
headers: {
|
|
"x-medusa-access-token": "test_token",
|
|
},
|
|
}
|
|
)
|
|
.catch((err) => {
|
|
console.log(err)
|
|
})
|
|
|
|
expect(response.status).toEqual(200)
|
|
expect(response.data.product).toEqual(
|
|
expect.objectContaining({
|
|
sales_channels: [
|
|
expect.objectContaining({
|
|
id: salesChannel.id,
|
|
name: salesChannel.name,
|
|
}),
|
|
],
|
|
})
|
|
)
|
|
|
|
response = await api
|
|
.post(
|
|
"/admin/products/test-product",
|
|
{},
|
|
{
|
|
headers: {
|
|
"x-medusa-access-token": "test_token",
|
|
},
|
|
}
|
|
)
|
|
.catch((err) => {
|
|
console.log(err)
|
|
})
|
|
|
|
expect(response.status).toEqual(200)
|
|
expect(response.data.product).toEqual(
|
|
expect.objectContaining({
|
|
sales_channels: [
|
|
expect.objectContaining({
|
|
id: salesChannel.id,
|
|
name: salesChannel.name,
|
|
}),
|
|
],
|
|
})
|
|
)
|
|
|
|
response = await api
|
|
.post(
|
|
"/admin/products/test-product",
|
|
{
|
|
sales_channels: [],
|
|
},
|
|
{
|
|
headers: {
|
|
"x-medusa-access-token": "test_token",
|
|
},
|
|
}
|
|
)
|
|
.catch((err) => {
|
|
console.log(err)
|
|
})
|
|
|
|
expect(response.status).toEqual(200)
|
|
expect(response.data.product).toEqual(
|
|
expect.objectContaining({
|
|
sales_channels: [],
|
|
})
|
|
)
|
|
})
|
|
|
|
it("should throw on update if the sales channels does not exists", async () => {
|
|
const err = await api
|
|
.post(
|
|
"/admin/products/test-product",
|
|
{
|
|
sales_channels: [{ id: "fake_id" }, { id: "fake_id_2" }],
|
|
},
|
|
{
|
|
headers: {
|
|
"x-medusa-access-token": "test_token",
|
|
},
|
|
}
|
|
)
|
|
.catch((err) => err)
|
|
|
|
expect(err.response.status).toEqual(400)
|
|
expect(err.response.data.message).toBe(
|
|
"Provided request body contains errors. Please check the data and retry the request"
|
|
)
|
|
expect(err.response.data.errors).toEqual([
|
|
"Sales Channels fake_id, fake_id_2 do not exist",
|
|
])
|
|
})
|
|
})
|
|
})
|
|
},
|
|
})
|