feat(dashboard, core-flows, js-sdk, types, medusa): listing order's shipping options (#13242)
* feat(dashboard, core-flows,js-sdk,types,medusa): listing order's shipping option * fix: typo * chore: migrate claim form * fix: cleanup rule logic * feat: add test case, rm params * fix: expand location name
This commit is contained in:
@@ -43,11 +43,11 @@ export const listShippingOptionsForCartWorkflowId =
|
||||
* @summary
|
||||
*
|
||||
* List a cart's shipping options.
|
||||
*
|
||||
*
|
||||
* @property hooks.setPricingContext - This hook is executed before the shipping options are retrieved. You can consume this hook to return any custom context useful for the prices retrieval of shipping options.
|
||||
*
|
||||
*
|
||||
* For example, assuming you have the following custom pricing rule:
|
||||
*
|
||||
*
|
||||
* ```json
|
||||
* {
|
||||
* "attribute": "location_id",
|
||||
@@ -55,13 +55,13 @@ export const listShippingOptionsForCartWorkflowId =
|
||||
* "value": "sloc_123",
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
*
|
||||
* You can consume the `setPricingContext` hook to add the `location_id` context to the prices calculation:
|
||||
*
|
||||
*
|
||||
* ```ts
|
||||
* import { listShippingOptionsForCartWorkflow } from "@medusajs/medusa/core-flows";
|
||||
* import { StepResponse } from "@medusajs/workflows-sdk";
|
||||
*
|
||||
*
|
||||
* listShippingOptionsForCartWorkflow.hooks.setPricingContext((
|
||||
* { cart, fulfillmentSetIds, additional_data }, { container }
|
||||
* ) => {
|
||||
@@ -70,13 +70,13 @@ export const listShippingOptionsForCartWorkflowId =
|
||||
* });
|
||||
* });
|
||||
* ```
|
||||
*
|
||||
*
|
||||
* The shipping options' prices will now be retrieved using the context you return.
|
||||
*
|
||||
*
|
||||
* :::note
|
||||
*
|
||||
*
|
||||
* Learn more about prices calculation context in the [Prices Calculation](https://docs.medusajs.com/resources/commerce-modules/pricing/price-calculation) documentation.
|
||||
*
|
||||
*
|
||||
* :::
|
||||
*/
|
||||
export const listShippingOptionsForCartWorkflow = createWorkflow(
|
||||
|
||||
@@ -88,6 +88,7 @@ export type FetchShippingOptionForOrderWorkflowOutput = ShippingOptionDTO & {
|
||||
is_calculated_price_tax_inclusive: boolean
|
||||
}
|
||||
}
|
||||
|
||||
export const fetchShippingOptionsForOrderWorkflowId = "fetch-shipping-option"
|
||||
/**
|
||||
* This workflow fetches a shipping option for an order. It's used in Return Merchandise Authorization (RMA) flows. It's used
|
||||
@@ -95,7 +96,7 @@ export const fetchShippingOptionsForOrderWorkflowId = "fetch-shipping-option"
|
||||
*
|
||||
* You can use this workflow within your customizations or your own custom workflows, allowing you to wrap custom logic around fetching
|
||||
* shipping options for an order.
|
||||
*
|
||||
*
|
||||
* @example
|
||||
* const { result } = await fetchShippingOptionForOrderWorkflow(container)
|
||||
* .run({
|
||||
@@ -114,15 +115,15 @@ export const fetchShippingOptionsForOrderWorkflowId = "fetch-shipping-option"
|
||||
* }
|
||||
* }
|
||||
* })
|
||||
*
|
||||
*
|
||||
* @summary
|
||||
*
|
||||
*
|
||||
* Fetch a shipping option for an order.
|
||||
*
|
||||
*
|
||||
* @property hooks.setPricingContext - This hook is executed before the shipping option is fetched. You can consume this hook to set the pricing context for the shipping option. This is useful when you have custom pricing rules that depend on the context of the order.
|
||||
*
|
||||
*
|
||||
* For example, assuming you have the following custom pricing rule:
|
||||
*
|
||||
*
|
||||
* ```json
|
||||
* {
|
||||
* "attribute": "location_id",
|
||||
@@ -130,13 +131,13 @@ export const fetchShippingOptionsForOrderWorkflowId = "fetch-shipping-option"
|
||||
* "value": "sloc_123",
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
*
|
||||
* You can consume the `setPricingContext` hook to add the `location_id` context to the prices calculation:
|
||||
*
|
||||
*
|
||||
* ```ts
|
||||
* import { fetchShippingOptionForOrderWorkflow } from "@medusajs/medusa/core-flows";
|
||||
* import { StepResponse } from "@medusajs/workflows-sdk";
|
||||
*
|
||||
*
|
||||
* fetchShippingOptionForOrderWorkflow.hooks.setPricingContext((
|
||||
* { shipping_option_id, currency_code, order_id, context, additional_data }, { container }
|
||||
* ) => {
|
||||
@@ -145,13 +146,13 @@ export const fetchShippingOptionsForOrderWorkflowId = "fetch-shipping-option"
|
||||
* });
|
||||
* });
|
||||
* ```
|
||||
*
|
||||
*
|
||||
* The shipping option's price will now be retrieved using the context you return.
|
||||
*
|
||||
*
|
||||
* :::note
|
||||
*
|
||||
*
|
||||
* Learn more about prices calculation context in the [Prices Calculation](https://docs.medusajs.com/resources/commerce-modules/pricing/price-calculation) documentation.
|
||||
*
|
||||
*
|
||||
* :::
|
||||
*
|
||||
* @privateRemarks
|
||||
|
||||
@@ -87,3 +87,4 @@ export * from "./update-order"
|
||||
export * from "./update-order-change-actions"
|
||||
export * from "./update-order-changes"
|
||||
export * from "./update-tax-lines"
|
||||
export * from "./list-shipping-options-for-order"
|
||||
|
||||
@@ -0,0 +1,205 @@
|
||||
import {
|
||||
createWorkflow,
|
||||
transform,
|
||||
WorkflowData,
|
||||
WorkflowResponse,
|
||||
} from "@medusajs/framework/workflows-sdk"
|
||||
import {
|
||||
AdditionalData,
|
||||
ListShippingOptionsForOrderWorkflowInput,
|
||||
} from "@medusajs/types"
|
||||
|
||||
import { useQueryGraphStep, validatePresenceOfStep } from "../../common"
|
||||
import { useRemoteQueryStep } from "../../common/steps/use-remote-query"
|
||||
|
||||
export const listShippingOptionsForOrderWorkflowId =
|
||||
"list-shipping-options-for-order"
|
||||
/**
|
||||
* This workflow lists the shipping options of an order. It's executed by the
|
||||
* [List Shipping Options Store API Route](https://docs.medusajs.com/api/store#shipping-options_getshippingoptions).
|
||||
*
|
||||
* :::note
|
||||
*
|
||||
* This workflow doesn't retrieve the calculated prices of the shipping options. If you need to retrieve the prices of the shipping options,
|
||||
* use the {@link listShippingOptionsForOrderWithPricingWorkflow} workflow.
|
||||
*
|
||||
* :::
|
||||
*
|
||||
* You can use this workflow within your own customizations or custom workflows, allowing you to wrap custom logic around to retrieve the shipping options of an order
|
||||
* in your custom flows.
|
||||
*
|
||||
* @example
|
||||
* const { result } = await listShippingOptionsForOrderWorkflow(container)
|
||||
* .run({
|
||||
* input: {
|
||||
* order_id: "order_123",
|
||||
* }
|
||||
* })
|
||||
*
|
||||
* @summary
|
||||
*
|
||||
* List a order's shipping options.
|
||||
*
|
||||
* :::
|
||||
*/
|
||||
export const listShippingOptionsForOrderWorkflow = createWorkflow(
|
||||
listShippingOptionsForOrderWorkflowId,
|
||||
(
|
||||
input: WorkflowData<
|
||||
ListShippingOptionsForOrderWorkflowInput & AdditionalData
|
||||
>
|
||||
) => {
|
||||
const orderQuery = useQueryGraphStep({
|
||||
entity: "order",
|
||||
filters: { id: input.order_id },
|
||||
fields: [
|
||||
"id",
|
||||
|
||||
"sales_channel_id",
|
||||
"region_id",
|
||||
"shipping_address.city",
|
||||
"shipping_address.country_code",
|
||||
"shipping_address.province",
|
||||
"shipping_address.postal_code",
|
||||
|
||||
"items.*",
|
||||
"items.variant.manage_inventory",
|
||||
"items.variant.inventory_items.inventory_item_id",
|
||||
"items.variant.inventory_items.inventory.requires_shipping",
|
||||
"items.variant.inventory_items.inventory.location_levels.*",
|
||||
],
|
||||
options: { throwIfKeyNotFound: true },
|
||||
}).config({ name: "get-order" })
|
||||
|
||||
const order = transform(
|
||||
{ orderQuery },
|
||||
({ orderQuery }) => orderQuery.data[0]
|
||||
)
|
||||
|
||||
validatePresenceOfStep({
|
||||
entity: order,
|
||||
fields: ["sales_channel_id", "region_id"],
|
||||
})
|
||||
|
||||
const scFulfillmentSetQuery = useQueryGraphStep({
|
||||
entity: "sales_channels",
|
||||
filters: { id: order.sales_channel_id },
|
||||
fields: [
|
||||
"stock_locations.fulfillment_sets.id",
|
||||
"stock_locations.id",
|
||||
"stock_locations.name",
|
||||
"stock_locations.address.*",
|
||||
],
|
||||
}).config({ name: "sales_channels-fulfillment-query" })
|
||||
|
||||
const scFulfillmentSets = transform(
|
||||
{ scFulfillmentSetQuery },
|
||||
({ scFulfillmentSetQuery }) => scFulfillmentSetQuery.data[0]
|
||||
)
|
||||
|
||||
const { fulfillmentSetIds } = transform(
|
||||
{ scFulfillmentSets },
|
||||
({ scFulfillmentSets }) => {
|
||||
const fulfillmentSetIds = new Set<string>()
|
||||
|
||||
scFulfillmentSets.stock_locations.forEach((stockLocation) => {
|
||||
stockLocation.fulfillment_sets.forEach((fulfillmentSet) => {
|
||||
fulfillmentSetIds.add(fulfillmentSet.id)
|
||||
})
|
||||
})
|
||||
|
||||
return {
|
||||
fulfillmentSetIds: Array.from(fulfillmentSetIds),
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
const queryVariables = transform(
|
||||
{ fulfillmentSetIds, order },
|
||||
({ fulfillmentSetIds, order }) => {
|
||||
return {
|
||||
filters: {
|
||||
fulfillment_set_id: fulfillmentSetIds,
|
||||
|
||||
address: {
|
||||
country_code: order.shipping_address?.country_code,
|
||||
province_code: order.shipping_address?.province,
|
||||
city: order.shipping_address?.city,
|
||||
postal_expression: order.shipping_address?.postal_code,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
const shippingOptions = useRemoteQueryStep({
|
||||
entry_point: "shipping_options",
|
||||
fields: [
|
||||
"id",
|
||||
"name",
|
||||
"price_type",
|
||||
"service_zone_id",
|
||||
"shipping_profile_id",
|
||||
"provider_id",
|
||||
"data",
|
||||
"service_zone.fulfillment_set_id",
|
||||
"service_zone.fulfillment_set.type",
|
||||
"service_zone.fulfillment_set.location.id",
|
||||
"service_zone.fulfillment_set.location.name",
|
||||
"service_zone.fulfillment_set.location.address.*",
|
||||
|
||||
"type.id",
|
||||
"type.label",
|
||||
"type.description",
|
||||
"type.code",
|
||||
|
||||
"provider.id",
|
||||
"provider.is_enabled",
|
||||
|
||||
"rules.attribute",
|
||||
"rules.value",
|
||||
"rules.operator",
|
||||
],
|
||||
variables: queryVariables,
|
||||
}).config({ name: "shipping-options-query" })
|
||||
|
||||
const shippingOptionsWithInventory = transform(
|
||||
{ shippingOptions, order },
|
||||
({ shippingOptions, order }) =>
|
||||
shippingOptions.map((shippingOption) => {
|
||||
const locationId =
|
||||
shippingOption.service_zone.fulfillment_set.location.id
|
||||
|
||||
const itemsAtLocationWithoutAvailableQuantity = order.items.filter(
|
||||
(item) => {
|
||||
if (!item.variant?.manage_inventory) {
|
||||
return false
|
||||
}
|
||||
|
||||
return item.variant.inventory_items.some((inventoryItem) => {
|
||||
if (!inventoryItem.inventory.requires_shipping) {
|
||||
return false
|
||||
}
|
||||
|
||||
const level = inventoryItem.inventory.location_levels.find(
|
||||
(locationLevel) => {
|
||||
return locationLevel.location_id === locationId
|
||||
}
|
||||
)
|
||||
|
||||
return !level ? true : level.available_quantity < item.quantity
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
return {
|
||||
...shippingOption,
|
||||
insufficient_inventory:
|
||||
itemsAtLocationWithoutAvailableQuantity.length > 0,
|
||||
}
|
||||
})
|
||||
)
|
||||
|
||||
return new WorkflowResponse(shippingOptionsWithInventory)
|
||||
}
|
||||
)
|
||||
Reference in New Issue
Block a user