chore: Move several more endpoints to use zod for validation, unify APIs (#7086)
This commit is contained in:
@@ -334,14 +334,14 @@ medusaIntegrationTestRunner({
|
||||
|
||||
it("should delete an inventory location level and create a new one", async () => {
|
||||
const result = await api.post(
|
||||
`/admin/inventory-items/${inventoryItem.id}/location-levels/batch/combi`,
|
||||
`/admin/inventory-items/${inventoryItem.id}/location-levels/op/batch`,
|
||||
{
|
||||
creates: [
|
||||
create: [
|
||||
{
|
||||
location_id: "location_2",
|
||||
},
|
||||
],
|
||||
deletes: [locationId],
|
||||
delete: [locationId],
|
||||
},
|
||||
adminHeaders
|
||||
)
|
||||
@@ -386,6 +386,7 @@ medusaIntegrationTestRunner({
|
||||
id: expect.any(String),
|
||||
object: "inventory-level",
|
||||
deleted: true,
|
||||
parent: expect.any(Object),
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ export const joinerConfig: ModuleJoinerConfig = {
|
||||
schema: moduleSchema,
|
||||
alias: [
|
||||
{
|
||||
name: ["inventory_items", "inventory"],
|
||||
name: ["inventory_items", "inventory_item", "inventory"],
|
||||
args: {
|
||||
entity: "InventoryItem",
|
||||
},
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
import {
|
||||
AdminFulfillmentSetsDeleteResponse,
|
||||
IFulfillmentModuleService,
|
||||
} from "@medusajs/types"
|
||||
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
|
||||
import { AdminFulfillmentSetsDeleteResponse } from "@medusajs/types"
|
||||
import { deleteFulfillmentSetsWorkflow } from "@medusajs/core-flows"
|
||||
|
||||
import {
|
||||
@@ -16,13 +12,6 @@ export const DELETE = async (
|
||||
) => {
|
||||
const { id } = req.params
|
||||
|
||||
const fulfillmentModuleService = req.scope.resolve<IFulfillmentModuleService>(
|
||||
ModuleRegistrationName.FULFILLMENT
|
||||
)
|
||||
|
||||
// Test if exists
|
||||
await fulfillmentModuleService.retrieve(id)
|
||||
|
||||
const { errors } = await deleteFulfillmentSetsWorkflow(req.scope).run({
|
||||
input: { ids: [id] },
|
||||
throwOnError: false,
|
||||
|
||||
@@ -1,17 +1,12 @@
|
||||
import { createServiceZonesWorkflow } from "@medusajs/core-flows"
|
||||
import {
|
||||
ContainerRegistrationKeys,
|
||||
remoteQueryObjectFromString,
|
||||
} from "@medusajs/utils"
|
||||
import { MedusaRequest, MedusaResponse } from "../../../../../types/routing"
|
||||
import { AdminCreateFulfillmentSetServiceZonesType } from "../../validators"
|
||||
import { refetchFulfillmentSet } from "../../helpers"
|
||||
|
||||
export const POST = async (
|
||||
req: MedusaRequest<AdminCreateFulfillmentSetServiceZonesType>,
|
||||
res: MedusaResponse
|
||||
) => {
|
||||
const remoteQuery = req.scope.resolve(ContainerRegistrationKeys.REMOTE_QUERY)
|
||||
|
||||
const workflowInput = {
|
||||
data: [
|
||||
{
|
||||
@@ -31,15 +26,11 @@ export const POST = async (
|
||||
throw errors[0].error
|
||||
}
|
||||
|
||||
const [fulfillment_set] = await remoteQuery(
|
||||
remoteQueryObjectFromString({
|
||||
entryPoint: "fulfillment_sets",
|
||||
variables: {
|
||||
id: req.params.id,
|
||||
},
|
||||
fields: req.remoteQueryConfig.fields,
|
||||
})
|
||||
const fulfillmentSet = await refetchFulfillmentSet(
|
||||
req.params.id,
|
||||
req.scope,
|
||||
req.remoteQueryConfig.fields
|
||||
)
|
||||
|
||||
res.status(200).json({ fulfillment_set })
|
||||
res.status(200).json({ fulfillment_set: fulfillmentSet })
|
||||
}
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
import { MedusaContainer } from "@medusajs/types"
|
||||
import {
|
||||
ContainerRegistrationKeys,
|
||||
remoteQueryObjectFromString,
|
||||
} from "@medusajs/utils"
|
||||
|
||||
export const refetchFulfillmentSet = async (
|
||||
fulfillmentSetId: string,
|
||||
scope: MedusaContainer,
|
||||
fields: string[]
|
||||
) => {
|
||||
const remoteQuery = scope.resolve(ContainerRegistrationKeys.REMOTE_QUERY)
|
||||
const queryObject = remoteQueryObjectFromString({
|
||||
entryPoint: "fulfillment_set",
|
||||
variables: {
|
||||
filters: { id: fulfillmentSetId },
|
||||
},
|
||||
fields: fields,
|
||||
})
|
||||
|
||||
const fulfillmentSets = await remoteQuery(queryObject)
|
||||
return fulfillmentSets[0]
|
||||
}
|
||||
@@ -30,7 +30,12 @@ export const adminFulfillmentSetsRoutesMiddlewares: MiddlewareRoute[] = [
|
||||
{
|
||||
method: ["DELETE"],
|
||||
matcher: "/admin/fulfillment-sets/:id/service-zones/:zone_id",
|
||||
middlewares: [],
|
||||
middlewares: [
|
||||
validateAndTransformQuery(
|
||||
AdminFulfillmentSetParams,
|
||||
QueryConfig.retrieveTransformQueryConfig
|
||||
),
|
||||
],
|
||||
},
|
||||
{
|
||||
method: ["DELETE"],
|
||||
|
||||
+22
-17
@@ -5,15 +5,19 @@ import {
|
||||
} from "@medusajs/utils"
|
||||
import { MedusaRequest, MedusaResponse } from "../../../../../../types/routing"
|
||||
|
||||
import { AdminPostInventoryItemsItemLocationLevelsLevelReq } from "../../../validators"
|
||||
import { deleteInventoryLevelsWorkflow } from "@medusajs/core-flows"
|
||||
import { updateInventoryLevelsWorkflow } from "@medusajs/core-flows"
|
||||
import {
|
||||
deleteInventoryLevelsWorkflow,
|
||||
updateInventoryLevelsWorkflow,
|
||||
} from "@medusajs/core-flows"
|
||||
import { refetchInventoryItem } from "../../../helpers"
|
||||
import { AdminUpdateInventoryLocationLevelType } from "../../../validators"
|
||||
|
||||
export const DELETE = async (req: MedusaRequest, res: MedusaResponse) => {
|
||||
const { id, location_id } = req.params
|
||||
|
||||
const remoteQuery = req.scope.resolve(ContainerRegistrationKeys.REMOTE_QUERY)
|
||||
|
||||
// TODO: We probably want to move this logic to the workflow
|
||||
const [{ id: levelId, reserved_quantity: reservedQuantity }] =
|
||||
await remoteQuery(
|
||||
remoteQueryObjectFromString({
|
||||
@@ -41,23 +45,28 @@ export const DELETE = async (req: MedusaRequest, res: MedusaResponse) => {
|
||||
},
|
||||
})
|
||||
|
||||
const inventoryItem = await refetchInventoryItem(
|
||||
id,
|
||||
req.scope,
|
||||
req.remoteQueryConfig.fields
|
||||
)
|
||||
|
||||
res.status(200).json({
|
||||
id: levelId,
|
||||
object: "inventory-level",
|
||||
deleted: true,
|
||||
parent: inventoryItem,
|
||||
})
|
||||
}
|
||||
|
||||
export const POST = async (
|
||||
req: MedusaRequest<AdminPostInventoryItemsItemLocationLevelsLevelReq>,
|
||||
req: MedusaRequest<AdminUpdateInventoryLocationLevelType>,
|
||||
res: MedusaResponse
|
||||
) => {
|
||||
const { id: inventory_item_id, location_id } = req.params
|
||||
const remoteQuery = req.scope.resolve(ContainerRegistrationKeys.REMOTE_QUERY)
|
||||
|
||||
const { id, location_id } = req.params
|
||||
const { errors } = await updateInventoryLevelsWorkflow(req.scope).run({
|
||||
input: {
|
||||
updates: [{ inventory_item_id, location_id, ...req.validatedBody }],
|
||||
updates: [{ ...req.validatedBody, inventory_item_id: id, location_id }],
|
||||
},
|
||||
throwOnError: false,
|
||||
})
|
||||
@@ -66,17 +75,13 @@ export const POST = async (
|
||||
throw errors[0].error
|
||||
}
|
||||
|
||||
const [inventory_item] = await remoteQuery(
|
||||
remoteQueryObjectFromString({
|
||||
entryPoint: "inventory",
|
||||
variables: {
|
||||
id: inventory_item_id,
|
||||
},
|
||||
fields: req.remoteQueryConfig.fields,
|
||||
})
|
||||
const inventoryItem = await refetchInventoryItem(
|
||||
id,
|
||||
req.scope,
|
||||
req.remoteQueryConfig.fields
|
||||
)
|
||||
|
||||
res.status(200).json({
|
||||
inventory_item,
|
||||
inventory_item: inventoryItem,
|
||||
})
|
||||
}
|
||||
|
||||
-55
@@ -1,55 +0,0 @@
|
||||
import {
|
||||
AdminPostInventoryItemsItemLocationLevelsBatchReq,
|
||||
AdminPostInventoryItemsItemLocationLevelsReq,
|
||||
} from "../../../../validators"
|
||||
import {
|
||||
ContainerRegistrationKeys,
|
||||
remoteQueryObjectFromString,
|
||||
} from "@medusajs/utils"
|
||||
import {
|
||||
MedusaRequest,
|
||||
MedusaResponse,
|
||||
} from "../../../../../../../types/routing"
|
||||
|
||||
import { bulkCreateDeleteLevelsWorkflow } from "@medusajs/core-flows"
|
||||
import { defaultAdminInventoryItemFields } from "../../../../query-config"
|
||||
|
||||
export const POST = async (
|
||||
req: MedusaRequest<AdminPostInventoryItemsItemLocationLevelsBatchReq>,
|
||||
res: MedusaResponse
|
||||
) => {
|
||||
const { id } = req.params
|
||||
|
||||
const remoteQuery = req.scope.resolve(ContainerRegistrationKeys.REMOTE_QUERY)
|
||||
|
||||
const workflow = bulkCreateDeleteLevelsWorkflow(req.scope)
|
||||
const { errors } = await workflow.run({
|
||||
input: {
|
||||
deletes: req.validatedBody.deletes.map((location_id) => ({
|
||||
location_id,
|
||||
inventory_item_id: id,
|
||||
})),
|
||||
creates: req.validatedBody.creates.map((c) => ({
|
||||
...c,
|
||||
inventory_item_id: id,
|
||||
})),
|
||||
},
|
||||
throwOnError: false,
|
||||
})
|
||||
|
||||
if (Array.isArray(errors) && errors[0]) {
|
||||
throw errors[0].error
|
||||
}
|
||||
|
||||
const itemQuery = remoteQueryObjectFromString({
|
||||
entryPoint: "inventory_items",
|
||||
variables: {
|
||||
id,
|
||||
},
|
||||
fields: defaultAdminInventoryItemFields,
|
||||
})
|
||||
|
||||
const [inventory_item] = await remoteQuery(itemQuery)
|
||||
|
||||
res.status(200).json({ inventory_item })
|
||||
}
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
import {
|
||||
AdminCreateInventoryLocationLevelType,
|
||||
AdminUpdateInventoryLocationLevelType,
|
||||
} from "../../../../validators"
|
||||
import {
|
||||
MedusaRequest,
|
||||
MedusaResponse,
|
||||
} from "../../../../../../../types/routing"
|
||||
|
||||
import { bulkCreateDeleteLevelsWorkflow } from "@medusajs/core-flows"
|
||||
import { BatchMethodRequest } from "@medusajs/types"
|
||||
|
||||
export const POST = async (
|
||||
req: MedusaRequest<
|
||||
BatchMethodRequest<
|
||||
AdminCreateInventoryLocationLevelType,
|
||||
AdminUpdateInventoryLocationLevelType
|
||||
>
|
||||
>,
|
||||
res: MedusaResponse
|
||||
) => {
|
||||
const { id } = req.params
|
||||
|
||||
// TODO: Normalize workflow and response, and add support for updates
|
||||
const workflow = bulkCreateDeleteLevelsWorkflow(req.scope)
|
||||
const { errors } = await workflow.run({
|
||||
input: {
|
||||
deletes:
|
||||
req.validatedBody.delete?.map((location_id) => ({
|
||||
location_id,
|
||||
inventory_item_id: id,
|
||||
})) ?? [],
|
||||
creates:
|
||||
req.validatedBody.create?.map((c) => ({
|
||||
...c,
|
||||
inventory_item_id: id,
|
||||
})) ?? [],
|
||||
},
|
||||
throwOnError: false,
|
||||
})
|
||||
|
||||
if (Array.isArray(errors) && errors[0]) {
|
||||
throw errors[0].error
|
||||
}
|
||||
|
||||
res.status(200).json({ inventory_item: {} })
|
||||
}
|
||||
@@ -4,26 +4,26 @@ import {
|
||||
} from "@medusajs/utils"
|
||||
import { MedusaRequest, MedusaResponse } from "../../../../../types/routing"
|
||||
|
||||
import { AdminPostInventoryItemsItemLocationLevelsReq } from "../../validators"
|
||||
import { MedusaError } from "@medusajs/utils"
|
||||
import { createInventoryLevelsWorkflow } from "@medusajs/core-flows"
|
||||
import { defaultAdminInventoryItemFields } from "../../query-config"
|
||||
import {
|
||||
AdminCreateInventoryLocationLevelType,
|
||||
AdminGetInventoryLocationLevelsParamsType,
|
||||
} from "../../validators"
|
||||
import { refetchInventoryItem } from "../../helpers"
|
||||
|
||||
export const POST = async (
|
||||
req: MedusaRequest<AdminPostInventoryItemsItemLocationLevelsReq>,
|
||||
req: MedusaRequest<AdminCreateInventoryLocationLevelType>,
|
||||
res: MedusaResponse
|
||||
) => {
|
||||
const { id } = req.params
|
||||
|
||||
const remoteQuery = req.scope.resolve(ContainerRegistrationKeys.REMOTE_QUERY)
|
||||
|
||||
const workflow = createInventoryLevelsWorkflow(req.scope)
|
||||
const { errors } = await workflow.run({
|
||||
input: {
|
||||
inventory_levels: [
|
||||
{
|
||||
inventory_item_id: id,
|
||||
...req.validatedBody,
|
||||
inventory_item_id: id,
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -34,20 +34,18 @@ export const POST = async (
|
||||
throw errors[0].error
|
||||
}
|
||||
|
||||
const itemQuery = remoteQueryObjectFromString({
|
||||
entryPoint: "inventory_items",
|
||||
variables: {
|
||||
id,
|
||||
},
|
||||
fields: defaultAdminInventoryItemFields,
|
||||
})
|
||||
|
||||
const [inventory_item] = await remoteQuery(itemQuery)
|
||||
|
||||
res.status(200).json({ inventory_item })
|
||||
const inventoryItem = await refetchInventoryItem(
|
||||
id,
|
||||
req.scope,
|
||||
req.remoteQueryConfig.fields
|
||||
)
|
||||
res.status(200).json({ inventory_item: inventoryItem })
|
||||
}
|
||||
|
||||
export const GET = async (req: MedusaRequest, res: MedusaResponse) => {
|
||||
export const GET = async (
|
||||
req: MedusaRequest<AdminGetInventoryLocationLevelsParamsType>,
|
||||
res: MedusaResponse
|
||||
) => {
|
||||
const remoteQuery = req.scope.resolve(ContainerRegistrationKeys.REMOTE_QUERY)
|
||||
|
||||
const query = remoteQueryObjectFromString({
|
||||
|
||||
@@ -1,36 +1,26 @@
|
||||
import {
|
||||
ContainerRegistrationKeys,
|
||||
MedusaError,
|
||||
remoteQueryObjectFromString,
|
||||
} from "@medusajs/utils"
|
||||
import { MedusaError } from "@medusajs/utils"
|
||||
import { MedusaRequest, MedusaResponse } from "../../../../types/routing"
|
||||
import {
|
||||
deleteInventoryItemWorkflow,
|
||||
updateInventoryItemsWorkflow,
|
||||
} from "@medusajs/core-flows"
|
||||
import {
|
||||
AdminGetInventoryItemParamsType,
|
||||
AdminUpdateInventoryItemType,
|
||||
} from "../validators"
|
||||
import { refetchInventoryItem } from "../helpers"
|
||||
|
||||
import { AdminPostInventoryItemsInventoryItemReq } from "../validators"
|
||||
|
||||
export const GET = async (req: MedusaRequest, res: MedusaResponse) => {
|
||||
export const GET = async (
|
||||
req: MedusaRequest<AdminGetInventoryItemParamsType>,
|
||||
res: MedusaResponse
|
||||
) => {
|
||||
const { id } = req.params
|
||||
const remoteQuery = req.scope.resolve(ContainerRegistrationKeys.REMOTE_QUERY)
|
||||
|
||||
const query = remoteQueryObjectFromString({
|
||||
entryPoint: "inventory",
|
||||
variables: {
|
||||
filters: { id },
|
||||
skip: 0,
|
||||
take: 1,
|
||||
},
|
||||
|
||||
fields: req.retrieveConfig.select as string[],
|
||||
})
|
||||
|
||||
const { rows } = await remoteQuery(query)
|
||||
|
||||
const [inventory_item] = rows
|
||||
|
||||
if (!inventory_item) {
|
||||
const inventoryItem = await refetchInventoryItem(
|
||||
id,
|
||||
req.scope,
|
||||
req.remoteQueryConfig.fields
|
||||
)
|
||||
if (!inventoryItem) {
|
||||
throw new MedusaError(
|
||||
MedusaError.Types.NOT_FOUND,
|
||||
`Inventory item with id: ${id} was not found`
|
||||
@@ -38,13 +28,13 @@ export const GET = async (req: MedusaRequest, res: MedusaResponse) => {
|
||||
}
|
||||
|
||||
res.status(200).json({
|
||||
inventory_item,
|
||||
inventory_item: inventoryItem,
|
||||
})
|
||||
}
|
||||
|
||||
// Update inventory item
|
||||
export const POST = async (
|
||||
req: MedusaRequest<AdminPostInventoryItemsInventoryItemReq>,
|
||||
req: MedusaRequest<AdminUpdateInventoryItemType>,
|
||||
res: MedusaResponse
|
||||
) => {
|
||||
const { id } = req.params
|
||||
@@ -55,20 +45,14 @@ export const POST = async (
|
||||
},
|
||||
})
|
||||
|
||||
const remoteQuery = req.scope.resolve(ContainerRegistrationKeys.REMOTE_QUERY)
|
||||
|
||||
const [inventory_item] = await remoteQuery(
|
||||
remoteQueryObjectFromString({
|
||||
entryPoint: "inventory",
|
||||
variables: {
|
||||
id,
|
||||
},
|
||||
fields: req.retrieveConfig.select as string[],
|
||||
})
|
||||
const inventoryItem = await refetchInventoryItem(
|
||||
id,
|
||||
req.scope,
|
||||
req.remoteQueryConfig.fields
|
||||
)
|
||||
|
||||
res.status(200).json({
|
||||
inventory_item,
|
||||
inventory_item: inventoryItem,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
import { MedusaContainer } from "@medusajs/types"
|
||||
import {
|
||||
ContainerRegistrationKeys,
|
||||
remoteQueryObjectFromString,
|
||||
} from "@medusajs/utils"
|
||||
|
||||
export const refetchInventoryItem = async (
|
||||
inventoryItemId: string,
|
||||
scope: MedusaContainer,
|
||||
fields: string[]
|
||||
) => {
|
||||
const remoteQuery = scope.resolve(ContainerRegistrationKeys.REMOTE_QUERY)
|
||||
const queryObject = remoteQueryObjectFromString({
|
||||
entryPoint: "inventory_item",
|
||||
variables: {
|
||||
filters: { id: inventoryItemId },
|
||||
skip: 0,
|
||||
take: 1,
|
||||
},
|
||||
fields: fields,
|
||||
})
|
||||
|
||||
// TODO: Why does the response type change if you pass skip and take, vs not passing it?
|
||||
// Also, why does the data change (in this case, not doing skip and take will not return the lazy fields of stockedQuantity and reserved_quantity)
|
||||
const { rows } = await remoteQuery(queryObject)
|
||||
|
||||
return rows[0]
|
||||
}
|
||||
@@ -1,21 +1,19 @@
|
||||
import * as QueryConfig from "./query-config"
|
||||
|
||||
import {
|
||||
AdminGetInventoryItemsItemLocationLevelsParams,
|
||||
AdminGetInventoryItemsItemParams,
|
||||
AdminGetInventoryItemsParams,
|
||||
AdminPostInventoryItemsInventoryItemParams,
|
||||
AdminPostInventoryItemsInventoryItemReq,
|
||||
AdminPostInventoryItemsItemLocationLevelsBatchReq,
|
||||
AdminPostInventoryItemsItemLocationLevelsLevelParams,
|
||||
AdminPostInventoryItemsItemLocationLevelsLevelReq,
|
||||
AdminPostInventoryItemsItemLocationLevelsReq,
|
||||
AdminPostInventoryItemsReq,
|
||||
} from "./validators"
|
||||
import { transformBody, transformQuery } from "../../../api/middlewares"
|
||||
|
||||
import { MiddlewareRoute } from "../../../types/middlewares"
|
||||
import { authenticate } from "../../../utils/authenticate-middleware"
|
||||
import { validateAndTransformQuery } from "../../utils/validate-query"
|
||||
import {
|
||||
AdminCreateInventoryItem,
|
||||
AdminCreateInventoryLocationLevel,
|
||||
AdminGetInventoryItemParams,
|
||||
AdminGetInventoryItemsParams,
|
||||
AdminGetInventoryLocationLevelParams,
|
||||
AdminGetInventoryLocationLevelsParams,
|
||||
AdminUpdateInventoryItem,
|
||||
AdminUpdateInventoryLocationLevel,
|
||||
} from "./validators"
|
||||
import { validateAndTransformBody } from "../../utils/validate-body"
|
||||
import { createBatchBody } from "../../utils/validators"
|
||||
|
||||
export const adminInventoryRoutesMiddlewares: MiddlewareRoute[] = [
|
||||
{
|
||||
@@ -27,7 +25,7 @@ export const adminInventoryRoutesMiddlewares: MiddlewareRoute[] = [
|
||||
method: ["GET"],
|
||||
matcher: "/admin/inventory-items",
|
||||
middlewares: [
|
||||
transformQuery(
|
||||
validateAndTransformQuery(
|
||||
AdminGetInventoryItemsParams,
|
||||
QueryConfig.listTransformQueryConfig
|
||||
),
|
||||
@@ -37,8 +35,8 @@ export const adminInventoryRoutesMiddlewares: MiddlewareRoute[] = [
|
||||
method: ["GET"],
|
||||
matcher: "/admin/inventory-items/:id",
|
||||
middlewares: [
|
||||
transformQuery(
|
||||
AdminGetInventoryItemsItemParams,
|
||||
validateAndTransformQuery(
|
||||
AdminGetInventoryItemParams,
|
||||
QueryConfig.retrieveTransformQueryConfig
|
||||
),
|
||||
],
|
||||
@@ -47,47 +45,9 @@ export const adminInventoryRoutesMiddlewares: MiddlewareRoute[] = [
|
||||
method: ["POST"],
|
||||
matcher: "/admin/inventory-items",
|
||||
middlewares: [
|
||||
transformBody(AdminPostInventoryItemsReq),
|
||||
transformQuery(
|
||||
AdminGetInventoryItemsItemParams,
|
||||
QueryConfig.retrieveTransformQueryConfig
|
||||
),
|
||||
],
|
||||
},
|
||||
{
|
||||
method: ["POST"],
|
||||
matcher: "/admin/inventory-items/:id/location-levels/batch/combi",
|
||||
middlewares: [
|
||||
transformBody(AdminPostInventoryItemsItemLocationLevelsBatchReq),
|
||||
],
|
||||
},
|
||||
{
|
||||
method: ["GET"],
|
||||
matcher: "/admin/inventory-items/:id/location-levels",
|
||||
middlewares: [
|
||||
transformQuery(
|
||||
AdminGetInventoryItemsItemLocationLevelsParams,
|
||||
QueryConfig.listLocationLevelsTransformQueryConfig
|
||||
),
|
||||
],
|
||||
},
|
||||
{
|
||||
method: ["POST"],
|
||||
matcher: "/admin/inventory-items/:id/location-levels",
|
||||
middlewares: [transformBody(AdminPostInventoryItemsItemLocationLevelsReq)],
|
||||
},
|
||||
{
|
||||
method: ["POST"],
|
||||
matcher: "/admin/inventory-items/:id/location-levels",
|
||||
middlewares: [transformBody(AdminPostInventoryItemsItemLocationLevelsReq)],
|
||||
},
|
||||
{
|
||||
method: ["POST"],
|
||||
matcher: "/admin/inventory-items/:id/location-levels/:location_id",
|
||||
middlewares: [
|
||||
transformBody(AdminPostInventoryItemsItemLocationLevelsLevelReq),
|
||||
transformQuery(
|
||||
AdminPostInventoryItemsItemLocationLevelsLevelParams,
|
||||
validateAndTransformBody(AdminCreateInventoryItem),
|
||||
validateAndTransformQuery(
|
||||
AdminGetInventoryItemParams,
|
||||
QueryConfig.retrieveTransformQueryConfig
|
||||
),
|
||||
],
|
||||
@@ -96,11 +56,69 @@ export const adminInventoryRoutesMiddlewares: MiddlewareRoute[] = [
|
||||
method: ["POST"],
|
||||
matcher: "/admin/inventory-items/:id",
|
||||
middlewares: [
|
||||
transformBody(AdminPostInventoryItemsInventoryItemReq),
|
||||
transformQuery(
|
||||
AdminPostInventoryItemsInventoryItemParams,
|
||||
validateAndTransformBody(AdminUpdateInventoryItem),
|
||||
validateAndTransformQuery(
|
||||
AdminGetInventoryItemParams,
|
||||
QueryConfig.retrieveTransformQueryConfig
|
||||
),
|
||||
],
|
||||
},
|
||||
{
|
||||
method: ["GET"],
|
||||
matcher: "/admin/inventory-items/:id/location-levels",
|
||||
middlewares: [
|
||||
validateAndTransformQuery(
|
||||
AdminGetInventoryLocationLevelsParams,
|
||||
QueryConfig.listLocationLevelsTransformQueryConfig
|
||||
),
|
||||
],
|
||||
},
|
||||
{
|
||||
method: ["POST"],
|
||||
matcher: "/admin/inventory-items/:id/location-levels",
|
||||
middlewares: [
|
||||
validateAndTransformBody(AdminCreateInventoryLocationLevel),
|
||||
validateAndTransformQuery(
|
||||
AdminGetInventoryItemParams,
|
||||
QueryConfig.retrieveTransformQueryConfig
|
||||
),
|
||||
],
|
||||
},
|
||||
{
|
||||
method: ["DELETE"],
|
||||
matcher: "/admin/inventory-items/:id/location-levels/:location_id",
|
||||
middlewares: [
|
||||
validateAndTransformQuery(
|
||||
AdminGetInventoryItemParams,
|
||||
QueryConfig.retrieveTransformQueryConfig
|
||||
),
|
||||
],
|
||||
},
|
||||
{
|
||||
method: ["POST"],
|
||||
matcher: "/admin/inventory-items/:id/location-levels/:location_id",
|
||||
middlewares: [
|
||||
validateAndTransformBody(AdminUpdateInventoryLocationLevel),
|
||||
validateAndTransformQuery(
|
||||
AdminGetInventoryItemParams,
|
||||
QueryConfig.retrieveTransformQueryConfig
|
||||
),
|
||||
],
|
||||
},
|
||||
{
|
||||
method: ["POST"],
|
||||
matcher: "/admin/inventory-items/:id/location-levels/op/batch",
|
||||
middlewares: [
|
||||
validateAndTransformBody(
|
||||
createBatchBody(
|
||||
AdminCreateInventoryLocationLevel,
|
||||
AdminUpdateInventoryLocationLevel
|
||||
)
|
||||
),
|
||||
validateAndTransformQuery(
|
||||
AdminGetInventoryLocationLevelParams,
|
||||
QueryConfig.retrieveLocationLevelsTransformQueryConfig
|
||||
),
|
||||
],
|
||||
},
|
||||
]
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
import { InventoryNext } from "@medusajs/types"
|
||||
import { defaultAdminProductsVariantFields } from "../products/query-config"
|
||||
|
||||
// eslint-disable-next-line max-len
|
||||
export const defaultAdminLocationLevelFields = [
|
||||
"id",
|
||||
@@ -35,12 +32,7 @@ export const defaultAdminInventoryItemFields = [
|
||||
"stocked_quantity",
|
||||
"created_at",
|
||||
"updated_at",
|
||||
...defaultAdminLocationLevelFields.map(
|
||||
(field) => `location_levels.${field.toString()}`
|
||||
),
|
||||
...defaultAdminProductsVariantFields
|
||||
.filter((field) => !field.startsWith("*"))
|
||||
.map((field) => `variant.${field}`),
|
||||
"*location_levels",
|
||||
]
|
||||
|
||||
export const retrieveTransformQueryConfig = {
|
||||
|
||||
@@ -7,36 +7,32 @@ import {
|
||||
remoteQueryObjectFromString,
|
||||
} from "@medusajs/utils"
|
||||
|
||||
import { AdminPostInventoryItemsReq } from "./validators"
|
||||
import { createInventoryItemsWorkflow } from "@medusajs/core-flows"
|
||||
import {
|
||||
AdminCreateInventoryItemType,
|
||||
AdminGetInventoryItemsParamsType,
|
||||
} from "./validators"
|
||||
import { refetchInventoryItem } from "./helpers"
|
||||
|
||||
// Create inventory-item
|
||||
export const POST = async (
|
||||
req: AuthenticatedMedusaRequest<AdminPostInventoryItemsReq>,
|
||||
req: AuthenticatedMedusaRequest<AdminCreateInventoryItemType>,
|
||||
res: MedusaResponse
|
||||
) => {
|
||||
const remoteQuery = req.scope.resolve(ContainerRegistrationKeys.REMOTE_QUERY)
|
||||
|
||||
const { result } = await createInventoryItemsWorkflow(req.scope).run({
|
||||
input: { items: [req.validatedBody] },
|
||||
})
|
||||
|
||||
const [inventory_item] = await remoteQuery(
|
||||
remoteQueryObjectFromString({
|
||||
entryPoint: "inventory_items",
|
||||
variables: {
|
||||
id: result[0].id,
|
||||
},
|
||||
fields: req.remoteQueryConfig.fields,
|
||||
})
|
||||
const inventoryItem = await refetchInventoryItem(
|
||||
result[0].id,
|
||||
req.scope,
|
||||
req.remoteQueryConfig.fields
|
||||
)
|
||||
|
||||
res.status(200).json({ inventory_item })
|
||||
res.status(200).json({ inventory_item: inventoryItem })
|
||||
}
|
||||
|
||||
// List inventory-items
|
||||
export const GET = async (
|
||||
req: AuthenticatedMedusaRequest,
|
||||
req: AuthenticatedMedusaRequest<AdminGetInventoryItemsParamsType>,
|
||||
res: MedusaResponse
|
||||
) => {
|
||||
const remoteQuery = req.scope.resolve(ContainerRegistrationKeys.REMOTE_QUERY)
|
||||
|
||||
@@ -1,408 +1,129 @@
|
||||
import { z } from "zod"
|
||||
import {
|
||||
DateComparisonOperator,
|
||||
FindParams,
|
||||
NumericalComparisonOperator,
|
||||
StringComparisonOperator,
|
||||
extendedFindParamsMixin,
|
||||
} from "../../../types/common"
|
||||
import {
|
||||
IsBoolean,
|
||||
IsEmail,
|
||||
IsNotEmpty,
|
||||
IsNumber,
|
||||
IsObject,
|
||||
IsOptional,
|
||||
IsString,
|
||||
Min,
|
||||
ValidateNested,
|
||||
} from "class-validator"
|
||||
import { Transform, Type } from "class-transformer"
|
||||
createFindParams,
|
||||
createOperatorMap,
|
||||
createSelectParams,
|
||||
} from "../../utils/validators"
|
||||
import { optionalBooleanMapper } from "../../../utils/validators/is-boolean"
|
||||
|
||||
import { IsType } from "../../../utils"
|
||||
export type AdminGetInventoryItemParamsType = z.infer<
|
||||
typeof AdminGetInventoryItemParams
|
||||
>
|
||||
export const AdminGetInventoryItemParams = createSelectParams()
|
||||
|
||||
export class AdminGetInventoryItemsItemParams extends FindParams {}
|
||||
|
||||
/**
|
||||
* Parameters used to filter and configure the pagination of the retrieved inventory items.
|
||||
*/
|
||||
export class AdminGetInventoryItemsParams extends extendedFindParamsMixin({
|
||||
export type AdminGetInventoryItemsParamsType = z.infer<
|
||||
typeof AdminGetInventoryItemsParams
|
||||
>
|
||||
export const AdminGetInventoryItemsParams = createFindParams({
|
||||
limit: 20,
|
||||
offset: 0,
|
||||
}) {
|
||||
/**
|
||||
* IDs to filter inventory items by.
|
||||
*/
|
||||
@IsOptional()
|
||||
@IsType([String, [String]])
|
||||
id?: string | string[]
|
||||
}).merge(
|
||||
z.object({
|
||||
q: z.string().optional(),
|
||||
id: z.union([z.string(), z.array(z.string())]).optional(),
|
||||
location_id: z.union([z.string(), z.array(z.string())]).optional(),
|
||||
sku: z.union([z.string(), z.array(z.string())]).optional(),
|
||||
origin_country: z.union([z.string(), z.array(z.string())]).optional(),
|
||||
mid_code: z.union([z.string(), z.array(z.string())]).optional(),
|
||||
hs_code: z.union([z.string(), z.array(z.string())]).optional(),
|
||||
material: z.union([z.string(), z.array(z.string())]).optional(),
|
||||
requires_shipping: z
|
||||
.preprocess(
|
||||
(val: any) => optionalBooleanMapper.get(val?.toLowerCase()),
|
||||
z.boolean().optional()
|
||||
)
|
||||
.optional(),
|
||||
weight: createOperatorMap(z.number(), parseFloat).optional(),
|
||||
length: createOperatorMap(z.number(), parseFloat).optional(),
|
||||
height: createOperatorMap(z.number(), parseFloat).optional(),
|
||||
width: createOperatorMap(z.number(), parseFloat).optional(),
|
||||
$and: z.lazy(() => AdminGetInventoryItemsParams.array()).optional(),
|
||||
$or: z.lazy(() => AdminGetInventoryItemsParams.array()).optional(),
|
||||
})
|
||||
)
|
||||
|
||||
/**
|
||||
* Search terms to search inventory items' sku, title, and description.
|
||||
*/
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
q?: string
|
||||
export type AdminGetInventoryLocationLevelParamsType = z.infer<
|
||||
typeof AdminGetInventoryLocationLevelParams
|
||||
>
|
||||
export const AdminGetInventoryLocationLevelParams = createSelectParams()
|
||||
|
||||
/**
|
||||
* Location IDs to filter inventory items by.
|
||||
*/
|
||||
@IsOptional()
|
||||
@IsType([String, [String]])
|
||||
location_id?: string | string[]
|
||||
export type AdminGetInventoryLocationLevelsParamsType = z.infer<
|
||||
typeof AdminGetInventoryLocationLevelsParams
|
||||
>
|
||||
export const AdminGetInventoryLocationLevelsParams = createFindParams({
|
||||
limit: 50,
|
||||
offset: 0,
|
||||
}).merge(
|
||||
z.object({
|
||||
location_id: z.union([z.string(), z.array(z.string())]).optional(),
|
||||
$and: z
|
||||
.lazy(() => AdminGetInventoryLocationLevelsParams.array())
|
||||
.optional(),
|
||||
$or: z.lazy(() => AdminGetInventoryLocationLevelsParams.array()).optional(),
|
||||
})
|
||||
)
|
||||
|
||||
/**
|
||||
* SKUs to filter inventory items by.
|
||||
*/
|
||||
@IsOptional()
|
||||
@IsType([String, [String]])
|
||||
sku?: string | string[]
|
||||
export type AdminCreateInventoryLocationLevelType = z.infer<
|
||||
typeof AdminCreateInventoryLocationLevel
|
||||
>
|
||||
export const AdminCreateInventoryLocationLevel = z
|
||||
.object({
|
||||
location_id: z.string(),
|
||||
stocked_quantity: z.number().min(0).optional(),
|
||||
incoming_quantity: z.number().min(0).optional(),
|
||||
})
|
||||
.strict()
|
||||
|
||||
/**
|
||||
* Origin countries to filter inventory items by.
|
||||
*/
|
||||
@IsOptional()
|
||||
@IsType([String, [String]])
|
||||
origin_country?: string | string[]
|
||||
export type AdminUpdateInventoryLocationLevelType = z.infer<
|
||||
typeof AdminUpdateInventoryLocationLevel
|
||||
>
|
||||
export const AdminUpdateInventoryLocationLevel = z
|
||||
.object({
|
||||
stocked_quantity: z.number().min(0).optional(),
|
||||
incoming_quantity: z.number().min(0).optional(),
|
||||
})
|
||||
.strict()
|
||||
|
||||
/**
|
||||
* MID codes to filter inventory items by.
|
||||
*/
|
||||
@IsOptional()
|
||||
@IsType([String, [String]])
|
||||
mid_code?: string | string[]
|
||||
export type AdminCreateInventoryItemType = z.infer<
|
||||
typeof AdminCreateInventoryItem
|
||||
>
|
||||
export const AdminCreateInventoryItem = z
|
||||
.object({
|
||||
sku: z.string().optional(),
|
||||
hs_code: z.string().optional(),
|
||||
weight: z.number().optional(),
|
||||
length: z.number().optional(),
|
||||
height: z.number().optional(),
|
||||
width: z.number().optional(),
|
||||
origin_country: z.string().optional(),
|
||||
mid_code: z.string().optional(),
|
||||
material: z.string().optional(),
|
||||
title: z.string().optional(),
|
||||
description: z.string().optional(),
|
||||
requires_shipping: z.boolean().optional(),
|
||||
thumbnail: z.string().optional(),
|
||||
metadata: z.record(z.string(), z.unknown()).optional(),
|
||||
})
|
||||
.strict()
|
||||
|
||||
/**
|
||||
* Materials to filter inventory items by.
|
||||
*/
|
||||
@IsOptional()
|
||||
@IsType([String, [String]])
|
||||
material?: string | string[]
|
||||
|
||||
/**
|
||||
* String filters to apply to inventory items' `hs_code` field.
|
||||
*/
|
||||
@IsOptional()
|
||||
@IsType([String, [String], StringComparisonOperator])
|
||||
hs_code?: string | string[] | StringComparisonOperator
|
||||
|
||||
/**
|
||||
* Number filters to apply to inventory items' `weight` field.
|
||||
*/
|
||||
@IsOptional()
|
||||
@IsType([Number, NumericalComparisonOperator])
|
||||
weight?: number | NumericalComparisonOperator
|
||||
|
||||
/**
|
||||
* Number filters to apply to inventory items' `length` field.
|
||||
*/
|
||||
@IsOptional()
|
||||
@IsType([Number, NumericalComparisonOperator])
|
||||
length?: number | NumericalComparisonOperator
|
||||
|
||||
/**
|
||||
* Number filters to apply to inventory items' `height` field.
|
||||
*/
|
||||
@IsOptional()
|
||||
@IsType([Number, NumericalComparisonOperator])
|
||||
height?: number | NumericalComparisonOperator
|
||||
|
||||
/**
|
||||
* Number filters to apply to inventory items' `width` field.
|
||||
*/
|
||||
@IsOptional()
|
||||
@IsType([Number, NumericalComparisonOperator])
|
||||
width?: number | NumericalComparisonOperator
|
||||
|
||||
/**
|
||||
* Filter inventory items by whether they require shipping.
|
||||
*/
|
||||
@IsBoolean()
|
||||
@IsOptional()
|
||||
@Transform(({ value }) => value === "true")
|
||||
requires_shipping?: boolean
|
||||
}
|
||||
|
||||
export class AdminPostInventoryItemsItemLocationLevelsReq {
|
||||
@IsString()
|
||||
location_id: string
|
||||
|
||||
@IsNumber()
|
||||
@IsOptional()
|
||||
stocked_quantity?: number
|
||||
|
||||
@IsOptional()
|
||||
@IsNumber()
|
||||
incoming_quantity?: number
|
||||
}
|
||||
|
||||
export class AdminPostInventoryItemsItemLocationLevelsBatchReq {
|
||||
@ValidateNested({ each: true })
|
||||
@Type(() => AdminPostInventoryItemsItemLocationLevelsReq)
|
||||
creates: AdminPostInventoryItemsItemLocationLevelsReq[]
|
||||
|
||||
@IsString({ each: true })
|
||||
deletes: string[]
|
||||
}
|
||||
|
||||
// eslint-disable-next-line
|
||||
export class AdminPostInventoryItemsItemLocationLevelsParams extends FindParams {}
|
||||
|
||||
/**
|
||||
* @schema AdminPostInventoryItemsReq
|
||||
* type: object
|
||||
* description: "The details of the inventory item to create."
|
||||
* properties:
|
||||
* sku:
|
||||
* description: The unique SKU of the associated Product Variant.
|
||||
* type: string
|
||||
* ean:
|
||||
* description: The EAN number of the item.
|
||||
* type: string
|
||||
* upc:
|
||||
* description: The UPC number of the item.
|
||||
* type: string
|
||||
* barcode:
|
||||
* description: A generic GTIN field for the Product Variant.
|
||||
* type: string
|
||||
* hs_code:
|
||||
* description: The Harmonized System code of the Inventory Item. May be used by Fulfillment Providers to pass customs information to shipping carriers.
|
||||
* type: string
|
||||
* inventory_quantity:
|
||||
* description: The amount of stock kept of the associated Product Variant.
|
||||
* type: integer
|
||||
* default: 0
|
||||
* allow_backorder:
|
||||
* description: Whether the associated Product Variant can be purchased when out of stock.
|
||||
* type: boolean
|
||||
* manage_inventory:
|
||||
* description: Whether Medusa should keep track of the inventory for the associated Product Variant.
|
||||
* type: boolean
|
||||
* default: true
|
||||
* weight:
|
||||
* description: The weight of the Inventory Item. May be used in shipping rate calculations.
|
||||
* type: number
|
||||
* length:
|
||||
* description: The length of the Inventory Item. May be used in shipping rate calculations.
|
||||
* type: number
|
||||
* height:
|
||||
* description: The height of the Inventory Item. May be used in shipping rate calculations.
|
||||
* type: number
|
||||
* width:
|
||||
* description: The width of the Inventory Item. May be used in shipping rate calculations.
|
||||
* type: number
|
||||
* origin_country:
|
||||
* description: The country in which the Inventory Item was produced. May be used by Fulfillment Providers to pass customs information to shipping carriers.
|
||||
* type: string
|
||||
* mid_code:
|
||||
* description: The Manufacturers Identification code that identifies the manufacturer of the Inventory Item. May be used by Fulfillment Providers to pass customs information to shipping carriers.
|
||||
* type: string
|
||||
* material:
|
||||
* description: The material and composition that the Inventory Item is made of, May be used by Fulfillment Providers to pass customs information to shipping carriers.
|
||||
* type: string
|
||||
* title:
|
||||
* description: The inventory item's title.
|
||||
* type: string
|
||||
* description:
|
||||
* description: The inventory item's description.
|
||||
* type: string
|
||||
* thumbnail:
|
||||
* description: The inventory item's thumbnail.
|
||||
* type: string
|
||||
* metadata:
|
||||
* description: An optional set of key-value pairs with additional information.
|
||||
* type: object
|
||||
* externalDocs:
|
||||
* description: "Learn about the metadata attribute, and how to delete and update it."
|
||||
* url: "https://docs.medusajs.com/development/entities/overview#metadata-attribute"
|
||||
*/
|
||||
export class AdminPostInventoryItemsReq {
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
sku?: string
|
||||
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
hs_code?: string
|
||||
|
||||
@IsNumber()
|
||||
@IsOptional()
|
||||
weight?: number
|
||||
|
||||
@IsNumber()
|
||||
@IsOptional()
|
||||
length?: number
|
||||
|
||||
@IsNumber()
|
||||
@IsOptional()
|
||||
height?: number
|
||||
|
||||
@IsNumber()
|
||||
@IsOptional()
|
||||
width?: number
|
||||
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
origin_country?: string
|
||||
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
mid_code?: string
|
||||
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
material?: string
|
||||
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
title?: string
|
||||
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
description?: string
|
||||
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
thumbnail?: string
|
||||
|
||||
@IsObject()
|
||||
@IsOptional()
|
||||
metadata?: Record<string, unknown>
|
||||
}
|
||||
|
||||
// eslint-disable-next-line max-len
|
||||
export class AdminGetInventoryItemsItemLocationLevelsParams extends extendedFindParamsMixin(
|
||||
{
|
||||
limit: 50,
|
||||
offset: 0,
|
||||
}
|
||||
) {
|
||||
/**
|
||||
* Location IDs to filter location levels.
|
||||
*/
|
||||
@IsOptional()
|
||||
@IsString({ each: true })
|
||||
location_id?: string[]
|
||||
}
|
||||
/**
|
||||
* @schema AdminPostInventoryItemsItemLocationLevelsLevelReq
|
||||
* type: object
|
||||
* properties:
|
||||
* stocked_quantity:
|
||||
* description: the total stock quantity of an inventory item at the given location ID
|
||||
* type: number
|
||||
* incoming_quantity:
|
||||
* description: the incoming stock quantity of an inventory item at the given location ID
|
||||
* type: number
|
||||
*/
|
||||
export class AdminPostInventoryItemsItemLocationLevelsLevelReq {
|
||||
@IsOptional()
|
||||
@IsNumber()
|
||||
@Min(0)
|
||||
incoming_quantity?: number
|
||||
|
||||
@IsOptional()
|
||||
@IsNumber()
|
||||
@Min(0)
|
||||
stocked_quantity?: number
|
||||
}
|
||||
|
||||
// eslint-disable-next-line
|
||||
export class AdminPostInventoryItemsItemLocationLevelsLevelParams extends FindParams {}
|
||||
/**
|
||||
* @schema AdminPostInventoryItemsInventoryItemReq
|
||||
* type: object
|
||||
* description: "The attributes to update in an inventory item."
|
||||
* properties:
|
||||
* hs_code:
|
||||
* description: The Harmonized System code of the Inventory Item. May be used by Fulfillment Providers to pass customs information to shipping carriers.
|
||||
* type: string
|
||||
* origin_country:
|
||||
* description: The country in which the Inventory Item was produced. May be used by Fulfillment Providers to pass customs information to shipping carriers.
|
||||
* type: string
|
||||
* mid_code:
|
||||
* description: The Manufacturers Identification code that identifies the manufacturer of the Inventory Item. May be used by Fulfillment Providers to pass customs information to shipping carriers.
|
||||
* type: string
|
||||
* material:
|
||||
* description: The material and composition that the Inventory Item is made of, May be used by Fulfillment Providers to pass customs information to shipping carriers.
|
||||
* type: string
|
||||
* weight:
|
||||
* description: The weight of the Inventory Item. May be used in shipping rate calculations.
|
||||
* type: number
|
||||
* height:
|
||||
* description: The height of the Inventory Item. May be used in shipping rate calculations.
|
||||
* type: number
|
||||
* width:
|
||||
* description: The width of the Inventory Item. May be used in shipping rate calculations.
|
||||
* type: number
|
||||
* length:
|
||||
* description: The length of the Inventory Item. May be used in shipping rate calculations.
|
||||
* type: number
|
||||
* title:
|
||||
* description: The inventory item's title.
|
||||
* type: string
|
||||
* description:
|
||||
* description: The inventory item's description.
|
||||
* type: string
|
||||
* thumbnail:
|
||||
* description: The inventory item's thumbnail.
|
||||
* type: string
|
||||
* requires_shipping:
|
||||
* description: Whether the item requires shipping.
|
||||
* type: boolean
|
||||
*/
|
||||
|
||||
export class AdminPostInventoryItemsInventoryItemReq {
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
sku?: string
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
origin_country?: string
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
hs_code?: string
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
mid_code?: string
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
material?: string
|
||||
|
||||
@IsOptional()
|
||||
@IsNumber()
|
||||
weight?: number
|
||||
|
||||
@IsOptional()
|
||||
@IsNumber()
|
||||
height?: number
|
||||
|
||||
@IsOptional()
|
||||
@IsNumber()
|
||||
length?: number
|
||||
|
||||
@IsOptional()
|
||||
@IsNumber()
|
||||
width?: number
|
||||
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
title?: string
|
||||
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
description?: string
|
||||
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
thumbnail?: string
|
||||
|
||||
@IsBoolean()
|
||||
@IsOptional()
|
||||
requires_shipping?: boolean
|
||||
}
|
||||
|
||||
export class AdminPostInventoryItemsInventoryItemParams extends FindParams {}
|
||||
export type AdminUpdateInventoryItemType = z.infer<
|
||||
typeof AdminUpdateInventoryItem
|
||||
>
|
||||
export const AdminUpdateInventoryItem = z
|
||||
.object({
|
||||
sku: z.string().optional(),
|
||||
hs_code: z.string().optional(),
|
||||
weight: z.number().optional(),
|
||||
length: z.number().optional(),
|
||||
height: z.number().optional(),
|
||||
width: z.number().optional(),
|
||||
origin_country: z.string().optional(),
|
||||
mid_code: z.string().optional(),
|
||||
material: z.string().optional(),
|
||||
title: z.string().optional(),
|
||||
description: z.string().optional(),
|
||||
requires_shipping: z.boolean().optional(),
|
||||
thumbnail: z.string().optional(),
|
||||
metadata: z.record(z.string(), z.unknown()).optional(),
|
||||
})
|
||||
.strict()
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { MedusaRequest, MedusaResponse } from "../../../../../types/routing"
|
||||
|
||||
import { refreshInviteTokensWorkflow } from "@medusajs/core-flows"
|
||||
import { refetchInvite } from "../../helpers"
|
||||
|
||||
export const POST = async (req: MedusaRequest, res: MedusaResponse) => {
|
||||
const workflow = refreshInviteTokensWorkflow(req.scope)
|
||||
@@ -9,7 +10,12 @@ export const POST = async (req: MedusaRequest, res: MedusaResponse) => {
|
||||
invite_ids: [req.params.id],
|
||||
}
|
||||
|
||||
const { result: invites } = await workflow.run({ input })
|
||||
const { result } = await workflow.run({ input })
|
||||
const invite = await refetchInvite(
|
||||
result[0].id,
|
||||
req.scope,
|
||||
req.remoteQueryConfig.fields
|
||||
)
|
||||
|
||||
res.status(200).json({ invite: invites[0] })
|
||||
res.status(200).json({ invite })
|
||||
}
|
||||
|
||||
@@ -2,31 +2,21 @@ import {
|
||||
AuthenticatedMedusaRequest,
|
||||
MedusaResponse,
|
||||
} from "../../../../types/routing"
|
||||
import {
|
||||
ContainerRegistrationKeys,
|
||||
MedusaError,
|
||||
remoteQueryObjectFromString,
|
||||
} from "@medusajs/utils"
|
||||
import { MedusaError } from "@medusajs/utils"
|
||||
|
||||
import { deleteInvitesWorkflow } from "@medusajs/core-flows"
|
||||
import { refetchInvite } from "../helpers"
|
||||
|
||||
// Get invite
|
||||
export const GET = async (
|
||||
req: AuthenticatedMedusaRequest,
|
||||
res: MedusaResponse
|
||||
) => {
|
||||
const { id } = req.params
|
||||
const remoteQuery = req.scope.resolve(ContainerRegistrationKeys.REMOTE_QUERY)
|
||||
|
||||
const query = remoteQueryObjectFromString({
|
||||
entryPoint: "invite",
|
||||
variables: {
|
||||
id,
|
||||
},
|
||||
fields: req.retrieveConfig.select as string[],
|
||||
})
|
||||
|
||||
const [invite] = await remoteQuery(query)
|
||||
const invite = await refetchInvite(
|
||||
id,
|
||||
req.scope,
|
||||
req.remoteQueryConfig.fields
|
||||
)
|
||||
|
||||
if (!invite) {
|
||||
throw new MedusaError(
|
||||
@@ -38,7 +28,6 @@ export const GET = async (
|
||||
res.status(200).json({ invite })
|
||||
}
|
||||
|
||||
// delete invite
|
||||
export const DELETE = async (
|
||||
req: AuthenticatedMedusaRequest,
|
||||
res: MedusaResponse
|
||||
|
||||
@@ -5,11 +5,10 @@ import {
|
||||
AuthenticatedMedusaRequest,
|
||||
MedusaResponse,
|
||||
} from "../../../../types/routing"
|
||||
|
||||
import { AdminPostInvitesInviteAcceptReq } from "../validators"
|
||||
import { AdminInviteAcceptType } from "../validators"
|
||||
|
||||
export const POST = async (
|
||||
req: AuthenticatedMedusaRequest<AdminPostInvitesInviteAcceptReq>,
|
||||
req: AuthenticatedMedusaRequest<AdminInviteAcceptType>,
|
||||
res: MedusaResponse
|
||||
) => {
|
||||
if (req.auth.actor_id) {
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
import { MedusaContainer } from "@medusajs/types"
|
||||
import {
|
||||
ContainerRegistrationKeys,
|
||||
remoteQueryObjectFromString,
|
||||
} from "@medusajs/utils"
|
||||
|
||||
export const refetchInvite = async (
|
||||
inviteId: string,
|
||||
scope: MedusaContainer,
|
||||
fields: string[]
|
||||
) => {
|
||||
const remoteQuery = scope.resolve(ContainerRegistrationKeys.REMOTE_QUERY)
|
||||
const queryObject = remoteQueryObjectFromString({
|
||||
entryPoint: "invite",
|
||||
variables: {
|
||||
filters: { id: inviteId },
|
||||
},
|
||||
fields: fields,
|
||||
})
|
||||
|
||||
const invites = await remoteQuery(queryObject)
|
||||
return invites[0]
|
||||
}
|
||||
@@ -1,42 +1,25 @@
|
||||
import * as QueryConfig from "./query-config"
|
||||
|
||||
import {
|
||||
AdminCreateInviteRequest,
|
||||
AdminGetInvitesInviteParams,
|
||||
AdminCreateInvite,
|
||||
AdminGetInviteAcceptParams,
|
||||
AdminGetInviteParams,
|
||||
AdminGetInvitesParams,
|
||||
AdminPostInvitesInviteAcceptParams,
|
||||
AdminPostInvitesInviteAcceptReq,
|
||||
AdminInviteAccept,
|
||||
} from "./validators"
|
||||
import { transformBody, transformQuery } from "../../../api/middlewares"
|
||||
|
||||
import { MiddlewareRoute } from "../../../types/middlewares"
|
||||
import { authenticate } from "../../../utils/authenticate-middleware"
|
||||
import { validateAndTransformQuery } from "../../utils/validate-query"
|
||||
import { validateAndTransformBody } from "../../utils/validate-body"
|
||||
|
||||
export const adminInviteRoutesMiddlewares: MiddlewareRoute[] = [
|
||||
{
|
||||
method: "ALL",
|
||||
matcher: "/admin/invites",
|
||||
middlewares: [authenticate("admin", ["session", "bearer"])],
|
||||
},
|
||||
{
|
||||
method: "POST",
|
||||
matcher: "/admin/invites/accept",
|
||||
middlewares: [
|
||||
authenticate("admin", ["session", "bearer"], {
|
||||
allowUnregistered: true,
|
||||
}),
|
||||
],
|
||||
},
|
||||
{
|
||||
method: ["GET", "DELETE"],
|
||||
matcher: "/admin/invites/:id",
|
||||
middlewares: [authenticate("admin", ["session", "bearer"])],
|
||||
},
|
||||
{
|
||||
method: ["GET"],
|
||||
matcher: "/admin/invites",
|
||||
middlewares: [
|
||||
transformQuery(
|
||||
authenticate("admin", ["session", "bearer", "api-key"]),
|
||||
validateAndTransformQuery(
|
||||
AdminGetInvitesParams,
|
||||
QueryConfig.listTransformQueryConfig
|
||||
),
|
||||
@@ -45,22 +28,52 @@ export const adminInviteRoutesMiddlewares: MiddlewareRoute[] = [
|
||||
{
|
||||
method: ["POST"],
|
||||
matcher: "/admin/invites",
|
||||
middlewares: [transformBody(AdminCreateInviteRequest)],
|
||||
middlewares: [
|
||||
authenticate("admin", ["session", "bearer", "api-key"]),
|
||||
validateAndTransformBody(AdminCreateInvite),
|
||||
validateAndTransformQuery(
|
||||
AdminGetInviteParams,
|
||||
QueryConfig.retrieveTransformQueryConfig
|
||||
),
|
||||
],
|
||||
},
|
||||
{
|
||||
method: "POST",
|
||||
matcher: "/admin/invites/accept",
|
||||
middlewares: [
|
||||
transformBody(AdminPostInvitesInviteAcceptReq),
|
||||
transformQuery(AdminPostInvitesInviteAcceptParams),
|
||||
authenticate("admin", ["session", "bearer"], {
|
||||
allowUnregistered: true,
|
||||
}),
|
||||
validateAndTransformBody(AdminInviteAccept),
|
||||
validateAndTransformQuery(
|
||||
AdminGetInviteAcceptParams,
|
||||
QueryConfig.retrieveTransformQueryConfig
|
||||
),
|
||||
],
|
||||
},
|
||||
{
|
||||
method: ["GET"],
|
||||
matcher: "/admin/invites/:id",
|
||||
middlewares: [
|
||||
transformQuery(
|
||||
AdminGetInvitesInviteParams,
|
||||
authenticate("admin", ["session", "bearer", "api-key"]),
|
||||
validateAndTransformQuery(
|
||||
AdminGetInviteParams,
|
||||
QueryConfig.retrieveTransformQueryConfig
|
||||
),
|
||||
],
|
||||
},
|
||||
{
|
||||
method: ["DELETE"],
|
||||
matcher: "/admin/invites/:id",
|
||||
middlewares: [authenticate("admin", ["session", "bearer", "api-key"])],
|
||||
},
|
||||
{
|
||||
method: "POST",
|
||||
matcher: "/admin/invites/:id/resend",
|
||||
middlewares: [
|
||||
authenticate("admin", ["session", "bearer", "api-key"]),
|
||||
validateAndTransformQuery(
|
||||
AdminGetInviteParams,
|
||||
QueryConfig.retrieveTransformQueryConfig
|
||||
),
|
||||
],
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
export const defaultAdminInviteRelations = []
|
||||
export const allowedAdminInviteRelations = []
|
||||
export const defaultAdminInviteFields = [
|
||||
"id",
|
||||
"email",
|
||||
@@ -13,9 +11,7 @@ export const defaultAdminInviteFields = [
|
||||
]
|
||||
|
||||
export const retrieveTransformQueryConfig = {
|
||||
defaultFields: defaultAdminInviteFields,
|
||||
defaultRelations: defaultAdminInviteRelations,
|
||||
allowedRelations: allowedAdminInviteRelations,
|
||||
defaults: defaultAdminInviteFields,
|
||||
isList: false,
|
||||
}
|
||||
|
||||
|
||||
@@ -7,32 +7,27 @@ import {
|
||||
remoteQueryObjectFromString,
|
||||
} from "@medusajs/utils"
|
||||
|
||||
import { CreateInviteDTO } from "@medusajs/types"
|
||||
import { createInvitesWorkflow } from "@medusajs/core-flows"
|
||||
import { AdminCreateInviteType, AdminGetInvitesParamsType } from "./validators"
|
||||
import { refetchInvite } from "./helpers"
|
||||
|
||||
// List invites
|
||||
export const GET = async (
|
||||
req: AuthenticatedMedusaRequest,
|
||||
req: AuthenticatedMedusaRequest<AdminGetInvitesParamsType>,
|
||||
res: MedusaResponse
|
||||
) => {
|
||||
const remoteQuery = req.scope.resolve(ContainerRegistrationKeys.REMOTE_QUERY)
|
||||
|
||||
const query = remoteQueryObjectFromString({
|
||||
const queryObject = remoteQueryObjectFromString({
|
||||
entryPoint: "invite",
|
||||
variables: {
|
||||
filters: req.filterableFields,
|
||||
order: req.listConfig.order,
|
||||
skip: req.listConfig.skip,
|
||||
take: req.listConfig.take,
|
||||
...req.remoteQueryConfig.pagination,
|
||||
},
|
||||
fields: req.listConfig.select as string[],
|
||||
fields: req.remoteQueryConfig.fields,
|
||||
})
|
||||
|
||||
const { rows: invites, metadata } = await remoteQuery({
|
||||
...query,
|
||||
})
|
||||
const { rows: invites, metadata } = await remoteQuery(queryObject)
|
||||
|
||||
res.status(200).json({
|
||||
res.json({
|
||||
invites,
|
||||
count: metadata.count,
|
||||
offset: metadata.skip,
|
||||
@@ -40,9 +35,8 @@ export const GET = async (
|
||||
})
|
||||
}
|
||||
|
||||
// Create invite
|
||||
export const POST = async (
|
||||
req: AuthenticatedMedusaRequest<CreateInviteDTO>,
|
||||
req: AuthenticatedMedusaRequest<AdminCreateInviteType>,
|
||||
res: MedusaResponse
|
||||
) => {
|
||||
const workflow = createInvitesWorkflow(req.scope)
|
||||
@@ -54,7 +48,11 @@ export const POST = async (
|
||||
}
|
||||
|
||||
const { result } = await workflow.run(input)
|
||||
const invite = await refetchInvite(
|
||||
result[0].id,
|
||||
req.scope,
|
||||
req.remoteQueryConfig.fields
|
||||
)
|
||||
|
||||
const [invite] = result
|
||||
res.status(200).json({ invite })
|
||||
}
|
||||
|
||||
@@ -1,146 +1,51 @@
|
||||
import { Type } from "class-transformer"
|
||||
import { z } from "zod"
|
||||
import {
|
||||
IsEmail,
|
||||
IsNotEmpty,
|
||||
IsOptional,
|
||||
IsString,
|
||||
ValidateNested,
|
||||
} from "class-validator"
|
||||
import {
|
||||
DateComparisonOperator,
|
||||
FindParams,
|
||||
extendedFindParamsMixin,
|
||||
} from "../../../types/common"
|
||||
import { IsType } from "../../../utils"
|
||||
createFindParams,
|
||||
createOperatorMap,
|
||||
createSelectParams,
|
||||
} from "../../utils/validators"
|
||||
|
||||
export class AdminGetInvitesInviteParams extends FindParams {}
|
||||
export type AdminGetInviteParamsType = z.infer<typeof AdminGetInviteParams>
|
||||
export const AdminGetInviteParams = createSelectParams()
|
||||
|
||||
export class AdminGetInvitesParams extends extendedFindParamsMixin({
|
||||
export type AdminGetInvitesParamsType = z.infer<typeof AdminGetInvitesParams>
|
||||
export const AdminGetInvitesParams = createFindParams({
|
||||
limit: 50,
|
||||
offset: 0,
|
||||
}) {
|
||||
/**
|
||||
* IDs to filter invites by.
|
||||
*/
|
||||
@IsOptional()
|
||||
@IsType([String, [String]])
|
||||
id?: string | string[]
|
||||
}).merge(
|
||||
z.object({
|
||||
q: z.string().optional(),
|
||||
id: z.union([z.string(), z.array(z.string())]).optional(),
|
||||
email: z.union([z.string(), z.array(z.string())]).optional(),
|
||||
created_at: createOperatorMap().optional(),
|
||||
updated_at: createOperatorMap().optional(),
|
||||
deleted_at: createOperatorMap().optional(),
|
||||
$and: z.lazy(() => AdminGetInvitesParams.array()).optional(),
|
||||
$or: z.lazy(() => AdminGetInvitesParams.array()).optional(),
|
||||
})
|
||||
)
|
||||
|
||||
/**
|
||||
* The field to sort the data by. By default, the sort order is ascending. To change the order to descending, prefix the field name with `-`.
|
||||
*/
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
order?: string
|
||||
export type AdminGetInviteAcceptParamsType = z.infer<
|
||||
typeof AdminGetInviteAcceptParams
|
||||
>
|
||||
export const AdminGetInviteAcceptParams = createSelectParams().merge(
|
||||
z.object({
|
||||
token: z.string(),
|
||||
})
|
||||
)
|
||||
|
||||
/**
|
||||
* Date filters to apply on the invites' `update_at` date.
|
||||
*/
|
||||
@IsOptional()
|
||||
@ValidateNested()
|
||||
@Type(() => DateComparisonOperator)
|
||||
updated_at?: DateComparisonOperator
|
||||
export type AdminCreateInviteType = z.infer<typeof AdminCreateInvite>
|
||||
export const AdminCreateInvite = z
|
||||
.object({
|
||||
email: z.string(),
|
||||
})
|
||||
.strict()
|
||||
|
||||
/**
|
||||
* Date filters to apply on the customer invites' `created_at` date.
|
||||
*/
|
||||
@IsOptional()
|
||||
@ValidateNested()
|
||||
@Type(() => DateComparisonOperator)
|
||||
created_at?: DateComparisonOperator
|
||||
|
||||
/**
|
||||
* Date filters to apply on the invites' `deleted_at` date.
|
||||
*/
|
||||
@IsOptional()
|
||||
@ValidateNested()
|
||||
@Type(() => DateComparisonOperator)
|
||||
deleted_at?: DateComparisonOperator
|
||||
|
||||
/**
|
||||
* Filter to apply on the invites' `email` field.
|
||||
*/
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
email?: string
|
||||
|
||||
/**
|
||||
* Comma-separated fields that should be included in the returned invites.
|
||||
*/
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
fields?: string
|
||||
|
||||
/**
|
||||
* The term to search invites emails.
|
||||
*/
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
q?: string
|
||||
}
|
||||
|
||||
export class AdminCreateInviteRequest {
|
||||
@IsEmail()
|
||||
email: string
|
||||
}
|
||||
|
||||
/**
|
||||
* @schema AdminPostInvitesInviteAcceptReq
|
||||
* type: object
|
||||
* description: "The details of the invite to be accepted."
|
||||
* required:
|
||||
* - token
|
||||
* - user
|
||||
* properties:
|
||||
* token:
|
||||
* description: "The token of the invite to accept. This is a unique token generated when the invite was created or resent."
|
||||
* type: string
|
||||
* user:
|
||||
* description: "The details of the user to create."
|
||||
* type: object
|
||||
* required:
|
||||
* - first_name
|
||||
* - last_name
|
||||
* - password
|
||||
* properties:
|
||||
* first_name:
|
||||
* type: string
|
||||
* description: the first name of the User
|
||||
* last_name:
|
||||
* type: string
|
||||
* description: the last name of the User
|
||||
* password:
|
||||
* description: The password for the User
|
||||
* type: string
|
||||
* format: password
|
||||
*/
|
||||
export class AdminPostInvitesInviteAcceptReq {
|
||||
/**
|
||||
* If email is not passed, we default to using the email of the invite.
|
||||
*/
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
email: string
|
||||
/**
|
||||
* The invite's first name.
|
||||
*/
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
first_name: string
|
||||
|
||||
/**
|
||||
* The invite's last name.
|
||||
*/
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
last_name: string
|
||||
}
|
||||
|
||||
export class AdminPostInvitesInviteAcceptParams {
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
token: string
|
||||
|
||||
@IsOptional()
|
||||
expand = undefined
|
||||
}
|
||||
export type AdminInviteAcceptType = z.infer<typeof AdminInviteAccept>
|
||||
export const AdminInviteAccept = z
|
||||
.object({
|
||||
email: z.string().optional(),
|
||||
first_name: z.string().optional(),
|
||||
last_name: z.string().optional(),
|
||||
})
|
||||
.strict()
|
||||
|
||||
@@ -1,21 +1,15 @@
|
||||
import { capturePaymentWorkflow } from "@medusajs/core-flows"
|
||||
import {
|
||||
ContainerRegistrationKeys,
|
||||
remoteQueryObjectFromString,
|
||||
} from "@medusajs/utils"
|
||||
import {
|
||||
AuthenticatedMedusaRequest,
|
||||
MedusaResponse,
|
||||
} from "../../../../../types/routing"
|
||||
import { defaultAdminPaymentFields } from "../../query-config"
|
||||
import { AdminPostPaymentsCapturesReq } from "../../validators"
|
||||
import { refetchPayment } from "../../helpers"
|
||||
import { AdminCreatePaymentCaptureType } from "../../validators"
|
||||
|
||||
export const POST = async (
|
||||
req: AuthenticatedMedusaRequest<AdminPostPaymentsCapturesReq>,
|
||||
req: AuthenticatedMedusaRequest<AdminCreatePaymentCaptureType>,
|
||||
res: MedusaResponse
|
||||
) => {
|
||||
const remoteQuery = req.scope.resolve(ContainerRegistrationKeys.REMOTE_QUERY)
|
||||
|
||||
const { id } = req.params
|
||||
|
||||
const { errors } = await capturePaymentWorkflow(req.scope).run({
|
||||
@@ -31,13 +25,11 @@ export const POST = async (
|
||||
throw errors[0].error
|
||||
}
|
||||
|
||||
const query = remoteQueryObjectFromString({
|
||||
entryPoint: "payments",
|
||||
variables: { id },
|
||||
fields: defaultAdminPaymentFields,
|
||||
})
|
||||
|
||||
const [payment] = await remoteQuery(query)
|
||||
const payment = await refetchPayment(
|
||||
id,
|
||||
req.scope,
|
||||
req.remoteQueryConfig.fields
|
||||
)
|
||||
|
||||
res.status(200).json({ payment })
|
||||
}
|
||||
|
||||
@@ -1,23 +1,16 @@
|
||||
import { refundPaymentWorkflow } from "@medusajs/core-flows"
|
||||
import {
|
||||
ContainerRegistrationKeys,
|
||||
remoteQueryObjectFromString,
|
||||
} from "@medusajs/utils"
|
||||
import {
|
||||
AuthenticatedMedusaRequest,
|
||||
MedusaResponse,
|
||||
} from "../../../../../types/routing"
|
||||
import { defaultAdminPaymentFields } from "../../query-config"
|
||||
import { AdminPostPaymentsRefundsReq } from "../../validators"
|
||||
import { refetchPayment } from "../../helpers"
|
||||
import { AdminCreatePaymentRefundType } from "../../validators"
|
||||
|
||||
export const POST = async (
|
||||
req: AuthenticatedMedusaRequest<AdminPostPaymentsRefundsReq>,
|
||||
req: AuthenticatedMedusaRequest<AdminCreatePaymentRefundType>,
|
||||
res: MedusaResponse
|
||||
) => {
|
||||
const remoteQuery = req.scope.resolve(ContainerRegistrationKeys.REMOTE_QUERY)
|
||||
|
||||
const { id } = req.params
|
||||
|
||||
const { errors } = await refundPaymentWorkflow(req.scope).run({
|
||||
input: {
|
||||
payment_id: id,
|
||||
@@ -31,13 +24,11 @@ export const POST = async (
|
||||
throw errors[0].error
|
||||
}
|
||||
|
||||
const query = remoteQueryObjectFromString({
|
||||
entryPoint: "payments",
|
||||
variables: { id },
|
||||
fields: defaultAdminPaymentFields,
|
||||
})
|
||||
|
||||
const [payment] = await remoteQuery(query)
|
||||
const payment = await refetchPayment(
|
||||
id,
|
||||
req.scope,
|
||||
req.remoteQueryConfig.fields
|
||||
)
|
||||
|
||||
res.status(200).json({ payment })
|
||||
}
|
||||
|
||||
@@ -1,28 +1,19 @@
|
||||
import { Modules } from "@medusajs/modules-sdk"
|
||||
import {
|
||||
ContainerRegistrationKeys,
|
||||
remoteQueryObjectFromString,
|
||||
} from "@medusajs/utils"
|
||||
import {
|
||||
AuthenticatedMedusaRequest,
|
||||
MedusaResponse,
|
||||
} from "../../../../types/routing"
|
||||
import { AdminGetPaymentParamsType } from "../validators"
|
||||
import { refetchPayment } from "../helpers"
|
||||
|
||||
export const GET = async (
|
||||
req: AuthenticatedMedusaRequest,
|
||||
req: AuthenticatedMedusaRequest<AdminGetPaymentParamsType>,
|
||||
res: MedusaResponse
|
||||
) => {
|
||||
const remoteQuery = req.scope.resolve(ContainerRegistrationKeys.REMOTE_QUERY)
|
||||
|
||||
const { id } = req.params
|
||||
|
||||
const query = remoteQueryObjectFromString({
|
||||
entryPoint: Modules.PAYMENT,
|
||||
variables: { id },
|
||||
fields: req.retrieveConfig.select as string[],
|
||||
})
|
||||
|
||||
const [payment] = await remoteQuery(query)
|
||||
const payment = await refetchPayment(
|
||||
req.params.id,
|
||||
req.scope,
|
||||
req.remoteQueryConfig.fields
|
||||
)
|
||||
|
||||
res.status(200).json({ payment })
|
||||
}
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
import { MedusaContainer } from "@medusajs/types"
|
||||
import {
|
||||
ContainerRegistrationKeys,
|
||||
remoteQueryObjectFromString,
|
||||
} from "@medusajs/utils"
|
||||
|
||||
export const refetchPayment = async (
|
||||
paymentId: string,
|
||||
scope: MedusaContainer,
|
||||
fields: string[]
|
||||
) => {
|
||||
const remoteQuery = scope.resolve(ContainerRegistrationKeys.REMOTE_QUERY)
|
||||
const queryObject = remoteQueryObjectFromString({
|
||||
entryPoint: "payment",
|
||||
variables: {
|
||||
filters: { id: paymentId },
|
||||
},
|
||||
fields: fields,
|
||||
})
|
||||
|
||||
const payments = await remoteQuery(queryObject)
|
||||
return payments[0]
|
||||
}
|
||||
@@ -1,25 +1,28 @@
|
||||
import { transformBody, transformQuery } from "../../../api/middlewares"
|
||||
import { MiddlewareRoute } from "../../../types/middlewares"
|
||||
import { authenticate } from "../../../utils/authenticate-middleware"
|
||||
import { unlessPath } from "../../utils/unless-path"
|
||||
import { validateAndTransformBody } from "../../utils/validate-body"
|
||||
import { validateAndTransformQuery } from "../../utils/validate-query"
|
||||
import * as queryConfig from "./query-config"
|
||||
import {
|
||||
AdminCreatePaymentCapture,
|
||||
AdminCreatePaymentRefund,
|
||||
AdminGetPaymentParams,
|
||||
AdminGetPaymentProvidersParams,
|
||||
AdminGetPaymentsParams,
|
||||
AdminGetPaymentsPaymentProvidersParams,
|
||||
AdminPostPaymentsCapturesReq,
|
||||
AdminPostPaymentsRefundsReq,
|
||||
} from "./validators"
|
||||
|
||||
export const adminPaymentRoutesMiddlewares: MiddlewareRoute[] = [
|
||||
{
|
||||
method: "ALL",
|
||||
matcher: "/admin/payments",
|
||||
middlewares: [authenticate("admin", ["session", "bearer"])],
|
||||
middlewares: [authenticate("admin", ["session", "bearer", "api-key"])],
|
||||
},
|
||||
{
|
||||
method: ["GET"],
|
||||
matcher: "/admin/payments",
|
||||
middlewares: [
|
||||
transformQuery(
|
||||
validateAndTransformQuery(
|
||||
AdminGetPaymentsParams,
|
||||
queryConfig.listTransformQueryConfig
|
||||
),
|
||||
@@ -29,8 +32,8 @@ export const adminPaymentRoutesMiddlewares: MiddlewareRoute[] = [
|
||||
method: ["GET"],
|
||||
matcher: "/admin/payments/payment-providers",
|
||||
middlewares: [
|
||||
transformQuery(
|
||||
AdminGetPaymentsPaymentProvidersParams,
|
||||
validateAndTransformQuery(
|
||||
AdminGetPaymentProvidersParams,
|
||||
queryConfig.listTransformPaymentProvidersQueryConfig
|
||||
),
|
||||
],
|
||||
@@ -39,20 +42,35 @@ export const adminPaymentRoutesMiddlewares: MiddlewareRoute[] = [
|
||||
method: ["GET"],
|
||||
matcher: "/admin/payments/:id",
|
||||
middlewares: [
|
||||
transformQuery(
|
||||
AdminGetPaymentsParams,
|
||||
queryConfig.retrieveTransformQueryConfig
|
||||
unlessPath(
|
||||
new RegExp("/admin/payments/payment-providers"),
|
||||
validateAndTransformQuery(
|
||||
AdminGetPaymentParams,
|
||||
queryConfig.retrieveTransformQueryConfig
|
||||
)
|
||||
),
|
||||
],
|
||||
},
|
||||
{
|
||||
method: ["POST"],
|
||||
matcher: "/admin/payments/:id/capture",
|
||||
middlewares: [transformBody(AdminPostPaymentsCapturesReq)],
|
||||
middlewares: [
|
||||
validateAndTransformBody(AdminCreatePaymentCapture),
|
||||
validateAndTransformQuery(
|
||||
AdminGetPaymentParams,
|
||||
queryConfig.retrieveTransformQueryConfig
|
||||
),
|
||||
],
|
||||
},
|
||||
{
|
||||
method: ["POST"],
|
||||
matcher: "/admin/payments/:id/refund",
|
||||
middlewares: [transformBody(AdminPostPaymentsRefundsReq)],
|
||||
middlewares: [
|
||||
validateAndTransformBody(AdminCreatePaymentRefund),
|
||||
validateAndTransformQuery(
|
||||
AdminGetPaymentParams,
|
||||
queryConfig.retrieveTransformQueryConfig
|
||||
),
|
||||
],
|
||||
},
|
||||
]
|
||||
|
||||
@@ -1,30 +1,33 @@
|
||||
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
|
||||
|
||||
import { IPaymentModuleService } from "@medusajs/types"
|
||||
import {
|
||||
AuthenticatedMedusaRequest,
|
||||
MedusaResponse,
|
||||
} from "../../../../types/routing"
|
||||
import { AdminGetPaymentsPaymentProvidersParams } from "../validators"
|
||||
import { AdminGetPaymentProvidersParamsType } from "../validators"
|
||||
import {
|
||||
ContainerRegistrationKeys,
|
||||
remoteQueryObjectFromString,
|
||||
} from "@medusajs/utils"
|
||||
|
||||
export const GET = async (
|
||||
req: AuthenticatedMedusaRequest<AdminGetPaymentsPaymentProvidersParams>,
|
||||
req: AuthenticatedMedusaRequest<AdminGetPaymentProvidersParamsType>,
|
||||
res: MedusaResponse
|
||||
) => {
|
||||
const paymentModule = req.scope.resolve<IPaymentModuleService>(
|
||||
ModuleRegistrationName.PAYMENT
|
||||
)
|
||||
const remoteQuery = req.scope.resolve(ContainerRegistrationKeys.REMOTE_QUERY)
|
||||
const queryObject = remoteQueryObjectFromString({
|
||||
entryPoint: "payment_provider",
|
||||
variables: {
|
||||
filters: req.filterableFields,
|
||||
...req.remoteQueryConfig.pagination,
|
||||
},
|
||||
fields: req.remoteQueryConfig.fields,
|
||||
})
|
||||
|
||||
const [payment_providers, count] =
|
||||
await paymentModule.listAndCountPaymentProviders(req.filterableFields, {
|
||||
skip: req.listConfig.skip,
|
||||
take: req.listConfig.take,
|
||||
})
|
||||
const { rows: payment_providers, metadata } = await remoteQuery(queryObject)
|
||||
|
||||
res.status(200).json({
|
||||
count,
|
||||
res.json({
|
||||
payment_providers,
|
||||
offset: req.listConfig.skip,
|
||||
limit: req.listConfig.take,
|
||||
count: metadata.count,
|
||||
offset: metadata.skip,
|
||||
limit: metadata.take,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -11,29 +11,19 @@ export const defaultAdminPaymentFields = [
|
||||
"refunds.amount",
|
||||
]
|
||||
|
||||
export const defaultAdminPaymentRelations = ["captures", "refunds"]
|
||||
|
||||
export const allowedAdminPaymentRelations = ["captures", "refunds"]
|
||||
|
||||
export const listTransformQueryConfig = {
|
||||
defaultFields: defaultAdminPaymentFields,
|
||||
defaultRelations: defaultAdminPaymentRelations,
|
||||
allowedRelations: allowedAdminPaymentRelations,
|
||||
defaults: defaultAdminPaymentFields,
|
||||
isList: true,
|
||||
}
|
||||
|
||||
export const retrieveTransformQueryConfig = {
|
||||
defaultFields: defaultAdminPaymentFields,
|
||||
defaultRelations: defaultAdminPaymentRelations,
|
||||
allowedRelations: allowedAdminPaymentRelations,
|
||||
defaults: defaultAdminPaymentFields,
|
||||
isList: false,
|
||||
}
|
||||
|
||||
export const defaultAdminPaymentPaymentProviderFields = ["id", "is_enabled"]
|
||||
|
||||
export const listTransformPaymentProvidersQueryConfig = {
|
||||
defaultFields: defaultAdminPaymentPaymentProviderFields,
|
||||
defaultRelations: [],
|
||||
allowedRelations: [],
|
||||
defaults: defaultAdminPaymentPaymentProviderFields,
|
||||
isList: true,
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { Modules } from "@medusajs/modules-sdk"
|
||||
import {
|
||||
ContainerRegistrationKeys,
|
||||
remoteQueryObjectFromString,
|
||||
@@ -7,27 +6,25 @@ import {
|
||||
AuthenticatedMedusaRequest,
|
||||
MedusaResponse,
|
||||
} from "../../../types/routing"
|
||||
import { AdminGetPaymentsParamsType } from "./validators"
|
||||
|
||||
export const GET = async (
|
||||
req: AuthenticatedMedusaRequest,
|
||||
req: AuthenticatedMedusaRequest<AdminGetPaymentsParamsType>,
|
||||
res: MedusaResponse
|
||||
) => {
|
||||
const remoteQuery = req.scope.resolve(ContainerRegistrationKeys.REMOTE_QUERY)
|
||||
|
||||
const query = remoteQueryObjectFromString({
|
||||
entryPoint: Modules.PAYMENT,
|
||||
const queryObject = remoteQueryObjectFromString({
|
||||
entryPoint: "payment",
|
||||
variables: {
|
||||
filters: req.filterableFields,
|
||||
order: req.listConfig.order,
|
||||
skip: req.listConfig.skip,
|
||||
take: req.listConfig.take,
|
||||
...req.remoteQueryConfig.pagination,
|
||||
},
|
||||
fields: req.listConfig.select as string[],
|
||||
fields: req.remoteQueryConfig.fields,
|
||||
})
|
||||
|
||||
const { rows: payments, metadata } = await remoteQuery(query)
|
||||
const { rows: payments, metadata } = await remoteQuery(queryObject)
|
||||
|
||||
res.status(200).json({
|
||||
res.json({
|
||||
payments,
|
||||
count: metadata.count,
|
||||
offset: metadata.skip,
|
||||
|
||||
@@ -1,79 +1,57 @@
|
||||
import { Type } from "class-transformer"
|
||||
import { IsBoolean, IsInt, IsOptional, ValidateNested } from "class-validator"
|
||||
import { z } from "zod"
|
||||
import {
|
||||
DateComparisonOperator,
|
||||
FindParams,
|
||||
extendedFindParamsMixin,
|
||||
} from "../../../types/common"
|
||||
import { IsType } from "../../../utils"
|
||||
createFindParams,
|
||||
createOperatorMap,
|
||||
createSelectParams,
|
||||
} from "../../utils/validators"
|
||||
|
||||
export class AdminGetPaymentsPaymentParams extends FindParams {}
|
||||
export type AdminGetPaymentParamsType = z.infer<typeof AdminGetPaymentParams>
|
||||
export const AdminGetPaymentParams = createSelectParams()
|
||||
|
||||
export class AdminGetPaymentsParams extends extendedFindParamsMixin({
|
||||
export type AdminGetPaymentsParamsType = z.infer<typeof AdminGetPaymentsParams>
|
||||
export const AdminGetPaymentsParams = createFindParams({
|
||||
limit: 20,
|
||||
offset: 0,
|
||||
}) {
|
||||
/**
|
||||
* IDs to filter users by.
|
||||
*/
|
||||
@IsOptional()
|
||||
@IsType([String, [String]])
|
||||
id?: string | string[]
|
||||
}).merge(
|
||||
z.object({
|
||||
id: z.union([z.string(), z.array(z.string())]).optional(),
|
||||
created_at: createOperatorMap().optional(),
|
||||
updated_at: createOperatorMap().optional(),
|
||||
deleted_at: createOperatorMap().optional(),
|
||||
$and: z.lazy(() => AdminGetPaymentsParams.array()).optional(),
|
||||
$or: z.lazy(() => AdminGetPaymentsParams.array()).optional(),
|
||||
})
|
||||
)
|
||||
|
||||
/**
|
||||
* Date filters to apply on the users' `update_at` date.
|
||||
*/
|
||||
@IsOptional()
|
||||
@ValidateNested()
|
||||
@Type(() => DateComparisonOperator)
|
||||
updated_at?: DateComparisonOperator
|
||||
export type AdminGetPaymentProvidersParamsType = z.infer<
|
||||
typeof AdminGetPaymentProvidersParams
|
||||
>
|
||||
export const AdminGetPaymentProvidersParams = createFindParams({
|
||||
limit: 20,
|
||||
offset: 0,
|
||||
}).merge(
|
||||
z.object({
|
||||
id: z.union([z.string(), z.array(z.string())]).optional(),
|
||||
is_enabled: z.boolean().optional(),
|
||||
$and: z.lazy(() => AdminGetPaymentProvidersParams.array()).optional(),
|
||||
$or: z.lazy(() => AdminGetPaymentProvidersParams.array()).optional(),
|
||||
})
|
||||
)
|
||||
|
||||
/**
|
||||
* Date filters to apply on the customer users' `created_at` date.
|
||||
*/
|
||||
@IsOptional()
|
||||
@ValidateNested()
|
||||
@Type(() => DateComparisonOperator)
|
||||
created_at?: DateComparisonOperator
|
||||
export type AdminCreatePaymentCaptureType = z.infer<
|
||||
typeof AdminCreatePaymentCapture
|
||||
>
|
||||
export const AdminCreatePaymentCapture = z
|
||||
.object({
|
||||
amount: z.number().optional(),
|
||||
})
|
||||
.strict()
|
||||
|
||||
/**
|
||||
* Date filters to apply on the users' `deleted_at` date.
|
||||
*/
|
||||
@IsOptional()
|
||||
@ValidateNested()
|
||||
@Type(() => DateComparisonOperator)
|
||||
deleted_at?: DateComparisonOperator
|
||||
}
|
||||
|
||||
export class AdminPostPaymentsCapturesReq {
|
||||
@IsInt()
|
||||
@IsOptional()
|
||||
amount?: number
|
||||
}
|
||||
|
||||
export class AdminPostPaymentsRefundsReq {
|
||||
@IsInt()
|
||||
@IsOptional()
|
||||
amount?: number
|
||||
}
|
||||
|
||||
export class AdminGetPaymentsPaymentProvidersParams extends extendedFindParamsMixin(
|
||||
{
|
||||
limit: 20,
|
||||
offset: 0,
|
||||
}
|
||||
) {
|
||||
/**
|
||||
* IDs to filter users by.
|
||||
*/
|
||||
@IsOptional()
|
||||
@IsType([String, [String]])
|
||||
id?: string | string[]
|
||||
|
||||
/**
|
||||
* Filter providers by `enabled` flag
|
||||
*/
|
||||
@IsBoolean()
|
||||
@IsOptional()
|
||||
is_enabled?: boolean
|
||||
}
|
||||
export type AdminCreatePaymentRefundType = z.infer<
|
||||
typeof AdminCreatePaymentRefund
|
||||
>
|
||||
export const AdminCreatePaymentRefund = z
|
||||
.object({
|
||||
amount: z.number().optional(),
|
||||
})
|
||||
.strict()
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
import { MedusaContainer } from "@medusajs/types"
|
||||
import { remoteQueryObjectFromString } from "@medusajs/utils"
|
||||
import {
|
||||
ContainerRegistrationKeys,
|
||||
remoteQueryObjectFromString,
|
||||
} from "@medusajs/utils"
|
||||
|
||||
export const refetchProductType = async (
|
||||
productTypeId: string,
|
||||
scope: MedusaContainer,
|
||||
fields: string[]
|
||||
) => {
|
||||
const remoteQuery = scope.resolve("remoteQuery")
|
||||
const remoteQuery = scope.resolve(ContainerRegistrationKeys.REMOTE_QUERY)
|
||||
const queryObject = remoteQueryObjectFromString({
|
||||
entryPoint: "product_type",
|
||||
variables: {
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
import { NextFunction } from "express"
|
||||
import { MedusaRequest, MedusaResponse } from "../../types/routing"
|
||||
import { MiddlewareFunction } from "../../types/middlewares"
|
||||
|
||||
// Due to how our route loader works, where we load all middlewares before routes, ambiguous routes end up having all middlewares on different routes executed before the route handler is.
|
||||
// This function allows us to skip middlewares for particular routes, so we can temporarily solve this without completely breaking the route loader for everyone.
|
||||
export const unlessPath =
|
||||
(onPath: RegExp, middleware: MiddlewareFunction) =>
|
||||
(req: MedusaRequest, res: MedusaResponse, next: NextFunction) => {
|
||||
if (onPath.test(req.path)) {
|
||||
return next()
|
||||
} else {
|
||||
return middleware(req, res, next)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user