fix(core-flows): draft order reservations (#12115)
* fix: draft order reservations * feat: add test case * fix: assert item ids
This commit is contained in:
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
"@medusajs/core-flows": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
fix(core-flows): draft order reservations + emit order placedevent on convert
|
||||||
@@ -12,6 +12,8 @@ jest.setTimeout(300000)
|
|||||||
medusaIntegrationTestRunner({
|
medusaIntegrationTestRunner({
|
||||||
testSuite: ({ dbConnection, getContainer, api }) => {
|
testSuite: ({ dbConnection, getContainer, api }) => {
|
||||||
let region: HttpTypes.AdminRegion
|
let region: HttpTypes.AdminRegion
|
||||||
|
let salesChannel: HttpTypes.AdminSalesChannel
|
||||||
|
let stockLocation: HttpTypes.AdminStockLocation
|
||||||
let testDraftOrder: HttpTypes.AdminDraftOrder
|
let testDraftOrder: HttpTypes.AdminDraftOrder
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
@@ -32,10 +34,32 @@ medusaIntegrationTestRunner({
|
|||||||
)
|
)
|
||||||
).data.region
|
).data.region
|
||||||
|
|
||||||
|
salesChannel = (
|
||||||
|
await api.post("/admin/sales-channels", { name: "test" }, adminHeaders)
|
||||||
|
).data.sales_channel
|
||||||
|
|
||||||
|
stockLocation = (
|
||||||
|
await api.post(
|
||||||
|
`/admin/stock-locations`,
|
||||||
|
{ name: "test location" },
|
||||||
|
adminHeaders
|
||||||
|
)
|
||||||
|
).data.stock_location
|
||||||
|
|
||||||
|
await api.post(
|
||||||
|
`/admin/stock-locations/${stockLocation.id}/sales-channels`,
|
||||||
|
{ add: [salesChannel.id] },
|
||||||
|
adminHeaders
|
||||||
|
)
|
||||||
|
|
||||||
testDraftOrder = (
|
testDraftOrder = (
|
||||||
await api.post(
|
await api.post(
|
||||||
"/admin/draft-orders",
|
"/admin/draft-orders",
|
||||||
{ email: "test@test.com", region_id: region.id },
|
{
|
||||||
|
email: "test@test.com",
|
||||||
|
region_id: region.id,
|
||||||
|
sales_channel_id: salesChannel.id,
|
||||||
|
},
|
||||||
adminHeaders
|
adminHeaders
|
||||||
)
|
)
|
||||||
).data.draft_order
|
).data.draft_order
|
||||||
@@ -115,5 +139,152 @@ medusaIntegrationTestRunner({
|
|||||||
expect(response.data.order.status).toBe("pending")
|
expect(response.data.order.status).toBe("pending")
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe("POST /draft-orders/:id/edit/items/:item_id", () => {
|
||||||
|
let product
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
const inventoryItem = (
|
||||||
|
await api.post(
|
||||||
|
`/admin/inventory-items`,
|
||||||
|
{ sku: "shirt" },
|
||||||
|
adminHeaders
|
||||||
|
)
|
||||||
|
).data.inventory_item
|
||||||
|
|
||||||
|
await api.post(
|
||||||
|
`/admin/inventory-items/${inventoryItem.id}/location-levels`,
|
||||||
|
{
|
||||||
|
location_id: stockLocation.id,
|
||||||
|
stocked_quantity: 10,
|
||||||
|
},
|
||||||
|
adminHeaders
|
||||||
|
)
|
||||||
|
|
||||||
|
product = (
|
||||||
|
await api.post(
|
||||||
|
"/admin/products",
|
||||||
|
{
|
||||||
|
title: "Shirt",
|
||||||
|
options: [{ title: "size", values: ["large", "small"] }],
|
||||||
|
variants: [
|
||||||
|
{
|
||||||
|
title: "L shirt",
|
||||||
|
options: { size: "large" },
|
||||||
|
inventory_items: [
|
||||||
|
{
|
||||||
|
inventory_item_id: inventoryItem.id,
|
||||||
|
required_quantity: 1,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
prices: [
|
||||||
|
{
|
||||||
|
currency_code: "usd",
|
||||||
|
amount: 10,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "S shirt",
|
||||||
|
options: { size: "small" },
|
||||||
|
inventory_items: [
|
||||||
|
{
|
||||||
|
inventory_item_id: inventoryItem.id,
|
||||||
|
required_quantity: 1,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
prices: [
|
||||||
|
{
|
||||||
|
currency_code: "usd",
|
||||||
|
amount: 10,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
adminHeaders
|
||||||
|
)
|
||||||
|
).data.product
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should create reservations for added items", async () => {
|
||||||
|
// 1. Create first edit and add items to it
|
||||||
|
let edit = (
|
||||||
|
await api.post(
|
||||||
|
`/admin/draft-orders/${testDraftOrder.id}/edit`,
|
||||||
|
{},
|
||||||
|
adminHeaders
|
||||||
|
)
|
||||||
|
).data.draft_order_preview
|
||||||
|
|
||||||
|
await api.post(
|
||||||
|
`/admin/draft-orders/${testDraftOrder.id}/edit/items`,
|
||||||
|
{
|
||||||
|
items: [{ variant_id: product.variants[0].id, quantity: 1 }],
|
||||||
|
},
|
||||||
|
adminHeaders
|
||||||
|
)
|
||||||
|
|
||||||
|
edit = (
|
||||||
|
await api.post(
|
||||||
|
`/admin/draft-orders/${testDraftOrder.id}/edit/confirm`,
|
||||||
|
{},
|
||||||
|
adminHeaders
|
||||||
|
)
|
||||||
|
).data.draft_order_preview
|
||||||
|
|
||||||
|
// Create second edit and add items to it
|
||||||
|
edit = (
|
||||||
|
await api.post(
|
||||||
|
`/admin/draft-orders/${testDraftOrder.id}/edit`,
|
||||||
|
{},
|
||||||
|
adminHeaders
|
||||||
|
)
|
||||||
|
).data.draft_order_preview
|
||||||
|
|
||||||
|
await api.post(
|
||||||
|
`/admin/draft-orders/${testDraftOrder.id}/edit/items`,
|
||||||
|
{
|
||||||
|
items: [{ variant_id: product.variants[1].id, quantity: 2 }],
|
||||||
|
},
|
||||||
|
adminHeaders
|
||||||
|
)
|
||||||
|
|
||||||
|
edit = (
|
||||||
|
await api.post(
|
||||||
|
`/admin/draft-orders/${testDraftOrder.id}/edit/confirm`,
|
||||||
|
{},
|
||||||
|
adminHeaders
|
||||||
|
)
|
||||||
|
).data.draft_order_preview
|
||||||
|
|
||||||
|
const reservations = (
|
||||||
|
await api.get(`/admin/reservations`, adminHeaders)
|
||||||
|
).data.reservations
|
||||||
|
|
||||||
|
const lineItem1Id = edit.items.find(
|
||||||
|
(item) => item.variant_id === product.variants[0].id
|
||||||
|
)?.id
|
||||||
|
|
||||||
|
const lineItem2Id = edit.items.find(
|
||||||
|
(item) => item.variant_id === product.variants[1].id
|
||||||
|
)?.id
|
||||||
|
|
||||||
|
// second edit didn't override the reservations for the first edit
|
||||||
|
expect(reservations.length).toBe(2)
|
||||||
|
expect(reservations).toEqual(
|
||||||
|
expect.arrayContaining([
|
||||||
|
expect.objectContaining({
|
||||||
|
line_item_id: lineItem1Id,
|
||||||
|
quantity: 1,
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
line_item_id: lineItem2Id,
|
||||||
|
quantity: 2,
|
||||||
|
}),
|
||||||
|
])
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -114,19 +114,25 @@ export const confirmDraftOrderEditWorkflow = createWorkflow(
|
|||||||
throw_if_key_not_found: true,
|
throw_if_key_not_found: true,
|
||||||
}).config({ name: "order-items-query" })
|
}).config({ name: "order-items-query" })
|
||||||
|
|
||||||
const lineItemIds = transform(
|
const { removedLineItemIds } = transform(
|
||||||
{ orderItems, previousOrderItems: order.items },
|
{ orderItems, previousOrderItems: order.items },
|
||||||
|
|
||||||
(data) => {
|
(data) => {
|
||||||
const previousItemIds = (data.previousOrderItems || []).map(
|
const previousItemIds = (data.previousOrderItems || []).map(
|
||||||
({ id }) => id
|
({ id }) => id
|
||||||
) // items that have been removed with the change
|
)
|
||||||
const newItemIds = data.orderItems.items.map(({ id }) => id)
|
const currentItemIds = data.orderItems.items.map(({ id }) => id)
|
||||||
return [...new Set([...previousItemIds, ...newItemIds])]
|
|
||||||
|
const removedItemIds = previousItemIds.filter(
|
||||||
|
(id) => !currentItemIds.includes(id)
|
||||||
|
)
|
||||||
|
|
||||||
|
return {
|
||||||
|
removedLineItemIds: removedItemIds,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
deleteReservationsByLineItemsStep(lineItemIds)
|
deleteReservationsByLineItemsStep(removedLineItemIds)
|
||||||
|
|
||||||
const { variants, items } = transform(
|
const { variants, items } = transform(
|
||||||
{ orderItems, orderPreview },
|
{ orderItems, orderPreview },
|
||||||
|
|||||||
@@ -1,4 +1,8 @@
|
|||||||
import { Modules, OrderStatus } from "@medusajs/framework/utils"
|
import {
|
||||||
|
Modules,
|
||||||
|
OrderStatus,
|
||||||
|
OrderWorkflowEvents,
|
||||||
|
} from "@medusajs/framework/utils"
|
||||||
import {
|
import {
|
||||||
createStep,
|
createStep,
|
||||||
createWorkflow,
|
createWorkflow,
|
||||||
@@ -7,7 +11,7 @@ import {
|
|||||||
WorkflowResponse,
|
WorkflowResponse,
|
||||||
} from "@medusajs/framework/workflows-sdk"
|
} from "@medusajs/framework/workflows-sdk"
|
||||||
import { IOrderModuleService, OrderDTO } from "@medusajs/types"
|
import { IOrderModuleService, OrderDTO } from "@medusajs/types"
|
||||||
import { useRemoteQueryStep } from "../../common"
|
import { emitEventStep, useRemoteQueryStep } from "../../common"
|
||||||
import { validateDraftOrderStep } from "../steps/validate-draft-order"
|
import { validateDraftOrderStep } from "../steps/validate-draft-order"
|
||||||
|
|
||||||
const convertDraftOrderWorkflowId = "convert-draft-order"
|
const convertDraftOrderWorkflowId = "convert-draft-order"
|
||||||
@@ -91,6 +95,11 @@ export const convertDraftOrderWorkflow = createWorkflow(
|
|||||||
|
|
||||||
const updatedOrder = convertDraftOrderStep({ id: input.id })
|
const updatedOrder = convertDraftOrderStep({ id: input.id })
|
||||||
|
|
||||||
|
emitEventStep({
|
||||||
|
eventName: OrderWorkflowEvents.PLACED,
|
||||||
|
data: { id: updatedOrder.id },
|
||||||
|
})
|
||||||
|
|
||||||
return new WorkflowResponse(updatedOrder)
|
return new WorkflowResponse(updatedOrder)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user