feat: Admin Shipping Profiles API (#7019)
This commit is contained in:
@@ -1,346 +0,0 @@
|
||||
const path = require("path")
|
||||
|
||||
const setupServer = require("../../../environment-helpers/setup-server")
|
||||
const { useApi } = require("../../../environment-helpers/use-api")
|
||||
const { initDb, useDb } = require("../../../environment-helpers/use-db")
|
||||
const {
|
||||
simpleProductFactory,
|
||||
simpleShippingOptionFactory,
|
||||
simpleShippingProfileFactory,
|
||||
} = require("../../../factories")
|
||||
const adminSeeder = require("../../../helpers/admin-seeder")
|
||||
|
||||
const adminReqConfig = {
|
||||
headers: {
|
||||
"x-medusa-access-token": "test_token",
|
||||
},
|
||||
}
|
||||
|
||||
jest.setTimeout(30000)
|
||||
|
||||
describe("/admin/shipping-profiles", () => {
|
||||
let medusaProcess
|
||||
let dbConnection
|
||||
|
||||
beforeAll(async () => {
|
||||
const cwd = path.resolve(path.join(__dirname, "..", ".."))
|
||||
dbConnection = await initDb({ cwd })
|
||||
medusaProcess = await setupServer({ cwd })
|
||||
})
|
||||
|
||||
afterAll(async () => {
|
||||
const db = useDb()
|
||||
await db.shutdown()
|
||||
|
||||
medusaProcess.kill()
|
||||
})
|
||||
|
||||
describe("GET /admin/shipping-profiles", () => {
|
||||
beforeEach(async () => {
|
||||
await adminSeeder(dbConnection)
|
||||
})
|
||||
|
||||
afterEach(async () => {
|
||||
const db = useDb()
|
||||
await db.teardown()
|
||||
})
|
||||
|
||||
it("lists shipping profiles", async () => {
|
||||
const api = useApi()
|
||||
|
||||
const {
|
||||
data: { shipping_profiles },
|
||||
status,
|
||||
} = await api.get("/admin/shipping-profiles", adminReqConfig)
|
||||
|
||||
expect(status).toEqual(200)
|
||||
|
||||
// Should contain default and gift_card profiles
|
||||
expect(shipping_profiles.length).toEqual(2)
|
||||
})
|
||||
|
||||
it("gets a shipping profile by id", async () => {
|
||||
const api = useApi()
|
||||
|
||||
const profile = await simpleShippingProfileFactory(dbConnection)
|
||||
|
||||
const {
|
||||
data: { shipping_profile },
|
||||
status,
|
||||
} = await api.get(
|
||||
`/admin/shipping-profiles/${profile.id}`,
|
||||
adminReqConfig
|
||||
)
|
||||
|
||||
expect(status).toEqual(200)
|
||||
expect(shipping_profile).toEqual(
|
||||
expect.objectContaining({
|
||||
...profile,
|
||||
updated_at: expect.any(String),
|
||||
created_at: expect.any(String),
|
||||
})
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe("POST /admin/shipping-profiles", () => {
|
||||
beforeEach(async () => {
|
||||
await adminSeeder(dbConnection)
|
||||
})
|
||||
|
||||
afterEach(async () => {
|
||||
const db = useDb()
|
||||
await db.teardown()
|
||||
})
|
||||
|
||||
it("creates a custom shipping profile", async () => {
|
||||
const api = useApi()
|
||||
|
||||
const payload = {
|
||||
name: "test-profile-2023",
|
||||
type: "custom",
|
||||
}
|
||||
|
||||
const {
|
||||
data: { shipping_profile },
|
||||
status,
|
||||
} = await api.post("/admin/shipping-profiles", payload, adminReqConfig)
|
||||
|
||||
expect(status).toEqual(200)
|
||||
expect(shipping_profile).toEqual(
|
||||
expect.objectContaining({
|
||||
id: expect.any(String),
|
||||
created_at: expect.any(String),
|
||||
updated_at: expect.any(String),
|
||||
deleted_at: null,
|
||||
...payload,
|
||||
})
|
||||
)
|
||||
})
|
||||
|
||||
it("creates a default shipping profile", async () => {
|
||||
const api = useApi()
|
||||
|
||||
const payload = {
|
||||
name: "test-profile-2023",
|
||||
type: "default",
|
||||
}
|
||||
|
||||
const {
|
||||
data: { shipping_profile },
|
||||
status,
|
||||
} = await api.post("/admin/shipping-profiles", payload, adminReqConfig)
|
||||
|
||||
expect(status).toEqual(200)
|
||||
expect(shipping_profile).toEqual(
|
||||
expect.objectContaining({
|
||||
id: expect.any(String),
|
||||
created_at: expect.any(String),
|
||||
updated_at: expect.any(String),
|
||||
deleted_at: null,
|
||||
...payload,
|
||||
})
|
||||
)
|
||||
})
|
||||
|
||||
it("creates a gift_card shipping profile", async () => {
|
||||
const api = useApi()
|
||||
|
||||
const payload = {
|
||||
name: "test-profile-2023",
|
||||
type: "gift_card",
|
||||
}
|
||||
|
||||
const {
|
||||
data: { shipping_profile },
|
||||
status,
|
||||
} = await api.post("/admin/shipping-profiles", payload, adminReqConfig)
|
||||
|
||||
expect(status).toEqual(200)
|
||||
expect(shipping_profile).toEqual(
|
||||
expect.objectContaining({
|
||||
id: expect.any(String),
|
||||
created_at: expect.any(String),
|
||||
updated_at: expect.any(String),
|
||||
deleted_at: null,
|
||||
...payload,
|
||||
})
|
||||
)
|
||||
})
|
||||
|
||||
it("creates a shipping profile with metadata", async () => {
|
||||
const api = useApi()
|
||||
|
||||
const payload = {
|
||||
name: "test-profile-2023",
|
||||
type: "default",
|
||||
metadata: {
|
||||
custom_key: "custom_value",
|
||||
},
|
||||
}
|
||||
|
||||
const {
|
||||
data: { shipping_profile },
|
||||
status,
|
||||
} = await api.post("/admin/shipping-profiles", payload, adminReqConfig)
|
||||
|
||||
expect(status).toEqual(200)
|
||||
expect(shipping_profile).toEqual(
|
||||
expect.objectContaining({
|
||||
id: expect.any(String),
|
||||
created_at: expect.any(String),
|
||||
updated_at: expect.any(String),
|
||||
deleted_at: null,
|
||||
...payload,
|
||||
})
|
||||
)
|
||||
})
|
||||
|
||||
it("fails to create a shipping profile with invalid type", async () => {
|
||||
const api = useApi()
|
||||
expect.assertions(2)
|
||||
|
||||
const payload = {
|
||||
name: "test-profile-2023",
|
||||
type: "invalid",
|
||||
}
|
||||
|
||||
await api
|
||||
.post("/admin/shipping-profiles", payload, adminReqConfig)
|
||||
.catch((err) => {
|
||||
expect(err.response.status).toEqual(400)
|
||||
expect(err.response.data.message).toEqual(
|
||||
"type must be one of 'default', 'custom', 'gift_card'"
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
it("updates a shipping profile", async () => {
|
||||
const api = useApi()
|
||||
|
||||
const testProducts = await Promise.all(
|
||||
[...Array(5).keys()].map(async () => {
|
||||
return await simpleProductFactory(dbConnection)
|
||||
})
|
||||
)
|
||||
|
||||
const testShippingOptions = await Promise.all(
|
||||
[...Array(5).keys()].map(async () => {
|
||||
return await simpleShippingOptionFactory(dbConnection)
|
||||
})
|
||||
)
|
||||
|
||||
const payload = {
|
||||
name: "test-profile-2023",
|
||||
type: "custom",
|
||||
metadata: {
|
||||
my_key: "my_value",
|
||||
},
|
||||
}
|
||||
|
||||
const {
|
||||
data: { shipping_profile: created },
|
||||
} = await api.post("/admin/shipping-profiles", payload, adminReqConfig)
|
||||
|
||||
const updatePayload = {
|
||||
name: "test-profile-2023-updated",
|
||||
products: testProducts.map((p) => p.id),
|
||||
shipping_options: testShippingOptions.map((o) => o.id),
|
||||
metadata: {
|
||||
my_key: "",
|
||||
my_new_key: "my_new_value",
|
||||
},
|
||||
}
|
||||
|
||||
const {
|
||||
data: { shipping_profile },
|
||||
status,
|
||||
} = await api.post(
|
||||
`/admin/shipping-profiles/${created.id}`,
|
||||
updatePayload,
|
||||
adminReqConfig
|
||||
)
|
||||
|
||||
expect(status).toEqual(200)
|
||||
expect(shipping_profile).toEqual(
|
||||
expect.objectContaining({
|
||||
name: "test-profile-2023-updated",
|
||||
created_at: expect.any(String),
|
||||
updated_at: expect.any(String),
|
||||
metadata: {
|
||||
my_new_key: "my_new_value",
|
||||
},
|
||||
deleted_at: null,
|
||||
type: "custom",
|
||||
})
|
||||
)
|
||||
|
||||
const {
|
||||
data: { products },
|
||||
} = await api.get(`/admin/products`, adminReqConfig)
|
||||
|
||||
expect(products.length).toEqual(5)
|
||||
expect(products).toEqual(
|
||||
expect.arrayContaining(
|
||||
testProducts.map((p) => {
|
||||
return expect.objectContaining({
|
||||
id: p.id,
|
||||
profile_id: shipping_profile.id,
|
||||
})
|
||||
})
|
||||
)
|
||||
)
|
||||
|
||||
const {
|
||||
data: { shipping_options },
|
||||
} = await api.get(`/admin/shipping-options`, adminReqConfig)
|
||||
|
||||
const numberOfShippingOptionsWithProfile = shipping_options.filter(
|
||||
(so) => so.profile_id === shipping_profile.id
|
||||
).length
|
||||
|
||||
expect(numberOfShippingOptionsWithProfile).toEqual(5)
|
||||
expect(shipping_options).toEqual(
|
||||
expect.arrayContaining(
|
||||
testShippingOptions.map((o) => {
|
||||
return expect.objectContaining({
|
||||
id: o.id,
|
||||
profile_id: shipping_profile.id,
|
||||
})
|
||||
})
|
||||
)
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe("DELETE /admin/shipping-profiles", () => {
|
||||
beforeEach(async () => {
|
||||
await adminSeeder(dbConnection)
|
||||
})
|
||||
|
||||
afterEach(async () => {
|
||||
const db = useDb()
|
||||
await db.teardown()
|
||||
})
|
||||
|
||||
it("deletes a shipping profile", async () => {
|
||||
expect.assertions(2)
|
||||
|
||||
const api = useApi()
|
||||
|
||||
const profile = await simpleShippingProfileFactory(dbConnection)
|
||||
|
||||
const { status } = await api.delete(
|
||||
`/admin/shipping-profiles/${profile.id}`,
|
||||
adminReqConfig
|
||||
)
|
||||
|
||||
expect(status).toEqual(200)
|
||||
await api
|
||||
.get(`/admin/shipping-profiles/${profile.id}`, adminReqConfig)
|
||||
.catch((err) => {
|
||||
expect(err.response.status).toEqual(404)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
228
integration-tests/api/__tests__/admin/shipping-profile.spec.ts
Normal file
228
integration-tests/api/__tests__/admin/shipping-profile.spec.ts
Normal file
@@ -0,0 +1,228 @@
|
||||
import { medusaIntegrationTestRunner } from "medusa-test-utils"
|
||||
import { breaking } from "../../../helpers/breaking"
|
||||
import {
|
||||
adminHeaders,
|
||||
createAdminUser,
|
||||
} from "../../../helpers/create-admin-user"
|
||||
|
||||
let {
|
||||
simpleProductFactory,
|
||||
simpleShippingOptionFactory,
|
||||
simpleShippingProfileFactory,
|
||||
} = {}
|
||||
|
||||
jest.setTimeout(30000)
|
||||
|
||||
medusaIntegrationTestRunner({
|
||||
env: {
|
||||
// MEDUSA_FF_MEDUSA_V2: true,
|
||||
},
|
||||
testSuite: ({ dbConnection, getContainer, api }) => {
|
||||
let appContainer
|
||||
|
||||
beforeAll(() => {
|
||||
;({
|
||||
simpleProductFactory,
|
||||
simpleShippingOptionFactory,
|
||||
simpleShippingProfileFactory,
|
||||
} = require("../../../factories"))
|
||||
})
|
||||
|
||||
beforeEach(async () => {
|
||||
appContainer = getContainer()
|
||||
|
||||
await createAdminUser(dbConnection, adminHeaders, appContainer)
|
||||
})
|
||||
|
||||
describe("Admin - Shipping Profiles", () => {
|
||||
// TODO: Missing update and delete tests
|
||||
it("should test the entire lifecycle of a shipping profile", async () => {
|
||||
const payload = {
|
||||
name: "test-profile-2023",
|
||||
type: "custom",
|
||||
}
|
||||
|
||||
const {
|
||||
data: { shipping_profile },
|
||||
status,
|
||||
} = await api.post("/admin/shipping-profiles", payload, adminHeaders)
|
||||
|
||||
expect(status).toEqual(200)
|
||||
expect(shipping_profile).toEqual(
|
||||
expect.objectContaining({
|
||||
id: expect.any(String),
|
||||
created_at: expect.any(String),
|
||||
updated_at: expect.any(String),
|
||||
...payload,
|
||||
})
|
||||
)
|
||||
|
||||
const {
|
||||
data: { shipping_profiles },
|
||||
} = await api.get("/admin/shipping-profiles", adminHeaders)
|
||||
|
||||
// In V1, response should contain default and gift_card profiles too
|
||||
expect(shipping_profiles.length).toEqual(
|
||||
breaking(
|
||||
() => 3,
|
||||
() => 1
|
||||
)
|
||||
)
|
||||
|
||||
const {
|
||||
data: { shipping_profile: retrievedProfile },
|
||||
} = await api.get(
|
||||
`/admin/shipping-profiles/${shipping_profile.id}`,
|
||||
adminHeaders
|
||||
)
|
||||
|
||||
expect(status).toEqual(200)
|
||||
expect(retrievedProfile).toEqual(
|
||||
expect.objectContaining({
|
||||
id: shipping_profile.id,
|
||||
updated_at: expect.any(String),
|
||||
created_at: expect.any(String),
|
||||
})
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe("POST /admin/shipping-profiles", () => {
|
||||
// TODO: There is no invalid types in V2 yet, so this will fail
|
||||
it("fails to create a shipping profile with invalid type", async () => {
|
||||
expect.assertions(2)
|
||||
|
||||
const payload = {
|
||||
name: "test-profile-2023",
|
||||
type: "invalid",
|
||||
}
|
||||
|
||||
await api
|
||||
.post("/admin/shipping-profiles", payload, adminHeaders)
|
||||
.catch((err) => {
|
||||
expect(err.response.status).toEqual(400)
|
||||
expect(err.response.data.message).toEqual(
|
||||
"type must be one of 'default', 'custom', 'gift_card'"
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
it("updates a shipping profile", async () => {
|
||||
// TODO: Update is not added yet
|
||||
const testProducts = await Promise.all(
|
||||
[...Array(5).keys()].map(async () => {
|
||||
return await simpleProductFactory(dbConnection)
|
||||
})
|
||||
)
|
||||
|
||||
const testShippingOptions = await Promise.all(
|
||||
[...Array(5).keys()].map(async () => {
|
||||
return await simpleShippingOptionFactory(dbConnection)
|
||||
})
|
||||
)
|
||||
|
||||
const payload = {
|
||||
name: "test-profile-2023",
|
||||
type: "custom",
|
||||
metadata: {
|
||||
my_key: "my_value",
|
||||
},
|
||||
}
|
||||
|
||||
const {
|
||||
data: { shipping_profile: created },
|
||||
} = await api.post("/admin/shipping-profiles", payload, adminHeaders)
|
||||
|
||||
const updatePayload = {
|
||||
name: "test-profile-2023-updated",
|
||||
products: testProducts.map((p) => p.id),
|
||||
shipping_options: testShippingOptions.map((o) => o.id),
|
||||
metadata: {
|
||||
my_key: "",
|
||||
my_new_key: "my_new_value",
|
||||
},
|
||||
}
|
||||
|
||||
const {
|
||||
data: { shipping_profile },
|
||||
status,
|
||||
} = await api.post(
|
||||
`/admin/shipping-profiles/${created.id}`,
|
||||
updatePayload,
|
||||
adminHeaders
|
||||
)
|
||||
|
||||
expect(status).toEqual(200)
|
||||
expect(shipping_profile).toEqual(
|
||||
expect.objectContaining({
|
||||
name: "test-profile-2023-updated",
|
||||
created_at: expect.any(String),
|
||||
updated_at: expect.any(String),
|
||||
metadata: {
|
||||
my_new_key: "my_new_value",
|
||||
},
|
||||
deleted_at: null,
|
||||
type: "custom",
|
||||
})
|
||||
)
|
||||
|
||||
const {
|
||||
data: { products },
|
||||
} = await api.get(`/admin/products`, adminHeaders)
|
||||
|
||||
expect(products.length).toEqual(5)
|
||||
expect(products).toEqual(
|
||||
expect.arrayContaining(
|
||||
testProducts.map((p) => {
|
||||
return expect.objectContaining({
|
||||
id: p.id,
|
||||
profile_id: shipping_profile.id,
|
||||
})
|
||||
})
|
||||
)
|
||||
)
|
||||
|
||||
const {
|
||||
data: { shipping_options },
|
||||
} = await api.get(`/admin/shipping-options`, adminHeaders)
|
||||
|
||||
const numberOfShippingOptionsWithProfile = shipping_options.filter(
|
||||
(so) => so.profile_id === shipping_profile.id
|
||||
).length
|
||||
|
||||
expect(numberOfShippingOptionsWithProfile).toEqual(5)
|
||||
expect(shipping_options).toEqual(
|
||||
expect.arrayContaining(
|
||||
testShippingOptions.map((o) => {
|
||||
return expect.objectContaining({
|
||||
id: o.id,
|
||||
profile_id: shipping_profile.id,
|
||||
})
|
||||
})
|
||||
)
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe("DELETE /admin/shipping-profiles", () => {
|
||||
// TODO: Delete is not added yet
|
||||
it("deletes a shipping profile", async () => {
|
||||
expect.assertions(2)
|
||||
|
||||
const profile = await simpleShippingProfileFactory(dbConnection)
|
||||
|
||||
const { status } = await api.delete(
|
||||
`/admin/shipping-profiles/${profile.id}`,
|
||||
adminHeaders
|
||||
)
|
||||
|
||||
expect(status).toEqual(200)
|
||||
await api
|
||||
.get(`/admin/shipping-profiles/${profile.id}`, adminHeaders)
|
||||
.catch((err) => {
|
||||
expect(err.response.status).toEqual(404)
|
||||
})
|
||||
})
|
||||
})
|
||||
},
|
||||
})
|
||||
@@ -0,0 +1,36 @@
|
||||
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
|
||||
import {
|
||||
CreateShippingProfileDTO,
|
||||
IFulfillmentModuleService,
|
||||
} from "@medusajs/types"
|
||||
import { StepResponse, createStep } from "@medusajs/workflows-sdk"
|
||||
|
||||
type StepInput = CreateShippingProfileDTO[]
|
||||
|
||||
export const createShippingProfilesStepId = "create-shipping-profiles"
|
||||
export const createShippingProfilesStep = createStep(
|
||||
createShippingProfilesStepId,
|
||||
async (input: StepInput, { container }) => {
|
||||
const service = container.resolve<IFulfillmentModuleService>(
|
||||
ModuleRegistrationName.FULFILLMENT
|
||||
)
|
||||
|
||||
const createdShippingProfiles = await service.createShippingProfiles(input)
|
||||
|
||||
return new StepResponse(
|
||||
createdShippingProfiles,
|
||||
createdShippingProfiles.map((created) => created.id)
|
||||
)
|
||||
},
|
||||
async (createdShippingProfiles, { container }) => {
|
||||
if (!createdShippingProfiles?.length) {
|
||||
return
|
||||
}
|
||||
|
||||
const service = container.resolve<IFulfillmentModuleService>(
|
||||
ModuleRegistrationName.FULFILLMENT
|
||||
)
|
||||
|
||||
await service.deleteShippingProfiles(createdShippingProfiles)
|
||||
}
|
||||
)
|
||||
@@ -4,4 +4,5 @@ export * from "./create-fulfillment-set"
|
||||
export * from "./create-service-zones"
|
||||
export * from "./upsert-shipping-options"
|
||||
export * from "./delete-service-zones"
|
||||
export * from "./create-shipping-profiles"
|
||||
export * from "./remove-rules-from-fulfillment-shipping-option"
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
import { FulfillmentWorkflow } from "@medusajs/types"
|
||||
import { WorkflowData, createWorkflow } from "@medusajs/workflows-sdk"
|
||||
import { createShippingProfilesStep } from "../steps"
|
||||
|
||||
export const createShippingProfilesWorkflowId =
|
||||
"create-shipping-profiles-workflow"
|
||||
export const createShippingProfilesWorkflow = createWorkflow(
|
||||
createShippingProfilesWorkflowId,
|
||||
(
|
||||
input: WorkflowData<FulfillmentWorkflow.CreateShippingProfilesWorkflowInput>
|
||||
): WorkflowData => {
|
||||
const shippingProfiles = createShippingProfilesStep(input.data)
|
||||
|
||||
return shippingProfiles
|
||||
}
|
||||
)
|
||||
@@ -1,7 +1,8 @@
|
||||
export * from "./add-rules-to-fulfillment-shipping-option"
|
||||
export * from "./create-service-zones"
|
||||
export * from "./create-shipping-options"
|
||||
export * from "./update-shipping-options"
|
||||
export * from "./create-shipping-profiles"
|
||||
export * from "./delete-service-zones"
|
||||
export * from "./remove-rules-from-fulfillment-shipping-option"
|
||||
export * from "./update-service-zones"
|
||||
export * from "./update-shipping-options"
|
||||
|
||||
@@ -40,7 +40,7 @@ export const GET = async (
|
||||
if (!service_zone) {
|
||||
throw new MedusaError(
|
||||
MedusaError.Types.NOT_FOUND,
|
||||
`Service zone with id ${req.params.zone_id} not found`
|
||||
`Service zone with id: ${req.params.zone_id} not found`
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
import { AdminShippingProfileResponse } from "@medusajs/types"
|
||||
import {
|
||||
ContainerRegistrationKeys,
|
||||
remoteQueryObjectFromString,
|
||||
} from "@medusajs/utils"
|
||||
import {
|
||||
AuthenticatedMedusaRequest,
|
||||
MedusaResponse,
|
||||
} from "../../../../types/routing"
|
||||
|
||||
export const GET = async (
|
||||
req: AuthenticatedMedusaRequest,
|
||||
res: MedusaResponse<AdminShippingProfileResponse>
|
||||
) => {
|
||||
const remoteQuery = req.scope.resolve(ContainerRegistrationKeys.REMOTE_QUERY)
|
||||
|
||||
const query = remoteQueryObjectFromString({
|
||||
entryPoint: "shipping_profiles",
|
||||
variables: { id: req.params.id },
|
||||
fields: req.remoteQueryConfig.fields,
|
||||
})
|
||||
|
||||
const [shippingProfile] = await remoteQuery(query)
|
||||
|
||||
res.status(200).json({ shipping_profile: shippingProfile })
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
import { MiddlewareRoute } from "../../../loaders/helpers/routing/types"
|
||||
import { authenticate } from "../../../utils/authenticate-middleware"
|
||||
import { validateAndTransformBody } from "../../utils/validate-body"
|
||||
import { validateAndTransformQuery } from "../../utils/validate-query"
|
||||
import {
|
||||
listTransformQueryConfig,
|
||||
retrieveTransformQueryConfig,
|
||||
} from "./query-config"
|
||||
import {
|
||||
AdminCreateShippingProfile,
|
||||
AdminShippingProfileParams,
|
||||
AdminShippingProfilesParams,
|
||||
} from "./validators"
|
||||
|
||||
export const adminShippingProfilesMiddlewares: MiddlewareRoute[] = [
|
||||
{
|
||||
matcher: "/admin/shipping-profiles*",
|
||||
middlewares: [authenticate("admin", ["bearer", "session", "api-key"])],
|
||||
},
|
||||
{
|
||||
method: ["POST"],
|
||||
matcher: "/admin/shipping-profiles",
|
||||
middlewares: [
|
||||
validateAndTransformQuery(
|
||||
AdminShippingProfilesParams,
|
||||
retrieveTransformQueryConfig
|
||||
),
|
||||
validateAndTransformBody(AdminCreateShippingProfile),
|
||||
],
|
||||
},
|
||||
{
|
||||
method: ["GET"],
|
||||
matcher: "/admin/shipping-profiles",
|
||||
middlewares: [
|
||||
validateAndTransformQuery(
|
||||
AdminShippingProfilesParams,
|
||||
listTransformQueryConfig
|
||||
),
|
||||
],
|
||||
},
|
||||
{
|
||||
method: ["GET"],
|
||||
matcher: "/admin/shipping-profiles/:id",
|
||||
middlewares: [
|
||||
validateAndTransformQuery(
|
||||
AdminShippingProfileParams,
|
||||
retrieveTransformQueryConfig
|
||||
),
|
||||
],
|
||||
},
|
||||
]
|
||||
@@ -0,0 +1,18 @@
|
||||
export const defaultAdminShippingProfileFields = [
|
||||
"id",
|
||||
"name",
|
||||
"type",
|
||||
"metadata",
|
||||
"created_at",
|
||||
"updated_at",
|
||||
]
|
||||
|
||||
export const retrieveTransformQueryConfig = {
|
||||
defaults: defaultAdminShippingProfileFields,
|
||||
isList: false,
|
||||
}
|
||||
|
||||
export const listTransformQueryConfig = {
|
||||
...retrieveTransformQueryConfig,
|
||||
isList: true,
|
||||
}
|
||||
71
packages/medusa/src/api-v2/admin/shipping-profiles/route.ts
Normal file
71
packages/medusa/src/api-v2/admin/shipping-profiles/route.ts
Normal file
@@ -0,0 +1,71 @@
|
||||
import { createShippingProfilesWorkflow } from "@medusajs/core-flows"
|
||||
import {
|
||||
AdminShippingProfileResponse,
|
||||
AdminShippingProfilesResponse,
|
||||
} from "@medusajs/types"
|
||||
import {
|
||||
ContainerRegistrationKeys,
|
||||
remoteQueryObjectFromString,
|
||||
} from "@medusajs/utils"
|
||||
import {
|
||||
AuthenticatedMedusaRequest,
|
||||
MedusaResponse,
|
||||
} from "../../../types/routing"
|
||||
import { AdminCreateShippingProfileType } from "./validators"
|
||||
|
||||
export const POST = async (
|
||||
req: AuthenticatedMedusaRequest<AdminCreateShippingProfileType>,
|
||||
res: MedusaResponse<AdminShippingProfileResponse>
|
||||
) => {
|
||||
const shippingProfilePayload = req.validatedBody
|
||||
|
||||
const { result, errors } = await createShippingProfilesWorkflow(
|
||||
req.scope
|
||||
).run({
|
||||
input: { data: [shippingProfilePayload] },
|
||||
throwOnError: false,
|
||||
})
|
||||
|
||||
if (Array.isArray(errors) && errors[0]) {
|
||||
throw errors[0].error
|
||||
}
|
||||
|
||||
const shippingProfileId = result?.[0].id
|
||||
|
||||
const remoteQuery = req.scope.resolve(ContainerRegistrationKeys.REMOTE_QUERY)
|
||||
|
||||
const query = remoteQueryObjectFromString({
|
||||
entryPoint: "shipping_profiles",
|
||||
variables: { id: shippingProfileId },
|
||||
fields: req.remoteQueryConfig.fields,
|
||||
})
|
||||
|
||||
const [shippingProfile] = await remoteQuery(query)
|
||||
|
||||
res.status(200).json({ shipping_profile: shippingProfile })
|
||||
}
|
||||
|
||||
export const GET = async (
|
||||
req: AuthenticatedMedusaRequest,
|
||||
res: MedusaResponse<AdminShippingProfilesResponse>
|
||||
) => {
|
||||
const remoteQuery = req.scope.resolve(ContainerRegistrationKeys.REMOTE_QUERY)
|
||||
|
||||
const query = remoteQueryObjectFromString({
|
||||
entryPoint: "shipping_profiles",
|
||||
variables: {
|
||||
filters: req.filterableFields,
|
||||
...req.remoteQueryConfig.pagination,
|
||||
},
|
||||
fields: req.remoteQueryConfig.fields,
|
||||
})
|
||||
|
||||
const { rows: shippingProfiles, metadata } = await remoteQuery(query)
|
||||
|
||||
res.status(200).json({
|
||||
shipping_profiles: shippingProfiles,
|
||||
count: metadata.count,
|
||||
offset: metadata.skip,
|
||||
limit: metadata.take,
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
import { z } from "zod"
|
||||
import { createFindParams, createSelectParams } from "../../utils/validators"
|
||||
|
||||
export const AdminShippingProfileParams = createSelectParams()
|
||||
export const AdminShippingProfilesParams = createFindParams({
|
||||
limit: 20,
|
||||
offset: 0,
|
||||
}).merge(
|
||||
z.object({
|
||||
type: z.string().optional(),
|
||||
name: z.string().optional(),
|
||||
})
|
||||
)
|
||||
|
||||
export const AdminCreateShippingProfile = z
|
||||
.object({
|
||||
name: z.string(),
|
||||
type: z.string(),
|
||||
metadata: z.record(z.string(), z.unknown()).optional(),
|
||||
})
|
||||
.strict()
|
||||
|
||||
export type AdminCreateShippingProfileType = z.infer<
|
||||
typeof AdminCreateShippingProfile
|
||||
>
|
||||
@@ -19,6 +19,7 @@ import { adminPromotionRoutesMiddlewares } from "./admin/promotions/middlewares"
|
||||
import { adminRegionRoutesMiddlewares } from "./admin/regions/middlewares"
|
||||
import { adminSalesChannelRoutesMiddlewares } from "./admin/sales-channels/middlewares"
|
||||
import { adminShippingOptionRoutesMiddlewares } from "./admin/shipping-options/middlewares"
|
||||
import { adminShippingProfilesMiddlewares } from "./admin/shipping-profiles/middlewares"
|
||||
import { adminStockLocationRoutesMiddlewares } from "./admin/stock-locations/middlewares"
|
||||
import { adminStoreRoutesMiddlewares } from "./admin/stores/middlewares"
|
||||
import { adminTaxRateRoutesMiddlewares } from "./admin/tax-rates/middlewares"
|
||||
@@ -69,5 +70,6 @@ export const config: MiddlewaresConfig = {
|
||||
...adminUploadRoutesMiddlewares,
|
||||
...adminFulfillmentSetsRoutesMiddlewares,
|
||||
...adminProductCategoryRoutesMiddlewares,
|
||||
...adminShippingProfilesMiddlewares,
|
||||
],
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ export * from "./api"
|
||||
export * from "./api-v2"
|
||||
export * from "./api/middlewares"
|
||||
export * from "./interfaces"
|
||||
export * from "./joiner-config"
|
||||
export * from "./models"
|
||||
export * from "./modules-config"
|
||||
export * from "./services"
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
import * as joinerConfigs from "./joiner-configs"
|
||||
|
||||
export const joinerConfig = Object.values(joinerConfigs).map(
|
||||
(config) => config.default
|
||||
)
|
||||
@@ -1 +0,0 @@
|
||||
export * as shippingProfile from "./shipping-profile-service"
|
||||
@@ -1,29 +0,0 @@
|
||||
import { ModuleJoinerConfig } from "@medusajs/types"
|
||||
|
||||
export default {
|
||||
serviceName: "shippingProfileService",
|
||||
primaryKeys: ["id"],
|
||||
linkableKeys: { profile_id: "ShippingProfile" },
|
||||
schema: `
|
||||
scalar Date
|
||||
scalar JSON
|
||||
|
||||
type ShippingProfile {
|
||||
id: ID!
|
||||
name: String!
|
||||
type: String!
|
||||
created_at: Date!
|
||||
updated_at: Date!
|
||||
deleted_at: Date
|
||||
metadata: JSON
|
||||
}
|
||||
`,
|
||||
alias: [
|
||||
{
|
||||
name: ["shipping_profile", "shipping_profiles"],
|
||||
args: {
|
||||
entity: "ShippingProfile",
|
||||
},
|
||||
},
|
||||
],
|
||||
} as ModuleJoinerConfig
|
||||
@@ -1,3 +1,12 @@
|
||||
import {
|
||||
MODULE_PACKAGE_NAMES,
|
||||
MedusaApp,
|
||||
MedusaAppMigrateUp,
|
||||
MedusaAppOutput,
|
||||
MedusaModule,
|
||||
Modules,
|
||||
ModulesDefinition,
|
||||
} from "@medusajs/modules-sdk"
|
||||
import {
|
||||
CommonTypes,
|
||||
InternalModuleDeclaration,
|
||||
@@ -8,21 +17,11 @@ import {
|
||||
import {
|
||||
ContainerRegistrationKeys,
|
||||
FlagRouter,
|
||||
isObject,
|
||||
MedusaV2Flag,
|
||||
isObject,
|
||||
} from "@medusajs/utils"
|
||||
import {
|
||||
MedusaApp,
|
||||
MedusaAppMigrateUp,
|
||||
MedusaAppOutput,
|
||||
MedusaModule,
|
||||
MODULE_PACKAGE_NAMES,
|
||||
Modules,
|
||||
ModulesDefinition,
|
||||
} from "@medusajs/modules-sdk"
|
||||
|
||||
import { asValue } from "awilix"
|
||||
import { joinerConfig } from "../joiner-config"
|
||||
import { remoteQueryFetchData } from "../utils/remote-query-fetch-data"
|
||||
|
||||
export function mergeDefaultModules(
|
||||
@@ -101,7 +100,6 @@ export async function migrateMedusaApp(
|
||||
|
||||
await MedusaAppMigrateUp({
|
||||
modulesConfig: configModules,
|
||||
servicesConfig: joinerConfig,
|
||||
remoteFetchData: remoteQueryFetchData(container),
|
||||
sharedContainer: container,
|
||||
sharedResourcesConfig,
|
||||
@@ -170,7 +168,6 @@ export const loadMedusaApp = async (
|
||||
const medusaApp = await MedusaApp({
|
||||
workerMode: configModule.projectConfig.worker_mode,
|
||||
modulesConfig: configModules,
|
||||
servicesConfig: joinerConfig,
|
||||
remoteFetchData: remoteQueryFetchData(container),
|
||||
sharedContainer: container,
|
||||
sharedResourcesConfig,
|
||||
@@ -291,7 +288,6 @@ export async function runModulesLoader({
|
||||
|
||||
await MedusaApp({
|
||||
modulesConfig: configModules,
|
||||
servicesConfig: joinerConfig,
|
||||
remoteFetchData: remoteQueryFetchData(container),
|
||||
sharedContainer: container,
|
||||
sharedResourcesConfig,
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import { PaginatedResponse } from "../../../common"
|
||||
|
||||
/**
|
||||
* @experimental
|
||||
*/
|
||||
export interface AdminShippingProfileResponse {
|
||||
export interface ShippingProfileResponse {
|
||||
id: string
|
||||
name: string
|
||||
type: string
|
||||
@@ -10,3 +12,11 @@ export interface AdminShippingProfileResponse {
|
||||
updated_at: Date
|
||||
deleted_at: Date | null
|
||||
}
|
||||
|
||||
export interface AdminShippingProfileResponse {
|
||||
shipping_profile: ShippingProfileResponse
|
||||
}
|
||||
|
||||
export interface AdminShippingProfilesResponse extends PaginatedResponse {
|
||||
shipping_profiles: ShippingProfileResponse[]
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
export * from "./create-shipping-options"
|
||||
export * from "./update-shipping-options"
|
||||
export * from "./service-zones"
|
||||
export * from "./shipping-profiles"
|
||||
export * from "./update-shipping-options"
|
||||
|
||||
20
packages/types/src/workflow/fulfillment/shipping-profiles.ts
Normal file
20
packages/types/src/workflow/fulfillment/shipping-profiles.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import { FilterableShippingProfileProps } from "../../fulfillment"
|
||||
|
||||
interface CreateShippingProfile {
|
||||
name: string
|
||||
type: string
|
||||
}
|
||||
|
||||
export interface CreateShippingProfilesWorkflowInput {
|
||||
data: CreateShippingProfile[]
|
||||
}
|
||||
|
||||
interface UpdateShippingProfile {
|
||||
name?: string
|
||||
type?: string
|
||||
}
|
||||
|
||||
export interface UpdateShippingProfilesWorkflowInput {
|
||||
selector: FilterableShippingProfileProps
|
||||
update: UpdateShippingProfile
|
||||
}
|
||||
Reference in New Issue
Block a user