fix: Switch to zod for customer endpoints, fix inconsistencies (#7094)
This commit is contained in:
@@ -13,7 +13,7 @@ const adminHeaders = {
|
|||||||
medusaIntegrationTestRunner({
|
medusaIntegrationTestRunner({
|
||||||
env,
|
env,
|
||||||
testSuite: ({ dbConnection, getContainer, api }) => {
|
testSuite: ({ dbConnection, getContainer, api }) => {
|
||||||
describe("POST /admin/customer-groups/:id/customers/batch/add", () => {
|
describe("POST /admin/customer-groups/:id/customers/batch", () => {
|
||||||
let appContainer
|
let appContainer
|
||||||
let customerModuleService: ICustomerModuleService
|
let customerModuleService: ICustomerModuleService
|
||||||
|
|
||||||
@@ -48,9 +48,9 @@ medusaIntegrationTestRunner({
|
|||||||
])
|
])
|
||||||
|
|
||||||
const response = await api.post(
|
const response = await api.post(
|
||||||
`/admin/customer-groups/${group.id}/customers/batch/add`,
|
`/admin/customer-groups/${group.id}/customers/batch`,
|
||||||
{
|
{
|
||||||
customer_ids: customers.map((c) => ({ id: c.id })),
|
create: customers.map((c) => c.id),
|
||||||
},
|
},
|
||||||
adminHeaders
|
adminHeaders
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ const adminHeaders = {
|
|||||||
medusaIntegrationTestRunner({
|
medusaIntegrationTestRunner({
|
||||||
env,
|
env,
|
||||||
testSuite: ({ dbConnection, getContainer, api }) => {
|
testSuite: ({ dbConnection, getContainer, api }) => {
|
||||||
describe("POST /admin/customer-groups/:id/customers/batch/remove", () => {
|
describe("POST /admin/customer-groups/:id/customers/batch", () => {
|
||||||
let appContainer
|
let appContainer
|
||||||
let customerModuleService: ICustomerModuleService
|
let customerModuleService: ICustomerModuleService
|
||||||
|
|
||||||
@@ -55,9 +55,9 @@ medusaIntegrationTestRunner({
|
|||||||
)
|
)
|
||||||
|
|
||||||
const response = await api.post(
|
const response = await api.post(
|
||||||
`/admin/customer-groups/${group.id}/customers/batch/remove`,
|
`/admin/customer-groups/${group.id}/customers/batch`,
|
||||||
{
|
{
|
||||||
customer_ids: customers.map((c) => ({ id: c.id })),
|
delete: customers.map((c) => c.id),
|
||||||
},
|
},
|
||||||
adminHeaders
|
adminHeaders
|
||||||
)
|
)
|
||||||
|
|||||||
+2
-2
@@ -13,7 +13,7 @@ const adminHeaders = {
|
|||||||
medusaIntegrationTestRunner({
|
medusaIntegrationTestRunner({
|
||||||
env,
|
env,
|
||||||
testSuite: ({ dbConnection, getContainer, api }) => {
|
testSuite: ({ dbConnection, getContainer, api }) => {
|
||||||
describe("GET /admin/customer-groups/:id/customers", () => {
|
describe("GET customer group customers", () => {
|
||||||
let appContainer
|
let appContainer
|
||||||
let customerModuleService: ICustomerModuleService
|
let customerModuleService: ICustomerModuleService
|
||||||
|
|
||||||
@@ -54,7 +54,7 @@ medusaIntegrationTestRunner({
|
|||||||
)
|
)
|
||||||
|
|
||||||
const response = await api.get(
|
const response = await api.get(
|
||||||
`/admin/customer-groups/${group.id}/customers`,
|
`/admin/customers?groups[]=${group.id}`,
|
||||||
adminHeaders
|
adminHeaders
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ medusaIntegrationTestRunner({
|
|||||||
})
|
})
|
||||||
|
|
||||||
const response = await api.post(
|
const response = await api.post(
|
||||||
`/admin/customers/${customer.id}/addresses`,
|
`/admin/customers/${customer.id}/addresses?fields=*addresses`,
|
||||||
{
|
{
|
||||||
first_name: "John",
|
first_name: "John",
|
||||||
last_name: "Doe",
|
last_name: "Doe",
|
||||||
@@ -45,13 +45,15 @@ medusaIntegrationTestRunner({
|
|||||||
)
|
)
|
||||||
|
|
||||||
expect(response.status).toEqual(200)
|
expect(response.status).toEqual(200)
|
||||||
expect(response.data.address).toEqual(
|
expect(response.data.customer.addresses).toEqual(
|
||||||
expect.objectContaining({
|
expect.arrayContaining([
|
||||||
id: expect.any(String),
|
expect.objectContaining({
|
||||||
first_name: "John",
|
id: expect.any(String),
|
||||||
last_name: "Doe",
|
first_name: "John",
|
||||||
address_1: "Test street 1",
|
last_name: "Doe",
|
||||||
})
|
address_1: "Test street 1",
|
||||||
|
}),
|
||||||
|
])
|
||||||
)
|
)
|
||||||
|
|
||||||
const customerWithAddresses = await customerModuleService.retrieve(
|
const customerWithAddresses = await customerModuleService.retrieve(
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ medusaIntegrationTestRunner({
|
|||||||
})
|
})
|
||||||
|
|
||||||
const response = await api.post(
|
const response = await api.post(
|
||||||
`/admin/customers/${customer.id}/addresses/${address.id}`,
|
`/admin/customers/${customer.id}/addresses/${address.id}?fields=*addresses`,
|
||||||
{
|
{
|
||||||
first_name: "Jane",
|
first_name: "Jane",
|
||||||
},
|
},
|
||||||
@@ -50,12 +50,14 @@ medusaIntegrationTestRunner({
|
|||||||
)
|
)
|
||||||
|
|
||||||
expect(response.status).toEqual(200)
|
expect(response.status).toEqual(200)
|
||||||
expect(response.data.address).toEqual(
|
expect(response.data.customer.addresses).toEqual(
|
||||||
expect.objectContaining({
|
expect.arrayContaining([
|
||||||
id: expect.any(String),
|
expect.objectContaining({
|
||||||
first_name: "Jane",
|
id: expect.any(String),
|
||||||
last_name: "Doe",
|
first_name: "Jane",
|
||||||
})
|
last_name: "Doe",
|
||||||
|
}),
|
||||||
|
])
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
import { Modules } from "@medusajs/modules-sdk"
|
import { Modules } from "@medusajs/modules-sdk"
|
||||||
import { ModuleJoinerConfig } from "@medusajs/types"
|
import { ModuleJoinerConfig } from "@medusajs/types"
|
||||||
import { MapToConfig } from "@medusajs/utils"
|
import { MapToConfig } from "@medusajs/utils"
|
||||||
import { Customer, CustomerGroup } from "@models"
|
import { Address, Customer, CustomerGroup } from "@models"
|
||||||
|
|
||||||
export const LinkableKeys = {
|
export const LinkableKeys = {
|
||||||
customer_id: Customer.name,
|
customer_id: Customer.name,
|
||||||
customer_group_id: CustomerGroup.name,
|
customer_group_id: CustomerGroup.name,
|
||||||
|
customer_address_id: Address.name,
|
||||||
}
|
}
|
||||||
|
|
||||||
const entityLinkableKeysMap: MapToConfig = {}
|
const entityLinkableKeysMap: MapToConfig = {}
|
||||||
@@ -37,5 +38,12 @@ export const joinerConfig: ModuleJoinerConfig = {
|
|||||||
methodSuffix: "CustomerGroups",
|
methodSuffix: "CustomerGroups",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: ["customer_address", "customer_addresses"],
|
||||||
|
args: {
|
||||||
|
entity: Address.name,
|
||||||
|
methodSuffix: "Addresses",
|
||||||
|
},
|
||||||
|
},
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,10 +12,8 @@ import {
|
|||||||
import {
|
import {
|
||||||
InjectManager,
|
InjectManager,
|
||||||
InjectTransactionManager,
|
InjectTransactionManager,
|
||||||
isDuplicateError,
|
|
||||||
isString,
|
isString,
|
||||||
MedusaContext,
|
MedusaContext,
|
||||||
MedusaError,
|
|
||||||
ModulesSdkUtils,
|
ModulesSdkUtils,
|
||||||
} from "@medusajs/utils"
|
} from "@medusajs/utils"
|
||||||
import { entityNameToLinkableKeysMap, joinerConfig } from "../joiner-config"
|
import { entityNameToLinkableKeysMap, joinerConfig } from "../joiner-config"
|
||||||
@@ -26,10 +24,6 @@ import {
|
|||||||
CustomerGroupCustomer,
|
CustomerGroupCustomer,
|
||||||
} from "@models"
|
} from "@models"
|
||||||
import { EntityManager } from "@mikro-orm/core"
|
import { EntityManager } from "@mikro-orm/core"
|
||||||
import {
|
|
||||||
UNIQUE_CUSTOMER_BILLING_ADDRESS,
|
|
||||||
UNIQUE_CUSTOMER_SHIPPING_ADDRESS,
|
|
||||||
} from "../models/address"
|
|
||||||
|
|
||||||
type InjectedDependencies = {
|
type InjectedDependencies = {
|
||||||
baseRepository: DAL.RepositoryService
|
baseRepository: DAL.RepositoryService
|
||||||
@@ -39,7 +33,11 @@ type InjectedDependencies = {
|
|||||||
customerGroupCustomerService: ModulesSdkTypes.InternalModuleService<any>
|
customerGroupCustomerService: ModulesSdkTypes.InternalModuleService<any>
|
||||||
}
|
}
|
||||||
|
|
||||||
const generateMethodForModels = [Address, CustomerGroup, CustomerGroupCustomer]
|
const generateMethodForModels = [
|
||||||
|
{ model: Address, singular: "Address", plural: "Addresses" },
|
||||||
|
CustomerGroup,
|
||||||
|
CustomerGroupCustomer,
|
||||||
|
]
|
||||||
|
|
||||||
export default class CustomerModuleService<
|
export default class CustomerModuleService<
|
||||||
TAddress extends Address = Address,
|
TAddress extends Address = Address,
|
||||||
@@ -47,7 +45,6 @@ export default class CustomerModuleService<
|
|||||||
TCustomerGroup extends CustomerGroup = CustomerGroup,
|
TCustomerGroup extends CustomerGroup = CustomerGroup,
|
||||||
TCustomerGroupCustomer extends CustomerGroupCustomer = CustomerGroupCustomer
|
TCustomerGroupCustomer extends CustomerGroupCustomer = CustomerGroupCustomer
|
||||||
>
|
>
|
||||||
// TODO seb I let you manage that when you are moving forward
|
|
||||||
extends ModulesSdkUtils.abstractModuleServiceFactory<
|
extends ModulesSdkUtils.abstractModuleServiceFactory<
|
||||||
InjectedDependencies,
|
InjectedDependencies,
|
||||||
CustomerDTO,
|
CustomerDTO,
|
||||||
|
|||||||
@@ -1,48 +0,0 @@
|
|||||||
import { createCustomerGroupCustomersWorkflow } from "@medusajs/core-flows"
|
|
||||||
import { AdminCustomerGroupResponse } from "@medusajs/types"
|
|
||||||
import {
|
|
||||||
ContainerRegistrationKeys,
|
|
||||||
remoteQueryObjectFromString,
|
|
||||||
} from "@medusajs/utils"
|
|
||||||
import {
|
|
||||||
AuthenticatedMedusaRequest,
|
|
||||||
MedusaResponse,
|
|
||||||
} from "../../../../../../../types/routing"
|
|
||||||
import { AdminPostCustomerGroupsGroupCustomersBatchReq } from "../../../../validators"
|
|
||||||
|
|
||||||
export const POST = async (
|
|
||||||
// eslint-disable-next-line max-len
|
|
||||||
req: AuthenticatedMedusaRequest<AdminPostCustomerGroupsGroupCustomersBatchReq>,
|
|
||||||
res: MedusaResponse<AdminCustomerGroupResponse>
|
|
||||||
) => {
|
|
||||||
const { id } = req.params
|
|
||||||
const { customer_ids } = req.validatedBody
|
|
||||||
|
|
||||||
const createCustomers = createCustomerGroupCustomersWorkflow(req.scope)
|
|
||||||
|
|
||||||
const { result, errors } = await createCustomers.run({
|
|
||||||
input: {
|
|
||||||
groupCustomers: customer_ids.map((c) => ({
|
|
||||||
customer_id: c.id,
|
|
||||||
customer_group_id: id,
|
|
||||||
})),
|
|
||||||
},
|
|
||||||
throwOnError: false,
|
|
||||||
})
|
|
||||||
|
|
||||||
if (Array.isArray(errors) && errors[0]) {
|
|
||||||
throw errors[0].error
|
|
||||||
}
|
|
||||||
|
|
||||||
const remoteQuery = req.scope.resolve(ContainerRegistrationKeys.REMOTE_QUERY)
|
|
||||||
|
|
||||||
const queryObject = remoteQueryObjectFromString({
|
|
||||||
entryPoint: "customer_group",
|
|
||||||
variables: { id },
|
|
||||||
fields: req.remoteQueryConfig.fields,
|
|
||||||
})
|
|
||||||
|
|
||||||
const [customer_group] = await remoteQuery(queryObject)
|
|
||||||
|
|
||||||
res.status(200).json({ customer_group })
|
|
||||||
}
|
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
import { deleteCustomerGroupCustomersWorkflow } from "@medusajs/core-flows"
|
|
||||||
import { AdminCustomerGroupResponse } from "@medusajs/types"
|
|
||||||
import {
|
|
||||||
ContainerRegistrationKeys,
|
|
||||||
remoteQueryObjectFromString,
|
|
||||||
} from "@medusajs/utils"
|
|
||||||
import {
|
|
||||||
AuthenticatedMedusaRequest,
|
|
||||||
MedusaResponse,
|
|
||||||
} from "../../../../../../../types/routing"
|
|
||||||
import { AdminPostCustomerGroupsGroupCustomersBatchReq } from "../../../../validators"
|
|
||||||
|
|
||||||
export const POST = async (
|
|
||||||
// eslint-disable-next-line max-len
|
|
||||||
req: AuthenticatedMedusaRequest<AdminPostCustomerGroupsGroupCustomersBatchReq>,
|
|
||||||
res: MedusaResponse<AdminCustomerGroupResponse>
|
|
||||||
) => {
|
|
||||||
const { id } = req.params
|
|
||||||
const { customer_ids } = req.validatedBody
|
|
||||||
|
|
||||||
const deleteCustomers = deleteCustomerGroupCustomersWorkflow(req.scope)
|
|
||||||
|
|
||||||
const { errors } = await deleteCustomers.run({
|
|
||||||
input: {
|
|
||||||
groupCustomers: customer_ids.map((c) => ({
|
|
||||||
customer_id: c.id,
|
|
||||||
customer_group_id: id,
|
|
||||||
})),
|
|
||||||
},
|
|
||||||
throwOnError: false,
|
|
||||||
})
|
|
||||||
|
|
||||||
if (Array.isArray(errors) && errors[0]) {
|
|
||||||
throw errors[0].error
|
|
||||||
}
|
|
||||||
|
|
||||||
const remoteQuery = req.scope.resolve(ContainerRegistrationKeys.REMOTE_QUERY)
|
|
||||||
|
|
||||||
const queryObject = remoteQueryObjectFromString({
|
|
||||||
entryPoint: "customer_group",
|
|
||||||
variables: { id },
|
|
||||||
fields: req.remoteQueryConfig.fields,
|
|
||||||
})
|
|
||||||
|
|
||||||
const [customer_group] = await remoteQuery(queryObject)
|
|
||||||
|
|
||||||
res.status(200).json({ customer_group })
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
import { AdminCustomerGroupResponse, BatchMethodRequest } from "@medusajs/types"
|
||||||
|
import {
|
||||||
|
AuthenticatedMedusaRequest,
|
||||||
|
MedusaResponse,
|
||||||
|
} from "../../../../../../types/routing"
|
||||||
|
import { AdminSetCustomersCustomerGroupType } from "../../../validators"
|
||||||
|
import {
|
||||||
|
createCustomerGroupCustomersWorkflow,
|
||||||
|
deleteCustomerGroupCustomersWorkflow,
|
||||||
|
} from "@medusajs/core-flows"
|
||||||
|
import { refetchCustomerGroup } from "../../../helpers"
|
||||||
|
|
||||||
|
export const POST = async (
|
||||||
|
req: AuthenticatedMedusaRequest<
|
||||||
|
BatchMethodRequest<
|
||||||
|
AdminSetCustomersCustomerGroupType,
|
||||||
|
AdminSetCustomersCustomerGroupType
|
||||||
|
>
|
||||||
|
>,
|
||||||
|
res: MedusaResponse<AdminCustomerGroupResponse>
|
||||||
|
) => {
|
||||||
|
const { id } = req.params
|
||||||
|
const { create, delete: toDelete } = req.validatedBody
|
||||||
|
|
||||||
|
if (!!create && create?.length > 0) {
|
||||||
|
const createCustomers = createCustomerGroupCustomersWorkflow(req.scope)
|
||||||
|
const { errors } = await createCustomers.run({
|
||||||
|
input: {
|
||||||
|
groupCustomers: create.map((c) => ({
|
||||||
|
customer_id: c,
|
||||||
|
customer_group_id: id,
|
||||||
|
})),
|
||||||
|
},
|
||||||
|
throwOnError: false,
|
||||||
|
})
|
||||||
|
|
||||||
|
if (Array.isArray(errors) && errors[0]) {
|
||||||
|
throw errors[0].error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!!toDelete && toDelete?.length > 0) {
|
||||||
|
const deleteCustomers = deleteCustomerGroupCustomersWorkflow(req.scope)
|
||||||
|
const { errors } = await deleteCustomers.run({
|
||||||
|
input: {
|
||||||
|
groupCustomers: toDelete.map((c) => ({
|
||||||
|
customer_id: c,
|
||||||
|
customer_group_id: id,
|
||||||
|
})),
|
||||||
|
},
|
||||||
|
throwOnError: false,
|
||||||
|
})
|
||||||
|
|
||||||
|
if (Array.isArray(errors) && errors[0]) {
|
||||||
|
throw errors[0].error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const customerGroup = await refetchCustomerGroup(
|
||||||
|
id,
|
||||||
|
req.scope,
|
||||||
|
req.remoteQueryConfig.fields
|
||||||
|
)
|
||||||
|
|
||||||
|
res.status(200).json({ customer_group: customerGroup })
|
||||||
|
}
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
import {
|
|
||||||
AuthenticatedMedusaRequest,
|
|
||||||
MedusaResponse,
|
|
||||||
} from "../../../../../types/routing"
|
|
||||||
|
|
||||||
import { ICustomerModuleService } from "@medusajs/types"
|
|
||||||
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
|
|
||||||
|
|
||||||
export const GET = async (
|
|
||||||
req: AuthenticatedMedusaRequest,
|
|
||||||
res: MedusaResponse
|
|
||||||
) => {
|
|
||||||
const { id } = req.params
|
|
||||||
|
|
||||||
const service = req.scope.resolve<ICustomerModuleService>(
|
|
||||||
ModuleRegistrationName.CUSTOMER
|
|
||||||
)
|
|
||||||
|
|
||||||
const [customers, count] = await service.listAndCount(
|
|
||||||
{ ...req.filterableFields, groups: id },
|
|
||||||
req.listConfig
|
|
||||||
)
|
|
||||||
|
|
||||||
const { offset, limit } = req.validatedQuery
|
|
||||||
|
|
||||||
res.json({
|
|
||||||
count,
|
|
||||||
customers,
|
|
||||||
offset,
|
|
||||||
limit,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
@@ -2,38 +2,29 @@ import {
|
|||||||
AuthenticatedMedusaRequest,
|
AuthenticatedMedusaRequest,
|
||||||
MedusaResponse,
|
MedusaResponse,
|
||||||
} from "../../../../types/routing"
|
} from "../../../../types/routing"
|
||||||
import {
|
|
||||||
CustomerGroupUpdatableFields,
|
|
||||||
ICustomerModuleService,
|
|
||||||
} from "@medusajs/types"
|
|
||||||
import {
|
import {
|
||||||
deleteCustomerGroupsWorkflow,
|
deleteCustomerGroupsWorkflow,
|
||||||
updateCustomerGroupsWorkflow,
|
updateCustomerGroupsWorkflow,
|
||||||
} from "@medusajs/core-flows"
|
} from "@medusajs/core-flows"
|
||||||
|
|
||||||
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
|
import { refetchCustomerGroup } from "../helpers"
|
||||||
|
import { AdminUpdateCustomerGroupType } from "../validators"
|
||||||
|
|
||||||
export const GET = async (
|
export const GET = async (
|
||||||
req: AuthenticatedMedusaRequest,
|
req: AuthenticatedMedusaRequest,
|
||||||
res: MedusaResponse
|
res: MedusaResponse
|
||||||
) => {
|
) => {
|
||||||
const customerModuleService = req.scope.resolve<ICustomerModuleService>(
|
const customerGroup = await refetchCustomerGroup(
|
||||||
ModuleRegistrationName.CUSTOMER
|
|
||||||
)
|
|
||||||
|
|
||||||
const group = await customerModuleService.retrieveCustomerGroup(
|
|
||||||
req.params.id,
|
req.params.id,
|
||||||
{
|
req.scope,
|
||||||
select: req.retrieveConfig.select,
|
req.remoteQueryConfig.fields
|
||||||
relations: req.retrieveConfig.relations,
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
res.status(200).json({ customer_group: group })
|
res.status(200).json({ customer_group: customerGroup })
|
||||||
}
|
}
|
||||||
|
|
||||||
export const POST = async (
|
export const POST = async (
|
||||||
req: AuthenticatedMedusaRequest<CustomerGroupUpdatableFields>,
|
req: AuthenticatedMedusaRequest<AdminUpdateCustomerGroupType>,
|
||||||
res: MedusaResponse
|
res: MedusaResponse
|
||||||
) => {
|
) => {
|
||||||
const updateGroups = updateCustomerGroupsWorkflow(req.scope)
|
const updateGroups = updateCustomerGroupsWorkflow(req.scope)
|
||||||
@@ -49,7 +40,12 @@ export const POST = async (
|
|||||||
throw errors[0].error
|
throw errors[0].error
|
||||||
}
|
}
|
||||||
|
|
||||||
res.status(200).json({ customer_group: result[0] })
|
const customerGroup = await refetchCustomerGroup(
|
||||||
|
req.params.id,
|
||||||
|
req.scope,
|
||||||
|
req.remoteQueryConfig.fields
|
||||||
|
)
|
||||||
|
res.status(200).json({ customer_group: customerGroup })
|
||||||
}
|
}
|
||||||
|
|
||||||
export const DELETE = async (
|
export const DELETE = async (
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
import { MedusaContainer } from "@medusajs/types"
|
||||||
|
import {
|
||||||
|
ContainerRegistrationKeys,
|
||||||
|
remoteQueryObjectFromString,
|
||||||
|
} from "@medusajs/utils"
|
||||||
|
|
||||||
|
export const refetchCustomerGroup = async (
|
||||||
|
customerGroupId: string,
|
||||||
|
scope: MedusaContainer,
|
||||||
|
fields: string[]
|
||||||
|
) => {
|
||||||
|
const remoteQuery = scope.resolve(ContainerRegistrationKeys.REMOTE_QUERY)
|
||||||
|
const queryObject = remoteQueryObjectFromString({
|
||||||
|
entryPoint: "customer_group",
|
||||||
|
variables: {
|
||||||
|
filters: { id: customerGroupId },
|
||||||
|
},
|
||||||
|
fields: fields,
|
||||||
|
})
|
||||||
|
|
||||||
|
const customerGroups = await remoteQuery(queryObject)
|
||||||
|
return customerGroups[0]
|
||||||
|
}
|
||||||
@@ -1,42 +1,39 @@
|
|||||||
import * as QueryConfig from "./query-config"
|
import * as QueryConfig from "./query-config"
|
||||||
|
|
||||||
import { transformBody, transformQuery } from "../../../api/middlewares"
|
|
||||||
import {
|
|
||||||
AdminDeleteCustomerGroupsGroupCustomersBatchReq,
|
|
||||||
AdminGetCustomerGroupsGroupCustomersParams,
|
|
||||||
AdminGetCustomerGroupsGroupParams,
|
|
||||||
AdminGetCustomerGroupsParams,
|
|
||||||
AdminPostCustomerGroupsGroupCustomersBatchReq,
|
|
||||||
AdminPostCustomerGroupsGroupReq,
|
|
||||||
AdminPostCustomerGroupsReq,
|
|
||||||
} from "./validators"
|
|
||||||
|
|
||||||
import { MiddlewareRoute } from "../../../loaders/helpers/routing/types"
|
import { MiddlewareRoute } from "../../../loaders/helpers/routing/types"
|
||||||
import { authenticate } from "../../../utils/authenticate-middleware"
|
import { authenticate } from "../../../utils/authenticate-middleware"
|
||||||
import { listTransformQueryConfig as customersListTransformQueryConfig } from "../customers/query-config"
|
import { validateAndTransformQuery } from "../../utils/validate-query"
|
||||||
|
import {
|
||||||
|
AdminCreateCustomerGroup,
|
||||||
|
AdminGetCustomerGroupParams,
|
||||||
|
AdminGetCustomerGroupsParams,
|
||||||
|
AdminSetCustomersCustomerGroup,
|
||||||
|
AdminUpdateCustomerGroup,
|
||||||
|
} from "./validators"
|
||||||
|
import { validateAndTransformBody } from "../../utils/validate-body"
|
||||||
|
import { createBatchBody } from "../../utils/validators"
|
||||||
|
|
||||||
export const adminCustomerGroupRoutesMiddlewares: MiddlewareRoute[] = [
|
export const adminCustomerGroupRoutesMiddlewares: MiddlewareRoute[] = [
|
||||||
|
{
|
||||||
|
method: ["ALL"],
|
||||||
|
matcher: "/admin/customer-groups*",
|
||||||
|
middlewares: [authenticate("admin", ["bearer", "session", "api-key"])],
|
||||||
|
},
|
||||||
{
|
{
|
||||||
method: ["GET"],
|
method: ["GET"],
|
||||||
matcher: "/admin/customer-groups",
|
matcher: "/admin/customer-groups",
|
||||||
middlewares: [
|
middlewares: [
|
||||||
transformQuery(
|
validateAndTransformQuery(
|
||||||
AdminGetCustomerGroupsParams,
|
AdminGetCustomerGroupsParams,
|
||||||
QueryConfig.listTransformQueryConfig
|
QueryConfig.listTransformQueryConfig
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
|
||||||
method: ["ALL"],
|
|
||||||
matcher: "/admin/customer-groups*",
|
|
||||||
middlewares: [authenticate("admin", ["bearer", "session"])],
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
method: ["GET"],
|
method: ["GET"],
|
||||||
matcher: "/admin/customer-groups/:id",
|
matcher: "/admin/customer-groups/:id",
|
||||||
middlewares: [
|
middlewares: [
|
||||||
transformQuery(
|
validateAndTransformQuery(
|
||||||
AdminGetCustomerGroupsGroupParams,
|
AdminGetCustomerGroupParams,
|
||||||
QueryConfig.retrieveTransformQueryConfig
|
QueryConfig.retrieveTransformQueryConfig
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@@ -44,41 +41,37 @@ export const adminCustomerGroupRoutesMiddlewares: MiddlewareRoute[] = [
|
|||||||
{
|
{
|
||||||
method: ["POST"],
|
method: ["POST"],
|
||||||
matcher: "/admin/customer-groups",
|
matcher: "/admin/customer-groups",
|
||||||
middlewares: [transformBody(AdminPostCustomerGroupsReq)],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
method: ["POST"],
|
|
||||||
matcher: "/admin/customer-groups/:id",
|
|
||||||
middlewares: [transformBody(AdminPostCustomerGroupsGroupReq)],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
method: ["GET"],
|
|
||||||
matcher: "/admin/customer-groups/:id/customers",
|
|
||||||
middlewares: [
|
middlewares: [
|
||||||
transformQuery(
|
validateAndTransformBody(AdminCreateCustomerGroup),
|
||||||
AdminGetCustomerGroupsGroupCustomersParams,
|
validateAndTransformQuery(
|
||||||
customersListTransformQueryConfig
|
AdminGetCustomerGroupParams,
|
||||||
),
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
method: ["POST"],
|
|
||||||
matcher: "/admin/customer-groups/:id/customers/batch/add",
|
|
||||||
middlewares: [
|
|
||||||
transformBody(AdminPostCustomerGroupsGroupCustomersBatchReq),
|
|
||||||
transformQuery(
|
|
||||||
AdminGetCustomerGroupsGroupParams,
|
|
||||||
QueryConfig.retrieveTransformQueryConfig
|
QueryConfig.retrieveTransformQueryConfig
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
method: ["POST"],
|
method: ["POST"],
|
||||||
matcher: "/admin/customer-groups/:id/customers/batch/remove",
|
matcher: "/admin/customer-groups/:id",
|
||||||
middlewares: [
|
middlewares: [
|
||||||
transformBody(AdminDeleteCustomerGroupsGroupCustomersBatchReq),
|
validateAndTransformBody(AdminUpdateCustomerGroup),
|
||||||
transformQuery(
|
validateAndTransformQuery(
|
||||||
AdminGetCustomerGroupsGroupParams,
|
AdminGetCustomerGroupParams,
|
||||||
|
QueryConfig.retrieveTransformQueryConfig
|
||||||
|
),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
method: ["POST"],
|
||||||
|
matcher: "/admin/customer-groups/:id/customers/batch",
|
||||||
|
middlewares: [
|
||||||
|
validateAndTransformBody(
|
||||||
|
createBatchBody(
|
||||||
|
AdminSetCustomersCustomerGroup,
|
||||||
|
AdminSetCustomersCustomerGroup
|
||||||
|
)
|
||||||
|
),
|
||||||
|
validateAndTransformQuery(
|
||||||
|
AdminGetCustomerGroupParams,
|
||||||
QueryConfig.retrieveTransformQueryConfig
|
QueryConfig.retrieveTransformQueryConfig
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -1,17 +1,14 @@
|
|||||||
export const defaultAdminCustomerGroupRelations = []
|
|
||||||
export const allowedAdminCustomerGroupRelations = ["customers"]
|
|
||||||
export const defaultAdminCustomerGroupFields = [
|
export const defaultAdminCustomerGroupFields = [
|
||||||
"id",
|
"id",
|
||||||
"name",
|
"name",
|
||||||
|
"created_by",
|
||||||
"created_at",
|
"created_at",
|
||||||
"updated_at",
|
"updated_at",
|
||||||
"deleted_at",
|
"deleted_at",
|
||||||
]
|
]
|
||||||
|
|
||||||
export const retrieveTransformQueryConfig = {
|
export const retrieveTransformQueryConfig = {
|
||||||
defaultFields: defaultAdminCustomerGroupFields,
|
defaults: defaultAdminCustomerGroupFields,
|
||||||
defaultRelations: defaultAdminCustomerGroupRelations,
|
|
||||||
allowedRelations: allowedAdminCustomerGroupRelations,
|
|
||||||
isList: false,
|
isList: false,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,39 +1,42 @@
|
|||||||
import {
|
import {
|
||||||
AuthenticatedMedusaRequest,
|
AuthenticatedMedusaRequest,
|
||||||
MedusaRequest,
|
|
||||||
MedusaResponse,
|
MedusaResponse,
|
||||||
} from "../../../types/routing"
|
} from "../../../types/routing"
|
||||||
import { CreateCustomerGroupDTO, ICustomerModuleService } from "@medusajs/types"
|
|
||||||
|
|
||||||
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
|
|
||||||
import { createCustomerGroupsWorkflow } from "@medusajs/core-flows"
|
import { createCustomerGroupsWorkflow } from "@medusajs/core-flows"
|
||||||
|
import {
|
||||||
|
ContainerRegistrationKeys,
|
||||||
|
remoteQueryObjectFromString,
|
||||||
|
} from "@medusajs/utils"
|
||||||
|
import { AdminCreateCustomerGroupType } from "./validators"
|
||||||
|
import { refetchCustomerGroup } from "./helpers"
|
||||||
|
|
||||||
export const GET = async (
|
export const GET = async (
|
||||||
req: AuthenticatedMedusaRequest,
|
req: AuthenticatedMedusaRequest,
|
||||||
res: MedusaResponse
|
res: MedusaResponse
|
||||||
) => {
|
) => {
|
||||||
const customerModuleService = req.scope.resolve<ICustomerModuleService>(
|
const remoteQuery = req.scope.resolve(ContainerRegistrationKeys.REMOTE_QUERY)
|
||||||
ModuleRegistrationName.CUSTOMER
|
|
||||||
)
|
|
||||||
|
|
||||||
const [groups, count] =
|
const query = remoteQueryObjectFromString({
|
||||||
await customerModuleService.listAndCountCustomerGroups(
|
entryPoint: "customer_group",
|
||||||
req.filterableFields,
|
variables: {
|
||||||
req.listConfig
|
filters: req.filterableFields,
|
||||||
)
|
...req.remoteQueryConfig.pagination,
|
||||||
|
},
|
||||||
|
fields: req.remoteQueryConfig.fields,
|
||||||
|
})
|
||||||
|
|
||||||
const { offset, limit } = req.validatedQuery
|
const { rows: customer_groups, metadata } = await remoteQuery(query)
|
||||||
|
|
||||||
res.json({
|
res.json({
|
||||||
count,
|
customer_groups,
|
||||||
customer_groups: groups,
|
count: metadata.count,
|
||||||
offset,
|
offset: metadata.skip,
|
||||||
limit,
|
limit: metadata.take,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export const POST = async (
|
export const POST = async (
|
||||||
req: AuthenticatedMedusaRequest<CreateCustomerGroupDTO>,
|
req: AuthenticatedMedusaRequest<AdminCreateCustomerGroupType>,
|
||||||
res: MedusaResponse
|
res: MedusaResponse
|
||||||
) => {
|
) => {
|
||||||
const createGroups = createCustomerGroupsWorkflow(req.scope)
|
const createGroups = createCustomerGroupsWorkflow(req.scope)
|
||||||
@@ -53,5 +56,11 @@ export const POST = async (
|
|||||||
throw errors[0].error
|
throw errors[0].error
|
||||||
}
|
}
|
||||||
|
|
||||||
res.status(200).json({ customer_group: result[0] })
|
const customerGroup = await refetchCustomerGroup(
|
||||||
|
result[0].id,
|
||||||
|
req.scope,
|
||||||
|
req.remoteQueryConfig.fields
|
||||||
|
)
|
||||||
|
|
||||||
|
res.status(200).json({ customer_group: customerGroup })
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,183 +1,73 @@
|
|||||||
import { FindParams, extendedFindParamsMixin } from "../../../types/common"
|
|
||||||
import {
|
import {
|
||||||
IsNotEmpty,
|
createFindParams,
|
||||||
IsOptional,
|
createOperatorMap,
|
||||||
IsString,
|
createSelectParams,
|
||||||
ValidateNested,
|
} from "../../utils/validators"
|
||||||
} from "class-validator"
|
import { z } from "zod"
|
||||||
import { Transform, Type } from "class-transformer"
|
|
||||||
|
|
||||||
import { IsType } from "../../../utils"
|
export type AdminGetCustomerGroupParamsType = z.infer<
|
||||||
import { OperatorMap } from "@medusajs/types"
|
typeof AdminGetCustomerGroupParams
|
||||||
import { OperatorMapValidator } from "../../../types/validators/operator-map"
|
>
|
||||||
|
export const AdminGetCustomerGroupParams = createSelectParams()
|
||||||
|
|
||||||
export class AdminGetCustomerGroupsGroupParams extends FindParams {}
|
export const AdminCustomerInGroupFilters = z.object({
|
||||||
|
id: z.union([z.string(), z.array(z.string())]).optional(),
|
||||||
|
email: z
|
||||||
|
.union([z.string(), z.array(z.string()), createOperatorMap()])
|
||||||
|
.optional(),
|
||||||
|
default_billing_address_id: z
|
||||||
|
.union([z.string(), z.array(z.string())])
|
||||||
|
.optional(),
|
||||||
|
default_shipping_address_id: z
|
||||||
|
.union([z.string(), z.array(z.string())])
|
||||||
|
.optional(),
|
||||||
|
company_name: z.union([z.string(), z.array(z.string())]).optional(),
|
||||||
|
first_name: z.union([z.string(), z.array(z.string())]).optional(),
|
||||||
|
last_name: z.union([z.string(), z.array(z.string())]).optional(),
|
||||||
|
created_by: z.union([z.string(), z.array(z.string())]).optional(),
|
||||||
|
created_at: createOperatorMap().optional(),
|
||||||
|
updated_at: createOperatorMap().optional(),
|
||||||
|
deleted_at: createOperatorMap().optional(),
|
||||||
|
})
|
||||||
|
|
||||||
class FilterableCustomerPropsValidator {
|
export type AdminGetCustomerGroupsParamsType = z.infer<
|
||||||
@IsOptional()
|
typeof AdminGetCustomerGroupsParams
|
||||||
@IsString({ each: true })
|
>
|
||||||
id?: string | string[]
|
export const AdminGetCustomerGroupsParams = createFindParams({
|
||||||
|
limit: 50,
|
||||||
@IsOptional()
|
|
||||||
@ValidateNested({ each: true })
|
|
||||||
@Type(() => OperatorMapValidator)
|
|
||||||
email?: string | string[] | OperatorMap<string>
|
|
||||||
|
|
||||||
@IsOptional()
|
|
||||||
@IsString({ each: true })
|
|
||||||
default_billing_address_id?: string | string[] | null
|
|
||||||
|
|
||||||
@IsOptional()
|
|
||||||
@IsString({ each: true })
|
|
||||||
default_shipping_address_id?: string | string[] | null
|
|
||||||
|
|
||||||
@IsOptional()
|
|
||||||
@IsString({ each: true })
|
|
||||||
company_name?: string | string[] | OperatorMap<string> | null
|
|
||||||
|
|
||||||
@IsOptional()
|
|
||||||
@IsString({ each: true })
|
|
||||||
first_name?: string | string[] | OperatorMap<string> | null
|
|
||||||
|
|
||||||
@IsOptional()
|
|
||||||
@IsString({ each: true })
|
|
||||||
last_name?: string | string[] | OperatorMap<string> | null
|
|
||||||
|
|
||||||
@IsOptional()
|
|
||||||
@IsString({ each: true })
|
|
||||||
created_by?: string | string[] | null
|
|
||||||
|
|
||||||
@IsOptional()
|
|
||||||
@ValidateNested()
|
|
||||||
@Type(() => OperatorMapValidator)
|
|
||||||
created_at?: OperatorMap<string>
|
|
||||||
|
|
||||||
@IsOptional()
|
|
||||||
@ValidateNested()
|
|
||||||
@Type(() => OperatorMapValidator)
|
|
||||||
updated_at?: OperatorMap<string>
|
|
||||||
}
|
|
||||||
|
|
||||||
export class AdminGetCustomerGroupsParams extends extendedFindParamsMixin({
|
|
||||||
limit: 100,
|
|
||||||
offset: 0,
|
offset: 0,
|
||||||
}) {
|
}).merge(
|
||||||
@IsOptional()
|
z.object({
|
||||||
@IsString()
|
q: z.string().optional(),
|
||||||
q?: string
|
id: z.union([z.string(), z.array(z.string())]).optional(),
|
||||||
|
name: z.union([z.string(), z.array(z.string())]).optional(),
|
||||||
|
customers: z
|
||||||
|
.union([z.string(), z.array(z.string()), AdminCustomerInGroupFilters])
|
||||||
|
.optional(),
|
||||||
|
created_by: z.union([z.string(), z.array(z.string())]).optional(),
|
||||||
|
created_at: createOperatorMap().optional(),
|
||||||
|
updated_at: createOperatorMap().optional(),
|
||||||
|
deleted_at: createOperatorMap().optional(),
|
||||||
|
$and: z.lazy(() => AdminGetCustomerGroupsParams.array()).optional(),
|
||||||
|
$or: z.lazy(() => AdminGetCustomerGroupsParams.array()).optional(),
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
@IsOptional()
|
export type AdminCreateCustomerGroupType = z.infer<
|
||||||
@IsString({ each: true })
|
typeof AdminCreateCustomerGroup
|
||||||
id?: string | string[]
|
>
|
||||||
|
export const AdminCreateCustomerGroup = z.object({
|
||||||
|
name: z.string(),
|
||||||
|
})
|
||||||
|
|
||||||
@IsOptional()
|
export type AdminUpdateCustomerGroupType = z.infer<
|
||||||
@ValidateNested({ each: true })
|
typeof AdminUpdateCustomerGroup
|
||||||
@Type(() => OperatorMapValidator)
|
>
|
||||||
name?: string | OperatorMap<string>
|
export const AdminUpdateCustomerGroup = z.object({
|
||||||
|
name: z.string(),
|
||||||
|
})
|
||||||
|
|
||||||
@IsOptional()
|
export type AdminSetCustomersCustomerGroupType = z.infer<
|
||||||
@ValidateNested()
|
typeof AdminSetCustomersCustomerGroup
|
||||||
@Type(() => FilterableCustomerPropsValidator)
|
>
|
||||||
customers?: FilterableCustomerPropsValidator | string | string[]
|
export const AdminSetCustomersCustomerGroup = z.string()
|
||||||
|
|
||||||
@IsOptional()
|
|
||||||
@IsString({ each: true })
|
|
||||||
created_by?: string | string[] | null
|
|
||||||
|
|
||||||
@IsOptional()
|
|
||||||
@ValidateNested()
|
|
||||||
@Type(() => OperatorMapValidator)
|
|
||||||
created_at?: OperatorMap<string>
|
|
||||||
|
|
||||||
@IsOptional()
|
|
||||||
@ValidateNested()
|
|
||||||
@Type(() => OperatorMapValidator)
|
|
||||||
updated_at?: OperatorMap<string>
|
|
||||||
|
|
||||||
// Additional filters from BaseFilterable
|
|
||||||
@IsOptional()
|
|
||||||
@ValidateNested({ each: true })
|
|
||||||
@Type(() => AdminGetCustomerGroupsParams)
|
|
||||||
$and?: AdminGetCustomerGroupsParams[]
|
|
||||||
|
|
||||||
@IsOptional()
|
|
||||||
@ValidateNested({ each: true })
|
|
||||||
@Type(() => AdminGetCustomerGroupsParams)
|
|
||||||
$or?: AdminGetCustomerGroupsParams[]
|
|
||||||
}
|
|
||||||
|
|
||||||
export class AdminPostCustomerGroupsReq {
|
|
||||||
@IsNotEmpty()
|
|
||||||
@IsString()
|
|
||||||
name: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export class AdminPostCustomerGroupsGroupReq {
|
|
||||||
@IsNotEmpty()
|
|
||||||
@IsString()
|
|
||||||
@IsOptional()
|
|
||||||
name?: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export class AdminGetCustomerGroupsGroupCustomersParams extends extendedFindParamsMixin(
|
|
||||||
{
|
|
||||||
limit: 100,
|
|
||||||
offset: 0,
|
|
||||||
}
|
|
||||||
) {
|
|
||||||
@IsOptional()
|
|
||||||
@IsString()
|
|
||||||
q?: string
|
|
||||||
|
|
||||||
@IsOptional()
|
|
||||||
@IsString({ each: true })
|
|
||||||
id?: string | string[]
|
|
||||||
|
|
||||||
@IsOptional()
|
|
||||||
@IsType([String, [String], OperatorMapValidator])
|
|
||||||
email?: string | string[] | OperatorMap<string>
|
|
||||||
|
|
||||||
@IsOptional()
|
|
||||||
@IsString({ each: true })
|
|
||||||
company_name?: string | string[] | OperatorMap<string> | null
|
|
||||||
|
|
||||||
@IsOptional()
|
|
||||||
@IsString({ each: true })
|
|
||||||
first_name?: string | string[] | OperatorMap<string> | null
|
|
||||||
|
|
||||||
@IsOptional()
|
|
||||||
@IsType([String, [String], OperatorMapValidator])
|
|
||||||
@Transform(({ value }) => (value === "null" ? null : value))
|
|
||||||
last_name?: string | string[] | OperatorMap<string> | null
|
|
||||||
|
|
||||||
@IsOptional()
|
|
||||||
@IsString({ each: true })
|
|
||||||
created_by?: string | string[] | null
|
|
||||||
|
|
||||||
@IsOptional()
|
|
||||||
@ValidateNested()
|
|
||||||
@Type(() => OperatorMapValidator)
|
|
||||||
created_at?: OperatorMap<string>
|
|
||||||
|
|
||||||
@IsOptional()
|
|
||||||
@ValidateNested()
|
|
||||||
@Type(() => OperatorMapValidator)
|
|
||||||
updated_at?: OperatorMap<string>
|
|
||||||
}
|
|
||||||
|
|
||||||
class CustomerGroupsBatchCustomer {
|
|
||||||
@IsString()
|
|
||||||
id: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export class AdminDeleteCustomerGroupsGroupCustomersBatchReq {
|
|
||||||
@ValidateNested({ each: true })
|
|
||||||
@Type(() => CustomerGroupsBatchCustomer)
|
|
||||||
customer_ids: CustomerGroupsBatchCustomer[]
|
|
||||||
}
|
|
||||||
|
|
||||||
export class AdminPostCustomerGroupsGroupCustomersBatchReq {
|
|
||||||
@ValidateNested({ each: true })
|
|
||||||
@Type(() => CustomerGroupsBatchCustomer)
|
|
||||||
customer_ids: CustomerGroupsBatchCustomer[]
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -2,35 +2,38 @@ import {
|
|||||||
AuthenticatedMedusaRequest,
|
AuthenticatedMedusaRequest,
|
||||||
MedusaResponse,
|
MedusaResponse,
|
||||||
} from "../../../../../../types/routing"
|
} from "../../../../../../types/routing"
|
||||||
import { CustomerAddressDTO, ICustomerModuleService } from "@medusajs/types"
|
|
||||||
import {
|
import {
|
||||||
deleteCustomerAddressesWorkflow,
|
deleteCustomerAddressesWorkflow,
|
||||||
updateCustomerAddressesWorkflow,
|
updateCustomerAddressesWorkflow,
|
||||||
} from "@medusajs/core-flows"
|
} from "@medusajs/core-flows"
|
||||||
|
|
||||||
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
|
import {
|
||||||
|
ContainerRegistrationKeys,
|
||||||
|
remoteQueryObjectFromString,
|
||||||
|
} from "@medusajs/utils"
|
||||||
|
import { AdminCreateCustomerAddressType } from "../../../validators"
|
||||||
|
import { refetchCustomer } from "../../../helpers"
|
||||||
|
|
||||||
export const GET = async (
|
export const GET = async (
|
||||||
req: AuthenticatedMedusaRequest,
|
req: AuthenticatedMedusaRequest,
|
||||||
res: MedusaResponse
|
res: MedusaResponse
|
||||||
) => {
|
) => {
|
||||||
const customerModuleService = req.scope.resolve<ICustomerModuleService>(
|
const remoteQuery = req.scope.resolve(ContainerRegistrationKeys.REMOTE_QUERY)
|
||||||
ModuleRegistrationName.CUSTOMER
|
const queryObject = remoteQueryObjectFromString({
|
||||||
)
|
entryPoint: "customer_address",
|
||||||
|
variables: {
|
||||||
|
filters: { id: req.params.address_id, customer_id: req.params.id },
|
||||||
|
},
|
||||||
|
fields: req.remoteQueryConfig.fields,
|
||||||
|
})
|
||||||
|
|
||||||
const [address] = await customerModuleService.listAddresses(
|
const [address] = await remoteQuery(queryObject)
|
||||||
{ id: req.params.address_id, customer_id: req.params.id },
|
|
||||||
{
|
|
||||||
select: req.retrieveConfig.select,
|
|
||||||
relations: req.retrieveConfig.relations,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
res.status(200).json({ address })
|
res.status(200).json({ address })
|
||||||
}
|
}
|
||||||
|
|
||||||
export const POST = async (
|
export const POST = async (
|
||||||
req: AuthenticatedMedusaRequest<Partial<CustomerAddressDTO>>,
|
req: AuthenticatedMedusaRequest<AdminCreateCustomerAddressType>,
|
||||||
res: MedusaResponse
|
res: MedusaResponse
|
||||||
) => {
|
) => {
|
||||||
const updateAddresses = updateCustomerAddressesWorkflow(req.scope)
|
const updateAddresses = updateCustomerAddressesWorkflow(req.scope)
|
||||||
@@ -46,7 +49,13 @@ export const POST = async (
|
|||||||
throw errors[0].error
|
throw errors[0].error
|
||||||
}
|
}
|
||||||
|
|
||||||
res.status(200).json({ address: result[0] })
|
const customer = await refetchCustomer(
|
||||||
|
req.params.id,
|
||||||
|
req.scope,
|
||||||
|
req.remoteQueryConfig.fields
|
||||||
|
)
|
||||||
|
|
||||||
|
res.status(200).json({ customer })
|
||||||
}
|
}
|
||||||
|
|
||||||
export const DELETE = async (
|
export const DELETE = async (
|
||||||
@@ -65,9 +74,16 @@ export const DELETE = async (
|
|||||||
throw errors[0].error
|
throw errors[0].error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const customer = await refetchCustomer(
|
||||||
|
req.params.id,
|
||||||
|
req.scope,
|
||||||
|
req.remoteQueryConfig.fields
|
||||||
|
)
|
||||||
|
|
||||||
res.status(200).json({
|
res.status(200).json({
|
||||||
id,
|
id,
|
||||||
object: "address",
|
object: "customer_address",
|
||||||
deleted: true,
|
deleted: true,
|
||||||
|
parent: customer,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,41 +1,43 @@
|
|||||||
import { createCustomerAddressesWorkflow } from "@medusajs/core-flows"
|
import { createCustomerAddressesWorkflow } from "@medusajs/core-flows"
|
||||||
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
|
|
||||||
import {
|
|
||||||
CreateCustomerAddressDTO,
|
|
||||||
ICustomerModuleService,
|
|
||||||
} from "@medusajs/types"
|
|
||||||
import {
|
import {
|
||||||
AuthenticatedMedusaRequest,
|
AuthenticatedMedusaRequest,
|
||||||
MedusaResponse,
|
MedusaResponse,
|
||||||
} from "../../../../../types/routing"
|
} from "../../../../../types/routing"
|
||||||
|
import {
|
||||||
|
ContainerRegistrationKeys,
|
||||||
|
remoteQueryObjectFromString,
|
||||||
|
} from "@medusajs/utils"
|
||||||
|
import { AdminCreateCustomerAddressType } from "../../validators"
|
||||||
|
import { refetchCustomer } from "../../helpers"
|
||||||
|
|
||||||
export const GET = async (
|
export const GET = async (
|
||||||
req: AuthenticatedMedusaRequest,
|
req: AuthenticatedMedusaRequest,
|
||||||
res: MedusaResponse
|
res: MedusaResponse
|
||||||
) => {
|
) => {
|
||||||
const customerId = req.params.id
|
const customerId = req.params.id
|
||||||
|
const remoteQuery = req.scope.resolve(ContainerRegistrationKeys.REMOTE_QUERY)
|
||||||
|
|
||||||
const customerModuleService = req.scope.resolve<ICustomerModuleService>(
|
const query = remoteQueryObjectFromString({
|
||||||
ModuleRegistrationName.CUSTOMER
|
entryPoint: "customer_address",
|
||||||
)
|
variables: {
|
||||||
|
filters: { ...req.filterableFields, customer_id: customerId },
|
||||||
|
...req.remoteQueryConfig.pagination,
|
||||||
|
},
|
||||||
|
fields: req.remoteQueryConfig.fields,
|
||||||
|
})
|
||||||
|
|
||||||
const [addresses, count] = await customerModuleService.listAndCountAddresses(
|
const { rows: addresses, metadata } = await remoteQuery(query)
|
||||||
{ ...req.filterableFields, customer_id: customerId },
|
|
||||||
req.listConfig
|
|
||||||
)
|
|
||||||
|
|
||||||
const { offset, limit } = req.validatedQuery
|
|
||||||
|
|
||||||
res.json({
|
res.json({
|
||||||
count,
|
|
||||||
addresses,
|
addresses,
|
||||||
offset,
|
count: metadata.count,
|
||||||
limit,
|
offset: metadata.skip,
|
||||||
|
limit: metadata.take,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export const POST = async (
|
export const POST = async (
|
||||||
req: AuthenticatedMedusaRequest<CreateCustomerAddressDTO>,
|
req: AuthenticatedMedusaRequest<AdminCreateCustomerAddressType>,
|
||||||
res: MedusaResponse
|
res: MedusaResponse
|
||||||
) => {
|
) => {
|
||||||
const customerId = req.params.id
|
const customerId = req.params.id
|
||||||
@@ -56,5 +58,11 @@ export const POST = async (
|
|||||||
throw errors[0].error
|
throw errors[0].error
|
||||||
}
|
}
|
||||||
|
|
||||||
res.status(200).json({ address: result[0] })
|
const customer = await refetchCustomer(
|
||||||
|
customerId,
|
||||||
|
req.scope,
|
||||||
|
req.remoteQueryConfig.fields
|
||||||
|
)
|
||||||
|
|
||||||
|
res.status(200).json({ customer })
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,37 +2,37 @@ import {
|
|||||||
deleteCustomersWorkflow,
|
deleteCustomersWorkflow,
|
||||||
updateCustomersWorkflow,
|
updateCustomersWorkflow,
|
||||||
} from "@medusajs/core-flows"
|
} from "@medusajs/core-flows"
|
||||||
import { AdminCustomerResponse, CustomerUpdatableFields } from "@medusajs/types"
|
import { AdminCustomerResponse } from "@medusajs/types"
|
||||||
import {
|
import { MedusaError } from "@medusajs/utils"
|
||||||
ContainerRegistrationKeys,
|
|
||||||
remoteQueryObjectFromString,
|
|
||||||
} from "@medusajs/utils"
|
|
||||||
import {
|
import {
|
||||||
AuthenticatedMedusaRequest,
|
AuthenticatedMedusaRequest,
|
||||||
MedusaResponse,
|
MedusaResponse,
|
||||||
} from "../../../../types/routing"
|
} from "../../../../types/routing"
|
||||||
|
import { refetchCustomer } from "../helpers"
|
||||||
|
import { AdminUpdateCustomerType } from "../validators"
|
||||||
|
|
||||||
export const GET = async (
|
export const GET = async (
|
||||||
req: AuthenticatedMedusaRequest,
|
req: AuthenticatedMedusaRequest,
|
||||||
res: MedusaResponse<AdminCustomerResponse>
|
res: MedusaResponse<AdminCustomerResponse>
|
||||||
) => {
|
) => {
|
||||||
const remoteQuery = req.scope.resolve(ContainerRegistrationKeys.REMOTE_QUERY)
|
const customer = await refetchCustomer(
|
||||||
|
req.params.id,
|
||||||
|
req.scope,
|
||||||
|
req.remoteQueryConfig.fields
|
||||||
|
)
|
||||||
|
|
||||||
const variables = { id: req.params.id }
|
if (!customer) {
|
||||||
|
throw new MedusaError(
|
||||||
const queryObject = remoteQueryObjectFromString({
|
MedusaError.Types.NOT_FOUND,
|
||||||
entryPoint: "customer",
|
`Customer with id: ${req.params.id} not found`
|
||||||
variables,
|
)
|
||||||
fields: req.remoteQueryConfig.fields,
|
}
|
||||||
})
|
|
||||||
|
|
||||||
const [customer] = await remoteQuery(queryObject)
|
|
||||||
|
|
||||||
res.status(200).json({ customer })
|
res.status(200).json({ customer })
|
||||||
}
|
}
|
||||||
|
|
||||||
export const POST = async (
|
export const POST = async (
|
||||||
req: AuthenticatedMedusaRequest<CustomerUpdatableFields>,
|
req: AuthenticatedMedusaRequest<AdminUpdateCustomerType>,
|
||||||
res: MedusaResponse<AdminCustomerResponse>
|
res: MedusaResponse<AdminCustomerResponse>
|
||||||
) => {
|
) => {
|
||||||
const { errors } = await updateCustomersWorkflow(req.scope).run({
|
const { errors } = await updateCustomersWorkflow(req.scope).run({
|
||||||
@@ -47,18 +47,11 @@ export const POST = async (
|
|||||||
throw errors[0].error
|
throw errors[0].error
|
||||||
}
|
}
|
||||||
|
|
||||||
const remoteQuery = req.scope.resolve(ContainerRegistrationKeys.REMOTE_QUERY)
|
const customer = await refetchCustomer(
|
||||||
|
req.params.id,
|
||||||
const queryObject = remoteQueryObjectFromString({
|
req.scope,
|
||||||
entryPoint: "customer",
|
req.remoteQueryConfig.fields
|
||||||
variables: {
|
)
|
||||||
filters: { id: req.params.id },
|
|
||||||
},
|
|
||||||
fields: req.remoteQueryConfig.fields,
|
|
||||||
})
|
|
||||||
|
|
||||||
const [customer] = await remoteQuery(queryObject)
|
|
||||||
|
|
||||||
res.status(200).json({ customer })
|
res.status(200).json({ customer })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
import { MedusaContainer } from "@medusajs/types"
|
||||||
|
import {
|
||||||
|
ContainerRegistrationKeys,
|
||||||
|
remoteQueryObjectFromString,
|
||||||
|
} from "@medusajs/utils"
|
||||||
|
|
||||||
|
export const refetchCustomer = async (
|
||||||
|
customerId: string,
|
||||||
|
scope: MedusaContainer,
|
||||||
|
fields: string[]
|
||||||
|
) => {
|
||||||
|
const remoteQuery = scope.resolve(ContainerRegistrationKeys.REMOTE_QUERY)
|
||||||
|
const queryObject = remoteQueryObjectFromString({
|
||||||
|
entryPoint: "customer",
|
||||||
|
variables: {
|
||||||
|
filters: { id: customerId },
|
||||||
|
},
|
||||||
|
fields: fields,
|
||||||
|
})
|
||||||
|
|
||||||
|
const customers = await remoteQuery(queryObject)
|
||||||
|
return customers[0]
|
||||||
|
}
|
||||||
@@ -19,7 +19,7 @@ export const adminCustomerRoutesMiddlewares: MiddlewareRoute[] = [
|
|||||||
{
|
{
|
||||||
method: ["ALL"],
|
method: ["ALL"],
|
||||||
matcher: "/admin/customers*",
|
matcher: "/admin/customers*",
|
||||||
middlewares: [authenticate("admin", ["bearer", "session"])],
|
middlewares: [authenticate("admin", ["bearer", "session", "api-key"])],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
method: ["GET"],
|
method: ["GET"],
|
||||||
@@ -38,7 +38,7 @@ export const adminCustomerRoutesMiddlewares: MiddlewareRoute[] = [
|
|||||||
validateAndTransformBody(AdminCreateCustomer),
|
validateAndTransformBody(AdminCreateCustomer),
|
||||||
validateAndTransformQuery(
|
validateAndTransformQuery(
|
||||||
AdminCustomerParams,
|
AdminCustomerParams,
|
||||||
QueryConfig.listTransformQueryConfig
|
QueryConfig.retrieveTransformQueryConfig
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@@ -48,7 +48,7 @@ export const adminCustomerRoutesMiddlewares: MiddlewareRoute[] = [
|
|||||||
middlewares: [
|
middlewares: [
|
||||||
validateAndTransformQuery(
|
validateAndTransformQuery(
|
||||||
AdminCustomerParams,
|
AdminCustomerParams,
|
||||||
QueryConfig.listTransformQueryConfig
|
QueryConfig.retrieveTransformQueryConfig
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@@ -59,19 +59,41 @@ export const adminCustomerRoutesMiddlewares: MiddlewareRoute[] = [
|
|||||||
validateAndTransformBody(AdminUpdateCustomer),
|
validateAndTransformBody(AdminUpdateCustomer),
|
||||||
validateAndTransformQuery(
|
validateAndTransformQuery(
|
||||||
AdminCustomerParams,
|
AdminCustomerParams,
|
||||||
QueryConfig.listTransformQueryConfig
|
QueryConfig.retrieveTransformQueryConfig
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
method: ["POST"],
|
method: ["POST"],
|
||||||
matcher: "/admin/customers/:id/addresses",
|
matcher: "/admin/customers/:id/addresses",
|
||||||
middlewares: [validateAndTransformBody(AdminCreateCustomerAddress)],
|
middlewares: [
|
||||||
|
validateAndTransformBody(AdminCreateCustomerAddress),
|
||||||
|
validateAndTransformQuery(
|
||||||
|
AdminCustomerParams,
|
||||||
|
QueryConfig.retrieveTransformQueryConfig
|
||||||
|
),
|
||||||
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
method: ["POST"],
|
method: ["POST"],
|
||||||
matcher: "/admin/customers/:id/addresses/:address_id",
|
matcher: "/admin/customers/:id/addresses/:address_id",
|
||||||
middlewares: [validateAndTransformBody(AdminUpdateCustomerAddress)],
|
middlewares: [
|
||||||
|
validateAndTransformBody(AdminUpdateCustomerAddress),
|
||||||
|
validateAndTransformQuery(
|
||||||
|
AdminCustomerParams,
|
||||||
|
QueryConfig.retrieveTransformQueryConfig
|
||||||
|
),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
method: ["DELETE"],
|
||||||
|
matcher: "/admin/customers/:id/addresses/:address_id",
|
||||||
|
middlewares: [
|
||||||
|
validateAndTransformQuery(
|
||||||
|
AdminCustomerParams,
|
||||||
|
QueryConfig.retrieveTransformQueryConfig
|
||||||
|
),
|
||||||
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
method: ["GET"],
|
method: ["GET"],
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
export const defaultAdminCustomerRelations = []
|
|
||||||
export const allowedAdminCustomerRelations = ["groups", "addresses"]
|
|
||||||
export const defaultAdminCustomerFields = [
|
export const defaultAdminCustomerFields = [
|
||||||
"id",
|
"id",
|
||||||
"company_name",
|
"company_name",
|
||||||
@@ -7,15 +5,14 @@ export const defaultAdminCustomerFields = [
|
|||||||
"last_name",
|
"last_name",
|
||||||
"email",
|
"email",
|
||||||
"phone",
|
"phone",
|
||||||
|
"created_by",
|
||||||
"created_at",
|
"created_at",
|
||||||
"updated_at",
|
"updated_at",
|
||||||
"deleted_at",
|
"deleted_at",
|
||||||
]
|
]
|
||||||
|
|
||||||
export const retrieveTransformQueryConfig = {
|
export const retrieveTransformQueryConfig = {
|
||||||
defaultFields: defaultAdminCustomerFields,
|
defaults: defaultAdminCustomerFields,
|
||||||
defaultRelations: defaultAdminCustomerRelations,
|
|
||||||
allowedRelations: allowedAdminCustomerRelations,
|
|
||||||
isList: false,
|
isList: false,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -24,8 +21,6 @@ export const listTransformQueryConfig = {
|
|||||||
isList: true,
|
isList: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
export const defaultAdminCustomerAddressRelations = []
|
|
||||||
export const allowedAdminCustomerAddressRelations = ["customer"]
|
|
||||||
export const defaultAdminCustomerAddressFields = [
|
export const defaultAdminCustomerAddressFields = [
|
||||||
"id",
|
"id",
|
||||||
"company",
|
"company",
|
||||||
@@ -45,9 +40,7 @@ export const defaultAdminCustomerAddressFields = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
export const retrieveAddressTransformQueryConfig = {
|
export const retrieveAddressTransformQueryConfig = {
|
||||||
defaultFields: defaultAdminCustomerAddressFields,
|
defaults: defaultAdminCustomerAddressFields,
|
||||||
defaultRelations: defaultAdminCustomerAddressRelations,
|
|
||||||
allowedRelations: allowedAdminCustomerAddressRelations,
|
|
||||||
isList: false,
|
isList: false,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,27 +3,29 @@ import {
|
|||||||
AdminCustomerListResponse,
|
AdminCustomerListResponse,
|
||||||
AdminCustomerResponse,
|
AdminCustomerResponse,
|
||||||
} from "@medusajs/types"
|
} from "@medusajs/types"
|
||||||
import { remoteQueryObjectFromString } from "@medusajs/utils"
|
import {
|
||||||
|
ContainerRegistrationKeys,
|
||||||
|
remoteQueryObjectFromString,
|
||||||
|
} from "@medusajs/utils"
|
||||||
import {
|
import {
|
||||||
AuthenticatedMedusaRequest,
|
AuthenticatedMedusaRequest,
|
||||||
MedusaResponse,
|
MedusaResponse,
|
||||||
} from "../../../types/routing"
|
} from "../../../types/routing"
|
||||||
import { AdminCreateCustomerType } from "./validators"
|
import { AdminCreateCustomerType } from "./validators"
|
||||||
|
import { refetchCustomer } from "./helpers"
|
||||||
|
|
||||||
export const GET = async (
|
export const GET = async (
|
||||||
req: AuthenticatedMedusaRequest,
|
req: AuthenticatedMedusaRequest,
|
||||||
res: MedusaResponse<AdminCustomerListResponse>
|
res: MedusaResponse<AdminCustomerListResponse>
|
||||||
) => {
|
) => {
|
||||||
const remoteQuery = req.scope.resolve("remoteQuery")
|
const remoteQuery = req.scope.resolve(ContainerRegistrationKeys.REMOTE_QUERY)
|
||||||
|
|
||||||
const variables = {
|
|
||||||
filters: req.filterableFields,
|
|
||||||
...req.remoteQueryConfig.pagination,
|
|
||||||
}
|
|
||||||
|
|
||||||
const query = remoteQueryObjectFromString({
|
const query = remoteQueryObjectFromString({
|
||||||
entryPoint: "customers",
|
entryPoint: "customers",
|
||||||
variables,
|
variables: {
|
||||||
|
filters: req.filterableFields,
|
||||||
|
...req.remoteQueryConfig.pagination,
|
||||||
|
},
|
||||||
fields: req.remoteQueryConfig.fields,
|
fields: req.remoteQueryConfig.fields,
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -59,5 +61,11 @@ export const POST = async (
|
|||||||
throw errors[0].error
|
throw errors[0].error
|
||||||
}
|
}
|
||||||
|
|
||||||
res.status(200).json({ customer: result[0] as AdminCustomerResponse["customer"] })
|
const customer = await refetchCustomer(
|
||||||
|
result[0].id,
|
||||||
|
req.scope,
|
||||||
|
req.remoteQueryConfig.fields
|
||||||
|
)
|
||||||
|
|
||||||
|
res.status(200).json({ customer })
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import {
|
|||||||
} from "../../utils/validators"
|
} from "../../utils/validators"
|
||||||
|
|
||||||
export const AdminCustomerParams = createSelectParams()
|
export const AdminCustomerParams = createSelectParams()
|
||||||
export const AdminCustomerGroupParams = createSelectParams()
|
|
||||||
|
|
||||||
export const AdminCustomerGroupInCustomerParams = z.object({
|
export const AdminCustomerGroupInCustomerParams = z.object({
|
||||||
id: z.union([z.string(), z.array(z.string())]).optional(),
|
id: z.union([z.string(), z.array(z.string())]).optional(),
|
||||||
@@ -35,9 +34,9 @@ export const AdminCustomersParams = createFindParams({
|
|||||||
first_name: z.union([z.string(), z.array(z.string())]).optional(),
|
first_name: z.union([z.string(), z.array(z.string())]).optional(),
|
||||||
last_name: z.union([z.string(), z.array(z.string())]).optional(),
|
last_name: z.union([z.string(), z.array(z.string())]).optional(),
|
||||||
created_by: z.union([z.string(), z.array(z.string())]).optional(),
|
created_by: z.union([z.string(), z.array(z.string())]).optional(),
|
||||||
created_at: createOperatorMap().optional().optional(),
|
created_at: createOperatorMap().optional(),
|
||||||
updated_at: createOperatorMap().optional().optional(),
|
updated_at: createOperatorMap().optional(),
|
||||||
deleted_at: createOperatorMap().optional().optional(),
|
deleted_at: createOperatorMap().optional(),
|
||||||
$and: z.lazy(() => AdminCustomersParams.array()).optional(),
|
$and: z.lazy(() => AdminCustomersParams.array()).optional(),
|
||||||
$or: z.lazy(() => AdminCustomersParams.array()).optional(),
|
$or: z.lazy(() => AdminCustomersParams.array()).optional(),
|
||||||
})
|
})
|
||||||
@@ -101,12 +100,6 @@ export const AdminCustomerAdressesParams = createFindParams({
|
|||||||
)
|
)
|
||||||
|
|
||||||
export type AdminCustomerParamsType = z.infer<typeof AdminCustomerParams>
|
export type AdminCustomerParamsType = z.infer<typeof AdminCustomerParams>
|
||||||
export type AdminCustomerGroupParamsType = z.infer<
|
|
||||||
typeof AdminCustomerGroupParams
|
|
||||||
>
|
|
||||||
export type AdminCustomerGroupInCustomerParamsType = z.infer<
|
|
||||||
typeof AdminCustomerGroupInCustomerParams
|
|
||||||
>
|
|
||||||
export type AdminCustomersParamsType = z.infer<typeof AdminCustomersParams>
|
export type AdminCustomersParamsType = z.infer<typeof AdminCustomersParams>
|
||||||
export type AdminCreateCustomerType = z.infer<typeof AdminCreateCustomer>
|
export type AdminCreateCustomerType = z.infer<typeof AdminCreateCustomer>
|
||||||
export type AdminUpdateCustomerType = z.infer<typeof AdminUpdateCustomer>
|
export type AdminUpdateCustomerType = z.infer<typeof AdminUpdateCustomer>
|
||||||
|
|||||||
Reference in New Issue
Block a user