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:
Oli Juhl
2024-03-18 21:57:29 +01:00
committed by GitHub
parent 4b06c17dc0
commit 0219a8677b
28 changed files with 1640 additions and 1146 deletions

View File

@@ -1,6 +1,6 @@
// 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 {
"deleted": true,
"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 {
"sales_channel": ObjectContaining {
"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 {
"sales_channel": ObjectContaining {
"description": "sales channel description",

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
import { ICustomerModuleService } from "@medusajs/types"
import { createStep, StepResponse } from "@medusajs/workflows-sdk"
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
type DeleteCustomerStepInput = string[]

View File

@@ -1,5 +1,5 @@
export * from "./auth"
export * from "./api-key"
export * from "./auth"
export * from "./customer"
export * from "./customer-group"
export * from "./definition"
@@ -14,6 +14,7 @@ export * from "./pricing"
export * from "./product"
export * from "./promotion"
export * from "./region"
export * from "./sales-channel"
export * from "./shipping-options"
export * from "./store"
export * from "./tax"

View File

@@ -0,0 +1,2 @@
export * from "./steps"
export * from "./workflows"

View File

@@ -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)
}
)

View File

@@ -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)
}
)

View File

@@ -0,0 +1,3 @@
export * from "./create-sales-channels"
export * from "./update-sales-channels"
export * from "./delete-sales-channels"

View File

@@ -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,
}))
)
}
)

View File

@@ -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 })
}
)

View File

@@ -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)
}
)

View File

@@ -0,0 +1,3 @@
export * from "./create-sales-channels"
export * from "./update-sales-channels"
export * from "./delete-sales-channels"

View File

@@ -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)
}
)

View File

@@ -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,
})
}

View File

@@ -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: [],
},
]

View File

@@ -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,
}

View File

@@ -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 })
}

View File

@@ -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>
}

View File

@@ -14,6 +14,7 @@ import { adminPricingRoutesMiddlewares } from "./admin/pricing/middlewares"
import { adminProductRoutesMiddlewares } from "./admin/products/middlewares"
import { adminPromotionRoutesMiddlewares } from "./admin/promotions/middlewares"
import { adminRegionRoutesMiddlewares } from "./admin/regions/middlewares"
import { adminSalesChannelRoutesMiddlewares } from "./admin/sales-channels/middlewares"
import { adminStoreRoutesMiddlewares } from "./admin/stores/middlewares"
import { adminTaxRateRoutesMiddlewares } from "./admin/tax-rates/middlewares"
import { adminTaxRegionRoutesMiddlewares } from "./admin/tax-regions/middlewares"
@@ -55,5 +56,6 @@ export const config: MiddlewaresConfig = {
...adminCollectionRoutesMiddlewares,
...adminPricingRoutesMiddlewares,
...adminFulfillmentRoutesMiddlewares,
...adminSalesChannelRoutesMiddlewares,
],
}

View File

@@ -4,8 +4,8 @@ import { ISalesChannelModuleService } from "@medusajs/types"
import { initialize } from "../../../src"
import { DB_URL, MikroOrmWrapper } from "../../utils"
import { createSalesChannels } from "../../__fixtures__"
import { DB_URL, MikroOrmWrapper } from "../../utils"
jest.setTimeout(30000)
@@ -84,13 +84,10 @@ describe("Sales Channel Service", () => {
const id = "channel-2"
it("should update the name of the SalesChannel successfully", async () => {
await service.update([
{
id,
name: "Update name 2",
is_disabled: true,
},
])
await service.update(id, {
name: "Update name 2",
is_disabled: true,
})
const channel = await service.retrieve(id)
@@ -102,11 +99,9 @@ describe("Sales Channel Service", () => {
let error
try {
await service.update([
{
id: "does-not-exist",
},
])
await service.update("does-not-exist", {
name: "does-not-exist",
})
} catch (e) {
error = e
}

View File

@@ -43,6 +43,15 @@
"default": "false",
"mappedType": "boolean"
},
"metadata": {
"name": "metadata",
"type": "jsonb",
"unsigned": false,
"autoincrement": false,
"primary": false,
"nullable": true,
"mappedType": "json"
},
"created_at": {
"name": "created_at",
"type": "timestamptz",

View File

@@ -3,7 +3,7 @@ import { Migration } from "@mikro-orm/migrations"
export class Migration20240115152146 extends Migration {
async up(): Promise<void> {
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(
'create index "IDX_sales_channel_deleted_at" on "sales_channel" ("deleted_at");'

View File

@@ -38,6 +38,9 @@ export default class SalesChannel {
})
created_at: Date
@Property({ columnType: "jsonb", nullable: true })
metadata: Record<string, unknown> | null = null
@Property({
onCreate: () => new Date(),
onUpdate: () => new Date(),

View File

@@ -2,6 +2,7 @@ import {
Context,
CreateSalesChannelDTO,
DAL,
FilterableSalesChannelProps,
InternalModuleDeclaration,
ISalesChannelModuleService,
ModuleJoinerConfig,
@@ -9,10 +10,19 @@ import {
SalesChannelDTO,
UpdateSalesChannelDTO,
} from "@medusajs/types"
import { MedusaContext, ModulesSdkUtils } from "@medusajs/utils"
import {
InjectManager,
InjectTransactionManager,
isString,
MedusaContext,
ModulesSdkUtils,
promiseAll,
} from "@medusajs/utils"
import { SalesChannel } from "@models"
import { UpsertSalesChannelDTO } from "@medusajs/types"
import { UpdateSalesChanneInput } from "@types"
import { entityNameToLinkableKeysMap, joinerConfig } from "../joiner-config"
type InjectedDependencies = {
@@ -51,19 +61,18 @@ export default class SalesChannelModuleService<
data: CreateSalesChannelDTO[],
sharedContext?: Context
): Promise<SalesChannelDTO[]>
async create(
data: CreateSalesChannelDTO,
sharedContext?: Context
): Promise<SalesChannelDTO>
@InjectManager("baseRepository_")
async create(
data: CreateSalesChannelDTO | CreateSalesChannelDTO[],
@MedusaContext() sharedContext: Context = {}
): Promise<SalesChannelDTO | SalesChannelDTO[]> {
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[]>(
Array.isArray(data) ? result : result[0],
@@ -73,23 +82,47 @@ export default class SalesChannelModuleService<
)
}
async update(
data: UpdateSalesChannelDTO[],
sharedContext?: Context
): Promise<SalesChannelDTO[]>
@InjectTransactionManager("baseRepository_")
async create_(
data: CreateSalesChannelDTO[],
@MedusaContext() sharedContext: Context
): Promise<SalesChannel[]> {
return await this.salesChannelService_.create(data, sharedContext)
}
async update(
id: string,
data: UpdateSalesChannelDTO,
sharedContext?: Context
): Promise<SalesChannelDTO>
async update(
selector: FilterableSalesChannelProps,
data: UpdateSalesChannelDTO,
sharedContext?: Context
): Promise<SalesChannelDTO[]>
@InjectManager("baseRepository_")
async update(
idOrSelector: string | FilterableSalesChannelProps,
data: UpdateSalesChannelDTO | UpdateSalesChannelDTO[],
@MedusaContext() sharedContext: Context = {}
): 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[]>(
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])
}
}

View File

@@ -1,5 +1,7 @@
import { Logger } from "@medusajs/types"
import { Logger, UpdateSalesChannelDTO } from "@medusajs/types"
export type InitializeModuleInjectableDependencies = {
logger?: Logger
}
export type UpdateSalesChanneInput = UpdateSalesChannelDTO & { id: string }

View File

@@ -63,12 +63,12 @@ export interface FilterableSalesChannelProps
/**
* The IDs to filter the sales channel by.
*/
id?: string[]
id?: string | string[]
/**
* Filter sales channels by their names.
*/
name?: string[]
name?: string | string[]
/**
* Filter sales channels by whether they're disabled.

View File

@@ -22,11 +22,6 @@ export interface CreateSalesChannelDTO {
* The attributes to update in the sales channel.
*/
export interface UpdateSalesChannelDTO {
/**
* The ID of the sales channel.
*/
id: string
/**
* The name of the sales channel.
*/
@@ -41,4 +36,34 @@ export interface UpdateSalesChannelDTO {
* Whether the sales channel is disabled.
*/
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
}

View File

@@ -1,9 +1,9 @@
import { IModuleService } from "../modules-sdk"
import { FilterableSalesChannelProps, SalesChannelDTO } from "./common"
import { FindConfig } from "../common"
import { Context } from "../shared-context"
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.
@@ -39,35 +39,25 @@ export interface ISalesChannelModuleService extends IModuleService {
sharedContext?: Context
): 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(
channelId: string,
data: UpdateSalesChannelDTO,
sharedContext?: Context
): 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.