Feat(link-module, core-flows, medusa): Add sales channel location management (#6905)
* add locations with sales channels * init, not working location based management * working adding sales channel stock locations * remote sales channels from location * remove console log * rm allowedFields * redo errorhandler * make validation take an array * add changeset * fix build * Update packages/core-flows/src/sales-channel/workflows/remove-locations-from-sales-channel.ts Co-authored-by: Oli Juhl <59018053+olivermrbl@users.noreply.github.com> * add default cases to return early * cleanup * add sc test and remove associations --------- Co-authored-by: Oli Juhl <59018053+olivermrbl@users.noreply.github.com>
This commit is contained in:
1 parent
27f4f0d724
commit
edafe7db47
19 files changed
+474
-34
No files matched your search
@@ -0,0 +1,7 @@
|
|||||||
|
---
|
||||||
|
"@medusajs/link-modules": patch
|
||||||
|
"@medusajs/core-flows": patch
|
||||||
|
"@medusajs/medusa": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
feat(link-modules, core-flows, medusa): add sales channel location management endpoint
|
||||||
@@ -1,6 +1,9 @@
|
|||||||
const { ModuleRegistrationName, Modules } = require("@medusajs/modules-sdk")
|
const { ModuleRegistrationName, Modules } = require("@medusajs/modules-sdk")
|
||||||
const { medusaIntegrationTestRunner } = require("medusa-test-utils")
|
const { medusaIntegrationTestRunner } = require("medusa-test-utils")
|
||||||
const { createAdminUser } = require("../../../helpers/create-admin-user")
|
const {
|
||||||
|
createAdminUser,
|
||||||
|
adminHeaders,
|
||||||
|
} = require("../../../helpers/create-admin-user")
|
||||||
const { breaking } = require("../../../helpers/breaking")
|
const { breaking } = require("../../../helpers/breaking")
|
||||||
const { ContainerRegistrationKeys } = require("@medusajs/utils")
|
const { ContainerRegistrationKeys } = require("@medusajs/utils")
|
||||||
|
|
||||||
@@ -345,7 +348,7 @@ medusaIntegrationTestRunner({
|
|||||||
})
|
})
|
||||||
|
|
||||||
it("should delete the requested sales channel", async () => {
|
it("should delete the requested sales channel", async () => {
|
||||||
let toDelete = await breaking(
|
const toDelete = await breaking(
|
||||||
async () => {
|
async () => {
|
||||||
return await dbConnection.manager.findOne(SalesChannel, {
|
return await dbConnection.manager.findOne(SalesChannel, {
|
||||||
where: { id: salesChannel.id },
|
where: { id: salesChannel.id },
|
||||||
@@ -403,6 +406,48 @@ medusaIntegrationTestRunner({
|
|||||||
)
|
)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it("should successfully delete channel associations", async () => {
|
||||||
|
await breaking(null, async () => {
|
||||||
|
const remoteLink = container.resolve(
|
||||||
|
ContainerRegistrationKeys.REMOTE_LINK
|
||||||
|
)
|
||||||
|
|
||||||
|
console.warn("testing")
|
||||||
|
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", () => {
|
describe("GET /admin/orders/:id", () => {
|
||||||
|
|||||||
@@ -279,5 +279,100 @@ medusaIntegrationTestRunner({
|
|||||||
expect(stockLocationLinks).toHaveLength(0)
|
expect(stockLocationLinks).toHaveLength(0)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe("Add sales channels", () => {
|
||||||
|
let salesChannel
|
||||||
|
let location
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
const salesChannelResponse = await api.post(
|
||||||
|
"/admin/sales-channels",
|
||||||
|
{
|
||||||
|
name: "test name",
|
||||||
|
description: "test description",
|
||||||
|
},
|
||||||
|
adminHeaders
|
||||||
|
)
|
||||||
|
salesChannel = salesChannelResponse.data.sales_channel
|
||||||
|
|
||||||
|
const locationResponse = await api.post(
|
||||||
|
"/admin/stock-locations",
|
||||||
|
{
|
||||||
|
name: "test location",
|
||||||
|
},
|
||||||
|
adminHeaders
|
||||||
|
)
|
||||||
|
|
||||||
|
location = locationResponse.data.stock_location
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should add sales channels to a location", async () => {
|
||||||
|
const salesChannelResponse = await api.post(
|
||||||
|
`/admin/stock-locations/${location.id}/sales-channels/batch/add?fields=*sales_channels`,
|
||||||
|
{ sales_channel_ids: [salesChannel.id] },
|
||||||
|
adminHeaders
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(
|
||||||
|
salesChannelResponse.data.stock_location.sales_channels
|
||||||
|
).toHaveLength(1)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("Remove sales channels", () => {
|
||||||
|
let salesChannel1
|
||||||
|
let salesChannel2
|
||||||
|
let location
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
const salesChannelResponse1 = await api.post(
|
||||||
|
"/admin/sales-channels",
|
||||||
|
{
|
||||||
|
name: "test name",
|
||||||
|
description: "test description",
|
||||||
|
},
|
||||||
|
adminHeaders
|
||||||
|
)
|
||||||
|
salesChannel1 = salesChannelResponse1.data.sales_channel
|
||||||
|
|
||||||
|
const salesChannelResponse2 = await api.post(
|
||||||
|
"/admin/sales-channels",
|
||||||
|
{
|
||||||
|
name: "test name",
|
||||||
|
description: "test description",
|
||||||
|
},
|
||||||
|
adminHeaders
|
||||||
|
)
|
||||||
|
salesChannel2 = salesChannelResponse2.data.sales_channel
|
||||||
|
|
||||||
|
const locationResponse = await api.post(
|
||||||
|
"/admin/stock-locations",
|
||||||
|
{
|
||||||
|
name: "test location",
|
||||||
|
},
|
||||||
|
adminHeaders
|
||||||
|
)
|
||||||
|
|
||||||
|
location = locationResponse.data.stock_location
|
||||||
|
|
||||||
|
await api.post(
|
||||||
|
`/admin/stock-locations/${location.id}/sales-channels/batch/add?fields=*sales_channels`,
|
||||||
|
{ sales_channel_ids: [salesChannel1.id, salesChannel2.id] },
|
||||||
|
adminHeaders
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should remove sales channels from a location", async () => {
|
||||||
|
const salesChannelResponse = await api.post(
|
||||||
|
`/admin/stock-locations/${location.id}/sales-channels/batch/remove?fields=*sales_channels`,
|
||||||
|
{ sales_channel_ids: [salesChannel1.id] },
|
||||||
|
adminHeaders
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(
|
||||||
|
salesChannelResponse.data.stock_location.sales_channels
|
||||||
|
).toHaveLength(1)
|
||||||
|
})
|
||||||
|
})
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
import { StepResponse, createStep } from "@medusajs/workflows-sdk"
|
||||||
|
|
||||||
|
import { ContainerRegistrationKeys } from "@medusajs/utils"
|
||||||
|
import { Modules } from "@medusajs/modules-sdk"
|
||||||
|
|
||||||
|
interface StepInput {
|
||||||
|
links: {
|
||||||
|
sales_channel_id: string
|
||||||
|
location_ids: string[]
|
||||||
|
}[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export const associateLocationsWithChannelStepId =
|
||||||
|
"associate-locations-with-channel-step"
|
||||||
|
export const associateLocationsWithChannelStep = createStep(
|
||||||
|
associateLocationsWithChannelStepId,
|
||||||
|
async (data: StepInput, { container }) => {
|
||||||
|
if (!data.links.length) {
|
||||||
|
return new StepResponse([], [])
|
||||||
|
}
|
||||||
|
|
||||||
|
const remoteLink = container.resolve(ContainerRegistrationKeys.REMOTE_LINK)
|
||||||
|
|
||||||
|
const links = data.links
|
||||||
|
.map((link) => {
|
||||||
|
return link.location_ids.map((id) => {
|
||||||
|
return {
|
||||||
|
[Modules.SALES_CHANNEL]: {
|
||||||
|
sales_channel_id: link.sales_channel_id,
|
||||||
|
},
|
||||||
|
[Modules.STOCK_LOCATION]: {
|
||||||
|
stock_location_id: id,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.flat()
|
||||||
|
|
||||||
|
const createdLinks = await remoteLink.create(links)
|
||||||
|
|
||||||
|
return new StepResponse(createdLinks, links)
|
||||||
|
},
|
||||||
|
async (links, { container }) => {
|
||||||
|
if (!links?.length) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const remoteLink = container.resolve(ContainerRegistrationKeys.REMOTE_LINK)
|
||||||
|
|
||||||
|
await remoteLink.dismiss(links)
|
||||||
|
}
|
||||||
|
)
|
||||||
@@ -4,4 +4,5 @@ export * from "./create-sales-channels"
|
|||||||
export * from "./delete-sales-channels"
|
export * from "./delete-sales-channels"
|
||||||
export * from "./detach-products-from-sales-channels"
|
export * from "./detach-products-from-sales-channels"
|
||||||
export * from "./update-sales-channels"
|
export * from "./update-sales-channels"
|
||||||
|
export * from "./associate-locations-with-channel"
|
||||||
|
export * from "./remove-locations-from-channels"
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
import { Modules, RemoteLink } from "@medusajs/modules-sdk"
|
||||||
|
import { StepResponse, createStep } from "@medusajs/workflows-sdk"
|
||||||
|
|
||||||
|
import { ContainerRegistrationKeys } from "@medusajs/utils"
|
||||||
|
|
||||||
|
export const removeLocationsFromSalesChannelStepId =
|
||||||
|
"remove-locations-from-sales-channel"
|
||||||
|
export const removeLocationsFromSalesChannelStep = createStep(
|
||||||
|
removeLocationsFromSalesChannelStepId,
|
||||||
|
async (
|
||||||
|
data: {
|
||||||
|
sales_channel_id: string
|
||||||
|
location_ids: string[]
|
||||||
|
}[],
|
||||||
|
{ container }
|
||||||
|
) => {
|
||||||
|
if (!data.length) {
|
||||||
|
return new StepResponse([], [])
|
||||||
|
}
|
||||||
|
|
||||||
|
const remoteLink = container.resolve<RemoteLink>(
|
||||||
|
ContainerRegistrationKeys.REMOTE_LINK
|
||||||
|
)
|
||||||
|
|
||||||
|
const linkModule = remoteLink.getLinkModule(
|
||||||
|
Modules.SALES_CHANNEL,
|
||||||
|
"sales_channel_id",
|
||||||
|
Modules.STOCK_LOCATION,
|
||||||
|
"stock_location_id"
|
||||||
|
)
|
||||||
|
|
||||||
|
if (!linkModule) {
|
||||||
|
return new StepResponse([], [])
|
||||||
|
}
|
||||||
|
|
||||||
|
const links = data
|
||||||
|
.map((d) =>
|
||||||
|
d.location_ids.map((locId) => ({
|
||||||
|
sales_channel_id: d.sales_channel_id,
|
||||||
|
stock_location_id: locId,
|
||||||
|
}))
|
||||||
|
)
|
||||||
|
.flat()
|
||||||
|
|
||||||
|
await linkModule.softDelete(links)
|
||||||
|
|
||||||
|
return new StepResponse(void 0, links)
|
||||||
|
},
|
||||||
|
async (links, { container }) => {
|
||||||
|
if (!links?.length) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const remoteLink = container.resolve<RemoteLink>(
|
||||||
|
ContainerRegistrationKeys.REMOTE_LINK
|
||||||
|
)
|
||||||
|
|
||||||
|
const linkModule = remoteLink.getLinkModule(
|
||||||
|
Modules.SALES_CHANNEL,
|
||||||
|
"sales_channel_id",
|
||||||
|
Modules.STOCK_LOCATION,
|
||||||
|
"stock_location_id"
|
||||||
|
)
|
||||||
|
|
||||||
|
if (!linkModule) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
await linkModule.restore(links)
|
||||||
|
}
|
||||||
|
)
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
import { WorkflowData, createWorkflow } from "@medusajs/workflows-sdk"
|
||||||
|
|
||||||
|
import { SalesChannelDTO } from "@medusajs/types"
|
||||||
|
import { associateLocationsWithChannelStep } from "../steps"
|
||||||
|
|
||||||
|
interface WorkflowInput {
|
||||||
|
data: {
|
||||||
|
sales_channel_id: string
|
||||||
|
location_ids: string[]
|
||||||
|
}[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export const addLocationsToSalesChannelWorkflowId =
|
||||||
|
"add-locations-to-sales-channel"
|
||||||
|
export const addLocationsToSalesChannelWorkflow = createWorkflow(
|
||||||
|
addLocationsToSalesChannelWorkflowId,
|
||||||
|
(input: WorkflowData<WorkflowInput>): WorkflowData<SalesChannelDTO[]> => {
|
||||||
|
return associateLocationsWithChannelStep({ links: input.data })
|
||||||
|
}
|
||||||
|
)
|
||||||
@@ -1,5 +1,8 @@
|
|||||||
import { WorkflowData, createWorkflow } from "@medusajs/workflows-sdk"
|
import { WorkflowData, createWorkflow } from "@medusajs/workflows-sdk"
|
||||||
|
|
||||||
|
import { Modules } from "@medusajs/modules-sdk"
|
||||||
import { deleteSalesChannelsStep } from "../steps/delete-sales-channels"
|
import { deleteSalesChannelsStep } from "../steps/delete-sales-channels"
|
||||||
|
import { removeRemoteLinkStep } from "../../common/steps/remove-remote-links"
|
||||||
|
|
||||||
type WorkflowInput = { ids: string[] }
|
type WorkflowInput = { ids: string[] }
|
||||||
|
|
||||||
@@ -7,6 +10,10 @@ export const deleteSalesChannelsWorkflowId = "delete-sales-channels"
|
|||||||
export const deleteSalesChannelsWorkflow = createWorkflow(
|
export const deleteSalesChannelsWorkflow = createWorkflow(
|
||||||
deleteSalesChannelsWorkflowId,
|
deleteSalesChannelsWorkflowId,
|
||||||
(input: WorkflowData<WorkflowInput>): WorkflowData<void> => {
|
(input: WorkflowData<WorkflowInput>): WorkflowData<void> => {
|
||||||
return deleteSalesChannelsStep(input.ids)
|
deleteSalesChannelsStep(input.ids)
|
||||||
|
|
||||||
|
removeRemoteLinkStep({
|
||||||
|
[Modules.SALES_CHANNEL]: { sales_channel_id: input.ids },
|
||||||
|
})
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@@ -3,4 +3,5 @@ export * from "./create-sales-channels"
|
|||||||
export * from "./delete-sales-channels"
|
export * from "./delete-sales-channels"
|
||||||
export * from "./remove-products-from-sales-channels"
|
export * from "./remove-products-from-sales-channels"
|
||||||
export * from "./update-sales-channels"
|
export * from "./update-sales-channels"
|
||||||
|
export * from "./add-locations-to-sales-channel"
|
||||||
|
export * from "./remove-locations-from-sales-channel"
|
||||||
+19
@@ -0,0 +1,19 @@
|
|||||||
|
import { WorkflowData, createWorkflow } from "@medusajs/workflows-sdk"
|
||||||
|
|
||||||
|
import { removeLocationsFromSalesChannelStep } from "../steps"
|
||||||
|
|
||||||
|
interface WorkflowInput {
|
||||||
|
data: {
|
||||||
|
sales_channel_id: string
|
||||||
|
location_ids: string[]
|
||||||
|
}[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export const removeLocationsFromSalesChannelWorkflowId =
|
||||||
|
"remove-locations-from-sales-channel"
|
||||||
|
export const removeLocationsFromSalesChannelWorkflow = createWorkflow(
|
||||||
|
removeLocationsFromSalesChannelWorkflowId,
|
||||||
|
(input: WorkflowData<WorkflowInput>): WorkflowData<void> => {
|
||||||
|
removeLocationsFromSalesChannelStep(input.data)
|
||||||
|
}
|
||||||
|
)
|
||||||
@@ -100,9 +100,11 @@ export default class LinkModuleService<TLink> implements ILinkModule {
|
|||||||
return this.primaryKey_.concat(this.foreignKey_).includes(name)
|
return this.primaryKey_.concat(this.foreignKey_).includes(name)
|
||||||
}
|
}
|
||||||
|
|
||||||
private validateFields(data: any) {
|
private validateFields(data: any | any[]) {
|
||||||
const keys = Object.keys(data)
|
const dataToValidate = Array.isArray(data) ? data : [data]
|
||||||
if (!keys.every((k) => this.isValidKeyName(k))) {
|
dataToValidate.forEach((d) => {
|
||||||
|
const keys = Object.keys(d)
|
||||||
|
if (keys.some((k) => !this.isValidKeyName(k))) {
|
||||||
throw new MedusaError(
|
throw new MedusaError(
|
||||||
MedusaError.Types.INVALID_DATA,
|
MedusaError.Types.INVALID_DATA,
|
||||||
`Invalid field name provided. Valid field names are ${this.primaryKey_.concat(
|
`Invalid field name provided. Valid field names are ${this.primaryKey_.concat(
|
||||||
@@ -110,6 +112,7 @@ export default class LinkModuleService<TLink> implements ILinkModule {
|
|||||||
)}`
|
)}`
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@InjectManager("baseRepository_")
|
@InjectManager("baseRepository_")
|
||||||
@@ -276,10 +279,12 @@ export default class LinkModuleService<TLink> implements ILinkModule {
|
|||||||
{ returnLinkableKeys }: SoftDeleteReturn = {},
|
{ returnLinkableKeys }: SoftDeleteReturn = {},
|
||||||
@MedusaContext() sharedContext: Context = {}
|
@MedusaContext() sharedContext: Context = {}
|
||||||
): Promise<Record<string, unknown[]> | void> {
|
): Promise<Record<string, unknown[]> | void> {
|
||||||
this.validateFields(data)
|
const inputArray = Array.isArray(data) ? data : [data]
|
||||||
|
|
||||||
|
this.validateFields(inputArray)
|
||||||
|
|
||||||
let [deletedEntities, cascadedEntitiesMap] = await this.softDelete_(
|
let [deletedEntities, cascadedEntitiesMap] = await this.softDelete_(
|
||||||
data,
|
inputArray,
|
||||||
sharedContext
|
sharedContext
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -324,7 +329,7 @@ export default class LinkModuleService<TLink> implements ILinkModule {
|
|||||||
|
|
||||||
@InjectTransactionManager(shouldForceTransaction, "baseRepository_")
|
@InjectTransactionManager(shouldForceTransaction, "baseRepository_")
|
||||||
protected async softDelete_(
|
protected async softDelete_(
|
||||||
data: any,
|
data: any[],
|
||||||
@MedusaContext() sharedContext: Context = {}
|
@MedusaContext() sharedContext: Context = {}
|
||||||
): Promise<[object[], Record<string, string[]>]> {
|
): Promise<[object[], Record<string, string[]>]> {
|
||||||
return await this.linkService_.softDelete(data, sharedContext)
|
return await this.linkService_.softDelete(data, sharedContext)
|
||||||
@@ -335,10 +340,11 @@ export default class LinkModuleService<TLink> implements ILinkModule {
|
|||||||
{ returnLinkableKeys }: RestoreReturn = {},
|
{ returnLinkableKeys }: RestoreReturn = {},
|
||||||
@MedusaContext() sharedContext: Context = {}
|
@MedusaContext() sharedContext: Context = {}
|
||||||
): Promise<Record<string, unknown[]> | void> {
|
): Promise<Record<string, unknown[]> | void> {
|
||||||
this.validateFields(data)
|
const inputArray = Array.isArray(data) ? data : [data]
|
||||||
|
this.validateFields(inputArray)
|
||||||
|
|
||||||
let [restoredEntities, cascadedEntitiesMap] = await this.restore_(
|
let [restoredEntities, cascadedEntitiesMap] = await this.restore_(
|
||||||
data,
|
inputArray,
|
||||||
sharedContext
|
sharedContext
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -87,15 +87,24 @@ export default class LinkService<TEntity> {
|
|||||||
|
|
||||||
@InjectTransactionManager(doNotForceTransaction, "linkRepository_")
|
@InjectTransactionManager(doNotForceTransaction, "linkRepository_")
|
||||||
async softDelete(
|
async softDelete(
|
||||||
data: any,
|
data: any[],
|
||||||
@MedusaContext() sharedContext: Context = {}
|
@MedusaContext() sharedContext: Context = {}
|
||||||
): Promise<[object[], Record<string, string[]>]> {
|
): Promise<[object[], Record<string, string[]>]> {
|
||||||
|
const deleteFilters = {
|
||||||
|
$or: data.map((dataEntry) => {
|
||||||
const filter = {}
|
const filter = {}
|
||||||
for (const key in data) {
|
for (const key in dataEntry) {
|
||||||
filter[key] = { $in: Array.isArray(data[key]) ? data[key] : [data[key]] }
|
filter[key] = {
|
||||||
|
$in: Array.isArray(dataEntry[key])
|
||||||
|
? dataEntry[key]
|
||||||
|
: [dataEntry[key]],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return filter
|
||||||
|
}),
|
||||||
}
|
}
|
||||||
|
|
||||||
return await this.linkRepository_.softDelete(filter, {
|
return await this.linkRepository_.softDelete(deleteFilters, {
|
||||||
transactionManager: sharedContext.transactionManager,
|
transactionManager: sharedContext.transactionManager,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -105,12 +114,21 @@ export default class LinkService<TEntity> {
|
|||||||
data: any,
|
data: any,
|
||||||
@MedusaContext() sharedContext: Context = {}
|
@MedusaContext() sharedContext: Context = {}
|
||||||
): Promise<[object[], Record<string, string[]>]> {
|
): Promise<[object[], Record<string, string[]>]> {
|
||||||
|
const restoreFilters = {
|
||||||
|
$or: data.map((dataEntry) => {
|
||||||
const filter = {}
|
const filter = {}
|
||||||
for (const key in data) {
|
for (const key in dataEntry) {
|
||||||
filter[key] = { $in: Array.isArray(data[key]) ? data[key] : [data[key]] }
|
filter[key] = {
|
||||||
|
$in: Array.isArray(dataEntry[key])
|
||||||
|
? dataEntry[key]
|
||||||
|
: [dataEntry[key]],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return filter
|
||||||
|
}),
|
||||||
}
|
}
|
||||||
|
|
||||||
return await this.linkRepository_.restore(data, {
|
return await this.linkRepository_.restore(restoreFilters, {
|
||||||
transactionManager: sharedContext.transactionManager,
|
transactionManager: sharedContext.transactionManager,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
import { removeRulesFromPromotionsWorkflow } from "@medusajs/core-flows"
|
|
||||||
import { RuleType } from "@medusajs/utils"
|
|
||||||
import {
|
import {
|
||||||
AuthenticatedMedusaRequest,
|
AuthenticatedMedusaRequest,
|
||||||
MedusaResponse,
|
MedusaResponse,
|
||||||
} from "../../../../../../../types/routing"
|
} from "../../../../../../../types/routing"
|
||||||
|
|
||||||
import { AdminPostPromotionsPromotionRulesBatchRemoveReq } from "../../../../validators"
|
import { AdminPostPromotionsPromotionRulesBatchRemoveReq } from "../../../../validators"
|
||||||
|
import { RuleType } from "@medusajs/utils"
|
||||||
|
import { removeRulesFromPromotionsWorkflow } from "@medusajs/core-flows"
|
||||||
|
|
||||||
export const POST = async (
|
export const POST = async (
|
||||||
req: AuthenticatedMedusaRequest<AdminPostPromotionsPromotionRulesBatchRemoveReq>,
|
req: AuthenticatedMedusaRequest<AdminPostPromotionsPromotionRulesBatchRemoveReq>,
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ export const GET = async (
|
|||||||
const queryObject = remoteQueryObjectFromString({
|
const queryObject = remoteQueryObjectFromString({
|
||||||
entryPoint: "sales_channels",
|
entryPoint: "sales_channels",
|
||||||
variables,
|
variables,
|
||||||
fields: defaultAdminSalesChannelFields,
|
fields: req.remoteQueryConfig.fields,
|
||||||
})
|
})
|
||||||
|
|
||||||
const [sales_channel] = await remoteQuery(queryObject)
|
const [sales_channel] = await remoteQuery(queryObject)
|
||||||
|
|||||||
+44
@@ -0,0 +1,44 @@
|
|||||||
|
import {
|
||||||
|
ContainerRegistrationKeys,
|
||||||
|
remoteQueryObjectFromString,
|
||||||
|
} from "@medusajs/utils"
|
||||||
|
import {
|
||||||
|
MedusaRequest,
|
||||||
|
MedusaResponse,
|
||||||
|
} from "../../../../../../../types/routing"
|
||||||
|
|
||||||
|
import { AdminStockLocationsLocationSalesChannelBatchReq } from "../../../../validators"
|
||||||
|
import { addLocationsToSalesChannelWorkflow } from "@medusajs/core-flows"
|
||||||
|
|
||||||
|
export const POST = async (
|
||||||
|
req: MedusaRequest<AdminStockLocationsLocationSalesChannelBatchReq>,
|
||||||
|
res: MedusaResponse
|
||||||
|
) => {
|
||||||
|
const workflowInput = {
|
||||||
|
data: req.validatedBody.sales_channel_ids.map((id) => ({
|
||||||
|
sales_channel_id: id,
|
||||||
|
location_ids: [req.params.id],
|
||||||
|
})),
|
||||||
|
}
|
||||||
|
|
||||||
|
const { errors } = await addLocationsToSalesChannelWorkflow(req.scope).run({
|
||||||
|
input: workflowInput,
|
||||||
|
throwOnError: false,
|
||||||
|
})
|
||||||
|
|
||||||
|
if (Array.isArray(errors) && errors[0]) {
|
||||||
|
throw errors[0].error
|
||||||
|
}
|
||||||
|
|
||||||
|
const remoteQuery = req.scope.resolve(ContainerRegistrationKeys.REMOTE_QUERY)
|
||||||
|
|
||||||
|
const queryObject = remoteQueryObjectFromString({
|
||||||
|
entryPoint: "stock_locations",
|
||||||
|
variables: { id: req.params.id },
|
||||||
|
fields: req.remoteQueryConfig.fields,
|
||||||
|
})
|
||||||
|
|
||||||
|
const [stock_location] = await remoteQuery(queryObject)
|
||||||
|
|
||||||
|
res.status(200).json({ stock_location })
|
||||||
|
}
|
||||||
+46
@@ -0,0 +1,46 @@
|
|||||||
|
import {
|
||||||
|
ContainerRegistrationKeys,
|
||||||
|
remoteQueryObjectFromString,
|
||||||
|
} from "@medusajs/utils"
|
||||||
|
import {
|
||||||
|
MedusaRequest,
|
||||||
|
MedusaResponse,
|
||||||
|
} from "../../../../../../../types/routing"
|
||||||
|
|
||||||
|
import { AdminStockLocationsLocationSalesChannelBatchReq } from "../../../../validators"
|
||||||
|
import { removeLocationsFromSalesChannelWorkflow } from "@medusajs/core-flows"
|
||||||
|
|
||||||
|
export const POST = async (
|
||||||
|
req: MedusaRequest<AdminStockLocationsLocationSalesChannelBatchReq>,
|
||||||
|
res: MedusaResponse
|
||||||
|
) => {
|
||||||
|
const workflowInput = {
|
||||||
|
data: req.validatedBody.sales_channel_ids.map((id) => ({
|
||||||
|
sales_channel_id: id,
|
||||||
|
location_ids: [req.params.id],
|
||||||
|
})),
|
||||||
|
}
|
||||||
|
|
||||||
|
const { errors } = await removeLocationsFromSalesChannelWorkflow(
|
||||||
|
req.scope
|
||||||
|
).run({
|
||||||
|
input: workflowInput,
|
||||||
|
throwOnError: false,
|
||||||
|
})
|
||||||
|
|
||||||
|
if (Array.isArray(errors) && errors[0]) {
|
||||||
|
throw errors[0].error
|
||||||
|
}
|
||||||
|
|
||||||
|
const remoteQuery = req.scope.resolve(ContainerRegistrationKeys.REMOTE_QUERY)
|
||||||
|
|
||||||
|
const queryObject = remoteQueryObjectFromString({
|
||||||
|
entryPoint: "stock_locations",
|
||||||
|
variables: { id: req.params.id },
|
||||||
|
fields: req.remoteQueryConfig.fields,
|
||||||
|
})
|
||||||
|
|
||||||
|
const [stock_location] = await remoteQuery(queryObject)
|
||||||
|
|
||||||
|
res.status(200).json({ stock_location })
|
||||||
|
}
|
||||||
@@ -7,6 +7,7 @@ import {
|
|||||||
AdminPostStockLocationsLocationReq,
|
AdminPostStockLocationsLocationReq,
|
||||||
AdminPostStockLocationsParams,
|
AdminPostStockLocationsParams,
|
||||||
AdminPostStockLocationsReq,
|
AdminPostStockLocationsReq,
|
||||||
|
AdminStockLocationsLocationSalesChannelBatchReq,
|
||||||
} from "./validators"
|
} from "./validators"
|
||||||
import { transformBody, transformQuery } from "../../../api/middlewares"
|
import { transformBody, transformQuery } from "../../../api/middlewares"
|
||||||
|
|
||||||
@@ -53,6 +54,17 @@ export const adminStockLocationRoutesMiddlewares: MiddlewareRoute[] = [
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
method: ["POST"],
|
||||||
|
matcher: "/admin/stock-locations/:id/sales-channels/batch*",
|
||||||
|
middlewares: [
|
||||||
|
transformBody(AdminStockLocationsLocationSalesChannelBatchReq),
|
||||||
|
transformQuery(
|
||||||
|
AdminPostStockLocationsLocationParams,
|
||||||
|
QueryConfig.retrieveTransformQueryConfig
|
||||||
|
),
|
||||||
|
],
|
||||||
|
},
|
||||||
{
|
{
|
||||||
method: ["GET"],
|
method: ["GET"],
|
||||||
matcher: "/admin/stock-locations/:id",
|
matcher: "/admin/stock-locations/:id",
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ export const defaultAdminStockLocationFields = [
|
|||||||
|
|
||||||
export const retrieveTransformQueryConfig = {
|
export const retrieveTransformQueryConfig = {
|
||||||
defaults: defaultAdminStockLocationFields,
|
defaults: defaultAdminStockLocationFields,
|
||||||
allowed: defaultAdminStockLocationFields,
|
|
||||||
isList: false,
|
isList: false,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,15 +1,6 @@
|
|||||||
|
import { FindParams, extendedFindParamsMixin } from "../../../types/common"
|
||||||
import {
|
import {
|
||||||
DateComparisonOperator,
|
|
||||||
FindParams,
|
|
||||||
NumericalComparisonOperator,
|
|
||||||
StringComparisonOperator,
|
|
||||||
extendedFindParamsMixin,
|
|
||||||
} from "../../../types/common"
|
|
||||||
import {
|
|
||||||
IsBoolean,
|
|
||||||
IsEmail,
|
|
||||||
IsNotEmpty,
|
IsNotEmpty,
|
||||||
IsNumber,
|
|
||||||
IsObject,
|
IsObject,
|
||||||
IsOptional,
|
IsOptional,
|
||||||
IsString,
|
IsString,
|
||||||
@@ -290,3 +281,8 @@ export class AdminPostStockLocationsLocationReq {
|
|||||||
export class AdminPostStockLocationsLocationParams extends FindParams {}
|
export class AdminPostStockLocationsLocationParams extends FindParams {}
|
||||||
|
|
||||||
export class AdminGetStockLocationsLocationParams extends FindParams {}
|
export class AdminGetStockLocationsLocationParams extends FindParams {}
|
||||||
|
|
||||||
|
export class AdminStockLocationsLocationSalesChannelBatchReq {
|
||||||
|
@IsString({ each: true })
|
||||||
|
sales_channel_ids: string[]
|
||||||
|
}
|
||||||
Reference in new issue
Block a user