feat: Move shipping option + profile test and more (#7609)
This commit is contained in:
1 parent
e44fe78b96
commit
dc087bf310
16 files changed
+627
-1110
No files matched your search
@@ -1,595 +0,0 @@
|
|||||||
const path = require("path")
|
|
||||||
const { ShippingProfile } = require("@medusajs/medusa")
|
|
||||||
|
|
||||||
const setupServer = require("../../../environment-helpers/setup-server")
|
|
||||||
const startServerWithEnvironment =
|
|
||||||
require("../../../environment-helpers/start-server-with-environment").default
|
|
||||||
const { useApi } = require("../../../environment-helpers/use-api")
|
|
||||||
const { initDb, useDb } = require("../../../environment-helpers/use-db")
|
|
||||||
const adminSeeder = require("../../../helpers/admin-seeder")
|
|
||||||
const shippingOptionSeeder = require("../../../helpers/shipping-option-seeder")
|
|
||||||
const {
|
|
||||||
simpleShippingOptionFactory,
|
|
||||||
simpleRegionFactory,
|
|
||||||
} = require("../../../factories")
|
|
||||||
|
|
||||||
const adminReqConfig = {
|
|
||||||
headers: {
|
|
||||||
"x-medusa-access-token": "test_token",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
jest.setTimeout(30000)
|
|
||||||
|
|
||||||
describe("/admin/shipping-options", () => {
|
|
||||||
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("POST /admin/shipping-options/:id", () => {
|
|
||||||
beforeEach(async () => {
|
|
||||||
await adminSeeder(dbConnection)
|
|
||||||
await shippingOptionSeeder(dbConnection)
|
|
||||||
})
|
|
||||||
|
|
||||||
afterEach(async () => {
|
|
||||||
const db = useDb()
|
|
||||||
await db.teardown()
|
|
||||||
})
|
|
||||||
|
|
||||||
it("should update a shipping option with no existing requirements", async () => {
|
|
||||||
const api = useApi()
|
|
||||||
|
|
||||||
const payload = {
|
|
||||||
name: "Test option",
|
|
||||||
amount: 100,
|
|
||||||
requirements: [
|
|
||||||
{
|
|
||||||
type: "min_subtotal",
|
|
||||||
amount: 1,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: "max_subtotal",
|
|
||||||
amount: 2,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}
|
|
||||||
|
|
||||||
const res = await api.post(
|
|
||||||
`/admin/shipping-options/test-out`,
|
|
||||||
payload,
|
|
||||||
adminReqConfig
|
|
||||||
)
|
|
||||||
|
|
||||||
const requirements = res.data.shipping_option.requirements
|
|
||||||
|
|
||||||
expect(res.status).toEqual(200)
|
|
||||||
expect(requirements.length).toEqual(2)
|
|
||||||
expect(requirements[0]).toEqual(
|
|
||||||
expect.objectContaining({
|
|
||||||
type: "min_subtotal",
|
|
||||||
shipping_option_id: "test-out",
|
|
||||||
amount: 1,
|
|
||||||
})
|
|
||||||
)
|
|
||||||
expect(requirements[1]).toEqual(
|
|
||||||
expect.objectContaining({
|
|
||||||
type: "max_subtotal",
|
|
||||||
shipping_option_id: "test-out",
|
|
||||||
amount: 2,
|
|
||||||
})
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
it("should update a shipping option with price_type", async () => {
|
|
||||||
const api = useApi()
|
|
||||||
|
|
||||||
const payload = {
|
|
||||||
price_type: "calculated",
|
|
||||||
requirements: [],
|
|
||||||
}
|
|
||||||
|
|
||||||
const res = await api
|
|
||||||
.post(`/admin/shipping-options/test-out`, payload, adminReqConfig)
|
|
||||||
.catch(console.log)
|
|
||||||
|
|
||||||
expect(res.status).toEqual(200)
|
|
||||||
expect(res.data.shipping_option).toEqual(
|
|
||||||
expect.objectContaining({
|
|
||||||
price_type: "calculated",
|
|
||||||
})
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
it("should fail to add a a requirement with an id if it does not exists", async () => {
|
|
||||||
const api = useApi()
|
|
||||||
|
|
||||||
const payload = {
|
|
||||||
name: "Test option",
|
|
||||||
amount: 100,
|
|
||||||
requirements: [
|
|
||||||
{
|
|
||||||
id: "not_allowed",
|
|
||||||
type: "min_subtotal",
|
|
||||||
amount: 1,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "really_not_allowed",
|
|
||||||
type: "max_subtotal",
|
|
||||||
amount: 2,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}
|
|
||||||
|
|
||||||
const res = await api
|
|
||||||
.post(`/admin/shipping-options/test-out`, payload, adminReqConfig)
|
|
||||||
.catch((err) => {
|
|
||||||
return err.response
|
|
||||||
})
|
|
||||||
|
|
||||||
expect(res.status).toEqual(400)
|
|
||||||
expect(res.data.message).toEqual(
|
|
||||||
"Shipping option requirement with id not_allowed does not exist"
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
it("should successfully updates a set of existing requirements", async () => {
|
|
||||||
const api = useApi()
|
|
||||||
|
|
||||||
const payload = {
|
|
||||||
requirements: [
|
|
||||||
{
|
|
||||||
id: "option-req",
|
|
||||||
type: "min_subtotal",
|
|
||||||
amount: 15,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "option-req-2",
|
|
||||||
type: "max_subtotal",
|
|
||||||
amount: 20,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
amount: 200,
|
|
||||||
}
|
|
||||||
|
|
||||||
const res = await api
|
|
||||||
.post(
|
|
||||||
`/admin/shipping-options/test-option-req`,
|
|
||||||
payload,
|
|
||||||
adminReqConfig
|
|
||||||
)
|
|
||||||
.catch((err) => {
|
|
||||||
console.log(err.response.data.message)
|
|
||||||
})
|
|
||||||
|
|
||||||
expect(res.status).toEqual(200)
|
|
||||||
})
|
|
||||||
|
|
||||||
it("should successfully updates a set of existing requirements by updating one and deleting the other", async () => {
|
|
||||||
const api = useApi()
|
|
||||||
|
|
||||||
const payload = {
|
|
||||||
requirements: [
|
|
||||||
{
|
|
||||||
id: "option-req",
|
|
||||||
type: "min_subtotal",
|
|
||||||
amount: 15,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}
|
|
||||||
|
|
||||||
const res = await api
|
|
||||||
.post(
|
|
||||||
`/admin/shipping-options/test-option-req`,
|
|
||||||
payload,
|
|
||||||
adminReqConfig
|
|
||||||
)
|
|
||||||
.catch((err) => {
|
|
||||||
console.log(err.response.data.message)
|
|
||||||
})
|
|
||||||
|
|
||||||
expect(res.status).toEqual(200)
|
|
||||||
})
|
|
||||||
|
|
||||||
it("should successfully updates a set of requirements because max. subtotal >= min. subtotal", async () => {
|
|
||||||
const api = useApi()
|
|
||||||
|
|
||||||
const payload = {
|
|
||||||
requirements: [
|
|
||||||
{
|
|
||||||
id: "option-req",
|
|
||||||
type: "min_subtotal",
|
|
||||||
amount: 150,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "option-req-2",
|
|
||||||
type: "max_subtotal",
|
|
||||||
amount: 200,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}
|
|
||||||
|
|
||||||
const res = await api
|
|
||||||
.post(
|
|
||||||
`/admin/shipping-options/test-option-req`,
|
|
||||||
payload,
|
|
||||||
adminReqConfig
|
|
||||||
)
|
|
||||||
.catch((err) => {
|
|
||||||
console.log(err.response.data.message)
|
|
||||||
})
|
|
||||||
|
|
||||||
expect(res.status).toEqual(200)
|
|
||||||
expect(res.data.shipping_option.requirements[0].amount).toEqual(150)
|
|
||||||
expect(res.data.shipping_option.requirements[1].amount).toEqual(200)
|
|
||||||
})
|
|
||||||
|
|
||||||
it("should fail to updates a set of requirements because max. subtotal <= min. subtotal", async () => {
|
|
||||||
const api = useApi()
|
|
||||||
|
|
||||||
const payload = {
|
|
||||||
requirements: [
|
|
||||||
{
|
|
||||||
id: "option-req",
|
|
||||||
type: "min_subtotal",
|
|
||||||
amount: 1500,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "option-req-2",
|
|
||||||
type: "max_subtotal",
|
|
||||||
amount: 200,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}
|
|
||||||
|
|
||||||
const res = await api
|
|
||||||
.post(
|
|
||||||
`/admin/shipping-options/test-option-req`,
|
|
||||||
payload,
|
|
||||||
adminReqConfig
|
|
||||||
)
|
|
||||||
.catch((err) => {
|
|
||||||
return err.response
|
|
||||||
})
|
|
||||||
|
|
||||||
expect(res.status).toEqual(400)
|
|
||||||
expect(res.data.message).toEqual(
|
|
||||||
"Max. subtotal must be greater than Min. subtotal"
|
|
||||||
)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe("POST /admin/shipping-options", () => {
|
|
||||||
let payload
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
|
||||||
await adminSeeder(dbConnection)
|
|
||||||
await shippingOptionSeeder(dbConnection)
|
|
||||||
|
|
||||||
const api = useApi()
|
|
||||||
await api.post(
|
|
||||||
`/admin/regions/region`,
|
|
||||||
{
|
|
||||||
fulfillment_providers: ["test-ful"],
|
|
||||||
},
|
|
||||||
adminReqConfig
|
|
||||||
)
|
|
||||||
|
|
||||||
const manager = dbConnection.manager
|
|
||||||
const defaultProfile = await manager.findOne(ShippingProfile, {
|
|
||||||
where: {
|
|
||||||
type: ShippingProfile.default,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
payload = {
|
|
||||||
name: "Test option",
|
|
||||||
amount: 100,
|
|
||||||
price_type: "flat_rate",
|
|
||||||
region_id: "region",
|
|
||||||
provider_id: "test-ful",
|
|
||||||
data: {},
|
|
||||||
profile_id: defaultProfile.id,
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
afterEach(async () => {
|
|
||||||
const db = useDb()
|
|
||||||
await db.teardown()
|
|
||||||
})
|
|
||||||
|
|
||||||
it("should create a shipping option with requirements", async () => {
|
|
||||||
const api = useApi()
|
|
||||||
payload.requirements = [
|
|
||||||
{
|
|
||||||
type: "max_subtotal",
|
|
||||||
amount: 2,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: "min_subtotal",
|
|
||||||
amount: 1,
|
|
||||||
},
|
|
||||||
]
|
|
||||||
|
|
||||||
const res = await api.post(
|
|
||||||
`/admin/shipping-options`,
|
|
||||||
payload,
|
|
||||||
adminReqConfig
|
|
||||||
)
|
|
||||||
|
|
||||||
expect(res.status).toEqual(200)
|
|
||||||
expect(res.data.shipping_option.requirements.length).toEqual(2)
|
|
||||||
})
|
|
||||||
|
|
||||||
it("should create a shipping option with no requirements", async () => {
|
|
||||||
const api = useApi()
|
|
||||||
const res = await api.post(
|
|
||||||
`/admin/shipping-options`,
|
|
||||||
payload,
|
|
||||||
adminReqConfig
|
|
||||||
)
|
|
||||||
|
|
||||||
expect(res.status).toEqual(200)
|
|
||||||
expect(res.data.shipping_option.requirements.length).toEqual(0)
|
|
||||||
})
|
|
||||||
|
|
||||||
it("should fail on same requirement types", async () => {
|
|
||||||
const api = useApi()
|
|
||||||
payload.requirements = [
|
|
||||||
{
|
|
||||||
type: "max_subtotal",
|
|
||||||
amount: 2,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: "max_subtotal",
|
|
||||||
amount: 1,
|
|
||||||
},
|
|
||||||
]
|
|
||||||
|
|
||||||
try {
|
|
||||||
await api.post(`/admin/shipping-options`, payload, adminReqConfig)
|
|
||||||
} catch (error) {
|
|
||||||
expect(error.response.data.message).toEqual(
|
|
||||||
"Only one requirement of each type is allowed"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
it("should fail when min_subtotal > max_subtotal", async () => {
|
|
||||||
const api = useApi()
|
|
||||||
payload.requirements = [
|
|
||||||
{
|
|
||||||
type: "max_subtotal",
|
|
||||||
amount: 2,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: "min_subtotal",
|
|
||||||
amount: 4,
|
|
||||||
},
|
|
||||||
]
|
|
||||||
|
|
||||||
try {
|
|
||||||
await api.post(`/admin/shipping-options`, payload, adminReqConfig)
|
|
||||||
} catch (error) {
|
|
||||||
expect(error.response.data.message).toEqual(
|
|
||||||
"Max. subtotal must be greater than Min. subtotal"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
describe("GET /admin/shipping-options", () => {
|
|
||||||
beforeEach(async () => {
|
|
||||||
await adminSeeder(dbConnection)
|
|
||||||
await shippingOptionSeeder(dbConnection)
|
|
||||||
})
|
|
||||||
|
|
||||||
afterEach(async () => {
|
|
||||||
const db = useDb()
|
|
||||||
await db.teardown()
|
|
||||||
})
|
|
||||||
|
|
||||||
it("should list shipping options", async () => {
|
|
||||||
const api = useApi()
|
|
||||||
const res = await api.get(`/admin/shipping-options`, adminReqConfig)
|
|
||||||
|
|
||||||
expect(res.status).toEqual(200)
|
|
||||||
})
|
|
||||||
|
|
||||||
it("should list admin only shipping options", async () => {
|
|
||||||
const api = useApi()
|
|
||||||
const res = await api.get(
|
|
||||||
`/admin/shipping-options?admin_only=true`,
|
|
||||||
adminReqConfig
|
|
||||||
)
|
|
||||||
|
|
||||||
expect(res.status).toEqual(200)
|
|
||||||
expect(res.data.shipping_options).toEqual(
|
|
||||||
expect.arrayContaining([
|
|
||||||
expect.objectContaining({
|
|
||||||
id: "test-option-req-admin-only",
|
|
||||||
admin_only: true,
|
|
||||||
}),
|
|
||||||
])
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
it("should list return shipping options", async () => {
|
|
||||||
const api = useApi()
|
|
||||||
const res = await api.get(
|
|
||||||
`/admin/shipping-options?is_return=true`,
|
|
||||||
adminReqConfig
|
|
||||||
)
|
|
||||||
|
|
||||||
expect(res.status).toEqual(200)
|
|
||||||
expect(res.data.shipping_options).toEqual(
|
|
||||||
expect.arrayContaining([
|
|
||||||
expect.objectContaining({
|
|
||||||
id: "test-option-req-return",
|
|
||||||
is_return: true,
|
|
||||||
}),
|
|
||||||
])
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
it("should list shipping options without return and admin options", async () => {
|
|
||||||
const api = useApi()
|
|
||||||
const res = await api.get(
|
|
||||||
`/admin/shipping-options?is_return=false&admin_only=true`,
|
|
||||||
adminReqConfig
|
|
||||||
)
|
|
||||||
|
|
||||||
expect(res.status).toEqual(200)
|
|
||||||
expect(res.data.shipping_options).not.toEqual(
|
|
||||||
expect.arrayContaining([
|
|
||||||
expect.objectContaining({
|
|
||||||
id: "test-option-req-return",
|
|
||||||
is_return: true,
|
|
||||||
}),
|
|
||||||
expect.objectContaining({
|
|
||||||
id: "test-option-req-admin-only",
|
|
||||||
admin_only: true,
|
|
||||||
}),
|
|
||||||
])
|
|
||||||
)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe("[MEDUSA_FF_TAX_INCLUSIVE_PRICING] /admin/shipping-options", () => {
|
|
||||||
let medusaProcess
|
|
||||||
let dbConnection
|
|
||||||
|
|
||||||
beforeAll(async () => {
|
|
||||||
const cwd = path.resolve(path.join(__dirname, "..", ".."))
|
|
||||||
const [process, connection] = await startServerWithEnvironment({
|
|
||||||
cwd,
|
|
||||||
env: { MEDUSA_FF_TAX_INCLUSIVE_PRICING: true },
|
|
||||||
})
|
|
||||||
dbConnection = connection
|
|
||||||
medusaProcess = process
|
|
||||||
})
|
|
||||||
|
|
||||||
afterAll(async () => {
|
|
||||||
const db = useDb()
|
|
||||||
await db.shutdown()
|
|
||||||
|
|
||||||
medusaProcess.kill()
|
|
||||||
})
|
|
||||||
|
|
||||||
describe("POST /admin/shipping-options", () => {
|
|
||||||
const shippingOptionIncludesTaxId = "shipping-option-1-includes-tax"
|
|
||||||
let region
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
|
||||||
try {
|
|
||||||
await adminSeeder(dbConnection)
|
|
||||||
region = await simpleRegionFactory(dbConnection, {
|
|
||||||
id: "region",
|
|
||||||
countries: ["fr"],
|
|
||||||
})
|
|
||||||
await simpleShippingOptionFactory(dbConnection, {
|
|
||||||
id: shippingOptionIncludesTaxId,
|
|
||||||
region_id: region.id,
|
|
||||||
})
|
|
||||||
} catch (err) {
|
|
||||||
console.log(err)
|
|
||||||
throw err
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
afterEach(async () => {
|
|
||||||
const db = useDb()
|
|
||||||
await db.teardown()
|
|
||||||
})
|
|
||||||
|
|
||||||
it("should creates a shipping option that includes tax", async () => {
|
|
||||||
const api = useApi()
|
|
||||||
|
|
||||||
const defaultProfile = await dbConnection.manager.findOne(
|
|
||||||
ShippingProfile,
|
|
||||||
{
|
|
||||||
where: {
|
|
||||||
type: ShippingProfile.default,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
const payload = {
|
|
||||||
name: "Test option",
|
|
||||||
amount: 100,
|
|
||||||
price_type: "flat_rate",
|
|
||||||
region_id: region.id,
|
|
||||||
provider_id: "test-ful",
|
|
||||||
data: {},
|
|
||||||
profile_id: defaultProfile.id,
|
|
||||||
includes_tax: true,
|
|
||||||
}
|
|
||||||
|
|
||||||
const response = await api
|
|
||||||
.post("/admin/shipping-options", payload, adminReqConfig)
|
|
||||||
.catch((err) => {
|
|
||||||
console.log(err)
|
|
||||||
})
|
|
||||||
|
|
||||||
expect(response.status).toEqual(200)
|
|
||||||
expect(response.data.shipping_option).toEqual(
|
|
||||||
expect.objectContaining({
|
|
||||||
id: expect.any(String),
|
|
||||||
includes_tax: true,
|
|
||||||
})
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
it("should update a shipping option that include_tax", async () => {
|
|
||||||
const api = useApi()
|
|
||||||
|
|
||||||
let response = await api
|
|
||||||
.get(
|
|
||||||
`/admin/shipping-options/${shippingOptionIncludesTaxId}`,
|
|
||||||
adminReqConfig
|
|
||||||
)
|
|
||||||
.catch((err) => {
|
|
||||||
console.log(err)
|
|
||||||
})
|
|
||||||
|
|
||||||
expect(response.data.shipping_option.includes_tax).toBe(false)
|
|
||||||
|
|
||||||
const payload = {
|
|
||||||
requirements: [
|
|
||||||
{
|
|
||||||
type: "min_subtotal",
|
|
||||||
amount: 1,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: "max_subtotal",
|
|
||||||
amount: 2,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
includes_tax: true,
|
|
||||||
}
|
|
||||||
|
|
||||||
response = await api
|
|
||||||
.post(
|
|
||||||
`/admin/shipping-options/${shippingOptionIncludesTaxId}`,
|
|
||||||
payload,
|
|
||||||
adminReqConfig
|
|
||||||
)
|
|
||||||
.catch((err) => {
|
|
||||||
console.log(err)
|
|
||||||
})
|
|
||||||
|
|
||||||
expect(response.data.shipping_option.includes_tax).toBe(true)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
@@ -1,244 +0,0 @@
|
|||||||
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 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),
|
|
||||||
})
|
|
||||||
)
|
|
||||||
|
|
||||||
const { data } = await api.delete(
|
|
||||||
`/admin/shipping-profiles/${shipping_profile.id}`,
|
|
||||||
adminHeaders
|
|
||||||
)
|
|
||||||
|
|
||||||
expect(data).toEqual({
|
|
||||||
id: retrievedProfile.id,
|
|
||||||
object: "shipping_profile",
|
|
||||||
deleted: true,
|
|
||||||
})
|
|
||||||
|
|
||||||
await api
|
|
||||||
.get(`/admin/shipping-profiles/${shipping_profile.id}`, adminHeaders)
|
|
||||||
.catch((err) => {
|
|
||||||
expect(err.response.status).toEqual(404)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
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", () => {
|
|
||||||
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)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
},
|
|
||||||
})
|
|
||||||
+202
-37
@@ -1,25 +1,16 @@
|
|||||||
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
|
|
||||||
import {
|
|
||||||
IFulfillmentModuleService,
|
|
||||||
IRegionModuleService,
|
|
||||||
} from "@medusajs/types"
|
|
||||||
import { RuleOperator } from "@medusajs/utils"
|
import { RuleOperator } from "@medusajs/utils"
|
||||||
import { medusaIntegrationTestRunner } from "medusa-test-utils"
|
import { medusaIntegrationTestRunner } from "medusa-test-utils"
|
||||||
import { createAdminUser } from "../../../../helpers/create-admin-user"
|
import {
|
||||||
|
adminHeaders,
|
||||||
|
createAdminUser,
|
||||||
|
} from "../../../../helpers/create-admin-user"
|
||||||
|
|
||||||
jest.setTimeout(50000)
|
jest.setTimeout(50000)
|
||||||
|
|
||||||
const env = { MEDUSA_FF_MEDUSA_V2: true }
|
// BREAKING: Shipping setup has significantly changed from v1, exact migration needs more investigation
|
||||||
const adminHeaders = { headers: { "x-medusa-access-token": "test_token" } }
|
|
||||||
|
|
||||||
medusaIntegrationTestRunner({
|
medusaIntegrationTestRunner({
|
||||||
env,
|
|
||||||
testSuite: ({ dbConnection, getContainer, api }) => {
|
testSuite: ({ dbConnection, getContainer, api }) => {
|
||||||
describe("Admin: Shipping Option API", () => {
|
describe("Admin: Shipping Option API", () => {
|
||||||
let appContainer
|
|
||||||
let fulfillmentModule: IFulfillmentModuleService
|
|
||||||
let regionService: IRegionModuleService
|
|
||||||
|
|
||||||
let shippingProfile
|
let shippingProfile
|
||||||
let fulfillmentSet
|
let fulfillmentSet
|
||||||
let region
|
let region
|
||||||
@@ -30,38 +21,64 @@ medusaIntegrationTestRunner({
|
|||||||
value: "old value",
|
value: "old value",
|
||||||
}
|
}
|
||||||
|
|
||||||
beforeAll(async () => {
|
|
||||||
appContainer = getContainer()
|
|
||||||
fulfillmentModule = appContainer.resolve(
|
|
||||||
ModuleRegistrationName.FULFILLMENT
|
|
||||||
)
|
|
||||||
regionService = appContainer.resolve(ModuleRegistrationName.REGION)
|
|
||||||
})
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
|
const appContainer = getContainer()
|
||||||
await createAdminUser(dbConnection, adminHeaders, appContainer)
|
await createAdminUser(dbConnection, adminHeaders, appContainer)
|
||||||
|
|
||||||
shippingProfile = await fulfillmentModule.createShippingProfiles({
|
shippingProfile = (
|
||||||
name: "Test",
|
await api.post(
|
||||||
type: "default",
|
`/admin/shipping-profiles`,
|
||||||
})
|
{
|
||||||
|
name: "Test",
|
||||||
|
type: "default",
|
||||||
|
},
|
||||||
|
adminHeaders
|
||||||
|
)
|
||||||
|
).data.shipping_profile
|
||||||
|
|
||||||
fulfillmentSet = await fulfillmentModule.create({
|
let location = (
|
||||||
name: "Test",
|
await api.post(
|
||||||
type: "test-type",
|
`/admin/stock-locations`,
|
||||||
service_zones: [
|
{
|
||||||
|
name: "Test location",
|
||||||
|
},
|
||||||
|
adminHeaders
|
||||||
|
)
|
||||||
|
).data.stock_location
|
||||||
|
|
||||||
|
location = (
|
||||||
|
await api.post(
|
||||||
|
`/admin/stock-locations/${location.id}/fulfillment-sets?fields=*fulfillment_sets`,
|
||||||
|
{
|
||||||
|
name: "Test",
|
||||||
|
type: "test-type",
|
||||||
|
},
|
||||||
|
adminHeaders
|
||||||
|
)
|
||||||
|
).data.stock_location
|
||||||
|
|
||||||
|
fulfillmentSet = (
|
||||||
|
await api.post(
|
||||||
|
`/admin/fulfillment-sets/${location.fulfillment_sets[0].id}/service-zones`,
|
||||||
{
|
{
|
||||||
name: "Test",
|
name: "Test",
|
||||||
geo_zones: [{ type: "country", country_code: "us" }],
|
geo_zones: [{ type: "country", country_code: "us" }],
|
||||||
},
|
},
|
||||||
],
|
adminHeaders
|
||||||
})
|
)
|
||||||
|
).data.fulfillment_set
|
||||||
|
|
||||||
region = await regionService.create({
|
region = (
|
||||||
name: "Test region",
|
await api.post(
|
||||||
countries: ["FR"],
|
`/admin/regions`,
|
||||||
currency_code: "eur",
|
{
|
||||||
})
|
name: "Test region",
|
||||||
|
countries: ["FR"],
|
||||||
|
currency_code: "eur",
|
||||||
|
},
|
||||||
|
adminHeaders
|
||||||
|
)
|
||||||
|
).data.region
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("POST /admin/shipping-options", () => {
|
describe("POST /admin/shipping-options", () => {
|
||||||
@@ -363,6 +380,154 @@ medusaIntegrationTestRunner({
|
|||||||
expect(shippingOptions.data.shipping_options).toHaveLength(0)
|
expect(shippingOptions.data.shipping_options).toHaveLength(0)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe("POST /admin/shipping-options/:id/rules/batch", () => {
|
||||||
|
it.skip("should throw error when required params are missing", async () => {
|
||||||
|
const shippingOptionPayload = {
|
||||||
|
name: "Test shipping option",
|
||||||
|
service_zone_id: fulfillmentSet.service_zones[0].id,
|
||||||
|
shipping_profile_id: shippingProfile.id,
|
||||||
|
provider_id: "manual_test-provider",
|
||||||
|
price_type: "flat",
|
||||||
|
type: {
|
||||||
|
label: "Test type",
|
||||||
|
description: "Test description",
|
||||||
|
code: "test-code",
|
||||||
|
},
|
||||||
|
prices: [
|
||||||
|
{
|
||||||
|
currency_code: "usd",
|
||||||
|
amount: 1000,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
region_id: region.id,
|
||||||
|
amount: 1000,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
rules: [shippingOptionRule],
|
||||||
|
}
|
||||||
|
|
||||||
|
const shippingOption = (
|
||||||
|
await api.post(
|
||||||
|
`/admin/shipping-options`,
|
||||||
|
shippingOptionPayload,
|
||||||
|
adminHeaders
|
||||||
|
)
|
||||||
|
).data.shipping_option
|
||||||
|
|
||||||
|
const { response } = await api
|
||||||
|
.post(
|
||||||
|
`/admin/shipping-options/${shippingOption.id}/rules/batch`,
|
||||||
|
{
|
||||||
|
create: [{ operator: RuleOperator.EQ, value: "new_value" }],
|
||||||
|
},
|
||||||
|
adminHeaders
|
||||||
|
)
|
||||||
|
.catch((e) => e)
|
||||||
|
|
||||||
|
expect(response.status).toEqual(400)
|
||||||
|
expect(response.data).toEqual({
|
||||||
|
type: "invalid_data",
|
||||||
|
message:
|
||||||
|
"attribute must be a string, attribute should not be empty",
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should throw error when shipping option does not exist", async () => {
|
||||||
|
const { response } = await api
|
||||||
|
.post(
|
||||||
|
`/admin/shipping-options/does-not-exist/rules/batch`,
|
||||||
|
{
|
||||||
|
create: [
|
||||||
|
{ attribute: "new_attr", operator: "eq", value: "new value" },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
adminHeaders
|
||||||
|
)
|
||||||
|
.catch((e) => e)
|
||||||
|
|
||||||
|
expect(response.status).toEqual(404)
|
||||||
|
expect(response.data).toEqual({
|
||||||
|
type: "not_found",
|
||||||
|
message:
|
||||||
|
"You tried to set relationship shipping_option_id: does-not-exist, but such entity does not exist",
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it.skip("should add rules to a shipping option successfully", async () => {
|
||||||
|
const shippingOptionPayload = {
|
||||||
|
name: "Test shipping option",
|
||||||
|
service_zone_id: fulfillmentSet.service_zones[0].id,
|
||||||
|
shipping_profile_id: shippingProfile.id,
|
||||||
|
provider_id: "manual_test-provider",
|
||||||
|
price_type: "flat",
|
||||||
|
type: {
|
||||||
|
label: "Test type",
|
||||||
|
description: "Test description",
|
||||||
|
code: "test-code",
|
||||||
|
},
|
||||||
|
prices: [
|
||||||
|
{
|
||||||
|
currency_code: "usd",
|
||||||
|
amount: 1000,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
region_id: region.id,
|
||||||
|
amount: 1000,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
rules: [shippingOptionRule],
|
||||||
|
}
|
||||||
|
|
||||||
|
const shippingOption = (
|
||||||
|
await api.post(
|
||||||
|
`/admin/shipping-options`,
|
||||||
|
shippingOptionPayload,
|
||||||
|
adminHeaders
|
||||||
|
)
|
||||||
|
).data.shipping_option
|
||||||
|
|
||||||
|
const response = await api.post(
|
||||||
|
`/admin/shipping-options/${shippingOption.id}/rules/batch`,
|
||||||
|
{
|
||||||
|
create: [
|
||||||
|
{ operator: "eq", attribute: "new_attr", value: "new value" },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
adminHeaders
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(response.status).toEqual(200)
|
||||||
|
|
||||||
|
const updatedShippingOption = (
|
||||||
|
await api.get(
|
||||||
|
`/admin/shipping-options/${shippingOption.id}`,
|
||||||
|
adminHeaders
|
||||||
|
)
|
||||||
|
).data.shipping_option
|
||||||
|
expect(updatedShippingOption).toEqual(
|
||||||
|
expect.objectContaining({
|
||||||
|
id: shippingOption.id,
|
||||||
|
rules: expect.arrayContaining([
|
||||||
|
expect.objectContaining({
|
||||||
|
id: expect.any(String),
|
||||||
|
operator: "eq",
|
||||||
|
attribute: "old_attr",
|
||||||
|
value: "old value",
|
||||||
|
shipping_option_id: shippingOption.id,
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
id: expect.any(String),
|
||||||
|
operator: "eq",
|
||||||
|
attribute: "new_attr",
|
||||||
|
value: "new value",
|
||||||
|
shipping_option_id: shippingOption.id,
|
||||||
|
}),
|
||||||
|
]),
|
||||||
|
})
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
@@ -0,0 +1,114 @@
|
|||||||
|
import { medusaIntegrationTestRunner } from "medusa-test-utils"
|
||||||
|
import {
|
||||||
|
adminHeaders,
|
||||||
|
createAdminUser,
|
||||||
|
} from "../../../../helpers/create-admin-user"
|
||||||
|
|
||||||
|
jest.setTimeout(30000)
|
||||||
|
|
||||||
|
medusaIntegrationTestRunner({
|
||||||
|
testSuite: ({ dbConnection, getContainer, api }) => {
|
||||||
|
beforeEach(async () => {
|
||||||
|
const appContainer = getContainer()
|
||||||
|
await createAdminUser(dbConnection, adminHeaders, appContainer)
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("Admin - Shipping Profiles", () => {
|
||||||
|
it("should test the entire lifecycle of a shipping profile", async () => {
|
||||||
|
const payload = {
|
||||||
|
name: "test-profile-2023",
|
||||||
|
type: "custom",
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create
|
||||||
|
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,
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
|
// List
|
||||||
|
const {
|
||||||
|
data: { shipping_profiles },
|
||||||
|
} = await api.get("/admin/shipping-profiles", adminHeaders)
|
||||||
|
|
||||||
|
expect(shipping_profiles.length).toEqual(1)
|
||||||
|
|
||||||
|
// Retrieve
|
||||||
|
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),
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
|
// update
|
||||||
|
const {
|
||||||
|
data: { shipping_profile: updatedProfile },
|
||||||
|
} = await api.post(
|
||||||
|
`/admin/shipping-profiles/${shipping_profile.id}`,
|
||||||
|
{
|
||||||
|
name: "test-profile-updated",
|
||||||
|
type: "express",
|
||||||
|
metadata: {
|
||||||
|
my_new_key: "my_new_value",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
adminHeaders
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(status).toEqual(200)
|
||||||
|
expect(updatedProfile).toEqual(
|
||||||
|
expect.objectContaining({
|
||||||
|
id: shipping_profile.id,
|
||||||
|
name: "test-profile-updated",
|
||||||
|
type: "express",
|
||||||
|
metadata: {
|
||||||
|
my_new_key: "my_new_value",
|
||||||
|
},
|
||||||
|
updated_at: expect.any(String),
|
||||||
|
created_at: expect.any(String),
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
|
// Delete
|
||||||
|
const { data } = await api.delete(
|
||||||
|
`/admin/shipping-profiles/${shipping_profile.id}`,
|
||||||
|
adminHeaders
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(data).toEqual({
|
||||||
|
id: retrievedProfile.id,
|
||||||
|
object: "shipping_profile",
|
||||||
|
deleted: true,
|
||||||
|
})
|
||||||
|
|
||||||
|
await api
|
||||||
|
.get(`/admin/shipping-profiles/${shipping_profile.id}`, adminHeaders)
|
||||||
|
.catch((err) => {
|
||||||
|
expect(err.response.status).toEqual(404)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
// TODO: Associate products with shipping profiles
|
||||||
|
},
|
||||||
|
})
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
const { defineConfig } = require("@medusajs/utils")
|
const { defineConfig, Modules } = require("@medusajs/utils")
|
||||||
const DB_HOST = process.env.DB_HOST
|
const DB_HOST = process.env.DB_HOST
|
||||||
const DB_USERNAME = process.env.DB_USERNAME
|
const DB_USERNAME = process.env.DB_USERNAME
|
||||||
const DB_PASSWORD = process.env.DB_PASSWORD
|
const DB_PASSWORD = process.env.DB_PASSWORD
|
||||||
@@ -7,6 +7,15 @@ const DB_URL = `postgres://${DB_USERNAME}:${DB_PASSWORD}@${DB_HOST}/${DB_NAME}`
|
|||||||
process.env.DATABASE_URL = DB_URL
|
process.env.DATABASE_URL = DB_URL
|
||||||
process.env.LOG_LEVEL = "error"
|
process.env.LOG_LEVEL = "error"
|
||||||
|
|
||||||
|
const customFulfillmentProvider = {
|
||||||
|
resolve: "@medusajs/fulfillment-manual",
|
||||||
|
options: {
|
||||||
|
config: {
|
||||||
|
"test-provider": {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = defineConfig({
|
module.exports = defineConfig({
|
||||||
admin: {
|
admin: {
|
||||||
disable: true,
|
disable: true,
|
||||||
@@ -16,4 +25,12 @@ module.exports = defineConfig({
|
|||||||
jwtSecret: "test",
|
jwtSecret: "test",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
modules: {
|
||||||
|
[Modules.FULFILLMENT]: {
|
||||||
|
/** @type {import('@medusajs/fulfillment').FulfillmentModuleOptions} */
|
||||||
|
options: {
|
||||||
|
providers: [customFulfillmentProvider],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
})
|
})
|
||||||
-211
@@ -1,211 +0,0 @@
|
|||||||
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
|
|
||||||
import { IFulfillmentModuleService } from "@medusajs/types"
|
|
||||||
import { RuleOperator } from "@medusajs/utils"
|
|
||||||
import { medusaIntegrationTestRunner } from "medusa-test-utils"
|
|
||||||
import { createAdminUser } from "../../../../helpers/create-admin-user"
|
|
||||||
|
|
||||||
jest.setTimeout(50000)
|
|
||||||
|
|
||||||
const env = { MEDUSA_FF_MEDUSA_V2: true }
|
|
||||||
const adminHeaders = { headers: { "x-medusa-access-token": "test_token" } }
|
|
||||||
|
|
||||||
medusaIntegrationTestRunner({
|
|
||||||
env,
|
|
||||||
testSuite: ({ dbConnection, getContainer, api }) => {
|
|
||||||
describe("Admin: Shipping Option Rules API", () => {
|
|
||||||
let appContainer
|
|
||||||
let shippingOption
|
|
||||||
let fulfillmentModule: IFulfillmentModuleService
|
|
||||||
const shippingOptionRule = {
|
|
||||||
operator: RuleOperator.EQ,
|
|
||||||
attribute: "old_attr",
|
|
||||||
value: "old value",
|
|
||||||
}
|
|
||||||
|
|
||||||
beforeAll(async () => {
|
|
||||||
appContainer = getContainer()
|
|
||||||
fulfillmentModule = appContainer.resolve(
|
|
||||||
ModuleRegistrationName.FULFILLMENT
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
|
||||||
await createAdminUser(dbConnection, adminHeaders, appContainer)
|
|
||||||
|
|
||||||
const shippingProfile = await fulfillmentModule.createShippingProfiles({
|
|
||||||
name: "Test",
|
|
||||||
type: "default",
|
|
||||||
})
|
|
||||||
|
|
||||||
const fulfillmentSet = await fulfillmentModule.create({
|
|
||||||
name: "Test",
|
|
||||||
type: "test-type",
|
|
||||||
service_zones: [
|
|
||||||
{
|
|
||||||
name: "Test",
|
|
||||||
geo_zones: [{ type: "country", country_code: "us" }],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
})
|
|
||||||
|
|
||||||
shippingOption = await fulfillmentModule.createShippingOptions({
|
|
||||||
name: "Test shipping option",
|
|
||||||
service_zone_id: fulfillmentSet.service_zones[0].id,
|
|
||||||
shipping_profile_id: shippingProfile.id,
|
|
||||||
provider_id: "manual_test-provider",
|
|
||||||
price_type: "flat",
|
|
||||||
type: {
|
|
||||||
label: "Test type",
|
|
||||||
description: "Test description",
|
|
||||||
code: "test-code",
|
|
||||||
},
|
|
||||||
rules: [shippingOptionRule],
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe("POST /admin/shipping-options/:id/rules/batch", () => {
|
|
||||||
it("should throw error when required params are missing", async () => {
|
|
||||||
const { response } = await api
|
|
||||||
.post(
|
|
||||||
`/admin/shipping-options/${shippingOption.id}/rules/batch`,
|
|
||||||
{
|
|
||||||
create: [{ operator: RuleOperator.EQ, value: "new_value" }],
|
|
||||||
},
|
|
||||||
adminHeaders
|
|
||||||
)
|
|
||||||
.catch((e) => e)
|
|
||||||
|
|
||||||
expect(response.status).toEqual(400)
|
|
||||||
expect(response.data).toEqual({
|
|
||||||
type: "invalid_data",
|
|
||||||
message:
|
|
||||||
"attribute must be a string, attribute should not be empty",
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
it.only("should throw error when shipping option does not exist", async () => {
|
|
||||||
const { response } = await api
|
|
||||||
.post(
|
|
||||||
`/admin/shipping-options/does-not-exist/rules/batch`,
|
|
||||||
{
|
|
||||||
create: [
|
|
||||||
{ attribute: "new_attr", operator: "eq", value: "new value" },
|
|
||||||
],
|
|
||||||
},
|
|
||||||
adminHeaders
|
|
||||||
)
|
|
||||||
.catch((e) => e)
|
|
||||||
|
|
||||||
expect(response.status).toEqual(404)
|
|
||||||
expect(response.data).toEqual({
|
|
||||||
type: "not_found",
|
|
||||||
message:
|
|
||||||
"You tried to set relationship shipping_option_id: does-not-exist, but such entity does not exist",
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
it("should add rules to a shipping option successfully", async () => {
|
|
||||||
const response = await api.post(
|
|
||||||
`/admin/shipping-options/${shippingOption.id}/rules/batch`,
|
|
||||||
{
|
|
||||||
create: [
|
|
||||||
{ operator: "eq", attribute: "new_attr", value: "new value" },
|
|
||||||
],
|
|
||||||
},
|
|
||||||
adminHeaders
|
|
||||||
)
|
|
||||||
|
|
||||||
expect(response.status).toEqual(200)
|
|
||||||
|
|
||||||
const updatedShippingOption = (
|
|
||||||
await api.get(
|
|
||||||
`/admin/shipping-options/${shippingOption.id}`,
|
|
||||||
adminHeaders
|
|
||||||
)
|
|
||||||
).data.shipping_option
|
|
||||||
expect(updatedShippingOption).toEqual(
|
|
||||||
expect.objectContaining({
|
|
||||||
id: shippingOption.id,
|
|
||||||
rules: expect.arrayContaining([
|
|
||||||
expect.objectContaining({
|
|
||||||
id: expect.any(String),
|
|
||||||
operator: "eq",
|
|
||||||
attribute: "old_attr",
|
|
||||||
value: "old value",
|
|
||||||
shipping_option_id: shippingOption.id,
|
|
||||||
}),
|
|
||||||
expect.objectContaining({
|
|
||||||
id: expect.any(String),
|
|
||||||
operator: "eq",
|
|
||||||
attribute: "new_attr",
|
|
||||||
value: "new value",
|
|
||||||
shipping_option_id: shippingOption.id,
|
|
||||||
}),
|
|
||||||
]),
|
|
||||||
})
|
|
||||||
)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe("POST /admin/shipping-options/:id/rules/batch", () => {
|
|
||||||
it("should throw error when required params are missing", async () => {
|
|
||||||
const { response } = await api
|
|
||||||
.post(
|
|
||||||
`/admin/shipping-options/${shippingOption.id}/rules/batch`,
|
|
||||||
{},
|
|
||||||
adminHeaders
|
|
||||||
)
|
|
||||||
.catch((e) => e)
|
|
||||||
|
|
||||||
expect(response.status).toEqual(400)
|
|
||||||
expect(response.data).toEqual({
|
|
||||||
type: "invalid_data",
|
|
||||||
message:
|
|
||||||
"each value in rule_ids must be a string, rule_ids should not be empty",
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
it("should throw error when shipping option does not exist", async () => {
|
|
||||||
const { response } = await api
|
|
||||||
.post(
|
|
||||||
`/admin/shipping-options/does-not-exist/rules/batch`,
|
|
||||||
{ delete: ["test"] },
|
|
||||||
adminHeaders
|
|
||||||
)
|
|
||||||
.catch((e) => e)
|
|
||||||
|
|
||||||
expect(response.status).toEqual(404)
|
|
||||||
expect(response.data).toEqual({
|
|
||||||
type: "not_found",
|
|
||||||
message: "ShippingOption with id: does-not-exist was not found",
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
it("should add rules to a shipping option successfully", async () => {
|
|
||||||
const response = await api.post(
|
|
||||||
`/admin/shipping-options/${shippingOption.id}/rules/batch`,
|
|
||||||
{
|
|
||||||
delete: [shippingOption.rules[0].id],
|
|
||||||
},
|
|
||||||
adminHeaders
|
|
||||||
)
|
|
||||||
|
|
||||||
expect(response.status).toEqual(200)
|
|
||||||
|
|
||||||
const updatedShippingOption = (
|
|
||||||
await api.get(
|
|
||||||
`/admin/shipping-options/${shippingOption.id}`,
|
|
||||||
adminHeaders
|
|
||||||
)
|
|
||||||
).data.shipping_option
|
|
||||||
expect(updatedShippingOption).toEqual(
|
|
||||||
expect.objectContaining({
|
|
||||||
id: shippingOption.id,
|
|
||||||
rules: [],
|
|
||||||
})
|
|
||||||
)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
},
|
|
||||||
})
|
|
||||||
@@ -12,5 +12,7 @@ export * from "./delete-shipping-option-rules"
|
|||||||
export * from "./delete-shipping-options"
|
export * from "./delete-shipping-options"
|
||||||
export * from "./set-shipping-options-prices"
|
export * from "./set-shipping-options-prices"
|
||||||
export * from "./update-fulfillment"
|
export * from "./update-fulfillment"
|
||||||
|
export * from "./update-shipping-profiles"
|
||||||
export * from "./upsert-shipping-options"
|
export * from "./upsert-shipping-options"
|
||||||
export * from "./validate-shipment"
|
export * from "./validate-shipment"
|
||||||
|
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
|
||||||
|
import {
|
||||||
|
FilterableShippingProfileProps,
|
||||||
|
IFulfillmentModuleService,
|
||||||
|
UpdateShippingProfileDTO,
|
||||||
|
} from "@medusajs/types"
|
||||||
|
import { getSelectsAndRelationsFromObjectArray } from "@medusajs/utils"
|
||||||
|
import { StepResponse, createStep } from "@medusajs/workflows-sdk"
|
||||||
|
|
||||||
|
type StepInput = {
|
||||||
|
update: UpdateShippingProfileDTO
|
||||||
|
selector: FilterableShippingProfileProps
|
||||||
|
}
|
||||||
|
|
||||||
|
export const updateShippingProfilesStepId = "update-shipping-profiles"
|
||||||
|
export const updateShippingProfilesStep = createStep(
|
||||||
|
updateShippingProfilesStepId,
|
||||||
|
async (input: StepInput, { container }) => {
|
||||||
|
const service = container.resolve<IFulfillmentModuleService>(
|
||||||
|
ModuleRegistrationName.FULFILLMENT
|
||||||
|
)
|
||||||
|
|
||||||
|
const { selects, relations } = getSelectsAndRelationsFromObjectArray([
|
||||||
|
input.update,
|
||||||
|
])
|
||||||
|
|
||||||
|
const prevData = await service.listShippingProfiles(input.selector, {
|
||||||
|
select: selects,
|
||||||
|
relations,
|
||||||
|
})
|
||||||
|
|
||||||
|
const profiles = await service.updateShippingProfiles(
|
||||||
|
input.selector,
|
||||||
|
input.update
|
||||||
|
)
|
||||||
|
|
||||||
|
return new StepResponse(profiles, prevData)
|
||||||
|
},
|
||||||
|
async (prevData, { container }) => {
|
||||||
|
if (!prevData?.length) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const service = container.resolve<IFulfillmentModuleService>(
|
||||||
|
ModuleRegistrationName.FULFILLMENT
|
||||||
|
)
|
||||||
|
|
||||||
|
await service.upsertShippingProfiles(prevData)
|
||||||
|
}
|
||||||
|
)
|
||||||
@@ -12,3 +12,5 @@ export * from "./delete-shipping-options"
|
|||||||
export * from "./update-fulfillment"
|
export * from "./update-fulfillment"
|
||||||
export * from "./update-service-zones"
|
export * from "./update-service-zones"
|
||||||
export * from "./update-shipping-options"
|
export * from "./update-shipping-options"
|
||||||
|
export * from "./update-shipping-profiles"
|
||||||
|
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
import { FulfillmentWorkflow } from "@medusajs/types"
|
||||||
|
import { WorkflowData, createWorkflow } from "@medusajs/workflows-sdk"
|
||||||
|
import { updateShippingProfilesStep } from "../steps/update-shipping-profiles"
|
||||||
|
|
||||||
|
export const updateShippingProfilesWorkflowId =
|
||||||
|
"update-shipping-profiles-workflow"
|
||||||
|
export const updateShippingProfilesWorkflow = createWorkflow(
|
||||||
|
updateShippingProfilesWorkflowId,
|
||||||
|
(
|
||||||
|
input: WorkflowData<FulfillmentWorkflow.UpdateShippingProfilesWorkflowInput>
|
||||||
|
): WorkflowData<FulfillmentWorkflow.CreateShippingProfilesWorkflowOutput> => {
|
||||||
|
const shippingProfiles = updateShippingProfilesStep(input)
|
||||||
|
|
||||||
|
return shippingProfiles
|
||||||
|
}
|
||||||
|
)
|
||||||
@@ -15,11 +15,32 @@ export interface CreateShippingProfileDTO {
|
|||||||
/**
|
/**
|
||||||
* Holds custom data in key-value pairs.
|
* Holds custom data in key-value pairs.
|
||||||
*/
|
*/
|
||||||
metadata?: Record<string, unknown>
|
metadata?: Record<string, unknown> | null
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The attributes to update in the shipping profile.
|
* The attributes to update in the shipping profile.
|
||||||
*/
|
*/
|
||||||
export interface UpdateShippingProfileDTO
|
export interface UpdateShippingProfileDTO {
|
||||||
extends Partial<CreateShippingProfileDTO> {}
|
/**
|
||||||
|
* The name of the shipping profile.
|
||||||
|
*/
|
||||||
|
name?: string
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The type of the shipping profile.
|
||||||
|
*/
|
||||||
|
type?: string
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds custom data in key-value pairs.
|
||||||
|
*/
|
||||||
|
metadata?: Record<string, unknown> | null
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The attributes to update in the shipping profile.
|
||||||
|
*/
|
||||||
|
export interface UpsertShippingProfileDTO extends UpdateShippingProfileDTO {
|
||||||
|
id?: string
|
||||||
|
}
|
||||||
@@ -40,7 +40,7 @@ import {
|
|||||||
UpsertShippingOptionDTO,
|
UpsertShippingOptionDTO,
|
||||||
} from "./mutations"
|
} from "./mutations"
|
||||||
import { CreateFulfillmentDTO } from "./mutations/fulfillment"
|
import { CreateFulfillmentDTO } from "./mutations/fulfillment"
|
||||||
import { CreateShippingProfileDTO } from "./mutations/shipping-profile"
|
import { CreateShippingProfileDTO, UpsertShippingProfileDTO } from "./mutations/shipping-profile"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The main service interface for the Fulfillment Module.
|
* The main service interface for the Fulfillment Module.
|
||||||
@@ -1649,7 +1649,8 @@ export interface IFulfillmentModuleService extends IModuleService {
|
|||||||
/**
|
/**
|
||||||
* This method updates existing shipping profiles.
|
* This method updates existing shipping profiles.
|
||||||
*
|
*
|
||||||
* @param {CreateShippingProfileDTO[]} data - The shipping profiles to be created.
|
* @param {UpdateShippingProfileDTO} data - The shipping profiles update data.
|
||||||
|
* @param {FilterableShippingProfileProps} selector - The selector of shipping profiles to update
|
||||||
* @param {Context} sharedContext - A context used to share resources, such as transaction manager, between the application and the module.
|
* @param {Context} sharedContext - A context used to share resources, such as transaction manager, between the application and the module.
|
||||||
* @returns {Promise<ShippingProfileDTO[]>} The updated shipping profiles.
|
* @returns {Promise<ShippingProfileDTO[]>} The updated shipping profiles.
|
||||||
*
|
*
|
||||||
@@ -1667,14 +1668,16 @@ export interface IFulfillmentModuleService extends IModuleService {
|
|||||||
* ])
|
* ])
|
||||||
*/
|
*/
|
||||||
updateShippingProfiles(
|
updateShippingProfiles(
|
||||||
data: UpdateShippingProfileDTO[],
|
selector: FilterableShippingProfileProps,
|
||||||
|
data: UpdateShippingProfileDTO,
|
||||||
sharedContext?: Context
|
sharedContext?: Context
|
||||||
): Promise<ShippingProfileDTO[]>
|
): Promise<ShippingProfileDTO[]>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method updates an existing shipping profiles.
|
* This method updates an existing shipping profiles.
|
||||||
*
|
*
|
||||||
* @param {CreateShippingProfileDTO} data - The shipping profile to be created.
|
* @param {string} id - The shipping profile to be updated.
|
||||||
|
* @param {UpdateShippingProfileDTO} data - The shipping profile to be created.
|
||||||
* @param {Context} sharedContext - A context used to share resources, such as transaction manager, between the application and the module.
|
* @param {Context} sharedContext - A context used to share resources, such as transaction manager, between the application and the module.
|
||||||
* @returns {Promise<ShippingProfileDTO>} The updated shipping profiles.
|
* @returns {Promise<ShippingProfileDTO>} The updated shipping profiles.
|
||||||
*
|
*
|
||||||
@@ -1686,6 +1689,7 @@ export interface IFulfillmentModuleService extends IModuleService {
|
|||||||
* })
|
* })
|
||||||
*/
|
*/
|
||||||
updateShippingProfiles(
|
updateShippingProfiles(
|
||||||
|
id: string,
|
||||||
data: UpdateShippingProfileDTO,
|
data: UpdateShippingProfileDTO,
|
||||||
sharedContext?: Context
|
sharedContext?: Context
|
||||||
): Promise<ShippingProfileDTO>
|
): Promise<ShippingProfileDTO>
|
||||||
@@ -1719,6 +1723,51 @@ export interface IFulfillmentModuleService extends IModuleService {
|
|||||||
*/
|
*/
|
||||||
deleteShippingProfiles(id: string, sharedContext?: Context): Promise<void>
|
deleteShippingProfiles(id: string, sharedContext?: Context): Promise<void>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method updates existing shipping profiles, or creates new ones if they don't exist.
|
||||||
|
*
|
||||||
|
* @param {UpdateShippingProfileDTO[]} data - The attributes to update or create for each profile.
|
||||||
|
* @param {Context} sharedContext - A context used to share resources, such as transaction manager, between the application and the module.
|
||||||
|
* @returns {Promise<ProductTagDTO[]>} The updated and created profiles.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* const productTags = await productModuleService.upsertShippingProfiles([
|
||||||
|
* {
|
||||||
|
* id: "id_1234",
|
||||||
|
* metadata: {
|
||||||
|
* test: true,
|
||||||
|
* },
|
||||||
|
* },
|
||||||
|
* {
|
||||||
|
* name: "Digital",
|
||||||
|
* },
|
||||||
|
* ])
|
||||||
|
*/
|
||||||
|
upsertShippingProfiles(
|
||||||
|
data: UpsertShippingProfileDTO[],
|
||||||
|
sharedContext?: Context
|
||||||
|
): Promise<ShippingProfileDTO[]>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method updates an existing shipping profile, or creates a new one if it doesn't exist.
|
||||||
|
*
|
||||||
|
* @param {UpdateShippingProfileDTO} data - The attributes to update or create for the profile.
|
||||||
|
* @param {Context} sharedContext - A context used to share resources, such as transaction manager, between the application and the module.
|
||||||
|
* @returns {Promise<ProductTagDTO>} The updated or created profile.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* const productTag = await productModuleService.upsertShippingProfiles({
|
||||||
|
* id: "id_1234",
|
||||||
|
* metadata: {
|
||||||
|
* test: true,
|
||||||
|
* },
|
||||||
|
* })
|
||||||
|
*/
|
||||||
|
upsertShippingProfiles(
|
||||||
|
data: UpsertShippingProfileDTO,
|
||||||
|
sharedContext?: Context
|
||||||
|
): Promise<ShippingProfileDTO>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method soft deletes shipping profiles by their IDs.
|
* This method soft deletes shipping profiles by their IDs.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -1,16 +1,22 @@
|
|||||||
|
import {
|
||||||
|
deleteShippingProfileWorkflow,
|
||||||
|
updateShippingProfilesWorkflow,
|
||||||
|
} from "@medusajs/core-flows"
|
||||||
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
|
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
|
||||||
import {
|
import {
|
||||||
AdminShippingProfileDeleteResponse,
|
AdminShippingProfileDeleteResponse,
|
||||||
AdminShippingProfileResponse,
|
AdminShippingProfileResponse,
|
||||||
IFulfillmentModuleService,
|
IFulfillmentModuleService,
|
||||||
} from "@medusajs/types"
|
} from "@medusajs/types"
|
||||||
import { deleteShippingProfileWorkflow } from "@medusajs/core-flows"
|
|
||||||
import {
|
import {
|
||||||
AuthenticatedMedusaRequest,
|
AuthenticatedMedusaRequest,
|
||||||
MedusaResponse,
|
MedusaResponse,
|
||||||
} from "../../../../types/routing"
|
} from "../../../../types/routing"
|
||||||
import { AdminGetShippingProfileParamsType } from "../validators"
|
|
||||||
import { refetchShippingProfile } from "../helpers"
|
import { refetchShippingProfile } from "../helpers"
|
||||||
|
import {
|
||||||
|
AdminGetShippingProfileParamsType,
|
||||||
|
AdminUpdateShippingProfileType,
|
||||||
|
} from "../validators"
|
||||||
|
|
||||||
export const GET = async (
|
export const GET = async (
|
||||||
req: AuthenticatedMedusaRequest<AdminGetShippingProfileParamsType>,
|
req: AuthenticatedMedusaRequest<AdminGetShippingProfileParamsType>,
|
||||||
@@ -48,3 +54,24 @@ export const DELETE = async (
|
|||||||
deleted: true,
|
deleted: true,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const POST = async (
|
||||||
|
req: AuthenticatedMedusaRequest<AdminUpdateShippingProfileType>,
|
||||||
|
res: MedusaResponse<AdminShippingProfileResponse>
|
||||||
|
) => {
|
||||||
|
const { id } = req.params
|
||||||
|
|
||||||
|
await updateShippingProfilesWorkflow(req.scope).run({
|
||||||
|
input: { selector: { id }, update: req.body },
|
||||||
|
})
|
||||||
|
|
||||||
|
const shippingProfile = await refetchShippingProfile(
|
||||||
|
req.params.id,
|
||||||
|
req.scope,
|
||||||
|
req.remoteQueryConfig.fields
|
||||||
|
)
|
||||||
|
|
||||||
|
res.status(200).json({
|
||||||
|
shipping_profile: shippingProfile,
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -9,6 +9,7 @@ import {
|
|||||||
AdminCreateShippingProfile,
|
AdminCreateShippingProfile,
|
||||||
AdminGetShippingProfileParams,
|
AdminGetShippingProfileParams,
|
||||||
AdminGetShippingProfilesParams,
|
AdminGetShippingProfilesParams,
|
||||||
|
AdminUpdateShippingProfile,
|
||||||
} from "./validators"
|
} from "./validators"
|
||||||
|
|
||||||
export const adminShippingProfilesMiddlewares: MiddlewareRoute[] = [
|
export const adminShippingProfilesMiddlewares: MiddlewareRoute[] = [
|
||||||
@@ -33,6 +34,17 @@ export const adminShippingProfilesMiddlewares: MiddlewareRoute[] = [
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
method: ["POST"],
|
||||||
|
matcher: "/admin/shipping-profiles/:id",
|
||||||
|
middlewares: [
|
||||||
|
validateAndTransformBody(AdminUpdateShippingProfile),
|
||||||
|
validateAndTransformQuery(
|
||||||
|
AdminGetShippingProfileParams,
|
||||||
|
retrieveTransformQueryConfig
|
||||||
|
),
|
||||||
|
],
|
||||||
|
},
|
||||||
{
|
{
|
||||||
method: ["GET"],
|
method: ["GET"],
|
||||||
matcher: "/admin/shipping-profiles/:id",
|
matcher: "/admin/shipping-profiles/:id",
|
||||||
|
|||||||
@@ -39,3 +39,14 @@ export const AdminCreateShippingProfile = z
|
|||||||
metadata: z.record(z.string(), z.unknown()).optional(),
|
metadata: z.record(z.string(), z.unknown()).optional(),
|
||||||
})
|
})
|
||||||
.strict()
|
.strict()
|
||||||
|
|
||||||
|
export type AdminUpdateShippingProfileType = z.infer<
|
||||||
|
typeof AdminUpdateShippingProfile
|
||||||
|
>
|
||||||
|
export const AdminUpdateShippingProfile = z
|
||||||
|
.object({
|
||||||
|
name: z.string().optional(),
|
||||||
|
type: z.string().optional(),
|
||||||
|
metadata: z.record(z.string(), z.unknown()).optional().nullable(),
|
||||||
|
})
|
||||||
|
.strict()
|
||||||
@@ -14,18 +14,18 @@ import {
|
|||||||
UpdateServiceZoneDTO,
|
UpdateServiceZoneDTO,
|
||||||
} from "@medusajs/types"
|
} from "@medusajs/types"
|
||||||
import {
|
import {
|
||||||
arrayDifference,
|
|
||||||
deepEqualObj,
|
|
||||||
EmitEvents,
|
EmitEvents,
|
||||||
getSetDifference,
|
|
||||||
InjectManager,
|
InjectManager,
|
||||||
InjectTransactionManager,
|
InjectTransactionManager,
|
||||||
isDefined,
|
|
||||||
isPresent,
|
|
||||||
isString,
|
|
||||||
MedusaContext,
|
MedusaContext,
|
||||||
MedusaError,
|
MedusaError,
|
||||||
ModulesSdkUtils,
|
ModulesSdkUtils,
|
||||||
|
arrayDifference,
|
||||||
|
deepEqualObj,
|
||||||
|
getSetDifference,
|
||||||
|
isDefined,
|
||||||
|
isPresent,
|
||||||
|
isString,
|
||||||
promiseAll,
|
promiseAll,
|
||||||
} from "@medusajs/utils"
|
} from "@medusajs/utils"
|
||||||
import {
|
import {
|
||||||
@@ -49,8 +49,8 @@ import {
|
|||||||
} from "@utils"
|
} from "@utils"
|
||||||
import { entityNameToLinkableKeysMap, joinerConfig } from "../joiner-config"
|
import { entityNameToLinkableKeysMap, joinerConfig } from "../joiner-config"
|
||||||
import { UpdateShippingOptionsInput } from "../types/service"
|
import { UpdateShippingOptionsInput } from "../types/service"
|
||||||
import FulfillmentProviderService from "./fulfillment-provider"
|
|
||||||
import { buildCreatedShippingOptionEvents } from "../utils/events"
|
import { buildCreatedShippingOptionEvents } from "../utils/events"
|
||||||
|
import FulfillmentProviderService from "./fulfillment-provider"
|
||||||
|
|
||||||
const generateMethodForModels = [
|
const generateMethodForModels = [
|
||||||
ServiceZone,
|
ServiceZone,
|
||||||
@@ -1541,25 +1541,106 @@ export default class FulfillmentModuleService<
|
|||||||
}
|
}
|
||||||
|
|
||||||
updateShippingProfiles(
|
updateShippingProfiles(
|
||||||
data: FulfillmentTypes.UpdateShippingProfileDTO[],
|
selector: FulfillmentTypes.FilterableShippingProfileProps,
|
||||||
|
data: FulfillmentTypes.UpdateShippingProfileDTO,
|
||||||
sharedContext?: Context
|
sharedContext?: Context
|
||||||
): Promise<FulfillmentTypes.ShippingProfileDTO[]>
|
): Promise<FulfillmentTypes.ShippingProfileDTO[]>
|
||||||
updateShippingProfiles(
|
updateShippingProfiles(
|
||||||
|
id: string,
|
||||||
data: FulfillmentTypes.UpdateShippingProfileDTO,
|
data: FulfillmentTypes.UpdateShippingProfileDTO,
|
||||||
sharedContext?: Context
|
sharedContext?: Context
|
||||||
): Promise<FulfillmentTypes.ShippingProfileDTO>
|
): Promise<FulfillmentTypes.ShippingProfileDTO>
|
||||||
|
|
||||||
@InjectTransactionManager("baseRepository_")
|
@InjectTransactionManager("baseRepository_")
|
||||||
async updateShippingProfiles(
|
async updateShippingProfiles(
|
||||||
data:
|
idOrSelector: string | FulfillmentTypes.FilterableShippingProfileProps,
|
||||||
| FulfillmentTypes.UpdateShippingProfileDTO
|
data: FulfillmentTypes.UpdateShippingProfileDTO,
|
||||||
| FulfillmentTypes.UpdateShippingProfileDTO[],
|
|
||||||
@MedusaContext() sharedContext: Context = {}
|
@MedusaContext() sharedContext: Context = {}
|
||||||
): Promise<
|
): Promise<
|
||||||
FulfillmentTypes.ShippingProfileDTO | FulfillmentTypes.ShippingProfileDTO[]
|
FulfillmentTypes.ShippingProfileDTO | FulfillmentTypes.ShippingProfileDTO[]
|
||||||
> {
|
> {
|
||||||
// TODO: should we implement that or can we get rid of the profiles concept entirely and link to the so instead?
|
let normalizedInput: ({
|
||||||
return []
|
id: string
|
||||||
|
} & FulfillmentTypes.UpdateShippingProfileDTO)[] = []
|
||||||
|
if (isString(idOrSelector)) {
|
||||||
|
await this.shippingProfileService_.retrieve(
|
||||||
|
idOrSelector,
|
||||||
|
{},
|
||||||
|
sharedContext
|
||||||
|
)
|
||||||
|
normalizedInput = [{ id: idOrSelector, ...data }]
|
||||||
|
} else {
|
||||||
|
const profiles = await this.shippingProfileService_.list(
|
||||||
|
idOrSelector,
|
||||||
|
{},
|
||||||
|
sharedContext
|
||||||
|
)
|
||||||
|
|
||||||
|
normalizedInput = profiles.map((profile) => ({
|
||||||
|
id: profile.id,
|
||||||
|
...data,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
const profiles = await this.shippingProfileService_.update(
|
||||||
|
normalizedInput,
|
||||||
|
sharedContext
|
||||||
|
)
|
||||||
|
|
||||||
|
const updatedProfiles = await this.baseRepository_.serialize<
|
||||||
|
FulfillmentTypes.ShippingProfileDTO[]
|
||||||
|
>(profiles)
|
||||||
|
|
||||||
|
return isString(idOrSelector) ? updatedProfiles[0] : updatedProfiles
|
||||||
|
}
|
||||||
|
|
||||||
|
async upsertShippingProfiles(
|
||||||
|
data: FulfillmentTypes.UpsertShippingProfileDTO[],
|
||||||
|
sharedContext?: Context
|
||||||
|
): Promise<FulfillmentTypes.ShippingProfileDTO[]>
|
||||||
|
async upsertShippingProfiles(
|
||||||
|
data: FulfillmentTypes.UpsertShippingProfileDTO,
|
||||||
|
sharedContext?: Context
|
||||||
|
): Promise<FulfillmentTypes.ShippingProfileDTO>
|
||||||
|
|
||||||
|
@InjectTransactionManager("baseRepository_")
|
||||||
|
async upsertShippingProfiles(
|
||||||
|
data:
|
||||||
|
| FulfillmentTypes.UpsertShippingProfileDTO[]
|
||||||
|
| FulfillmentTypes.UpsertShippingProfileDTO,
|
||||||
|
@MedusaContext() sharedContext: Context = {}
|
||||||
|
): Promise<
|
||||||
|
FulfillmentTypes.ShippingProfileDTO[] | FulfillmentTypes.ShippingProfileDTO
|
||||||
|
> {
|
||||||
|
const input = Array.isArray(data) ? data : [data]
|
||||||
|
const forUpdate = input.filter((prof) => !!prof.id)
|
||||||
|
const forCreate = input.filter(
|
||||||
|
(prof): prof is FulfillmentTypes.CreateShippingProfileDTO => !prof.id
|
||||||
|
)
|
||||||
|
|
||||||
|
let created: ShippingProfile[] = []
|
||||||
|
let updated: ShippingProfile[] = []
|
||||||
|
|
||||||
|
if (forCreate.length) {
|
||||||
|
created = await this.shippingProfileService_.create(
|
||||||
|
forCreate,
|
||||||
|
sharedContext
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if (forUpdate.length) {
|
||||||
|
updated = await this.shippingProfileService_.update(
|
||||||
|
forUpdate,
|
||||||
|
sharedContext
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = [...created, ...updated]
|
||||||
|
const allProfiles = await this.baseRepository_.serialize<
|
||||||
|
| FulfillmentTypes.ShippingProfileDTO[]
|
||||||
|
| FulfillmentTypes.ShippingProfileDTO
|
||||||
|
>(result)
|
||||||
|
|
||||||
|
return Array.isArray(data) ? allProfiles : allProfiles[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
updateGeoZones(
|
updateGeoZones(
|
||||||
|
|||||||
Reference in new issue
Block a user