feat(core-flows,dashboard,types,fulfillment,medusa): uses requires shipping throughout lifecycle (#9170)
what: - uses requires shipping throughout lifecycle https://github.com/user-attachments/assets/d5ba89d3-5ea0-49c4-b2d5-490c4764933e
This commit is contained in:
1 parent
e54b339324
commit
69f6645716
22 files changed
+490
-108
No files matched your search
@@ -87,6 +87,7 @@ export const completeCartFields = [
|
||||
"items.variant.allow_backorder",
|
||||
"items.variant.inventory_items.inventory_item_id",
|
||||
"items.variant.inventory_items.required_quantity",
|
||||
"items.variant.inventory_items.inventory.requires_shipping",
|
||||
"items.variant.inventory_items.inventory.location_levels.stock_locations.id",
|
||||
"items.variant.inventory_items.inventory.location_levels.stock_locations.name",
|
||||
"items.variant.inventory_items.inventory.location_levels.stock_locations.sales_channels.id",
|
||||
@@ -116,6 +117,7 @@ export const productVariantsFields = [
|
||||
"calculated_price.is_calculated_price_tax_inclusive",
|
||||
"inventory_items.inventory_item_id",
|
||||
"inventory_items.required_quantity",
|
||||
"inventory_items.inventory.requires_shipping",
|
||||
"inventory_items.inventory.location_levels.stock_locations.id",
|
||||
"inventory_items.inventory.location_levels.stock_locations.name",
|
||||
"inventory_items.inventory.location_levels.stock_locations.sales_channels.id",
|
||||
|
||||
@@ -3,8 +3,10 @@ import {
|
||||
CartLineItemDTO,
|
||||
CreateOrderAdjustmentDTO,
|
||||
CreateOrderLineItemTaxLineDTO,
|
||||
InventoryItemDTO,
|
||||
ProductVariantDTO,
|
||||
} from "@medusajs/types"
|
||||
import { isDefined } from "@medusajs/utils"
|
||||
|
||||
interface Input {
|
||||
item?: CartLineItemDTO
|
||||
@@ -12,7 +14,9 @@ interface Input {
|
||||
metadata?: Record<string, any>
|
||||
unitPrice: BigNumberInput
|
||||
isTaxInclusive?: boolean
|
||||
variant: ProductVariantDTO
|
||||
variant: ProductVariantDTO & {
|
||||
inventory_items: { inventory: InventoryItemDTO }[]
|
||||
}
|
||||
taxLines?: CreateOrderLineItemTaxLineDTO[]
|
||||
adjustments?: CreateOrderAdjustmentDTO[]
|
||||
cartId?: string
|
||||
@@ -35,6 +39,19 @@ export function prepareLineItemData(data: Input) {
|
||||
throw new Error("Variant does not have a product")
|
||||
}
|
||||
|
||||
// Note: If any of the items require shipping, we enable fulfillment
|
||||
// unless explicitly set to not require shipping by the item in the request
|
||||
const { inventory_items: inventoryItems } = variant
|
||||
const someInventoryRequiresShipping = inventoryItems.length
|
||||
? inventoryItems.some(
|
||||
(inventoryItem) => !!inventoryItem.inventory.requires_shipping
|
||||
)
|
||||
: true
|
||||
|
||||
const requiresShipping = isDefined(item?.requires_shipping)
|
||||
? item.requires_shipping
|
||||
: someInventoryRequiresShipping
|
||||
|
||||
const lineItem: any = {
|
||||
quantity,
|
||||
title: variant.title ?? item?.title,
|
||||
@@ -58,7 +75,7 @@ export function prepareLineItemData(data: Input) {
|
||||
variant_option_values: item?.variant_option_values,
|
||||
|
||||
is_discountable: variant.product.discountable ?? item?.is_discountable,
|
||||
requires_shipping: variant.requires_shipping ?? item?.requires_shipping,
|
||||
requires_shipping: requiresShipping,
|
||||
|
||||
unit_price: unitPrice,
|
||||
is_tax_inclusive: !!isTaxInclusive,
|
||||
|
||||
@@ -16,6 +16,7 @@ export const productVariantsFields = [
|
||||
"calculated_price.calculated_amount",
|
||||
"inventory_items.inventory_item_id",
|
||||
"inventory_items.required_quantity",
|
||||
"inventory_items.inventory.requires_shipping",
|
||||
"inventory_items.inventory.location_levels.stock_locations.id",
|
||||
"inventory_items.inventory.location_levels.stock_locations.name",
|
||||
"inventory_items.inventory.location_levels.stock_locations.sales_channels.id",
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import {
|
||||
OrderChangeDTO,
|
||||
OrderDTO,
|
||||
OrderLineItemDTO,
|
||||
OrderWorkflow,
|
||||
ReturnDTO,
|
||||
} from "@medusajs/types"
|
||||
@@ -41,6 +42,37 @@ export function throwIfItemsDoesNotExistsInOrder({
|
||||
}
|
||||
}
|
||||
|
||||
export function throwIfItemsAreNotGroupedByShippingRequirement({
|
||||
order,
|
||||
inputItems,
|
||||
}: {
|
||||
order: Pick<OrderDTO, "id" | "items">
|
||||
inputItems: OrderWorkflow.CreateOrderFulfillmentWorkflowInput["items"]
|
||||
}) {
|
||||
const itemsWithShipping: string[] = []
|
||||
const itemsWithoutShipping: string[] = []
|
||||
const orderItemsMap = new Map<string, OrderLineItemDTO>(
|
||||
(order.items || []).map((item) => [item.id, item])
|
||||
)
|
||||
|
||||
for (const inputItem of inputItems) {
|
||||
const orderItem = orderItemsMap.get(inputItem.id)!
|
||||
|
||||
if (orderItem.requires_shipping) {
|
||||
itemsWithShipping.push(orderItem.id)
|
||||
} else {
|
||||
itemsWithoutShipping.push(orderItem.id)
|
||||
}
|
||||
}
|
||||
|
||||
if (itemsWithShipping.length && itemsWithoutShipping.length) {
|
||||
throw new MedusaError(
|
||||
MedusaError.Types.INVALID_DATA,
|
||||
`Fulfillment can only be created entirely with items with shipping or items without shipping. Split this request into 2 fulfillments.`
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export function throwIfIsCancelled(
|
||||
obj: unknown & { id: string; canceled_at?: any },
|
||||
type: string
|
||||
|
||||
@@ -26,6 +26,7 @@ import {
|
||||
} from "../../reservation"
|
||||
import { registerOrderFulfillmentStep } from "../steps"
|
||||
import {
|
||||
throwIfItemsAreNotGroupedByShippingRequirement,
|
||||
throwIfItemsDoesNotExistsInOrder,
|
||||
throwIfOrderIsCancelled,
|
||||
} from "../utils/order-validation"
|
||||
@@ -35,18 +36,16 @@ import {
|
||||
*/
|
||||
export const createFulfillmentValidateOrder = createStep(
|
||||
"create-fulfillment-validate-order",
|
||||
(
|
||||
{
|
||||
order,
|
||||
inputItems,
|
||||
}: {
|
||||
order: OrderDTO
|
||||
inputItems: OrderWorkflow.CreateOrderFulfillmentWorkflowInput["items"]
|
||||
},
|
||||
context
|
||||
) => {
|
||||
({
|
||||
order,
|
||||
inputItems,
|
||||
}: {
|
||||
order: OrderDTO
|
||||
inputItems: OrderWorkflow.CreateOrderFulfillmentWorkflowInput["items"]
|
||||
}) => {
|
||||
throwIfOrderIsCancelled({ order })
|
||||
throwIfItemsDoesNotExistsInOrder({ order, inputItems })
|
||||
throwIfItemsAreNotGroupedByShippingRequirement({ order, inputItems })
|
||||
}
|
||||
)
|
||||
|
||||
@@ -91,16 +90,29 @@ function prepareFulfillmentData({
|
||||
reservations: ReservationItemDTO[]
|
||||
itemsList?: OrderLineItemDTO[]
|
||||
}) {
|
||||
const inputItems = input.items
|
||||
const fulfillableItems = input.items
|
||||
const orderItemsMap = new Map<string, Required<OrderDTO>["items"][0]>(
|
||||
(itemsList ?? order.items)!.map((i) => [i.id, i])
|
||||
)
|
||||
|
||||
const reservationItemMap = new Map<string, ReservationItemDTO>(
|
||||
reservations.map((r) => [r.line_item_id as string, r])
|
||||
)
|
||||
const fulfillmentItems = inputItems.map((i) => {
|
||||
|
||||
// Note: If any of the items require shipping, we enable fulfillment
|
||||
// unless explicitly set to not require shipping by the item in the request
|
||||
const someItemsRequireShipping = fulfillableItems.length
|
||||
? fulfillableItems.some((item) => {
|
||||
const orderItem = orderItemsMap.get(item.id)!
|
||||
|
||||
return orderItem.requires_shipping
|
||||
})
|
||||
: true
|
||||
|
||||
const fulfillmentItems = fulfillableItems.map((i) => {
|
||||
const orderItem = orderItemsMap.get(i.id)!
|
||||
const reservation = reservationItemMap.get(i.id)!
|
||||
|
||||
return {
|
||||
line_item_id: i.id,
|
||||
inventory_item_id: reservation?.inventory_item_id,
|
||||
@@ -134,6 +146,7 @@ function prepareFulfillmentData({
|
||||
shipping_option_id: shippingOption.id,
|
||||
data: shippingMethod.data,
|
||||
items: fulfillmentItems,
|
||||
requires_shipping: someItemsRequireShipping,
|
||||
labels: input.labels ?? [],
|
||||
delivery_address: shippingAddress as any,
|
||||
packed_at: new Date(),
|
||||
|
||||
@@ -8,7 +8,6 @@ import {
|
||||
parallelize,
|
||||
transform,
|
||||
} from "@medusajs/workflows-sdk"
|
||||
import { useRemoteQueryStep } from "../../common"
|
||||
import { findOneOrAnyRegionStep } from "../../cart/steps/find-one-or-any-region"
|
||||
import { findOrCreateCustomerStep } from "../../cart/steps/find-or-create-customer"
|
||||
import { findSalesChannelStep } from "../../cart/steps/find-sales-channel"
|
||||
@@ -16,6 +15,7 @@ import { getVariantPriceSetsStep } from "../../cart/steps/get-variant-price-sets
|
||||
import { validateVariantPricesStep } from "../../cart/steps/validate-variant-prices"
|
||||
import { prepareLineItemData } from "../../cart/utils/prepare-line-item-data"
|
||||
import { confirmVariantInventoryWorkflow } from "../../cart/workflows/confirm-variant-inventory"
|
||||
import { useRemoteQueryStep } from "../../common"
|
||||
import { createOrdersStep } from "../steps"
|
||||
import { productVariantsFields } from "../utils/fields"
|
||||
import { prepareCustomLineItemData } from "../utils/prepare-custom-line-item-data"
|
||||
|
||||
Reference in new issue
Block a user