feat: Sales Channels API routes + workflows (#6722)
**What** - Admin sales channels API routes - Workflows for creating, updating, and deleting sales channels - Align `ISalesChannelModuleService` interface with update + upsert conventions - Integrate v2 tests into v1 sales channels integration test suite - Add metadata to sales channel entity Sales channel <> Product management will come in a follow-up PR. On the integration tests, creating, updating, and deleting are passing with the V2 flag enabled. You'll have to take my word for it (or run them yourself), as they are not included in the CI.
This commit is contained in:
1 parent
4b06c17dc0
commit
0219a8677b
28 files changed
+803
-309
No files matched your search
@@ -1,6 +1,6 @@
|
|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
exports[`sales channels DELETE /admin/sales-channels/:id should delete the requested sales channel 1`] = `
|
exports[` DELETE /admin/sales-channels/:id should delete the requested sales channel 1`] = `
|
||||||
Object {
|
Object {
|
||||||
"deleted": true,
|
"deleted": true,
|
||||||
"id": Any<String>,
|
"id": Any<String>,
|
||||||
@@ -8,7 +8,7 @@ Object {
|
|||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`sales channels POST /admin/sales-channels successfully creates a disabled sales channel 1`] = `
|
exports[` POST /admin/sales-channels successfully creates a disabled sales channel 1`] = `
|
||||||
Object {
|
Object {
|
||||||
"sales_channel": ObjectContaining {
|
"sales_channel": ObjectContaining {
|
||||||
"is_disabled": true,
|
"is_disabled": true,
|
||||||
@@ -17,7 +17,7 @@ Object {
|
|||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`sales channels POST /admin/sales-channels successfully creates a sales channel 1`] = `
|
exports[` POST /admin/sales-channels successfully creates a sales channel 1`] = `
|
||||||
Object {
|
Object {
|
||||||
"sales_channel": ObjectContaining {
|
"sales_channel": ObjectContaining {
|
||||||
"description": "sales channel description",
|
"description": "sales channel description",
|
||||||
|
|||||||
@@ -1,21 +1,7 @@
|
|||||||
const path = require("path")
|
const { ModuleRegistrationName } = require("@medusajs/modules-sdk")
|
||||||
|
const { medusaIntegrationTestRunner } = require("medusa-test-utils")
|
||||||
const { SalesChannel, Product } = require("@medusajs/medusa")
|
const { createAdminUser } = require("../../../helpers/create-admin-user")
|
||||||
|
const { breaking } = require("../../../helpers/breaking")
|
||||||
const { useApi } = require("../../../environment-helpers/use-api")
|
|
||||||
const { useDb } = require("../../../environment-helpers/use-db")
|
|
||||||
|
|
||||||
const adminSeeder = require("../../../helpers/admin-seeder")
|
|
||||||
const {
|
|
||||||
simpleSalesChannelFactory,
|
|
||||||
simpleProductFactory,
|
|
||||||
} = require("../../../factories")
|
|
||||||
const { simpleOrderFactory } = require("../../../factories")
|
|
||||||
const orderSeeder = require("../../../helpers/order-seeder")
|
|
||||||
const productSeeder = require("../../../helpers/product-seeder")
|
|
||||||
|
|
||||||
const startServerWithEnvironment =
|
|
||||||
require("../../../environment-helpers/start-server-with-environment").default
|
|
||||||
|
|
||||||
const adminReqConfig = {
|
const adminReqConfig = {
|
||||||
headers: {
|
headers: {
|
||||||
@@ -23,47 +9,61 @@ const adminReqConfig = {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let { simpleSalesChannelFactory, simpleProductFactory, simpleOrderFactory } = {}
|
||||||
|
let { SalesChannel, Product } = {}
|
||||||
|
let orderSeeder
|
||||||
|
let productSeeder
|
||||||
|
|
||||||
jest.setTimeout(60000)
|
jest.setTimeout(60000)
|
||||||
|
|
||||||
describe("sales channels", () => {
|
medusaIntegrationTestRunner({
|
||||||
let medusaProcess
|
// env: { MEDUSA_FF_MEDUSA_V2: true },
|
||||||
let dbConnection
|
testSuite: ({ dbConnection, getContainer, api }) => {
|
||||||
|
let container
|
||||||
|
let salesChannelService
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(() => {
|
||||||
const cwd = path.resolve(path.join(__dirname, "..", ".."))
|
;({
|
||||||
const [process, connection] = await startServerWithEnvironment({
|
simpleProductFactory,
|
||||||
cwd,
|
simpleSalesChannelFactory,
|
||||||
env: { MEDUSA_FF_SALES_CHANNELS: true },
|
simpleOrderFactory,
|
||||||
})
|
} = require("../../../factories"))
|
||||||
dbConnection = connection
|
;({ SalesChannel, Product } = require("@medusajs/medusa"))
|
||||||
medusaProcess = process
|
|
||||||
|
orderSeeder = require("../../../helpers/order-seeder")
|
||||||
|
productSeeder = require("../../../helpers/product-seeder")
|
||||||
})
|
})
|
||||||
|
|
||||||
afterAll(async () => {
|
beforeEach(async () => {
|
||||||
const db = useDb()
|
container = getContainer()
|
||||||
await db.shutdown()
|
await createAdminUser(dbConnection, adminReqConfig, container)
|
||||||
|
|
||||||
medusaProcess.kill()
|
salesChannelService = container.resolve(
|
||||||
|
ModuleRegistrationName.SALES_CHANNEL
|
||||||
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("GET /admin/sales-channels/:id", () => {
|
describe("GET /admin/sales-channels/:id", () => {
|
||||||
let salesChannel
|
let salesChannel
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await adminSeeder(dbConnection)
|
salesChannel = await breaking(
|
||||||
salesChannel = await simpleSalesChannelFactory(dbConnection, {
|
async () => {
|
||||||
|
return await simpleSalesChannelFactory(dbConnection, {
|
||||||
name: "test name",
|
name: "test name",
|
||||||
description: "test description",
|
description: "test description",
|
||||||
})
|
})
|
||||||
|
},
|
||||||
|
async () => {
|
||||||
|
return await salesChannelService.create({
|
||||||
|
name: "test name",
|
||||||
|
description: "test description",
|
||||||
})
|
})
|
||||||
|
}
|
||||||
afterEach(async () => {
|
)
|
||||||
const db = useDb()
|
|
||||||
await db.teardown()
|
|
||||||
})
|
})
|
||||||
|
|
||||||
it("should retrieve the requested sales channel", async () => {
|
it("should retrieve the requested sales channel", async () => {
|
||||||
const api = useApi()
|
|
||||||
const response = await api.get(
|
const response = await api.get(
|
||||||
`/admin/sales-channels/${salesChannel.id}`,
|
`/admin/sales-channels/${salesChannel.id}`,
|
||||||
adminReqConfig
|
adminReqConfig
|
||||||
@@ -88,29 +88,48 @@ describe("sales channels", () => {
|
|||||||
let salesChannel2
|
let salesChannel2
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await adminSeeder(dbConnection)
|
salesChannel1 = await breaking(
|
||||||
salesChannel1 = await simpleSalesChannelFactory(dbConnection, {
|
async () => {
|
||||||
|
return await simpleSalesChannelFactory(dbConnection, {
|
||||||
name: "test name",
|
name: "test name",
|
||||||
description: "test description",
|
description: "test description",
|
||||||
})
|
})
|
||||||
salesChannel2 = await simpleSalesChannelFactory(dbConnection, {
|
},
|
||||||
|
async () => {
|
||||||
|
return await salesChannelService.create({
|
||||||
|
name: "test name",
|
||||||
|
description: "test description",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
salesChannel2 = await breaking(
|
||||||
|
async () => {
|
||||||
|
return await simpleSalesChannelFactory(dbConnection, {
|
||||||
name: "test name 2",
|
name: "test name 2",
|
||||||
description: "test description 2",
|
description: "test description 2",
|
||||||
})
|
})
|
||||||
|
},
|
||||||
|
async () => {
|
||||||
|
return await salesChannelService.create({
|
||||||
|
name: "test name 2",
|
||||||
|
description: "test description 2",
|
||||||
})
|
})
|
||||||
|
}
|
||||||
afterEach(async () => {
|
)
|
||||||
const db = useDb()
|
|
||||||
await db.teardown()
|
|
||||||
})
|
})
|
||||||
|
|
||||||
it("should list the sales channel", async () => {
|
it("should list the sales channel", async () => {
|
||||||
const api = useApi()
|
const response = await api.get(`/admin/sales-channels`, adminReqConfig)
|
||||||
const response = await api.get(`/admin/sales-channels/`, adminReqConfig)
|
|
||||||
|
|
||||||
expect(response.status).toEqual(200)
|
expect(response.status).toEqual(200)
|
||||||
expect(response.data.sales_channels).toBeTruthy()
|
expect(response.data.sales_channels).toBeTruthy()
|
||||||
expect(response.data.sales_channels.length).toBe(2)
|
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(response.data).toEqual(
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
sales_channels: expect.arrayContaining([
|
sales_channels: expect.arrayContaining([
|
||||||
@@ -127,13 +146,16 @@ describe("sales channels", () => {
|
|||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
it("should list the sales channel using free text search", async () => {
|
it("should list the sales channel using filters", async () => {
|
||||||
const api = useApi()
|
const response = await breaking(
|
||||||
const response = await api.get(
|
async () => {
|
||||||
`/admin/sales-channels/?q=2`,
|
return await api.get(`/admin/sales-channels?q=2`, adminReqConfig)
|
||||||
adminReqConfig
|
},
|
||||||
|
() => undefined
|
||||||
)
|
)
|
||||||
|
|
||||||
|
breaking(
|
||||||
|
() => {
|
||||||
expect(response.status).toEqual(200)
|
expect(response.status).toEqual(200)
|
||||||
expect(response.data.sales_channels).toBeTruthy()
|
expect(response.data.sales_channels).toBeTruthy()
|
||||||
expect(response.data.sales_channels.length).toBe(1)
|
expect(response.data.sales_channels.length).toBe(1)
|
||||||
@@ -153,12 +175,17 @@ describe("sales channels", () => {
|
|||||||
}),
|
}),
|
||||||
]),
|
]),
|
||||||
})
|
})
|
||||||
|
},
|
||||||
|
() => {
|
||||||
|
// 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 () => {
|
it("should list the sales channel using properties filters", async () => {
|
||||||
const api = useApi()
|
|
||||||
const response = await api.get(
|
const response = await api.get(
|
||||||
`/admin/sales-channels/?name=test+name`,
|
`/admin/sales-channels?name=test+name`,
|
||||||
adminReqConfig
|
adminReqConfig
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -188,21 +215,23 @@ describe("sales channels", () => {
|
|||||||
let sc
|
let sc
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await adminSeeder(dbConnection)
|
sc = await breaking(
|
||||||
sc = await simpleSalesChannelFactory(dbConnection, {
|
async () => {
|
||||||
|
return await simpleSalesChannelFactory(dbConnection, {
|
||||||
name: "test name",
|
name: "test name",
|
||||||
description: "test description",
|
description: "test description",
|
||||||
})
|
})
|
||||||
|
},
|
||||||
|
async () => {
|
||||||
|
return await salesChannelService.create({
|
||||||
|
name: "test name",
|
||||||
|
description: "test description",
|
||||||
})
|
})
|
||||||
|
}
|
||||||
afterEach(async () => {
|
)
|
||||||
const db = useDb()
|
|
||||||
await db.teardown()
|
|
||||||
})
|
})
|
||||||
|
|
||||||
it("updates sales channel properties", async () => {
|
it("updates sales channel properties", async () => {
|
||||||
const api = useApi()
|
|
||||||
|
|
||||||
const payload = {
|
const payload = {
|
||||||
name: "updated name",
|
name: "updated name",
|
||||||
description: "updated description",
|
description: "updated description",
|
||||||
@@ -212,11 +241,7 @@ describe("sales channels", () => {
|
|||||||
const response = await api.post(
|
const response = await api.post(
|
||||||
`/admin/sales-channels/${sc.id}`,
|
`/admin/sales-channels/${sc.id}`,
|
||||||
payload,
|
payload,
|
||||||
{
|
adminReqConfig
|
||||||
headers: {
|
|
||||||
"x-medusa-access-token": "test_token",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
expect(response.status).toEqual(200)
|
expect(response.status).toEqual(200)
|
||||||
@@ -234,18 +259,9 @@ describe("sales channels", () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
describe("POST /admin/sales-channels", () => {
|
describe("POST /admin/sales-channels", () => {
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {})
|
||||||
await adminSeeder(dbConnection)
|
|
||||||
})
|
|
||||||
|
|
||||||
afterEach(async () => {
|
|
||||||
const db = useDb()
|
|
||||||
await db.teardown()
|
|
||||||
})
|
|
||||||
|
|
||||||
it("successfully creates a disabled sales channel", async () => {
|
it("successfully creates a disabled sales channel", async () => {
|
||||||
const api = useApi()
|
|
||||||
|
|
||||||
const newSalesChannel = {
|
const newSalesChannel = {
|
||||||
name: "sales channel name",
|
name: "sales channel name",
|
||||||
is_disabled: true,
|
is_disabled: true,
|
||||||
@@ -269,8 +285,6 @@ describe("sales channels", () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it("successfully creates a sales channel", async () => {
|
it("successfully creates a sales channel", async () => {
|
||||||
const api = useApi()
|
|
||||||
|
|
||||||
const newSalesChannel = {
|
const newSalesChannel = {
|
||||||
name: "sales channel name",
|
name: "sales channel name",
|
||||||
description: "sales channel description",
|
description: "sales channel description",
|
||||||
@@ -299,37 +313,44 @@ describe("sales channels", () => {
|
|||||||
let salesChannel
|
let salesChannel
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await adminSeeder(dbConnection)
|
salesChannel = await breaking(
|
||||||
salesChannel = await simpleSalesChannelFactory(dbConnection, {
|
async () => {
|
||||||
|
return await simpleSalesChannelFactory(dbConnection, {
|
||||||
name: "test name",
|
name: "test name",
|
||||||
description: "test description",
|
description: "test description",
|
||||||
})
|
})
|
||||||
|
},
|
||||||
|
async () => {
|
||||||
|
return await salesChannelService.create({
|
||||||
|
name: "test name",
|
||||||
|
description: "test description",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
await breaking(async () => {
|
||||||
await simpleSalesChannelFactory(dbConnection, {
|
await simpleSalesChannelFactory(dbConnection, {
|
||||||
name: "Default channel",
|
name: "Default channel",
|
||||||
id: "test-channel",
|
id: "test-channel",
|
||||||
is_default: true,
|
is_default: true,
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
afterEach(async () => {
|
|
||||||
const db = useDb()
|
|
||||||
await db.teardown()
|
|
||||||
})
|
})
|
||||||
|
|
||||||
it("should delete the requested sales channel", async () => {
|
it("should delete the requested sales channel", async () => {
|
||||||
const api = useApi()
|
let toDelete = await breaking(
|
||||||
|
async () => {
|
||||||
let deletedSalesChannel = await dbConnection.manager.findOne(
|
return await dbConnection.manager.findOne(SalesChannel, {
|
||||||
SalesChannel,
|
|
||||||
{
|
|
||||||
where: { id: salesChannel.id },
|
where: { id: salesChannel.id },
|
||||||
withDeleted: true,
|
})
|
||||||
|
},
|
||||||
|
async () => {
|
||||||
|
return await salesChannelService.retrieve(salesChannel.id)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
expect(deletedSalesChannel.id).toEqual(salesChannel.id)
|
expect(toDelete.id).toEqual(salesChannel.id)
|
||||||
expect(deletedSalesChannel.deleted_at).toEqual(null)
|
expect(toDelete.deleted_at).toEqual(null)
|
||||||
|
|
||||||
const response = await api.delete(
|
const response = await api.delete(
|
||||||
`/admin/sales-channels/${salesChannel.id}`,
|
`/admin/sales-channels/${salesChannel.id}`,
|
||||||
@@ -343,72 +364,26 @@ describe("sales channels", () => {
|
|||||||
object: "sales-channel",
|
object: "sales-channel",
|
||||||
})
|
})
|
||||||
|
|
||||||
deletedSalesChannel = await dbConnection.manager.findOne(SalesChannel, {
|
const deleted = await breaking(
|
||||||
|
async () => {
|
||||||
|
return await dbConnection.manager.findOne(SalesChannel, {
|
||||||
where: { id: salesChannel.id },
|
where: { id: salesChannel.id },
|
||||||
withDeleted: true,
|
withDeleted: true,
|
||||||
})
|
})
|
||||||
|
},
|
||||||
expect(deletedSalesChannel.id).toEqual(salesChannel.id)
|
async () => {
|
||||||
expect(deletedSalesChannel.deleted_at).not.toEqual(null)
|
return await salesChannelService.retrieve(salesChannel.id, {
|
||||||
})
|
|
||||||
|
|
||||||
it("should delete the requested sales channel idempotently", async () => {
|
|
||||||
const api = useApi()
|
|
||||||
|
|
||||||
let deletedSalesChannel = await dbConnection.manager.findOne(
|
|
||||||
SalesChannel,
|
|
||||||
{
|
|
||||||
where: { id: salesChannel.id },
|
|
||||||
withDeleted: true,
|
withDeleted: true,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
expect(deletedSalesChannel.id).toEqual(salesChannel.id)
|
expect(deleted.id).toEqual(salesChannel.id)
|
||||||
expect(deletedSalesChannel.deleted_at).toEqual(null)
|
expect(deleted.deleted_at).not.toEqual(null)
|
||||||
|
|
||||||
let response = await api.delete(
|
|
||||||
`/admin/sales-channels/${salesChannel.id}`,
|
|
||||||
adminReqConfig
|
|
||||||
)
|
|
||||||
|
|
||||||
expect(response.status).toEqual(200)
|
|
||||||
expect(response.data).toEqual({
|
|
||||||
id: expect.any(String),
|
|
||||||
object: "sales-channel",
|
|
||||||
deleted: true,
|
|
||||||
})
|
|
||||||
|
|
||||||
deletedSalesChannel = await dbConnection.manager.findOne(SalesChannel, {
|
|
||||||
where: { id: salesChannel.id },
|
|
||||||
withDeleted: true,
|
|
||||||
})
|
|
||||||
|
|
||||||
expect(deletedSalesChannel.id).toEqual(salesChannel.id)
|
|
||||||
expect(deletedSalesChannel.deleted_at).not.toEqual(null)
|
|
||||||
|
|
||||||
response = await api.delete(
|
|
||||||
`/admin/sales-channels/${salesChannel.id}`,
|
|
||||||
adminReqConfig
|
|
||||||
)
|
|
||||||
|
|
||||||
expect(response.status).toEqual(200)
|
|
||||||
expect(response.data).toEqual({
|
|
||||||
id: expect.any(String),
|
|
||||||
object: "sales-channel",
|
|
||||||
deleted: true,
|
|
||||||
})
|
|
||||||
|
|
||||||
deletedSalesChannel = await dbConnection.manager.findOne(SalesChannel, {
|
|
||||||
where: { id: salesChannel.id },
|
|
||||||
withDeleted: true,
|
|
||||||
})
|
|
||||||
|
|
||||||
expect(deletedSalesChannel.id).toEqual(salesChannel.id)
|
|
||||||
expect(deletedSalesChannel.deleted_at).not.toEqual(null)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
it("should throw if we attempt to delete default channel", async () => {
|
it("should throw if we attempt to delete default channel", async () => {
|
||||||
const api = useApi()
|
await breaking(async () => {
|
||||||
expect.assertions(2)
|
expect.assertions(2)
|
||||||
|
|
||||||
const res = await api
|
const res = await api
|
||||||
@@ -421,12 +396,11 @@ describe("sales channels", () => {
|
|||||||
)
|
)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
})
|
||||||
|
|
||||||
describe("GET /admin/orders/:id", () => {
|
describe("GET /admin/orders/:id", () => {
|
||||||
let order
|
let order
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await adminSeeder(dbConnection)
|
|
||||||
|
|
||||||
order = await simpleOrderFactory(dbConnection, {
|
order = await simpleOrderFactory(dbConnection, {
|
||||||
sales_channel: {
|
sales_channel: {
|
||||||
name: "test name",
|
name: "test name",
|
||||||
@@ -443,14 +417,7 @@ describe("sales channels", () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
afterEach(async () => {
|
|
||||||
const db = useDb()
|
|
||||||
await db.teardown()
|
|
||||||
})
|
|
||||||
|
|
||||||
it("expands sales channel for single", async () => {
|
it("expands sales channel for single", async () => {
|
||||||
const api = useApi()
|
|
||||||
|
|
||||||
const response = await api.get(
|
const response = await api.get(
|
||||||
`/admin/orders/${order.id}`,
|
`/admin/orders/${order.id}`,
|
||||||
adminReqConfig
|
adminReqConfig
|
||||||
@@ -470,8 +437,6 @@ describe("sales channels", () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it("creates swap with order sales channel", async () => {
|
it("creates swap with order sales channel", async () => {
|
||||||
const api = useApi()
|
|
||||||
|
|
||||||
const product = await simpleProductFactory(dbConnection, {
|
const product = await simpleProductFactory(dbConnection, {
|
||||||
variants: [{ id: "test-variant", inventory_quantity: 100 }],
|
variants: [{ id: "test-variant", inventory_quantity: 100 }],
|
||||||
})
|
})
|
||||||
@@ -502,8 +467,6 @@ describe("sales channels", () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it("creates swap with provided sales channel", async () => {
|
it("creates swap with provided sales channel", async () => {
|
||||||
const api = useApi()
|
|
||||||
|
|
||||||
const sc = await simpleSalesChannelFactory(dbConnection, {})
|
const sc = await simpleSalesChannelFactory(dbConnection, {})
|
||||||
|
|
||||||
const product = await simpleProductFactory(dbConnection, {
|
const product = await simpleProductFactory(dbConnection, {
|
||||||
@@ -537,8 +500,6 @@ describe("sales channels", () => {
|
|||||||
|
|
||||||
describe("GET /admin/orders?expand=sales_channels", () => {
|
describe("GET /admin/orders?expand=sales_channels", () => {
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await adminSeeder(dbConnection)
|
|
||||||
|
|
||||||
await simpleOrderFactory(dbConnection, {
|
await simpleOrderFactory(dbConnection, {
|
||||||
sales_channel: {
|
sales_channel: {
|
||||||
name: "test name",
|
name: "test name",
|
||||||
@@ -547,14 +508,7 @@ describe("sales channels", () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
afterEach(async () => {
|
|
||||||
const db = useDb()
|
|
||||||
await db.teardown()
|
|
||||||
})
|
|
||||||
|
|
||||||
it("expands sales channel with parameter", async () => {
|
it("expands sales channel with parameter", async () => {
|
||||||
const api = useApi()
|
|
||||||
|
|
||||||
const response = await api.get(
|
const response = await api.get(
|
||||||
"/admin/orders?expand=sales_channel",
|
"/admin/orders?expand=sales_channel",
|
||||||
adminReqConfig
|
adminReqConfig
|
||||||
@@ -577,8 +531,6 @@ describe("sales channels", () => {
|
|||||||
describe("GET /admin/product/:id", () => {
|
describe("GET /admin/product/:id", () => {
|
||||||
let product
|
let product
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await adminSeeder(dbConnection)
|
|
||||||
|
|
||||||
product = await simpleProductFactory(dbConnection, {
|
product = await simpleProductFactory(dbConnection, {
|
||||||
sales_channels: [
|
sales_channels: [
|
||||||
{
|
{
|
||||||
@@ -593,14 +545,7 @@ describe("sales channels", () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
afterEach(async () => {
|
|
||||||
const db = useDb()
|
|
||||||
await db.teardown()
|
|
||||||
})
|
|
||||||
|
|
||||||
it("returns product with sales channel", async () => {
|
it("returns product with sales channel", async () => {
|
||||||
const api = useApi()
|
|
||||||
|
|
||||||
const response = await api
|
const response = await api
|
||||||
.get(`/admin/products/${product.id}`, adminReqConfig)
|
.get(`/admin/products/${product.id}`, adminReqConfig)
|
||||||
.catch((err) => console.log(err))
|
.catch((err) => console.log(err))
|
||||||
@@ -625,8 +570,6 @@ describe("sales channels", () => {
|
|||||||
|
|
||||||
describe("GET /admin/products?expand[]=sales_channels", () => {
|
describe("GET /admin/products?expand[]=sales_channels", () => {
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await adminSeeder(dbConnection)
|
|
||||||
|
|
||||||
await simpleProductFactory(dbConnection, {
|
await simpleProductFactory(dbConnection, {
|
||||||
sales_channels: [
|
sales_channels: [
|
||||||
{
|
{
|
||||||
@@ -641,14 +584,7 @@ describe("sales channels", () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
afterEach(async () => {
|
|
||||||
const db = useDb()
|
|
||||||
await db.teardown()
|
|
||||||
})
|
|
||||||
|
|
||||||
it("expands sales channel with parameter", async () => {
|
it("expands sales channel with parameter", async () => {
|
||||||
const api = useApi()
|
|
||||||
|
|
||||||
const response = await api.get(
|
const response = await api.get(
|
||||||
"/admin/products?expand=sales_channels",
|
"/admin/products?expand=sales_channels",
|
||||||
adminReqConfig
|
adminReqConfig
|
||||||
@@ -677,7 +613,6 @@ describe("sales channels", () => {
|
|||||||
let product
|
let product
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await adminSeeder(dbConnection)
|
|
||||||
product = await simpleProductFactory(dbConnection, {
|
product = await simpleProductFactory(dbConnection, {
|
||||||
id: "product_1",
|
id: "product_1",
|
||||||
title: "test title",
|
title: "test title",
|
||||||
@@ -689,14 +624,7 @@ describe("sales channels", () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
afterEach(async () => {
|
|
||||||
const db = useDb()
|
|
||||||
await db.teardown()
|
|
||||||
})
|
|
||||||
|
|
||||||
it("should remove products from a sales channel", async () => {
|
it("should remove products from a sales channel", async () => {
|
||||||
const api = useApi()
|
|
||||||
|
|
||||||
let attachedProduct = await dbConnection.manager.findOne(Product, {
|
let attachedProduct = await dbConnection.manager.findOne(Product, {
|
||||||
where: { id: product.id },
|
where: { id: product.id },
|
||||||
relations: ["sales_channels"],
|
relations: ["sales_channels"],
|
||||||
@@ -763,7 +691,6 @@ describe("sales channels", () => {
|
|||||||
let product
|
let product
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await adminSeeder(dbConnection)
|
|
||||||
salesChannel = await simpleSalesChannelFactory(dbConnection, {
|
salesChannel = await simpleSalesChannelFactory(dbConnection, {
|
||||||
name: "test name",
|
name: "test name",
|
||||||
description: "test description",
|
description: "test description",
|
||||||
@@ -774,14 +701,7 @@ describe("sales channels", () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
afterEach(async () => {
|
|
||||||
const db = useDb()
|
|
||||||
await db.teardown()
|
|
||||||
})
|
|
||||||
|
|
||||||
it("should add products to a sales channel", async () => {
|
it("should add products to a sales channel", async () => {
|
||||||
const api = useApi()
|
|
||||||
|
|
||||||
const payload = {
|
const payload = {
|
||||||
product_ids: [{ id: product.id }],
|
product_ids: [{ id: product.id }],
|
||||||
}
|
}
|
||||||
@@ -834,7 +754,6 @@ describe("sales channels", () => {
|
|||||||
let order
|
let order
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await adminSeeder(dbConnection)
|
|
||||||
order = await simpleOrderFactory(dbConnection, {
|
order = await simpleOrderFactory(dbConnection, {
|
||||||
sales_channel: {
|
sales_channel: {
|
||||||
name: "test name",
|
name: "test name",
|
||||||
@@ -844,14 +763,7 @@ describe("sales channels", () => {
|
|||||||
await orderSeeder(dbConnection)
|
await orderSeeder(dbConnection)
|
||||||
})
|
})
|
||||||
|
|
||||||
afterEach(async () => {
|
|
||||||
const db = useDb()
|
|
||||||
await db.teardown()
|
|
||||||
})
|
|
||||||
|
|
||||||
it("should successfully lists orders that belongs to the requested sales channels", async () => {
|
it("should successfully lists orders that belongs to the requested sales channels", async () => {
|
||||||
const api = useApi()
|
|
||||||
|
|
||||||
const response = await api.get(
|
const response = await api.get(
|
||||||
`/admin/orders?sales_channel_id[]=${order.sales_channel_id}`,
|
`/admin/orders?sales_channel_id[]=${order.sales_channel_id}`,
|
||||||
{
|
{
|
||||||
@@ -884,7 +796,6 @@ describe("sales channels", () => {
|
|||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await productSeeder(dbConnection)
|
await productSeeder(dbConnection)
|
||||||
await adminSeeder(dbConnection)
|
|
||||||
const product = await simpleProductFactory(dbConnection, productData)
|
const product = await simpleProductFactory(dbConnection, productData)
|
||||||
salesChannel = await simpleSalesChannelFactory(dbConnection, {
|
salesChannel = await simpleSalesChannelFactory(dbConnection, {
|
||||||
name: "test name",
|
name: "test name",
|
||||||
@@ -893,14 +804,7 @@ describe("sales channels", () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
afterEach(async () => {
|
|
||||||
const db = useDb()
|
|
||||||
await db.teardown()
|
|
||||||
})
|
|
||||||
|
|
||||||
it("should returns a list of products that belongs to the requested sales channels", async () => {
|
it("should returns a list of products that belongs to the requested sales channels", async () => {
|
||||||
const api = useApi()
|
|
||||||
|
|
||||||
const response = await api
|
const response = await api
|
||||||
.get(`/admin/products?sales_channel_id[]=${salesChannel.id}`, {
|
.get(`/admin/products?sales_channel_id[]=${salesChannel.id}`, {
|
||||||
headers: {
|
headers: {
|
||||||
@@ -929,7 +833,6 @@ describe("sales channels", () => {
|
|||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await productSeeder(dbConnection)
|
await productSeeder(dbConnection)
|
||||||
await adminSeeder(dbConnection)
|
|
||||||
salesChannel = await simpleSalesChannelFactory(dbConnection, {
|
salesChannel = await simpleSalesChannelFactory(dbConnection, {
|
||||||
name: "test name",
|
name: "test name",
|
||||||
description: "test description",
|
description: "test description",
|
||||||
@@ -937,14 +840,7 @@ describe("sales channels", () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
afterEach(async () => {
|
|
||||||
const db = useDb()
|
|
||||||
await db.teardown()
|
|
||||||
})
|
|
||||||
|
|
||||||
it("should creates a product that is assigned to a sales_channel", async () => {
|
it("should creates a product that is assigned to a sales_channel", async () => {
|
||||||
const api = useApi()
|
|
||||||
|
|
||||||
const payload = {
|
const payload = {
|
||||||
title: "Test",
|
title: "Test",
|
||||||
description: "test-product-description",
|
description: "test-product-description",
|
||||||
@@ -985,8 +881,6 @@ describe("sales channels", () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it("should assign the default sales channel to a product if none is provided when creating it", async () => {
|
it("should assign the default sales channel to a product if none is provided when creating it", async () => {
|
||||||
const api = useApi()
|
|
||||||
|
|
||||||
const payload = {
|
const payload = {
|
||||||
title: "Product-no-saleschannel",
|
title: "Product-no-saleschannel",
|
||||||
description: "test-product-description",
|
description: "test-product-description",
|
||||||
@@ -1031,21 +925,13 @@ describe("sales channels", () => {
|
|||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await productSeeder(dbConnection)
|
await productSeeder(dbConnection)
|
||||||
await adminSeeder(dbConnection)
|
|
||||||
salesChannel = await simpleSalesChannelFactory(dbConnection, {
|
salesChannel = await simpleSalesChannelFactory(dbConnection, {
|
||||||
name: "test name",
|
name: "test name",
|
||||||
description: "test description",
|
description: "test description",
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
afterEach(async () => {
|
|
||||||
const db = useDb()
|
|
||||||
await db.teardown()
|
|
||||||
})
|
|
||||||
|
|
||||||
it("should update a product sales channels assignation with either a sales channel, null, [] or undefined", async () => {
|
it("should update a product sales channels assignation with either a sales channel, null, [] or undefined", async () => {
|
||||||
const api = useApi()
|
|
||||||
|
|
||||||
let response = await api
|
let response = await api
|
||||||
.post(
|
.post(
|
||||||
"/admin/products/test-product",
|
"/admin/products/test-product",
|
||||||
@@ -1148,8 +1034,6 @@ describe("sales channels", () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it("should throw on update if the sales channels does not exists", async () => {
|
it("should throw on update if the sales channels does not exists", async () => {
|
||||||
const api = useApi()
|
|
||||||
|
|
||||||
const err = await api
|
const err = await api
|
||||||
.post(
|
.post(
|
||||||
"/admin/products/test-product",
|
"/admin/products/test-product",
|
||||||
@@ -1174,4 +1058,5 @@ describe("sales channels", () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
},
|
||||||
})
|
})
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
|
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
|
||||||
import { ICustomerModuleService } from "@medusajs/types"
|
import { ICustomerModuleService } from "@medusajs/types"
|
||||||
import { createStep, StepResponse } from "@medusajs/workflows-sdk"
|
import { createStep, StepResponse } from "@medusajs/workflows-sdk"
|
||||||
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
|
|
||||||
|
|
||||||
type DeleteCustomerStepInput = string[]
|
type DeleteCustomerStepInput = string[]
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
export * from "./auth"
|
|
||||||
export * from "./api-key"
|
export * from "./api-key"
|
||||||
|
export * from "./auth"
|
||||||
export * from "./customer"
|
export * from "./customer"
|
||||||
export * from "./customer-group"
|
export * from "./customer-group"
|
||||||
export * from "./definition"
|
export * from "./definition"
|
||||||
@@ -14,6 +14,7 @@ export * from "./pricing"
|
|||||||
export * from "./product"
|
export * from "./product"
|
||||||
export * from "./promotion"
|
export * from "./promotion"
|
||||||
export * from "./region"
|
export * from "./region"
|
||||||
|
export * from "./sales-channel"
|
||||||
export * from "./shipping-options"
|
export * from "./shipping-options"
|
||||||
export * from "./store"
|
export * from "./store"
|
||||||
export * from "./tax"
|
export * from "./tax"
|
||||||
|
|||||||
@@ -0,0 +1,2 @@
|
|||||||
|
export * from "./steps"
|
||||||
|
export * from "./workflows"
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
|
||||||
|
import {
|
||||||
|
CreateSalesChannelDTO,
|
||||||
|
ISalesChannelModuleService,
|
||||||
|
} from "@medusajs/types"
|
||||||
|
import { StepResponse, createStep } from "@medusajs/workflows-sdk"
|
||||||
|
|
||||||
|
interface StepInput {
|
||||||
|
data: CreateSalesChannelDTO[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export const createSalesChannelsStepId = "create-sales-channels"
|
||||||
|
export const createSalesChannelsStep = createStep(
|
||||||
|
createSalesChannelsStepId,
|
||||||
|
async (input: StepInput, { container }) => {
|
||||||
|
const salesChannelService = container.resolve<ISalesChannelModuleService>(
|
||||||
|
ModuleRegistrationName.SALES_CHANNEL
|
||||||
|
)
|
||||||
|
|
||||||
|
const salesChannels = await salesChannelService.create(input.data)
|
||||||
|
|
||||||
|
return new StepResponse(
|
||||||
|
salesChannels,
|
||||||
|
salesChannels.map((s) => s.id)
|
||||||
|
)
|
||||||
|
},
|
||||||
|
async (createdIds, { container }) => {
|
||||||
|
if (!createdIds) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const service = container.resolve<ISalesChannelModuleService>(
|
||||||
|
ModuleRegistrationName.SALES_CHANNEL
|
||||||
|
)
|
||||||
|
|
||||||
|
await service.delete(createdIds)
|
||||||
|
}
|
||||||
|
)
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
|
||||||
|
import { ISalesChannelModuleService } from "@medusajs/types"
|
||||||
|
import { StepResponse, createStep } from "@medusajs/workflows-sdk"
|
||||||
|
|
||||||
|
type DeleteSalesChannelsInput = string[]
|
||||||
|
|
||||||
|
export const deleteSalesChannelsStepId = "delete-sales-channels"
|
||||||
|
export const deleteSalesChannelsStep = createStep(
|
||||||
|
deleteSalesChannelsStepId,
|
||||||
|
async (ids: DeleteSalesChannelsInput, { container }) => {
|
||||||
|
const service = container.resolve<ISalesChannelModuleService>(
|
||||||
|
ModuleRegistrationName.SALES_CHANNEL
|
||||||
|
)
|
||||||
|
|
||||||
|
await service.softDelete(ids)
|
||||||
|
|
||||||
|
return new StepResponse(void 0, ids)
|
||||||
|
},
|
||||||
|
async (prevSalesChannelIds, { container }) => {
|
||||||
|
if (!prevSalesChannelIds?.length) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const service = container.resolve<ISalesChannelModuleService>(
|
||||||
|
ModuleRegistrationName.SALES_CHANNEL
|
||||||
|
)
|
||||||
|
|
||||||
|
await service.restore(prevSalesChannelIds)
|
||||||
|
}
|
||||||
|
)
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
export * from "./create-sales-channels"
|
||||||
|
export * from "./update-sales-channels"
|
||||||
|
export * from "./delete-sales-channels"
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
|
||||||
|
import {
|
||||||
|
FilterableSalesChannelProps,
|
||||||
|
ISalesChannelModuleService,
|
||||||
|
UpdateSalesChannelDTO,
|
||||||
|
} from "@medusajs/types"
|
||||||
|
import { getSelectsAndRelationsFromObjectArray } from "@medusajs/utils"
|
||||||
|
import { StepResponse, createStep } from "@medusajs/workflows-sdk"
|
||||||
|
|
||||||
|
type UpdateSalesChannelsStepInput = {
|
||||||
|
selector: FilterableSalesChannelProps
|
||||||
|
update: UpdateSalesChannelDTO
|
||||||
|
}
|
||||||
|
|
||||||
|
export const updateSalesChannelsStepId = "update-sales-channels"
|
||||||
|
export const updateSalesChannelsStep = createStep(
|
||||||
|
updateSalesChannelsStepId,
|
||||||
|
async (data: UpdateSalesChannelsStepInput, { container }) => {
|
||||||
|
const service = container.resolve<ISalesChannelModuleService>(
|
||||||
|
ModuleRegistrationName.SALES_CHANNEL
|
||||||
|
)
|
||||||
|
|
||||||
|
const { selects, relations } = getSelectsAndRelationsFromObjectArray([
|
||||||
|
data.update,
|
||||||
|
])
|
||||||
|
|
||||||
|
const prevData = await service.list(data.selector, {
|
||||||
|
select: selects,
|
||||||
|
relations,
|
||||||
|
})
|
||||||
|
|
||||||
|
const channels = await service.update(data.selector, data.update)
|
||||||
|
|
||||||
|
return new StepResponse(channels, prevData)
|
||||||
|
},
|
||||||
|
async (prevData, { container }) => {
|
||||||
|
if (!prevData?.length) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const service = container.resolve<ISalesChannelModuleService>(
|
||||||
|
ModuleRegistrationName.SALES_CHANNEL
|
||||||
|
)
|
||||||
|
|
||||||
|
await service.upsert(
|
||||||
|
prevData.map((r) => ({
|
||||||
|
id: r.id,
|
||||||
|
name: r.name,
|
||||||
|
description: r.description,
|
||||||
|
is_disabled: r.is_disabled,
|
||||||
|
metadata: r.metadata,
|
||||||
|
}))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
import { CreateSalesChannelDTO, SalesChannelDTO } from "@medusajs/types"
|
||||||
|
import { WorkflowData, createWorkflow } from "@medusajs/workflows-sdk"
|
||||||
|
import { createSalesChannelsStep } from "../steps/create-sales-channels"
|
||||||
|
|
||||||
|
type WorkflowInput = { salesChannelsData: CreateSalesChannelDTO[] }
|
||||||
|
|
||||||
|
export const createSalesChannelsWorkflowId = "create-sales-channels"
|
||||||
|
export const createSalesChannelsWorkflow = createWorkflow(
|
||||||
|
createSalesChannelsWorkflowId,
|
||||||
|
(input: WorkflowData<WorkflowInput>): WorkflowData<SalesChannelDTO[]> => {
|
||||||
|
return createSalesChannelsStep({ data: input.salesChannelsData })
|
||||||
|
}
|
||||||
|
)
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
import { WorkflowData, createWorkflow } from "@medusajs/workflows-sdk"
|
||||||
|
import { deleteSalesChannelsStep } from "../steps/delete-sales-channels"
|
||||||
|
|
||||||
|
type WorkflowInput = { ids: string[] }
|
||||||
|
|
||||||
|
export const deleteSalesChannelsWorkflowId = "delete-sales-channels"
|
||||||
|
export const deleteSalesChannelsWorkflow = createWorkflow(
|
||||||
|
deleteSalesChannelsWorkflowId,
|
||||||
|
(input: WorkflowData<WorkflowInput>): WorkflowData<void> => {
|
||||||
|
return deleteSalesChannelsStep(input.ids)
|
||||||
|
}
|
||||||
|
)
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
export * from "./create-sales-channels"
|
||||||
|
export * from "./update-sales-channels"
|
||||||
|
export * from "./delete-sales-channels"
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
import {
|
||||||
|
FilterableSalesChannelProps,
|
||||||
|
SalesChannelDTO,
|
||||||
|
UpdateSalesChannelDTO,
|
||||||
|
} from "@medusajs/types"
|
||||||
|
import { WorkflowData, createWorkflow } from "@medusajs/workflows-sdk"
|
||||||
|
import { updateSalesChannelsStep } from "../steps/update-sales-channels"
|
||||||
|
|
||||||
|
type UpdateSalesChannelsStepInput = {
|
||||||
|
selector: FilterableSalesChannelProps
|
||||||
|
update: UpdateSalesChannelDTO
|
||||||
|
}
|
||||||
|
|
||||||
|
export const updateSalesChannelsWorkflowId = "update-sales-channels"
|
||||||
|
export const updateSalesChannelsWorkflow = createWorkflow(
|
||||||
|
updateSalesChannelsWorkflowId,
|
||||||
|
(
|
||||||
|
input: WorkflowData<UpdateSalesChannelsStepInput>
|
||||||
|
): WorkflowData<SalesChannelDTO[]> => {
|
||||||
|
return updateSalesChannelsStep(input)
|
||||||
|
}
|
||||||
|
)
|
||||||
@@ -0,0 +1,85 @@
|
|||||||
|
import {
|
||||||
|
deleteSalesChannelsWorkflow,
|
||||||
|
updateSalesChannelsWorkflow,
|
||||||
|
} from "@medusajs/core-flows"
|
||||||
|
import {
|
||||||
|
ContainerRegistrationKeys,
|
||||||
|
remoteQueryObjectFromString,
|
||||||
|
} from "@medusajs/utils"
|
||||||
|
import {
|
||||||
|
AuthenticatedMedusaRequest,
|
||||||
|
MedusaResponse,
|
||||||
|
} from "../../../../types/routing"
|
||||||
|
import { defaultAdminSalesChannelFields } from "../query-config"
|
||||||
|
|
||||||
|
export const GET = async (
|
||||||
|
req: AuthenticatedMedusaRequest,
|
||||||
|
res: MedusaResponse
|
||||||
|
) => {
|
||||||
|
const remoteQuery = req.scope.resolve(ContainerRegistrationKeys.REMOTE_QUERY)
|
||||||
|
|
||||||
|
const variables = {
|
||||||
|
id: req.params.id,
|
||||||
|
}
|
||||||
|
|
||||||
|
const queryObject = remoteQueryObjectFromString({
|
||||||
|
entryPoint: "sales_channels",
|
||||||
|
variables,
|
||||||
|
fields: defaultAdminSalesChannelFields,
|
||||||
|
})
|
||||||
|
|
||||||
|
const [sales_channel] = await remoteQuery(queryObject)
|
||||||
|
|
||||||
|
res.json({ sales_channel })
|
||||||
|
}
|
||||||
|
|
||||||
|
export const POST = async (
|
||||||
|
req: AuthenticatedMedusaRequest,
|
||||||
|
res: MedusaResponse
|
||||||
|
) => {
|
||||||
|
const { errors } = await updateSalesChannelsWorkflow(req.scope).run({
|
||||||
|
input: {
|
||||||
|
selector: { id: req.params.id },
|
||||||
|
update: req.validatedBody,
|
||||||
|
},
|
||||||
|
throwOnError: false,
|
||||||
|
})
|
||||||
|
|
||||||
|
if (Array.isArray(errors) && errors[0]) {
|
||||||
|
throw errors[0].error
|
||||||
|
}
|
||||||
|
|
||||||
|
const remoteQuery = req.scope.resolve(ContainerRegistrationKeys.REMOTE_QUERY)
|
||||||
|
|
||||||
|
const queryObject = remoteQueryObjectFromString({
|
||||||
|
entryPoint: "sales_channels",
|
||||||
|
variables: { id: req.params.id },
|
||||||
|
fields: defaultAdminSalesChannelFields,
|
||||||
|
})
|
||||||
|
|
||||||
|
const [sales_channel] = await remoteQuery(queryObject)
|
||||||
|
|
||||||
|
res.status(200).json({ sales_channel })
|
||||||
|
}
|
||||||
|
|
||||||
|
export const DELETE = async (
|
||||||
|
req: AuthenticatedMedusaRequest,
|
||||||
|
res: MedusaResponse
|
||||||
|
) => {
|
||||||
|
const id = req.params.id
|
||||||
|
|
||||||
|
const { errors } = await deleteSalesChannelsWorkflow(req.scope).run({
|
||||||
|
input: { ids: [id] },
|
||||||
|
throwOnError: false,
|
||||||
|
})
|
||||||
|
|
||||||
|
if (Array.isArray(errors) && errors[0]) {
|
||||||
|
throw errors[0].error
|
||||||
|
}
|
||||||
|
|
||||||
|
res.status(200).json({
|
||||||
|
id,
|
||||||
|
object: "sales-channel",
|
||||||
|
deleted: true,
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
import { transformBody, transformQuery } from "../../../api/middlewares"
|
||||||
|
import { MiddlewareRoute } from "../../../loaders/helpers/routing/types"
|
||||||
|
import { authenticate } from "../../../utils/authenticate-middleware"
|
||||||
|
import * as QueryConfig from "./query-config"
|
||||||
|
import {
|
||||||
|
AdminGetSalesChannelsParams,
|
||||||
|
AdminGetSalesChannelsSalesChannelParams,
|
||||||
|
AdminPostSalesChannelsReq,
|
||||||
|
AdminPostSalesChannelsSalesChannelReq,
|
||||||
|
} from "./validators"
|
||||||
|
|
||||||
|
export const adminSalesChannelRoutesMiddlewares: MiddlewareRoute[] = [
|
||||||
|
{
|
||||||
|
method: ["ALL"],
|
||||||
|
matcher: "/admin/sales-channels*",
|
||||||
|
middlewares: [authenticate("admin", ["bearer", "session", "api-key"])],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
method: ["GET"],
|
||||||
|
matcher: "/admin/sales-channels",
|
||||||
|
middlewares: [
|
||||||
|
transformQuery(
|
||||||
|
AdminGetSalesChannelsParams,
|
||||||
|
QueryConfig.listTransformQueryConfig
|
||||||
|
),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
method: ["GET"],
|
||||||
|
matcher: "/admin/sales-channels/:id",
|
||||||
|
middlewares: [
|
||||||
|
transformQuery(
|
||||||
|
AdminGetSalesChannelsSalesChannelParams,
|
||||||
|
QueryConfig.retrieveTransformQueryConfig
|
||||||
|
),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
method: ["POST"],
|
||||||
|
matcher: "/admin/sales-channels",
|
||||||
|
middlewares: [
|
||||||
|
transformBody(AdminPostSalesChannelsReq),
|
||||||
|
transformQuery(
|
||||||
|
AdminGetSalesChannelsSalesChannelParams,
|
||||||
|
QueryConfig.retrieveTransformQueryConfig
|
||||||
|
),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
method: ["POST"],
|
||||||
|
matcher: "/admin/sales-channels/:id",
|
||||||
|
middlewares: [transformBody(AdminPostSalesChannelsSalesChannelReq)],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
method: ["DELETE"],
|
||||||
|
matcher: "/admin/sales-channels/:id",
|
||||||
|
middlewares: [],
|
||||||
|
},
|
||||||
|
]
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
export const defaultAdminSalesChannelFields = [
|
||||||
|
"id",
|
||||||
|
"name",
|
||||||
|
"description",
|
||||||
|
"is_disabled",
|
||||||
|
"created_at",
|
||||||
|
"updated_at",
|
||||||
|
"deleted_at",
|
||||||
|
]
|
||||||
|
|
||||||
|
export const retrieveTransformQueryConfig = {
|
||||||
|
defaults: defaultAdminSalesChannelFields,
|
||||||
|
isList: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
export const listTransformQueryConfig = {
|
||||||
|
...retrieveTransformQueryConfig,
|
||||||
|
isList: true,
|
||||||
|
}
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
import { createSalesChannelsWorkflow } from "@medusajs/core-flows"
|
||||||
|
import { CreateSalesChannelDTO } from "@medusajs/types"
|
||||||
|
import {
|
||||||
|
ContainerRegistrationKeys,
|
||||||
|
remoteQueryObjectFromString,
|
||||||
|
} from "@medusajs/utils"
|
||||||
|
import {
|
||||||
|
AuthenticatedMedusaRequest,
|
||||||
|
MedusaResponse,
|
||||||
|
} from "../../../types/routing"
|
||||||
|
|
||||||
|
export const GET = async (
|
||||||
|
req: AuthenticatedMedusaRequest,
|
||||||
|
res: MedusaResponse
|
||||||
|
) => {
|
||||||
|
const remoteQuery = req.scope.resolve(ContainerRegistrationKeys.REMOTE_QUERY)
|
||||||
|
|
||||||
|
const variables = {
|
||||||
|
filters: req.filterableFields,
|
||||||
|
...req.remoteQueryConfig.pagination,
|
||||||
|
}
|
||||||
|
|
||||||
|
const queryObject = remoteQueryObjectFromString({
|
||||||
|
entryPoint: "sales_channels",
|
||||||
|
variables,
|
||||||
|
fields: req.remoteQueryConfig.fields,
|
||||||
|
})
|
||||||
|
|
||||||
|
const { rows: sales_channels, metadata } = await remoteQuery(queryObject)
|
||||||
|
|
||||||
|
res.json({
|
||||||
|
sales_channels,
|
||||||
|
count: metadata.count,
|
||||||
|
offset: metadata.skip,
|
||||||
|
limit: metadata.take,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export const POST = async (
|
||||||
|
req: AuthenticatedMedusaRequest<CreateSalesChannelDTO>,
|
||||||
|
res: MedusaResponse
|
||||||
|
) => {
|
||||||
|
const salesChannelsData = [req.validatedBody]
|
||||||
|
|
||||||
|
const { errors } = await createSalesChannelsWorkflow(req.scope).run({
|
||||||
|
input: { salesChannelsData },
|
||||||
|
throwOnError: false,
|
||||||
|
})
|
||||||
|
|
||||||
|
if (Array.isArray(errors) && errors[0]) {
|
||||||
|
throw errors[0].error
|
||||||
|
}
|
||||||
|
|
||||||
|
const remoteQuery = req.scope.resolve(ContainerRegistrationKeys.REMOTE_QUERY)
|
||||||
|
|
||||||
|
const queryObject = remoteQueryObjectFromString({
|
||||||
|
entryPoint: "sales_channels",
|
||||||
|
variables: { id: req.params.id },
|
||||||
|
fields: req.remoteQueryConfig.fields,
|
||||||
|
})
|
||||||
|
|
||||||
|
const [sales_channel] = await remoteQuery(queryObject)
|
||||||
|
|
||||||
|
res.status(200).json({ sales_channel })
|
||||||
|
}
|
||||||
@@ -0,0 +1,102 @@
|
|||||||
|
import { OperatorMap } from "@medusajs/types"
|
||||||
|
import { Type } from "class-transformer"
|
||||||
|
import {
|
||||||
|
IsBoolean,
|
||||||
|
IsNotEmpty,
|
||||||
|
IsOptional,
|
||||||
|
IsString,
|
||||||
|
ValidateNested,
|
||||||
|
} from "class-validator"
|
||||||
|
import { FindParams, extendedFindParamsMixin } from "../../../types/common"
|
||||||
|
import { OperatorMapValidator } from "../../../types/validators/operator-map"
|
||||||
|
|
||||||
|
export class AdminGetSalesChannelsSalesChannelParams extends FindParams {}
|
||||||
|
|
||||||
|
export class AdminGetSalesChannelsParams extends extendedFindParamsMixin({
|
||||||
|
limit: 20,
|
||||||
|
offset: 0,
|
||||||
|
}) {
|
||||||
|
/**
|
||||||
|
* ID to filter sales channels by.
|
||||||
|
*/
|
||||||
|
@IsString()
|
||||||
|
@IsOptional()
|
||||||
|
id?: string
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Name to filter sales channels by.
|
||||||
|
*/
|
||||||
|
@IsOptional()
|
||||||
|
@IsString()
|
||||||
|
name?: string
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Description to filter sales channels by.
|
||||||
|
*/
|
||||||
|
@IsOptional()
|
||||||
|
@IsString()
|
||||||
|
description?: string
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Date filters to apply on sales channels' `created_at` field.
|
||||||
|
*/
|
||||||
|
@IsOptional()
|
||||||
|
@ValidateNested()
|
||||||
|
@Type(() => OperatorMapValidator)
|
||||||
|
created_at?: OperatorMap<string>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Date filters to apply on sales channels' `updated_at` field.
|
||||||
|
*/
|
||||||
|
@IsOptional()
|
||||||
|
@ValidateNested()
|
||||||
|
@Type(() => OperatorMapValidator)
|
||||||
|
updated_at?: OperatorMap<string>
|
||||||
|
|
||||||
|
@IsOptional()
|
||||||
|
@ValidateNested({ each: true })
|
||||||
|
@Type(() => AdminGetSalesChannelsParams)
|
||||||
|
$and?: AdminGetSalesChannelsParams[]
|
||||||
|
|
||||||
|
@IsOptional()
|
||||||
|
@ValidateNested({ each: true })
|
||||||
|
@Type(() => AdminGetSalesChannelsParams)
|
||||||
|
$or?: AdminGetSalesChannelsParams[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export class AdminPostSalesChannelsReq {
|
||||||
|
@IsString()
|
||||||
|
name: string
|
||||||
|
|
||||||
|
@IsString()
|
||||||
|
@IsOptional()
|
||||||
|
description: string
|
||||||
|
|
||||||
|
@IsBoolean()
|
||||||
|
@IsOptional()
|
||||||
|
is_disabled?: boolean
|
||||||
|
|
||||||
|
@IsNotEmpty()
|
||||||
|
@IsString()
|
||||||
|
@IsOptional()
|
||||||
|
metadata?: Record<string, unknown>
|
||||||
|
}
|
||||||
|
|
||||||
|
export class AdminPostSalesChannelsSalesChannelReq {
|
||||||
|
@IsOptional()
|
||||||
|
@IsString()
|
||||||
|
name?: string
|
||||||
|
|
||||||
|
@IsOptional()
|
||||||
|
@IsString()
|
||||||
|
description?: string
|
||||||
|
|
||||||
|
@IsBoolean()
|
||||||
|
@IsOptional()
|
||||||
|
is_disabled?: boolean
|
||||||
|
|
||||||
|
@IsNotEmpty()
|
||||||
|
@IsString()
|
||||||
|
@IsOptional()
|
||||||
|
metadata?: Record<string, unknown>
|
||||||
|
}
|
||||||
@@ -14,6 +14,7 @@ import { adminPricingRoutesMiddlewares } from "./admin/pricing/middlewares"
|
|||||||
import { adminProductRoutesMiddlewares } from "./admin/products/middlewares"
|
import { adminProductRoutesMiddlewares } from "./admin/products/middlewares"
|
||||||
import { adminPromotionRoutesMiddlewares } from "./admin/promotions/middlewares"
|
import { adminPromotionRoutesMiddlewares } from "./admin/promotions/middlewares"
|
||||||
import { adminRegionRoutesMiddlewares } from "./admin/regions/middlewares"
|
import { adminRegionRoutesMiddlewares } from "./admin/regions/middlewares"
|
||||||
|
import { adminSalesChannelRoutesMiddlewares } from "./admin/sales-channels/middlewares"
|
||||||
import { adminStoreRoutesMiddlewares } from "./admin/stores/middlewares"
|
import { adminStoreRoutesMiddlewares } from "./admin/stores/middlewares"
|
||||||
import { adminTaxRateRoutesMiddlewares } from "./admin/tax-rates/middlewares"
|
import { adminTaxRateRoutesMiddlewares } from "./admin/tax-rates/middlewares"
|
||||||
import { adminTaxRegionRoutesMiddlewares } from "./admin/tax-regions/middlewares"
|
import { adminTaxRegionRoutesMiddlewares } from "./admin/tax-regions/middlewares"
|
||||||
@@ -55,5 +56,6 @@ export const config: MiddlewaresConfig = {
|
|||||||
...adminCollectionRoutesMiddlewares,
|
...adminCollectionRoutesMiddlewares,
|
||||||
...adminPricingRoutesMiddlewares,
|
...adminPricingRoutesMiddlewares,
|
||||||
...adminFulfillmentRoutesMiddlewares,
|
...adminFulfillmentRoutesMiddlewares,
|
||||||
|
...adminSalesChannelRoutesMiddlewares,
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
+6
-11
@@ -4,8 +4,8 @@ import { ISalesChannelModuleService } from "@medusajs/types"
|
|||||||
|
|
||||||
import { initialize } from "../../../src"
|
import { initialize } from "../../../src"
|
||||||
|
|
||||||
import { DB_URL, MikroOrmWrapper } from "../../utils"
|
|
||||||
import { createSalesChannels } from "../../__fixtures__"
|
import { createSalesChannels } from "../../__fixtures__"
|
||||||
|
import { DB_URL, MikroOrmWrapper } from "../../utils"
|
||||||
|
|
||||||
jest.setTimeout(30000)
|
jest.setTimeout(30000)
|
||||||
|
|
||||||
@@ -84,13 +84,10 @@ describe("Sales Channel Service", () => {
|
|||||||
const id = "channel-2"
|
const id = "channel-2"
|
||||||
|
|
||||||
it("should update the name of the SalesChannel successfully", async () => {
|
it("should update the name of the SalesChannel successfully", async () => {
|
||||||
await service.update([
|
await service.update(id, {
|
||||||
{
|
|
||||||
id,
|
|
||||||
name: "Update name 2",
|
name: "Update name 2",
|
||||||
is_disabled: true,
|
is_disabled: true,
|
||||||
},
|
})
|
||||||
])
|
|
||||||
|
|
||||||
const channel = await service.retrieve(id)
|
const channel = await service.retrieve(id)
|
||||||
|
|
||||||
@@ -102,11 +99,9 @@ describe("Sales Channel Service", () => {
|
|||||||
let error
|
let error
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await service.update([
|
await service.update("does-not-exist", {
|
||||||
{
|
name: "does-not-exist",
|
||||||
id: "does-not-exist",
|
})
|
||||||
},
|
|
||||||
])
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
error = e
|
error = e
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,6 +43,15 @@
|
|||||||
"default": "false",
|
"default": "false",
|
||||||
"mappedType": "boolean"
|
"mappedType": "boolean"
|
||||||
},
|
},
|
||||||
|
"metadata": {
|
||||||
|
"name": "metadata",
|
||||||
|
"type": "jsonb",
|
||||||
|
"unsigned": false,
|
||||||
|
"autoincrement": false,
|
||||||
|
"primary": false,
|
||||||
|
"nullable": true,
|
||||||
|
"mappedType": "json"
|
||||||
|
},
|
||||||
"created_at": {
|
"created_at": {
|
||||||
"name": "created_at",
|
"name": "created_at",
|
||||||
"type": "timestamptz",
|
"type": "timestamptz",
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { Migration } from "@mikro-orm/migrations"
|
|||||||
export class Migration20240115152146 extends Migration {
|
export class Migration20240115152146 extends Migration {
|
||||||
async up(): Promise<void> {
|
async up(): Promise<void> {
|
||||||
this.addSql(
|
this.addSql(
|
||||||
'create table if not exists "sales_channel" ("id" text not null, "name" text not null, "description" text null, "is_disabled" boolean not null default false, "created_at" timestamptz not null default now(), "updated_at" timestamptz not null default now(), "deleted_at" timestamptz null, constraint "sales_channel_pkey" primary key ("id"));'
|
'create table if not exists "sales_channel" ("id" text not null, "name" text not null, "description" text null, "is_disabled" boolean not null default false, "metadata" jsonb NULL, "created_at" timestamptz not null default now(), "updated_at" timestamptz not null default now(), "deleted_at" timestamptz null, constraint "sales_channel_pkey" primary key ("id"));'
|
||||||
)
|
)
|
||||||
this.addSql(
|
this.addSql(
|
||||||
'create index "IDX_sales_channel_deleted_at" on "sales_channel" ("deleted_at");'
|
'create index "IDX_sales_channel_deleted_at" on "sales_channel" ("deleted_at");'
|
||||||
|
|||||||
@@ -38,6 +38,9 @@ export default class SalesChannel {
|
|||||||
})
|
})
|
||||||
created_at: Date
|
created_at: Date
|
||||||
|
|
||||||
|
@Property({ columnType: "jsonb", nullable: true })
|
||||||
|
metadata: Record<string, unknown> | null = null
|
||||||
|
|
||||||
@Property({
|
@Property({
|
||||||
onCreate: () => new Date(),
|
onCreate: () => new Date(),
|
||||||
onUpdate: () => new Date(),
|
onUpdate: () => new Date(),
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import {
|
|||||||
Context,
|
Context,
|
||||||
CreateSalesChannelDTO,
|
CreateSalesChannelDTO,
|
||||||
DAL,
|
DAL,
|
||||||
|
FilterableSalesChannelProps,
|
||||||
InternalModuleDeclaration,
|
InternalModuleDeclaration,
|
||||||
ISalesChannelModuleService,
|
ISalesChannelModuleService,
|
||||||
ModuleJoinerConfig,
|
ModuleJoinerConfig,
|
||||||
@@ -9,10 +10,19 @@ import {
|
|||||||
SalesChannelDTO,
|
SalesChannelDTO,
|
||||||
UpdateSalesChannelDTO,
|
UpdateSalesChannelDTO,
|
||||||
} from "@medusajs/types"
|
} from "@medusajs/types"
|
||||||
import { MedusaContext, ModulesSdkUtils } from "@medusajs/utils"
|
import {
|
||||||
|
InjectManager,
|
||||||
|
InjectTransactionManager,
|
||||||
|
isString,
|
||||||
|
MedusaContext,
|
||||||
|
ModulesSdkUtils,
|
||||||
|
promiseAll,
|
||||||
|
} from "@medusajs/utils"
|
||||||
|
|
||||||
import { SalesChannel } from "@models"
|
import { SalesChannel } from "@models"
|
||||||
|
|
||||||
|
import { UpsertSalesChannelDTO } from "@medusajs/types"
|
||||||
|
import { UpdateSalesChanneInput } from "@types"
|
||||||
import { entityNameToLinkableKeysMap, joinerConfig } from "../joiner-config"
|
import { entityNameToLinkableKeysMap, joinerConfig } from "../joiner-config"
|
||||||
|
|
||||||
type InjectedDependencies = {
|
type InjectedDependencies = {
|
||||||
@@ -51,19 +61,18 @@ export default class SalesChannelModuleService<
|
|||||||
data: CreateSalesChannelDTO[],
|
data: CreateSalesChannelDTO[],
|
||||||
sharedContext?: Context
|
sharedContext?: Context
|
||||||
): Promise<SalesChannelDTO[]>
|
): Promise<SalesChannelDTO[]>
|
||||||
|
|
||||||
async create(
|
async create(
|
||||||
data: CreateSalesChannelDTO,
|
data: CreateSalesChannelDTO,
|
||||||
sharedContext?: Context
|
sharedContext?: Context
|
||||||
): Promise<SalesChannelDTO>
|
): Promise<SalesChannelDTO>
|
||||||
|
@InjectManager("baseRepository_")
|
||||||
async create(
|
async create(
|
||||||
data: CreateSalesChannelDTO | CreateSalesChannelDTO[],
|
data: CreateSalesChannelDTO | CreateSalesChannelDTO[],
|
||||||
@MedusaContext() sharedContext: Context = {}
|
@MedusaContext() sharedContext: Context = {}
|
||||||
): Promise<SalesChannelDTO | SalesChannelDTO[]> {
|
): Promise<SalesChannelDTO | SalesChannelDTO[]> {
|
||||||
const input = Array.isArray(data) ? data : [data]
|
const input = Array.isArray(data) ? data : [data]
|
||||||
|
|
||||||
const result = await this.salesChannelService_.create(input, sharedContext)
|
const result = await this.create_(input, sharedContext)
|
||||||
|
|
||||||
return await this.baseRepository_.serialize<SalesChannelDTO[]>(
|
return await this.baseRepository_.serialize<SalesChannelDTO[]>(
|
||||||
Array.isArray(data) ? result : result[0],
|
Array.isArray(data) ? result : result[0],
|
||||||
@@ -73,23 +82,47 @@ export default class SalesChannelModuleService<
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
async update(
|
@InjectTransactionManager("baseRepository_")
|
||||||
data: UpdateSalesChannelDTO[],
|
async create_(
|
||||||
sharedContext?: Context
|
data: CreateSalesChannelDTO[],
|
||||||
): Promise<SalesChannelDTO[]>
|
@MedusaContext() sharedContext: Context
|
||||||
|
): Promise<SalesChannel[]> {
|
||||||
|
return await this.salesChannelService_.create(data, sharedContext)
|
||||||
|
}
|
||||||
|
|
||||||
async update(
|
async update(
|
||||||
|
id: string,
|
||||||
data: UpdateSalesChannelDTO,
|
data: UpdateSalesChannelDTO,
|
||||||
sharedContext?: Context
|
sharedContext?: Context
|
||||||
): Promise<SalesChannelDTO>
|
): Promise<SalesChannelDTO>
|
||||||
|
|
||||||
async update(
|
async update(
|
||||||
|
selector: FilterableSalesChannelProps,
|
||||||
|
data: UpdateSalesChannelDTO,
|
||||||
|
sharedContext?: Context
|
||||||
|
): Promise<SalesChannelDTO[]>
|
||||||
|
@InjectManager("baseRepository_")
|
||||||
|
async update(
|
||||||
|
idOrSelector: string | FilterableSalesChannelProps,
|
||||||
data: UpdateSalesChannelDTO | UpdateSalesChannelDTO[],
|
data: UpdateSalesChannelDTO | UpdateSalesChannelDTO[],
|
||||||
@MedusaContext() sharedContext: Context = {}
|
@MedusaContext() sharedContext: Context = {}
|
||||||
): Promise<SalesChannelDTO | SalesChannelDTO[]> {
|
): Promise<SalesChannelDTO | SalesChannelDTO[]> {
|
||||||
const input = Array.isArray(data) ? data : [data]
|
let normalizedInput: UpdateSalesChanneInput[] = []
|
||||||
|
if (isString(idOrSelector)) {
|
||||||
|
normalizedInput = [{ id: idOrSelector, ...data }]
|
||||||
|
} else {
|
||||||
|
const channels = await this.salesChannelService_.list(
|
||||||
|
idOrSelector,
|
||||||
|
{},
|
||||||
|
sharedContext
|
||||||
|
)
|
||||||
|
|
||||||
const result = await this.salesChannelService_.update(input, sharedContext)
|
normalizedInput = channels.map((channel) => ({
|
||||||
|
id: channel.id,
|
||||||
|
...data,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = await this.update_(normalizedInput, sharedContext)
|
||||||
|
|
||||||
return await this.baseRepository_.serialize<SalesChannelDTO[]>(
|
return await this.baseRepository_.serialize<SalesChannelDTO[]>(
|
||||||
Array.isArray(data) ? result : result[0],
|
Array.isArray(data) ? result : result[0],
|
||||||
@@ -98,4 +131,45 @@ export default class SalesChannelModuleService<
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@InjectTransactionManager("baseRepository_")
|
||||||
|
async update_(data: UpdateSalesChannelDTO[], sharedContext: Context) {
|
||||||
|
return await this.salesChannelService_.update(data, sharedContext)
|
||||||
|
}
|
||||||
|
|
||||||
|
async upsert(
|
||||||
|
data: UpsertSalesChannelDTO[],
|
||||||
|
sharedContext?: Context
|
||||||
|
): Promise<SalesChannelDTO[]>
|
||||||
|
async upsert(
|
||||||
|
data: UpsertSalesChannelDTO,
|
||||||
|
sharedContext?: Context
|
||||||
|
): Promise<SalesChannelDTO>
|
||||||
|
@InjectTransactionManager("baseRepository_")
|
||||||
|
async upsert(
|
||||||
|
data: UpsertSalesChannelDTO | UpsertSalesChannelDTO[],
|
||||||
|
@MedusaContext() sharedContext: Context = {}
|
||||||
|
): Promise<SalesChannelDTO | SalesChannelDTO[]> {
|
||||||
|
const input = Array.isArray(data) ? data : [data]
|
||||||
|
const forUpdate = input.filter(
|
||||||
|
(channel): channel is UpdateSalesChannelDTO => !!channel.id
|
||||||
|
)
|
||||||
|
const forCreate = input.filter(
|
||||||
|
(channel): channel is CreateSalesChannelDTO => !channel.id
|
||||||
|
)
|
||||||
|
|
||||||
|
const operations: Promise<SalesChannel[]>[] = []
|
||||||
|
|
||||||
|
if (forCreate.length) {
|
||||||
|
operations.push(this.create_(forCreate, sharedContext))
|
||||||
|
}
|
||||||
|
if (forUpdate.length) {
|
||||||
|
operations.push(this.update_(forUpdate, sharedContext))
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = (await promiseAll(operations)).flat()
|
||||||
|
return await this.baseRepository_.serialize<
|
||||||
|
SalesChannelDTO[] | SalesChannelDTO
|
||||||
|
>(Array.isArray(data) ? result : result[0])
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,7 @@
|
|||||||
import { Logger } from "@medusajs/types"
|
import { Logger, UpdateSalesChannelDTO } from "@medusajs/types"
|
||||||
|
|
||||||
export type InitializeModuleInjectableDependencies = {
|
export type InitializeModuleInjectableDependencies = {
|
||||||
logger?: Logger
|
logger?: Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type UpdateSalesChanneInput = UpdateSalesChannelDTO & { id: string }
|
||||||
@@ -63,12 +63,12 @@ export interface FilterableSalesChannelProps
|
|||||||
/**
|
/**
|
||||||
* The IDs to filter the sales channel by.
|
* The IDs to filter the sales channel by.
|
||||||
*/
|
*/
|
||||||
id?: string[]
|
id?: string | string[]
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Filter sales channels by their names.
|
* Filter sales channels by their names.
|
||||||
*/
|
*/
|
||||||
name?: string[]
|
name?: string | string[]
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Filter sales channels by whether they're disabled.
|
* Filter sales channels by whether they're disabled.
|
||||||
|
|||||||
@@ -22,11 +22,6 @@ export interface CreateSalesChannelDTO {
|
|||||||
* The attributes to update in the sales channel.
|
* The attributes to update in the sales channel.
|
||||||
*/
|
*/
|
||||||
export interface UpdateSalesChannelDTO {
|
export interface UpdateSalesChannelDTO {
|
||||||
/**
|
|
||||||
* The ID of the sales channel.
|
|
||||||
*/
|
|
||||||
id: string
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The name of the sales channel.
|
* The name of the sales channel.
|
||||||
*/
|
*/
|
||||||
@@ -41,4 +36,34 @@ export interface UpdateSalesChannelDTO {
|
|||||||
* Whether the sales channel is disabled.
|
* Whether the sales channel is disabled.
|
||||||
*/
|
*/
|
||||||
is_disabled?: boolean
|
is_disabled?: boolean
|
||||||
|
/**
|
||||||
|
* Holds custom data in key-value pairs.
|
||||||
|
*/
|
||||||
|
metadata?: Record<string, unknown>
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface UpsertSalesChannelDTO {
|
||||||
|
/**
|
||||||
|
* The ID of the sales channel.
|
||||||
|
*/
|
||||||
|
id?: string
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The name of the sales channel.
|
||||||
|
*/
|
||||||
|
name?: string
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The description of the sales channel.
|
||||||
|
*/
|
||||||
|
description?: string | null
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether the sales channel is disabled.
|
||||||
|
*/
|
||||||
|
is_disabled?: boolean
|
||||||
|
/**
|
||||||
|
* Holds custom data in key-value pairs.
|
||||||
|
*/
|
||||||
|
metadata?: Record<string, unknown> | null
|
||||||
}
|
}
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
import { IModuleService } from "../modules-sdk"
|
|
||||||
import { FilterableSalesChannelProps, SalesChannelDTO } from "./common"
|
|
||||||
import { FindConfig } from "../common"
|
import { FindConfig } from "../common"
|
||||||
import { Context } from "../shared-context"
|
|
||||||
import { RestoreReturn, SoftDeleteReturn } from "../dal"
|
import { RestoreReturn, SoftDeleteReturn } from "../dal"
|
||||||
import { CreateSalesChannelDTO, UpdateSalesChannelDTO } from "./mutations"
|
import { IModuleService } from "../modules-sdk"
|
||||||
|
import { Context } from "../shared-context"
|
||||||
|
import { FilterableSalesChannelProps, SalesChannelDTO } from "./common"
|
||||||
|
import { CreateSalesChannelDTO, UpdateSalesChannelDTO, UpsertSalesChannelDTO } from "./mutations"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The main service interface for the sales channel module.
|
* The main service interface for the sales channel module.
|
||||||
@@ -39,35 +39,25 @@ export interface ISalesChannelModuleService extends IModuleService {
|
|||||||
sharedContext?: Context
|
sharedContext?: Context
|
||||||
): Promise<SalesChannelDTO>
|
): Promise<SalesChannelDTO>
|
||||||
|
|
||||||
/**
|
|
||||||
* This method updates existing sales channels.
|
|
||||||
*
|
|
||||||
* @param {UpdateSalesChannelDTO[]} data - The attributes to update in each sales channel.
|
|
||||||
* @param {Context} sharedContext - A context used to share resources, such as transaction manager, between the application and the module.
|
|
||||||
* @returns {Promise<SalesChannelDTO[]>} The updated sales channels.
|
|
||||||
*
|
|
||||||
* @example
|
|
||||||
* {example-code}
|
|
||||||
*/
|
|
||||||
update(
|
|
||||||
data: UpdateSalesChannelDTO[],
|
|
||||||
sharedContext?: Context
|
|
||||||
): Promise<SalesChannelDTO[]>
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method updates an existing sales channel.
|
|
||||||
*
|
|
||||||
* @param {UpdateSalesChannelDTO} data - The attributes to update in the sales channel.
|
|
||||||
* @param {Context} sharedContext - A context used to share resources, such as transaction manager, between the application and the module.
|
|
||||||
* @returns {Promise<SalesChannelDTO>} The updated sales channel.
|
|
||||||
*
|
|
||||||
* @example
|
|
||||||
* {example-code}
|
|
||||||
*/
|
|
||||||
update(
|
update(
|
||||||
|
channelId: string,
|
||||||
data: UpdateSalesChannelDTO,
|
data: UpdateSalesChannelDTO,
|
||||||
sharedContext?: Context
|
sharedContext?: Context
|
||||||
): Promise<SalesChannelDTO>
|
): Promise<SalesChannelDTO>
|
||||||
|
update(
|
||||||
|
selector: FilterableSalesChannelProps,
|
||||||
|
data: UpdateSalesChannelDTO,
|
||||||
|
sharedContext?: Context
|
||||||
|
): Promise<SalesChannelDTO[]>
|
||||||
|
|
||||||
|
upsert(
|
||||||
|
data: UpsertSalesChannelDTO,
|
||||||
|
sharedContext?: Context
|
||||||
|
): Promise<SalesChannelDTO>
|
||||||
|
upsert(
|
||||||
|
data: UpsertSalesChannelDTO[],
|
||||||
|
sharedContext?: Context
|
||||||
|
): Promise<SalesChannelDTO[]>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method deletes sales channels by their IDs.
|
* This method deletes sales channels by their IDs.
|
||||||
|
|||||||
Reference in new issue
Block a user