feat: List shipping options for cart (#6677)
This commit is contained in:
@@ -3,6 +3,7 @@ import { IPricingModuleService, PricingContext } from "@medusajs/types"
|
||||
import {
|
||||
ContainerRegistrationKeys,
|
||||
MedusaError,
|
||||
arrayDifference,
|
||||
remoteQueryObjectFromString,
|
||||
} from "@medusajs/utils"
|
||||
import { StepResponse, createStep } from "@medusajs/workflows-sdk"
|
||||
@@ -12,7 +13,7 @@ interface StepInput {
|
||||
context?: Record<string, unknown>
|
||||
}
|
||||
|
||||
export const getShippingOptionPriceSetsStepId = "get-variant-price-sets"
|
||||
export const getShippingOptionPriceSetsStepId = "get-shipping-option-price-sets"
|
||||
export const getShippingOptionPriceSetsStep = createStep(
|
||||
getShippingOptionPriceSetsStepId,
|
||||
async (data: StepInput, { container }) => {
|
||||
@@ -38,26 +39,22 @@ export const getShippingOptionPriceSetsStep = createStep(
|
||||
|
||||
const optionPriceSets = await remoteQuery(query)
|
||||
|
||||
const notFound: string[] = []
|
||||
const priceSetIds: string[] = []
|
||||
const optionsMissingPrices = arrayDifference(
|
||||
data.optionIds,
|
||||
optionPriceSets.map((v) => v.shipping_option_id)
|
||||
)
|
||||
|
||||
optionPriceSets.forEach((v) => {
|
||||
if (v.price_set_id) {
|
||||
priceSetIds.push(v.price_set_id)
|
||||
} else {
|
||||
notFound.push(v.shipping_option_id)
|
||||
}
|
||||
})
|
||||
|
||||
if (notFound.length) {
|
||||
if (optionsMissingPrices.length) {
|
||||
throw new MedusaError(
|
||||
MedusaError.Types.INVALID_DATA,
|
||||
`Shipping options with IDs ${notFound.join(", ")} do not have a price`
|
||||
`Shipping options with IDs ${optionsMissingPrices.join(
|
||||
", "
|
||||
)} do not have a price`
|
||||
)
|
||||
}
|
||||
|
||||
const calculatedPriceSets = await pricingModuleService.calculatePrices(
|
||||
{ id: priceSetIds },
|
||||
{ id: optionPriceSets.map((v) => v.price_set_id) },
|
||||
{ context: data.context as PricingContext["context"] }
|
||||
)
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ export * from "./add-shipping-method-to-cart"
|
||||
export * from "./add-to-cart"
|
||||
export * from "./create-carts"
|
||||
export * from "./create-payment-collection-for-cart"
|
||||
export * from "./list-shipping-options-for-cart"
|
||||
export * from "./refresh-payment-collection"
|
||||
export * from "./update-cart"
|
||||
export * from "./update-cart-promotions"
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
import { ListShippingOptionsForCartWorkflowInputDTO } from "@medusajs/types"
|
||||
import {
|
||||
WorkflowData,
|
||||
createWorkflow,
|
||||
transform,
|
||||
} from "@medusajs/workflows-sdk"
|
||||
import { useRemoteQueryStep } from "../../../common/steps/use-remote-query"
|
||||
import { listShippingOptionsForContextStep } from "../../../shipping-options"
|
||||
import { getShippingOptionPriceSetsStep } from "../steps"
|
||||
|
||||
export const listShippingOptionsForCartWorkflowId =
|
||||
"list-shipping-options-for-cart"
|
||||
export const listShippingOptionsForCartWorkflow = createWorkflow(
|
||||
listShippingOptionsForCartWorkflowId,
|
||||
(input: WorkflowData<ListShippingOptionsForCartWorkflowInputDTO>) => {
|
||||
const scLocationFulfillmentSets = useRemoteQueryStep({
|
||||
entry_point: "sales_channels",
|
||||
fields: ["stock_locations.fulfillment_sets.id"],
|
||||
variables: { id: input.sales_channel_id },
|
||||
})
|
||||
|
||||
const listOptionsInput = transform(
|
||||
{ scLocationFulfillmentSets, input },
|
||||
(data) => {
|
||||
const fulfillmentSetIds = data.scLocationFulfillmentSets
|
||||
.map((sc) =>
|
||||
sc.stock_locations.map((loc) =>
|
||||
loc.fulfillment_sets.map(({ id }) => id)
|
||||
)
|
||||
)
|
||||
.flat(2)
|
||||
|
||||
return {
|
||||
context: {
|
||||
fulfillment_set_id: fulfillmentSetIds,
|
||||
service_zone: {
|
||||
geo_zones: {
|
||||
city: data.input.shipping_address?.city,
|
||||
country_code: data.input.shipping_address?.country_code,
|
||||
province_code: data.input.shipping_address?.province,
|
||||
},
|
||||
},
|
||||
},
|
||||
config: {
|
||||
select: [
|
||||
"id",
|
||||
"name",
|
||||
"price_type",
|
||||
"service_zone_id",
|
||||
"shipping_profile_id",
|
||||
"provider_id",
|
||||
"data",
|
||||
"amount",
|
||||
],
|
||||
relations: ["type", "provider"],
|
||||
},
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
const options = listShippingOptionsForContextStep(listOptionsInput)
|
||||
|
||||
const optionIds = transform({ options }, (data) =>
|
||||
data.options.map((option) => option.id)
|
||||
)
|
||||
|
||||
// TODO: Separate shipping options based on price_type, flat_rate vs calculated
|
||||
const priceSets = getShippingOptionPriceSetsStep({
|
||||
optionIds,
|
||||
context: {
|
||||
currency_code: input.currency_code,
|
||||
},
|
||||
})
|
||||
|
||||
const shippingOptionsWithPrice = transform(
|
||||
{ priceSets, options },
|
||||
(data) => {
|
||||
const options = data.options.map((option) => {
|
||||
const price = data.priceSets?.[option.id].calculated_amount
|
||||
|
||||
return {
|
||||
...option,
|
||||
amount: price,
|
||||
}
|
||||
})
|
||||
|
||||
return options
|
||||
}
|
||||
)
|
||||
|
||||
return shippingOptionsWithPrice
|
||||
}
|
||||
)
|
||||
@@ -9,6 +9,7 @@ export * from "./payment"
|
||||
export * from "./product"
|
||||
export * from "./promotion"
|
||||
export * from "./region"
|
||||
export * from "./shipping-options"
|
||||
export * from "./store"
|
||||
export * from "./tax"
|
||||
export * from "./user"
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
export * from "./steps"
|
||||
@@ -0,0 +1 @@
|
||||
export * from "./list-shipping-options-for-context"
|
||||
@@ -0,0 +1,30 @@
|
||||
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
|
||||
import {
|
||||
FindConfig,
|
||||
IFulfillmentModuleService,
|
||||
ShippingOptionDTO,
|
||||
} from "@medusajs/types"
|
||||
import { StepResponse, createStep } from "@medusajs/workflows-sdk"
|
||||
|
||||
interface StepInput {
|
||||
context: Record<string, unknown>
|
||||
config?: FindConfig<ShippingOptionDTO>
|
||||
}
|
||||
|
||||
export const listShippingOptionsForContextStepId =
|
||||
"list-shipping-options-for-context"
|
||||
export const listShippingOptionsForContextStep = createStep(
|
||||
listShippingOptionsForContextStepId,
|
||||
async (data: StepInput, { container }) => {
|
||||
const fulfillmentService = container.resolve<IFulfillmentModuleService>(
|
||||
ModuleRegistrationName.FULFILLMENT
|
||||
)
|
||||
|
||||
const shippingOptions = await fulfillmentService.listShippingOptions(
|
||||
data.context,
|
||||
data.config
|
||||
)
|
||||
|
||||
return new StepResponse(shippingOptions)
|
||||
}
|
||||
)
|
||||
Reference in New Issue
Block a user