feat(medusa): filter shipping options by location (#8511)
what: - filters shipping options by location ID RESOLVES CC-328
This commit is contained in:
@@ -43,9 +43,7 @@ medusaIntegrationTestRunner({
|
||||
location = (
|
||||
await api.post(
|
||||
`/admin/stock-locations`,
|
||||
{
|
||||
name: "Test location",
|
||||
},
|
||||
{ name: "Test location" },
|
||||
adminHeaders
|
||||
)
|
||||
).data.stock_location
|
||||
@@ -53,10 +51,15 @@ medusaIntegrationTestRunner({
|
||||
location = (
|
||||
await api.post(
|
||||
`/admin/stock-locations/${location.id}/fulfillment-sets?fields=*fulfillment_sets`,
|
||||
{
|
||||
name: "Test",
|
||||
type: "test-type",
|
||||
},
|
||||
{ name: "Test", type: "test-type" },
|
||||
adminHeaders
|
||||
)
|
||||
).data.stock_location
|
||||
|
||||
location2 = (
|
||||
await api.post(
|
||||
`/admin/stock-locations`,
|
||||
{ name: "Test location 2" },
|
||||
adminHeaders
|
||||
)
|
||||
).data.stock_location
|
||||
@@ -91,6 +94,46 @@ medusaIntegrationTestRunner({
|
||||
).data.region
|
||||
})
|
||||
|
||||
describe("GET /admin/shipping-options", () => {
|
||||
it("should filters options by stock_location_id", 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 }],
|
||||
}
|
||||
|
||||
const {
|
||||
data: { shipping_option: shippingOption },
|
||||
} = await api.post(
|
||||
`/admin/shipping-options`,
|
||||
shippingOptionPayload,
|
||||
adminHeaders
|
||||
)
|
||||
|
||||
const shippingOptions = await api.get(
|
||||
`/admin/shipping-options?stock_location_id=${location.id}`,
|
||||
adminHeaders
|
||||
)
|
||||
|
||||
expect(shippingOptions.data.shipping_options).toHaveLength(1)
|
||||
|
||||
const shippingOptions2 = await api.get(
|
||||
`/admin/shipping-options?stock_location_id=${location2.id}`,
|
||||
adminHeaders
|
||||
)
|
||||
|
||||
expect(shippingOptions2.data.shipping_options).toHaveLength(0)
|
||||
})
|
||||
})
|
||||
|
||||
describe("POST /admin/shipping-options", () => {
|
||||
it("should throw error when required params are missing", async () => {
|
||||
const shippingOptionPayload = {
|
||||
|
||||
@@ -1,4 +1,13 @@
|
||||
import { MiddlewareRoute } from "@medusajs/framework"
|
||||
import { maybeApplyLinkFilter } from "../../utils/maybe-apply-link-filter"
|
||||
import { validateAndTransformBody } from "../../utils/validate-body"
|
||||
import { validateAndTransformQuery } from "../../utils/validate-query"
|
||||
import { createBatchBody } from "../../utils/validators"
|
||||
import {
|
||||
listTransformQueryConfig,
|
||||
retrieveRuleTransformQueryConfig,
|
||||
retrieveTransformQueryConfig,
|
||||
} from "./query-config"
|
||||
import {
|
||||
AdminCreateShippingOption,
|
||||
AdminCreateShippingOptionRule,
|
||||
@@ -8,14 +17,6 @@ import {
|
||||
AdminUpdateShippingOption,
|
||||
AdminUpdateShippingOptionRule,
|
||||
} from "./validators"
|
||||
import {
|
||||
listTransformQueryConfig,
|
||||
retrieveRuleTransformQueryConfig,
|
||||
retrieveTransformQueryConfig,
|
||||
} from "./query-config"
|
||||
import { validateAndTransformBody } from "../../utils/validate-body"
|
||||
import { validateAndTransformQuery } from "../../utils/validate-query"
|
||||
import { createBatchBody } from "../../utils/validators"
|
||||
|
||||
export const adminShippingOptionRoutesMiddlewares: MiddlewareRoute[] = [
|
||||
{
|
||||
@@ -26,6 +27,12 @@ export const adminShippingOptionRoutesMiddlewares: MiddlewareRoute[] = [
|
||||
AdminGetShippingOptionsParams,
|
||||
listTransformQueryConfig
|
||||
),
|
||||
maybeApplyLinkFilter({
|
||||
entryPoint: "location_fulfillment_set",
|
||||
resourceId: "fulfillment_set_id",
|
||||
filterableField: "stock_location_id",
|
||||
filterByField: "service_zone.fulfillment_set_id",
|
||||
}),
|
||||
],
|
||||
},
|
||||
{
|
||||
|
||||
@@ -27,6 +27,7 @@ export const AdminGetShippingOptionsParams = createFindParams({
|
||||
service_zone_id: z.union([z.string(), z.array(z.string())]).optional(),
|
||||
shipping_profile_id: z.union([z.string(), z.array(z.string())]).optional(),
|
||||
provider_id: z.union([z.string(), z.array(z.string())]).optional(),
|
||||
stock_location_id: z.union([z.string(), z.array(z.string())]).optional(),
|
||||
shipping_option_type_id: z
|
||||
.union([z.string(), z.array(z.string())])
|
||||
.optional(),
|
||||
|
||||
@@ -10,6 +10,7 @@ export function maybeApplyLinkFilter({
|
||||
entryPoint,
|
||||
resourceId,
|
||||
filterableField,
|
||||
filterByField = "id",
|
||||
}) {
|
||||
return async (req: MedusaRequest, _, next: NextFunction) => {
|
||||
const filterableFields = req.filterableFields
|
||||
@@ -37,21 +38,65 @@ export function maybeApplyLinkFilter({
|
||||
})
|
||||
|
||||
const resources = await remoteQuery(queryObject)
|
||||
let existingFilters = filterableFields[filterByField] as
|
||||
| string[]
|
||||
| string
|
||||
| undefined
|
||||
|
||||
let existingIdFilters = filterableFields.id as string[] | string | undefined
|
||||
if (existingIdFilters) {
|
||||
if (typeof existingIdFilters === "string") {
|
||||
existingIdFilters = [existingIdFilters]
|
||||
if (existingFilters) {
|
||||
if (typeof existingFilters === "string") {
|
||||
existingFilters = [existingFilters]
|
||||
}
|
||||
|
||||
filterableFields.id = arrayIntersection(
|
||||
existingIdFilters,
|
||||
filterableFields[filterByField] = arrayIntersection(
|
||||
existingFilters,
|
||||
resources.map((p) => p[resourceId])
|
||||
)
|
||||
} else {
|
||||
filterableFields.id = resources.map((p) => p[resourceId])
|
||||
filterableFields[filterByField] = resources.map((p) => p[resourceId])
|
||||
}
|
||||
|
||||
req.filterableFields = transformFilterableFields(filterableFields)
|
||||
|
||||
return next()
|
||||
}
|
||||
}
|
||||
/*
|
||||
Transforms an object key string into nested objects
|
||||
before = {
|
||||
"test.something.another": []
|
||||
}
|
||||
|
||||
after = {
|
||||
test: {
|
||||
something: {
|
||||
another: []
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
function transformFilterableFields(filterableFields: Record<string, unknown>) {
|
||||
const result = {};
|
||||
for (const key of Object.keys(filterableFields)) {
|
||||
const value = filterableFields[key];
|
||||
const keys = key.split(".");
|
||||
let current = result;
|
||||
|
||||
// Iterate over the keys, creating nested objects as needed
|
||||
for (let i = 0; i < keys.length; i++) {
|
||||
const part = keys[i];
|
||||
current[part] ??= {};
|
||||
|
||||
if (i === keys.length - 1) {
|
||||
// If its the last key, assign the value
|
||||
current[part] = value;
|
||||
break;
|
||||
}
|
||||
|
||||
current = current[part];
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user