feat(core-flows,js-sdk,medusa,types): draft order delete (#12172)
This commit is contained in:
1 parent
52eebcee6f
commit
9866baa852
11 files changed
+521
-2
No files matched your search
@@ -0,0 +1,26 @@
|
||||
import { IOrderModuleService } from "@medusajs/framework/types"
|
||||
import { createStep } from "@medusajs/framework/workflows-sdk"
|
||||
import { Modules } from "@medusajs/framework/utils"
|
||||
|
||||
/**
|
||||
* The details of canceling the orders.
|
||||
*/
|
||||
export type DeleteDraftOrdersStepInput = {
|
||||
/**
|
||||
* The IDs of the orders to delete.
|
||||
*/
|
||||
orderIds: string[]
|
||||
}
|
||||
|
||||
export const deleteDraftOrdersStepId = "delete-draft-orders"
|
||||
/**
|
||||
* This step deletes one or more draft orders.
|
||||
*/
|
||||
export const deleteDraftOrdersStep = createStep(
|
||||
deleteDraftOrdersStepId,
|
||||
async (data: DeleteDraftOrdersStepInput, { container }) => {
|
||||
const service = container.resolve<IOrderModuleService>(Modules.ORDER)
|
||||
|
||||
await service.deleteOrders(data.orderIds)
|
||||
}
|
||||
)
|
||||
@@ -1 +1,2 @@
|
||||
export * from "./validate-draft-order"
|
||||
export * from "./delete-draft-order"
|
||||
@@ -0,0 +1,85 @@
|
||||
import {
|
||||
WorkflowData,
|
||||
WorkflowResponse,
|
||||
createStep,
|
||||
createWorkflow,
|
||||
transform,
|
||||
} from "@medusajs/framework/workflows-sdk"
|
||||
import { OrderDTO } from "@medusajs/framework/types"
|
||||
import { Modules } from "@medusajs/framework/utils"
|
||||
|
||||
import { removeRemoteLinkStep, useQueryGraphStep } from "../../common"
|
||||
import { deleteDraftOrdersStep } from "../steps"
|
||||
|
||||
/**
|
||||
* The data to validate the order's cancelation.
|
||||
*/
|
||||
export type DeleteDraftOrderStepInput = {
|
||||
/**
|
||||
* The order ids to delete.
|
||||
*/
|
||||
order_ids: string[]
|
||||
}
|
||||
|
||||
const validateDraftOrdersStep = createStep(
|
||||
"validate-draft-orders",
|
||||
async (data: { orders: OrderDTO[] }) => {
|
||||
if (
|
||||
data.orders.some(
|
||||
(order) => order.status !== "draft" || !order.is_draft_order
|
||||
)
|
||||
) {
|
||||
throw new Error("One or more orders are not draft")
|
||||
}
|
||||
|
||||
if (data.orders.some((order) => order.deleted_at)) {
|
||||
throw new Error("One or more orders are already deleted")
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
export const deleteDraftOrderWorkflowId = "delete-draft-order"
|
||||
/**
|
||||
* This workflow deletes draft orders.
|
||||
*
|
||||
* You can also use this workflow within your customizations or your own custom workflows, allowing you to wrap custom logic around canceling an order.
|
||||
*
|
||||
* @example
|
||||
* const { result } = await deleteDraftOrderWorkflow(container)
|
||||
* .run({
|
||||
* input: {
|
||||
* order_ids: ["order_123", "order_456"],
|
||||
* }
|
||||
* })
|
||||
*
|
||||
* @summary
|
||||
*
|
||||
* Delete draft orders.
|
||||
*
|
||||
* @property hooks.orderCanceled - This hook is executed after the order is canceled. You can consume this hook to perform custom actions on the canceled order.
|
||||
*/
|
||||
export const deleteDraftOrdersWorkflow = createWorkflow(
|
||||
deleteDraftOrderWorkflowId,
|
||||
(input: WorkflowData<DeleteDraftOrderStepInput>) => {
|
||||
const orderQuery = useQueryGraphStep({
|
||||
entity: "orders",
|
||||
fields: ["id", "status", "is_draft_order", "deleted_at"],
|
||||
filters: { id: input.order_ids },
|
||||
options: { throwIfKeyNotFound: true },
|
||||
}).config({ name: "get-draft-order" })
|
||||
|
||||
const orders = transform({ orderQuery }, ({ orderQuery }) => {
|
||||
return orderQuery.data
|
||||
})
|
||||
|
||||
validateDraftOrdersStep({ orders })
|
||||
|
||||
removeRemoteLinkStep({
|
||||
[Modules.ORDER]: { order_id: input.order_ids },
|
||||
})
|
||||
|
||||
deleteDraftOrdersStep({ orderIds: input.order_ids })
|
||||
|
||||
return new WorkflowResponse(void 0)
|
||||
}
|
||||
)
|
||||
@@ -15,3 +15,4 @@ export * from "./update-draft-order-action-shipping-method"
|
||||
export * from "./update-draft-order-item"
|
||||
export * from "./update-draft-order-shipping-method"
|
||||
export * from "./remove-draft-order-shipping-method"
|
||||
export * from "./delete-draft-order"
|
||||
@@ -162,6 +162,29 @@ export class DraftOrder {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* This method deletes a draft order. It sends a request to the
|
||||
* [Delete Draft Order](https://docs.medusajs.com/api/admin#draft-orders_deleteordereditsid) API route.
|
||||
*
|
||||
* @param id - The draft order's ID.
|
||||
* @param headers - Headers to pass in the request.
|
||||
*
|
||||
* @example
|
||||
* sdk.admin.draftOrder.delete("order_123")
|
||||
* .then(({ id, object, deleted }) => {
|
||||
* console.log(id, object, deleted)
|
||||
* })
|
||||
*/
|
||||
async delete(id: string, headers?: ClientHeaders) {
|
||||
return await this.client.fetch<HttpTypes.DeleteResponse<"draft-order">>(
|
||||
`/admin/draft-orders/${id}`,
|
||||
{
|
||||
method: "DELETE",
|
||||
headers,
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* This method updates a draft order. It sends a request to the
|
||||
* [Update Draft Order](https://docs.medusajs.com/api/admin#draft-orders_postdraftordersid) API route.
|
||||
|
||||
@@ -1147,6 +1147,11 @@ export interface OrderDTO {
|
||||
*/
|
||||
updated_at: string | Date
|
||||
|
||||
/**
|
||||
* When the order was deleted.
|
||||
*/
|
||||
deleted_at?: string | Date
|
||||
|
||||
/**
|
||||
* The original item total of the order.
|
||||
*/
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import {
|
||||
getOrderDetailWorkflow,
|
||||
updateDraftOrderWorkflow,
|
||||
deleteDraftOrdersWorkflow,
|
||||
} from "@medusajs/core-flows"
|
||||
import {
|
||||
AuthenticatedMedusaRequest,
|
||||
@@ -54,3 +55,22 @@ export const POST = async (
|
||||
.status(200)
|
||||
.json({ draft_order: result.data[0] as HttpTypes.AdminDraftOrder })
|
||||
}
|
||||
|
||||
export const DELETE = async (
|
||||
req: AuthenticatedMedusaRequest,
|
||||
res: MedusaResponse
|
||||
) => {
|
||||
const { id } = req.params
|
||||
|
||||
await deleteDraftOrdersWorkflow(req.scope).run({
|
||||
input: {
|
||||
order_ids: [id],
|
||||
},
|
||||
})
|
||||
|
||||
res.status(200).json({
|
||||
id,
|
||||
object: "draft-order",
|
||||
deleted: true,
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
import { Migration } from "@mikro-orm/migrations"
|
||||
|
||||
export class Migration20250522181137 extends Migration {
|
||||
override async up(): Promise<void> {
|
||||
this.addSql(
|
||||
`DELETE FROM "order_summary" WHERE "order_id" NOT IN (SELECT id FROM "order");`
|
||||
)
|
||||
|
||||
this.addSql(`ALTER TABLE "order_summary"
|
||||
ADD CONSTRAINT
|
||||
"order_summary_order_id_foreign" FOREIGN KEY ("order_id") REFERENCES "order" ("id")
|
||||
ON UPDATE CASCADE
|
||||
ON DELETE CASCADE;`)
|
||||
}
|
||||
|
||||
override async down(): Promise<void> {
|
||||
this.addSql(
|
||||
`ALTER TABLE "order_summary" DROP CONSTRAINT IF EXISTS "order_summary_order_id_foreign";`
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -728,7 +728,14 @@ export default class OrderModuleService
|
||||
const creditLinesToCreate: CreateOrderCreditLineDTO[] = []
|
||||
const createdOrders: InferEntityType<typeof Order>[] = []
|
||||
|
||||
for (const { items, shipping_methods, credit_lines, ...order } of data) {
|
||||
for (const {
|
||||
items,
|
||||
shipping_methods,
|
||||
credit_lines,
|
||||
shipping_address,
|
||||
billing_address,
|
||||
...order
|
||||
} of data) {
|
||||
const ord = order as any
|
||||
|
||||
const shippingMethods = shipping_methods?.map((sm: any) => {
|
||||
@@ -844,6 +851,70 @@ export default class OrderModuleService
|
||||
})
|
||||
}
|
||||
|
||||
@InjectTransactionManager()
|
||||
// @ts-expect-error
|
||||
async deleteOrders(
|
||||
orderIds: string | string[],
|
||||
@MedusaContext() sharedContext: Context = {}
|
||||
): Promise<void> {
|
||||
const ids = Array.isArray(orderIds) ? orderIds : [orderIds]
|
||||
|
||||
const orders = await this.orderService_.list(
|
||||
{ id: ids },
|
||||
{
|
||||
select: ["id", "shipping_address_id", "billing_address_id"],
|
||||
},
|
||||
sharedContext
|
||||
)
|
||||
|
||||
const orderAddressIds = orders
|
||||
.map((order) => [order.shipping_address_id, order.billing_address_id])
|
||||
.flat(1)
|
||||
|
||||
const orderChanges = await this.orderChangeService_.list(
|
||||
{ order_id: ids },
|
||||
{ select: ["id"] },
|
||||
sharedContext
|
||||
)
|
||||
|
||||
const orderChangeIds = orderChanges.map((orderChange) => orderChange.id)
|
||||
|
||||
const orderItems = await this.orderItemService_.list(
|
||||
{ order_id: ids },
|
||||
{ select: ["id", "item_id"] },
|
||||
sharedContext
|
||||
)
|
||||
|
||||
const lineItemIds = orderItems.map((orderItem) => orderItem.item_id)
|
||||
|
||||
const orderShipping = await this.orderShippingService_.list(
|
||||
{ order_id: ids },
|
||||
{ select: ["shipping_method_id"] },
|
||||
sharedContext
|
||||
)
|
||||
|
||||
const orderShippingMethodIds = orderShipping.map(
|
||||
(orderShipping) => orderShipping.shipping_method_id
|
||||
)
|
||||
|
||||
await promiseAll([
|
||||
this.orderAddressService_.delete(orderAddressIds, sharedContext),
|
||||
// Delete order changes & actions
|
||||
this.orderChangeService_.delete(orderChangeIds, sharedContext),
|
||||
])
|
||||
|
||||
// Delete order, order items, summary, shipping methods and transactions
|
||||
await super.deleteOrders(ids, sharedContext)
|
||||
|
||||
await promiseAll([
|
||||
this.orderLineItemService_.delete(lineItemIds, sharedContext),
|
||||
this.orderShippingMethodService_.delete(
|
||||
orderShippingMethodIds,
|
||||
sharedContext
|
||||
),
|
||||
])
|
||||
}
|
||||
|
||||
// @ts-expect-error
|
||||
async updateOrders(
|
||||
data: OrderTypes.UpdateOrderDTO[]
|
||||
|
||||
Reference in new issue
Block a user