fix(order): ignore reservation when manage_inventory is false (#7594)
This commit is contained in:
1 parent
0929c4f457
commit
68fb04b849
2 files changed
+105
-9
No files matched your search
@@ -96,6 +96,11 @@ async function prepareDataFixtures({ container }) {
|
|||||||
title: "Test variant",
|
title: "Test variant",
|
||||||
sku: "test-variant",
|
sku: "test-variant",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
title: "Test variant no inventory management",
|
||||||
|
sku: "test-variant-no-inventory",
|
||||||
|
manage_inventory: false,
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
])
|
])
|
||||||
@@ -228,7 +233,15 @@ async function createOrderFixture({ container, product, location }) {
|
|||||||
provider_id: "coupon_kings",
|
provider_id: "coupon_kings",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
} as any,
|
},
|
||||||
|
{
|
||||||
|
title: product.title,
|
||||||
|
variant_sku: product.variants[1].sku,
|
||||||
|
variant_title: product.variants[1].title,
|
||||||
|
variant_id: product.variants[1].id,
|
||||||
|
quantity: 1,
|
||||||
|
unit_price: 200,
|
||||||
|
},
|
||||||
],
|
],
|
||||||
transactions: [
|
transactions: [
|
||||||
{
|
{
|
||||||
@@ -282,6 +295,7 @@ async function createOrderFixture({ container, product, location }) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
const inventoryModule = container.resolve(ModuleRegistrationName.INVENTORY)
|
const inventoryModule = container.resolve(ModuleRegistrationName.INVENTORY)
|
||||||
|
|
||||||
const reservation = await inventoryModule.createReservationItems([
|
const reservation = await inventoryModule.createReservationItems([
|
||||||
{
|
{
|
||||||
line_item_id: order.items![0].id,
|
line_item_id: order.items![0].id,
|
||||||
@@ -429,6 +443,81 @@ medusaIntegrationTestRunner({
|
|||||||
])
|
])
|
||||||
expect(stockAvailabilityAfterCancelled).toEqual(2)
|
expect(stockAvailabilityAfterCancelled).toEqual(2)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it("should revert an order fulfillment when it fails and recreate it when tried again", async () => {
|
||||||
|
const order = await createOrderFixture({ container, product, location })
|
||||||
|
|
||||||
|
// Create a fulfillment
|
||||||
|
const createOrderFulfillmentData: OrderWorkflow.CreateOrderFulfillmentWorkflowInput =
|
||||||
|
{
|
||||||
|
order_id: order.id,
|
||||||
|
created_by: "user_1",
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
id: order.items![0].id,
|
||||||
|
quantity: 1,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
no_notification: false,
|
||||||
|
location_id: undefined,
|
||||||
|
}
|
||||||
|
|
||||||
|
const worflow = createOrderFulfillmentWorkflow(container)
|
||||||
|
worflow.addAction("fail", {
|
||||||
|
invoke: () => {
|
||||||
|
throw new Error("Fulfillment failed")
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
await worflow
|
||||||
|
.run({
|
||||||
|
input: createOrderFulfillmentData,
|
||||||
|
})
|
||||||
|
.catch(() => void 0)
|
||||||
|
|
||||||
|
worflow.deleteAction("fail")
|
||||||
|
|
||||||
|
await worflow.run({
|
||||||
|
input: createOrderFulfillmentData,
|
||||||
|
})
|
||||||
|
|
||||||
|
const remoteQuery = container.resolve(
|
||||||
|
ContainerRegistrationKeys.REMOTE_QUERY
|
||||||
|
)
|
||||||
|
const remoteQueryObject = remoteQueryObjectFromString({
|
||||||
|
entryPoint: "order",
|
||||||
|
variables: {
|
||||||
|
id: order.id,
|
||||||
|
},
|
||||||
|
fields: [
|
||||||
|
"*",
|
||||||
|
"items.*",
|
||||||
|
"shipping_methods.*",
|
||||||
|
"total",
|
||||||
|
"item_total",
|
||||||
|
"fulfillments.*",
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
|
const [orderFulfill] = await remoteQuery(remoteQueryObject)
|
||||||
|
|
||||||
|
expect(orderFulfill.fulfillments).toHaveLength(1)
|
||||||
|
expect(orderFulfill.items[0].detail.fulfilled_quantity).toEqual(1)
|
||||||
|
|
||||||
|
const inventoryModule = container.resolve(
|
||||||
|
ModuleRegistrationName.INVENTORY
|
||||||
|
)
|
||||||
|
const reservation = await inventoryModule.listReservationItems({
|
||||||
|
line_item_id: order.items![0].id,
|
||||||
|
})
|
||||||
|
expect(reservation).toHaveLength(0)
|
||||||
|
|
||||||
|
const stockAvailability = await inventoryModule.retrieveStockedQuantity(
|
||||||
|
inventoryItem.id,
|
||||||
|
[location.id]
|
||||||
|
)
|
||||||
|
expect(stockAvailability).toEqual(1)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
@@ -94,7 +94,7 @@ function prepareFulfillmentData({
|
|||||||
const reservation = reservationItemMap.get(i.id)!
|
const reservation = reservationItemMap.get(i.id)!
|
||||||
return {
|
return {
|
||||||
line_item_id: i.id,
|
line_item_id: i.id,
|
||||||
inventory_item_id: reservation.inventory_item_id,
|
inventory_item_id: reservation?.inventory_item_id,
|
||||||
quantity: i.quantity,
|
quantity: i.quantity,
|
||||||
title: orderItem.variant_title ?? orderItem.title,
|
title: orderItem.variant_title ?? orderItem.title,
|
||||||
sku: orderItem.variant_sku || "",
|
sku: orderItem.variant_sku || "",
|
||||||
@@ -114,6 +114,9 @@ function prepareFulfillmentData({
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const shippingAddress = order.shipping_address ?? { id: undefined }
|
||||||
|
delete shippingAddress.id
|
||||||
|
|
||||||
return {
|
return {
|
||||||
input: {
|
input: {
|
||||||
location_id: locationId,
|
location_id: locationId,
|
||||||
@@ -121,18 +124,12 @@ function prepareFulfillmentData({
|
|||||||
shipping_option_id: shippingOption.id,
|
shipping_option_id: shippingOption.id,
|
||||||
items: fulfillmentItems,
|
items: fulfillmentItems,
|
||||||
labels: [] as FulfillmentWorkflow.CreateFulfillmentLabelWorkflowDTO[], // TODO: shipping labels
|
labels: [] as FulfillmentWorkflow.CreateFulfillmentLabelWorkflowDTO[], // TODO: shipping labels
|
||||||
delivery_address: order.shipping_address ?? ({} as any),
|
delivery_address: shippingAddress as any,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function prepareInventoryUpdate({ reservations, order, input }) {
|
function prepareInventoryUpdate({ reservations, order, input }) {
|
||||||
if (!reservations || !reservations.length) {
|
|
||||||
throw new Error(
|
|
||||||
`No stock reservation found for items ${input.items.map((i) => i.id)}`
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
const reservationMap = reservations.reduce((acc, reservation) => {
|
const reservationMap = reservations.reduce((acc, reservation) => {
|
||||||
acc[reservation.line_item_id as string] = reservation
|
acc[reservation.line_item_id as string] = reservation
|
||||||
return acc
|
return acc
|
||||||
@@ -157,6 +154,15 @@ function prepareInventoryUpdate({ reservations, order, input }) {
|
|||||||
|
|
||||||
for (const item of order.items) {
|
for (const item of order.items) {
|
||||||
const reservation = reservationMap[item.id]
|
const reservation = reservationMap[item.id]
|
||||||
|
if (!reservation) {
|
||||||
|
if (item.manage_inventory) {
|
||||||
|
throw new Error(
|
||||||
|
`No stock reservation found for item ${item.id} - ${item.title} (${item.variant_title})`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
const inputQuantity = inputItemsMap[item.id]?.quantity ?? item.quantity
|
const inputQuantity = inputItemsMap[item.id]?.quantity ?? item.quantity
|
||||||
|
|
||||||
const quantity = reservation.quantity - inputQuantity
|
const quantity = reservation.quantity - inputQuantity
|
||||||
@@ -199,6 +205,7 @@ export const createOrderFulfillmentWorkflow = createWorkflow(
|
|||||||
"region_id",
|
"region_id",
|
||||||
"currency_code",
|
"currency_code",
|
||||||
"items.*",
|
"items.*",
|
||||||
|
"items.variant.manage_inventory",
|
||||||
"shipping_address.*",
|
"shipping_address.*",
|
||||||
"shipping_methods.shipping_option_id", // TODO: which shipping method to use when multiple?
|
"shipping_methods.shipping_option_id", // TODO: which shipping method to use when multiple?
|
||||||
],
|
],
|
||||||
|
|||||||
Reference in new issue
Block a user