feat(core-flows): Refresh adjustments when editing orders (#13189)

* wip

* add tests

* add more tests

* fixes buy-get promotion

* Create empty-pillows-promise.md

* chore: use query graph

* Update packages/core/core-flows/src/order/workflows/order-edit/refresh-order-edit-adjustments.ts

Co-authored-by: Frane Polić <16856471+fPolic@users.noreply.github.com>

---------

Co-authored-by: Frane Polić <16856471+fPolic@users.noreply.github.com>
This commit is contained in:
Oli Juhl
2025-08-20 15:04:27 +02:00
committed by GitHub
parent d4a9728879
commit b152210554
23 changed files with 1055 additions and 264 deletions

View File

@@ -51,7 +51,7 @@ export const useRemoteQueryStepId = "use-remote-query"
* This step fetches data across modules using the remote query.
*
* Learn more in the [Remote Query documentation](https://docs.medusajs.com/learn/fundamentals/module-links/query).
*
*
* :::note
*
* This step is deprecated. Use {@link useQueryGraphStep} instead.

View File

@@ -28,6 +28,15 @@ export interface RefreshDraftOrderAdjustmentsWorkflowInput {
* The draft order to refresh the adjustments for.
*/
order: OrderDTO
// TODO: I will reintroduce this type, once I have migrated all of the order flows to fit the expected type.
// Doing this in a single PR is too much work, so I'm going to do it in smaller PRs.
//
// order: Omit<OrderDTO, "items"> & {
// items?: ComputeActionItemLine[]
// promotions?: PromotionDTO[]
// }
/**
* The promo codes to add or remove from the draft order.
*/
@@ -35,7 +44,7 @@ export interface RefreshDraftOrderAdjustmentsWorkflowInput {
/**
* The action to apply with the promo codes. You can
* either:
*
*
* - Add the promo codes to the draft order.
* - Remove the promo codes from the draft order.
* - Replace the existing promo codes with the new ones.
@@ -47,10 +56,10 @@ export interface RefreshDraftOrderAdjustmentsWorkflowInput {
* This workflow refreshes the adjustments or promotions for a draft order. It's used by other workflows
* like {@link addDraftOrderItemsWorkflow} to refresh the promotions whenever changes
* are made to the draft order.
*
*
* You can use this workflow within your customizations or your own custom workflows, allowing you to wrap custom logic around
* refreshing the adjustments or promotions for a draft order.
*
*
* @example
* const { result } = await refreshDraftOrderAdjustmentsWorkflow(container)
* .run({
@@ -61,9 +70,9 @@ export interface RefreshDraftOrderAdjustmentsWorkflowInput {
* action: PromotionActions.ADD,
* }
* })
*
*
* @summary
*
*
* Refresh the promotions in a draft order.
*/
export const refreshDraftOrderAdjustmentsWorkflow = createWorkflow(

View File

@@ -10,9 +10,11 @@ import {
createWorkflow,
transform,
} from "@medusajs/framework/workflows-sdk"
import { useRemoteQueryStep } from "../../../common"
import { useQueryGraphStep } from "../../../common"
import { createOrderChangeStep } from "../../steps/create-order-change"
import { throwIfOrderIsCancelled } from "../../utils/order-validation"
import { refreshOrderEditAdjustmentsWorkflow } from "./refresh-order-edit-adjustments"
import { fieldsToRefreshOrderEdit } from "./utils/fields"
/**
* The data to validate that an order-edit can be requested for an order.
@@ -27,14 +29,14 @@ export type BeginOrderEditValidationStepInput = {
/**
* This step validates that an order-edit can be requested for an order.
* If the order is canceled, the step will throw an error.
*
*
* :::note
*
*
* You can retrieve an order's details using [Query](https://docs.medusajs.com/learn/fundamentals/module-links/query),
* or [useQueryGraphStep](https://docs.medusajs.com/resources/references/medusa-workflows/steps/useQueryGraphStep).
*
*
* :::
*
*
* @example
* const data = beginOrderEditValidationStep({
* order: {
@@ -54,13 +56,13 @@ export const beginOrderEditOrderWorkflowId = "begin-order-edit-order"
/**
* This workflow creates an order edit request. It' used by the
* [Create Order Edit Admin API Route](https://docs.medusajs.com/api/admin#order-edits_postorderedits).
*
* To request the order edit, use the {@link requestOrderEditRequestWorkflow}. The order edit is then only applied after the
*
* To request the order edit, use the {@link requestOrderEditRequestWorkflow}. The order edit is then only applied after the
* order edit is confirmed using the {@link confirmOrderEditRequestWorkflow}.
*
*
* You can use this workflow within your customizations or your own custom workflows, allowing you to create an order edit
* for an order in your custom flows.
*
*
* @example
* const { result } = await beginOrderEditOrderWorkflow(container)
* .run({
@@ -68,9 +70,9 @@ export const beginOrderEditOrderWorkflowId = "begin-order-edit-order"
* order_id: "order_123",
* }
* })
*
*
* @summary
*
*
* Create an order edit request.
*/
export const beginOrderEditOrderWorkflow = createWorkflow(
@@ -78,12 +80,17 @@ export const beginOrderEditOrderWorkflow = createWorkflow(
function (
input: WorkflowData<OrderWorkflow.BeginorderEditWorkflowInput>
): WorkflowResponse<OrderChangeDTO> {
const order: OrderDTO = useRemoteQueryStep({
entry_point: "orders",
fields: ["id", "status"],
variables: { id: input.order_id },
list: false,
throw_if_key_not_found: true,
const orderResult = useQueryGraphStep({
entity: "order",
fields: fieldsToRefreshOrderEdit,
filters: { id: input.order_id },
options: {
throwIfKeyNotFound: true,
},
})
const order = transform({ orderResult }, ({ orderResult }) => {
return orderResult.data[0]
})
beginOrderEditValidationStep({ order })
@@ -97,6 +104,13 @@ export const beginOrderEditOrderWorkflow = createWorkflow(
internal_note: input.internal_note,
}
})
refreshOrderEditAdjustmentsWorkflow.runAsStep({
input: {
order: order,
},
})
return new WorkflowResponse(createOrderChangeStep(orderChangeInput))
}
)

View File

@@ -11,12 +11,14 @@ import {
parallelize,
transform,
} from "@medusajs/framework/workflows-sdk"
import { emitEventStep, useRemoteQueryStep } from "../../../common"
import { emitEventStep, useQueryGraphStep } from "../../../common"
import { deleteOrderChangesStep, deleteOrderShippingMethods } from "../../steps"
import {
throwIfIsCancelled,
throwIfOrderChangeIsNotActive,
} from "../../utils/order-validation"
import { refreshOrderEditAdjustmentsWorkflow } from "./refresh-order-edit-adjustments"
import { fieldsToRefreshOrderEdit } from "./utils/fields"
/**
* The data to validate that a requested order edit can be canceled.
@@ -101,26 +103,35 @@ export const cancelBeginOrderEditWorkflow = createWorkflow(
function (
input: WorkflowData<CancelBeginOrderEditWorkflowInput>
): WorkflowData<void> {
const order: OrderDTO = useRemoteQueryStep({
entry_point: "orders",
fields: ["id", "version", "canceled_at"],
variables: { id: input.order_id },
list: false,
throw_if_key_not_found: true,
const orderResult = useQueryGraphStep({
entity: "order",
fields: fieldsToRefreshOrderEdit,
filters: { id: input.order_id },
options: {
throwIfKeyNotFound: true,
},
}).config({ name: "order-query" })
const orderChange: OrderChangeDTO = useRemoteQueryStep({
entry_point: "order_change",
const order = transform({ orderResult }, ({ orderResult }) => {
return orderResult.data[0]
})
const orderChangeResult = useQueryGraphStep({
entity: "order_change",
fields: ["id", "status", "version", "actions.*"],
variables: {
filters: {
order_id: input.order_id,
status: [OrderChangeStatus.PENDING, OrderChangeStatus.REQUESTED],
},
filters: {
order_id: input.order_id,
status: [OrderChangeStatus.PENDING, OrderChangeStatus.REQUESTED],
},
list: false,
}).config({ name: "order-change-query" })
const orderChange = transform(
{ orderChangeResult },
({ orderChangeResult }) => {
return orderChangeResult.data[0]
}
)
cancelBeginOrderEditValidationStep({ order, orderChange })
const shippingToRemove = transform(
@@ -150,5 +161,11 @@ export const cancelBeginOrderEditWorkflow = createWorkflow(
data: eventData,
})
)
refreshOrderEditAdjustmentsWorkflow.runAsStep({
input: {
order: order,
},
})
}
)

View File

@@ -21,7 +21,11 @@ import {
prepareConfirmInventoryInput,
requiredOrderFieldsForInventoryConfirmation,
} from "../../../cart/utils/prepare-confirm-inventory-input"
import { emitEventStep, useRemoteQueryStep } from "../../../common"
import {
emitEventStep,
useQueryGraphStep,
useRemoteQueryStep,
} from "../../../common"
import { deleteReservationsByLineItemsStep } from "../../../reservation"
import { previewOrderChangeStep } from "../../steps"
import { confirmOrderChanges } from "../../steps/confirm-order-changes"
@@ -30,6 +34,7 @@ import {
throwIfOrderChangeIsNotActive,
} from "../../utils/order-validation"
import { createOrUpdateOrderPaymentCollectionWorkflow } from "../create-or-update-order-payment-collection"
import { fieldsToRefreshOrderEdit } from "./utils/fields"
/**
* The data to validate that a requested order edit can be confirmed.
@@ -118,26 +123,21 @@ export const confirmOrderEditRequestWorkflow = createWorkflow(
function (
input: ConfirmOrderEditRequestWorkflowInput
): WorkflowResponse<OrderPreviewDTO> {
const order: OrderDTO = useRemoteQueryStep({
entry_point: "orders",
fields: [
"id",
"version",
"canceled_at",
"items.id",
"items.title",
"items.variant_title",
"items.variant_sku",
"items.variant_barcode",
"shipping_address.*",
],
variables: { id: input.order_id },
list: false,
throw_if_key_not_found: true,
const orderResult = useQueryGraphStep({
entity: "order",
fields: fieldsToRefreshOrderEdit,
filters: { id: input.order_id },
options: {
throwIfKeyNotFound: true,
},
}).config({ name: "order-query" })
const orderChange: OrderChangeDTO = useRemoteQueryStep({
entry_point: "order_change",
const order = transform({ orderResult }, ({ orderResult }) => {
return orderResult.data[0]
})
const orderChangeResult = useQueryGraphStep({
entity: "order_change",
fields: [
"id",
"status",
@@ -150,15 +150,19 @@ export const confirmOrderEditRequestWorkflow = createWorkflow(
"actions.reference_id",
"actions.internal_note",
],
variables: {
filters: {
order_id: input.order_id,
status: [OrderChangeStatus.PENDING, OrderChangeStatus.REQUESTED],
},
filters: {
order_id: input.order_id,
status: [OrderChangeStatus.PENDING, OrderChangeStatus.REQUESTED],
},
list: false,
}).config({ name: "order-change-query" })
const orderChange = transform(
{ orderChangeResult },
({ orderChangeResult }) => {
return orderChangeResult.data[0]
}
)
confirmOrderEditRequestValidationStep({
order,
orderChange,

View File

@@ -13,6 +13,7 @@ import {
createWorkflow,
transform,
} from "@medusajs/framework/workflows-sdk"
import { pricingContextResult } from "../../../cart/utils/schemas"
import { useRemoteQueryStep } from "../../../common"
import { previewOrderChangeStep } from "../../steps"
import { createOrderShippingMethods } from "../../steps/create-order-shipping-methods"
@@ -23,7 +24,6 @@ import {
import { prepareShippingMethod } from "../../utils/prepare-shipping-method"
import { createOrderChangeActionsWorkflow } from "../create-order-change-actions"
import { updateOrderTaxLinesWorkflow } from "../update-tax-lines"
import { pricingContextResult } from "../../../cart/utils/schemas"
/**
* The data to validate that a shipping method can be created for an order edit.

View File

@@ -4,7 +4,10 @@ import {
OrderPreviewDTO,
OrderWorkflow,
} from "@medusajs/framework/types"
import { ChangeActionType, OrderChangeStatus } from "@medusajs/framework/utils"
import {
ChangeActionType,
OrderChangeStatus
} from "@medusajs/framework/utils"
import {
WorkflowData,
WorkflowResponse,
@@ -12,7 +15,7 @@ import {
createWorkflow,
transform,
} from "@medusajs/framework/workflows-sdk"
import { useRemoteQueryStep } from "../../../common"
import { useQueryGraphStep } from "../../../common"
import { previewOrderChangeStep } from "../../steps/preview-order-change"
import {
throwIfIsCancelled,
@@ -21,6 +24,8 @@ import {
import { addOrderLineItemsWorkflow } from "../add-line-items"
import { createOrderChangeActionsWorkflow } from "../create-order-change-actions"
import { updateOrderTaxLinesWorkflow } from "../update-tax-lines"
import { refreshOrderEditAdjustmentsWorkflow } from "./refresh-order-edit-adjustments"
import { fieldsToRefreshOrderEdit } from "./utils/fields"
/**
* The data to validate that new items can be added to an order edit.
@@ -39,14 +44,14 @@ export type OrderEditAddNewItemValidationStepInput = {
/**
* This step validates that new items can be added to an order edit.
* If the order is canceled or the order change is not active, the step will throw an error.
*
*
* :::note
*
*
* You can retrieve an order and order change details using [Query](https://docs.medusajs.com/learn/fundamentals/module-links/query),
* or [useQueryGraphStep](https://docs.medusajs.com/resources/references/medusa-workflows/steps/useQueryGraphStep).
*
*
* :::
*
*
* @example
* const data = orderEditAddNewItemValidationStep({
* order: {
@@ -74,10 +79,10 @@ export const orderEditAddNewItemWorkflowId = "order-edit-add-new-item"
/**
* This workflow adds new items to an order edit. It's used by the
* [Add Items to Order Edit Admin API Route](https://docs.medusajs.com/api/admin#order-edits_postordereditsiditems).
*
*
* You can use this workflow within your customizations or your own custom workflows, allowing you to add new items to an order edit
* in your custom flows.
*
*
* @example
* const { result } = await orderEditAddNewItemWorkflow(container)
* .run({
@@ -91,9 +96,9 @@ export const orderEditAddNewItemWorkflowId = "order-edit-add-new-item"
* ]
* }
* })
*
*
* @summary
*
*
* Add new items to an order edit.
*/
export const orderEditAddNewItemWorkflow = createWorkflow(
@@ -101,26 +106,35 @@ export const orderEditAddNewItemWorkflow = createWorkflow(
function (
input: WorkflowData<OrderWorkflow.OrderEditAddNewItemWorkflowInput>
): WorkflowResponse<OrderPreviewDTO> {
const order: OrderDTO = useRemoteQueryStep({
entry_point: "orders",
fields: ["id", "status", "canceled_at", "items.*"],
variables: { id: input.order_id },
list: false,
throw_if_key_not_found: true,
const orderResult = useQueryGraphStep({
entity: "order",
fields: fieldsToRefreshOrderEdit,
filters: { id: input.order_id },
options: {
throwIfKeyNotFound: true,
},
}).config({ name: "order-query" })
const orderChange: OrderChangeDTO = useRemoteQueryStep({
entry_point: "order_change",
fields: ["id", "status"],
variables: {
filters: {
order_id: input.order_id,
status: [OrderChangeStatus.PENDING, OrderChangeStatus.REQUESTED],
},
const order = transform({ orderResult }, ({ orderResult }) => {
return orderResult.data[0]
})
const orderChangeResult = useQueryGraphStep({
entity: "order_change",
fields: ["id", "status", "version", "actions.*"],
filters: {
order_id: input.order_id,
status: [OrderChangeStatus.PENDING, OrderChangeStatus.REQUESTED],
},
list: false,
}).config({ name: "order-change-query" })
const orderChange = transform(
{ orderChangeResult },
({ orderChangeResult }) => {
return orderChangeResult.data[0]
}
)
orderEditAddNewItemValidationStep({
order,
orderChange,
@@ -170,6 +184,12 @@ export const orderEditAddNewItemWorkflow = createWorkflow(
input: orderChangeActionInput,
})
refreshOrderEditAdjustmentsWorkflow.runAsStep({
input: {
order: order,
},
})
return new WorkflowResponse(previewOrderChangeStep(input.order_id))
}
)

View File

@@ -17,13 +17,15 @@ import {
createWorkflow,
transform,
} from "@medusajs/framework/workflows-sdk"
import { useRemoteQueryStep } from "../../../common"
import { useQueryGraphStep } from "../../../common"
import { previewOrderChangeStep } from "../../steps/preview-order-change"
import {
throwIfIsCancelled,
throwIfOrderChangeIsNotActive,
} from "../../utils/order-validation"
import { createOrderChangeActionsWorkflow } from "../create-order-change-actions"
import { refreshOrderEditAdjustmentsWorkflow } from "./refresh-order-edit-adjustments"
import { fieldsToRefreshOrderEdit } from "./utils/fields"
/**
* The data to validate that the quantity of an existing item in an order can be updated in an order edit.
@@ -42,14 +44,14 @@ export type OrderEditUpdateItemQuantityValidationStepInput = {
/**
* This step validates that the quantity of an existing item in an order can be updated in an order edit.
* If the order is canceled or the order change is not active, the step will throw an error.
*
*
* :::note
*
*
* You can retrieve an order and order change details using [Query](https://docs.medusajs.com/learn/fundamentals/module-links/query),
* or [useQueryGraphStep](https://docs.medusajs.com/resources/references/medusa-workflows/steps/useQueryGraphStep).
*
*
* :::
*
*
* @example
* const data = orderEditUpdateItemQuantityValidationStep({
* order: {
@@ -78,12 +80,12 @@ export const orderEditUpdateItemQuantityWorkflowId =
/**
* This workflow updates the quantity of an existing item in an order's edit. It's used by the
* [Update Order Item Quantity Admin API Route](https://docs.medusajs.com/api/admin#order-edits_postordereditsiditemsitemitem_id).
*
*
* You can also use this workflow to remove an item from an order by setting its quantity to `0`.
*
* You can use this workflow within your customizations or your own custom workflows, allowing you to update the quantity of an existing
*
* You can use this workflow within your customizations or your own custom workflows, allowing you to update the quantity of an existing
* item in an order's edit in your custom flow.
*
*
* @example
* const { result } = await orderEditUpdateItemQuantityWorkflow(container)
* .run({
@@ -97,9 +99,9 @@ export const orderEditUpdateItemQuantityWorkflowId =
* ]
* }
* })
*
*
* @summary
*
*
* Update or remove an existing order item's quantity in the order's edit.
*/
export const orderEditUpdateItemQuantityWorkflow = createWorkflow(
@@ -107,26 +109,35 @@ export const orderEditUpdateItemQuantityWorkflow = createWorkflow(
function (
input: WorkflowData<OrderWorkflow.OrderEditUpdateItemQuantityWorkflowInput>
): WorkflowResponse<OrderPreviewDTO> {
const order: OrderDTO = useRemoteQueryStep({
entry_point: "orders",
fields: ["id", "status", "canceled_at", "items.*"],
variables: { id: input.order_id },
list: false,
throw_if_key_not_found: true,
const orderResult = useQueryGraphStep({
entity: "order",
fields: fieldsToRefreshOrderEdit,
filters: { id: input.order_id },
options: {
throwIfKeyNotFound: true,
},
}).config({ name: "order-query" })
const orderChange: OrderChangeDTO = useRemoteQueryStep({
entry_point: "order_change",
fields: ["id", "status"],
variables: {
filters: {
order_id: input.order_id,
status: [OrderChangeStatus.PENDING, OrderChangeStatus.REQUESTED],
},
const order = transform({ orderResult }, ({ orderResult }) => {
return orderResult.data[0]
})
const orderChangeResult = useQueryGraphStep({
entity: "order_change",
fields: ["id", "status", "version", "actions.*"],
filters: {
order_id: input.order_id,
status: [OrderChangeStatus.PENDING, OrderChangeStatus.REQUESTED],
},
list: false,
}).config({ name: "order-change-query" })
const orderChange = transform(
{ orderChangeResult },
({ orderChangeResult }) => {
return orderChangeResult.data[0]
}
)
orderEditUpdateItemQuantityValidationStep({
order,
orderChange,
@@ -166,6 +177,12 @@ export const orderEditUpdateItemQuantityWorkflow = createWorkflow(
input: orderChangeActionInput,
})
refreshOrderEditAdjustmentsWorkflow.runAsStep({
input: {
order: order,
},
})
return new WorkflowResponse(previewOrderChangeStep(input.order_id))
}
)

View File

@@ -0,0 +1,79 @@
import { PromotionActions } from "@medusajs/framework/utils"
import {
createWorkflow,
transform,
WorkflowData,
WorkflowResponse,
} from "@medusajs/framework/workflows-sdk"
import {
ComputeActionItemLine,
OrderStatus,
PromotionDTO,
} from "@medusajs/types"
import {
refreshDraftOrderAdjustmentsWorkflow
} from "../../../draft-order/workflows/refresh-draft-order-adjustments"
import { previewOrderChangeStep } from "../../steps"
export const refreshOrderEditAdjustmentsWorkflowId =
"refresh-order-edit-adjustments"
/**
* The details of the order to refresh the adjustments for.
*/
export interface RefreshOrderEditAdjustmentsWorkflowInput {
/**
* The order edit to refresh the adjustments for.
*/
order: {
id: string
status: OrderStatus
currency_code: string
canceled_at?: string | Date
items: ComputeActionItemLine[]
promotions: PromotionDTO[]
}
}
export const refreshOrderEditAdjustmentsWorkflow = createWorkflow(
refreshOrderEditAdjustmentsWorkflowId,
function (input: WorkflowData<RefreshOrderEditAdjustmentsWorkflowInput>) {
const orderEditPromoCodes: string[] = transform({ input }, ({ input }) => {
return input.order.promotions
.map((p) => p?.code)
.filter(Boolean) as string[]
})
// we want the previewed order to contain updated promotions,
// so we fetch it to use it for refreshing adjustments
const orderPreview = previewOrderChangeStep(input.order.id).config({
name: "order-preview",
})
const orderToRefresh = transform(
{ input, orderPreview },
({ input, orderPreview }) => {
return {
...orderPreview,
items: orderPreview.items.map((item) => ({
...item,
// Buy-Get promotions rely on the product ID, so we need to manually set it before refreshing adjustments
product: { id: item.product_id },
})),
currency_code: input.order.currency_code,
promotions: input.order.promotions,
}
}
)
refreshDraftOrderAdjustmentsWorkflow.runAsStep({
input: {
order: orderToRefresh,
promo_codes: orderEditPromoCodes,
action: PromotionActions.REPLACE,
},
})
return new WorkflowResponse(void 0)
}
)

View File

@@ -5,14 +5,18 @@ import {
OrderPreviewDTO,
OrderWorkflow,
} from "@medusajs/framework/types"
import { ChangeActionType, OrderChangeStatus } from "@medusajs/framework/utils"
import {
ChangeActionType,
OrderChangeStatus
} from "@medusajs/framework/utils"
import {
WorkflowData,
WorkflowResponse,
createStep,
createWorkflow,
transform,
} from "@medusajs/framework/workflows-sdk"
import { useRemoteQueryStep } from "../../../common"
import { useQueryGraphStep } from "../../../common"
import {
deleteOrderChangeActionsStep,
previewOrderChangeStep,
@@ -21,6 +25,8 @@ import {
throwIfIsCancelled,
throwIfOrderChangeIsNotActive,
} from "../../utils/order-validation"
import { refreshOrderEditAdjustmentsWorkflow } from "./refresh-order-edit-adjustments"
import { fieldsToRefreshOrderEdit } from "./utils/fields"
/**
* The data to validate that an item that was added in an order edit can be removed.
@@ -41,17 +47,17 @@ export type RemoveOrderEditItemActionValidationStepInput = {
}
/**
* This step validates that an item that was added in the order edit can be removed
* This step validates that an item that was added in the order edit can be removed
* from the order edit. If the order is canceled or the order change is not active,
* the step will throw an error.
*
*
* :::note
*
*
* You can retrieve an order and order change details using [Query](https://docs.medusajs.com/learn/fundamentals/module-links/query),
* or [useQueryGraphStep](https://docs.medusajs.com/resources/references/medusa-workflows/steps/useQueryGraphStep).
*
*
* :::
*
*
* @example
* const data = removeOrderEditItemActionValidationStep({
* order: {
@@ -103,10 +109,10 @@ export const removeItemOrderEditActionWorkflowId =
/**
* This workflow removes an item that was added to an order edit. It's used by the
* [Remove Item from Order Edit Admin API Route](https://docs.medusajs.com/api/admin#order-edits_deleteordereditsiditemsaction_id).
*
* You can use this workflow within your customizations or your own custom workflows, allowing you to remove an item that was
*
* You can use this workflow within your customizations or your own custom workflows, allowing you to remove an item that was
* added to an order edit in your custom flow.
*
*
* @example
* const { result } = await removeItemOrderEditActionWorkflow(container)
* .run({
@@ -115,9 +121,9 @@ export const removeItemOrderEditActionWorkflowId =
* action_id: "orchact_123",
* }
* })
*
*
* @summary
*
*
* Remove an item that was added to an order edit.
*/
export const removeItemOrderEditActionWorkflow = createWorkflow(
@@ -125,26 +131,35 @@ export const removeItemOrderEditActionWorkflow = createWorkflow(
function (
input: WorkflowData<OrderWorkflow.DeleteOrderEditItemActionWorkflowInput>
): WorkflowResponse<OrderPreviewDTO> {
const order: OrderDTO = useRemoteQueryStep({
entry_point: "orders",
fields: ["id", "status", "canceled_at", "items.*"],
variables: { id: input.order_id },
list: false,
throw_if_key_not_found: true,
const orderResult = useQueryGraphStep({
entity: "order",
fields: fieldsToRefreshOrderEdit,
filters: { id: input.order_id },
options: {
throwIfKeyNotFound: true,
},
}).config({ name: "order-query" })
const orderChange: OrderChangeDTO = useRemoteQueryStep({
entry_point: "order_change",
const order = transform({ orderResult }, ({ orderResult }) => {
return orderResult.data[0]
})
const orderChangeResult = useQueryGraphStep({
entity: "order_change",
fields: ["id", "status", "version", "actions.*"],
variables: {
filters: {
order_id: input.order_id,
status: [OrderChangeStatus.PENDING, OrderChangeStatus.REQUESTED],
},
filters: {
order_id: input.order_id,
status: [OrderChangeStatus.PENDING, OrderChangeStatus.REQUESTED],
},
list: false,
}).config({ name: "order-change-query" })
const orderChange = transform(
{ orderChangeResult },
({ orderChangeResult }) => {
return orderChangeResult.data[0]
}
)
removeOrderEditItemActionValidationStep({
order,
input,
@@ -153,6 +168,12 @@ export const removeItemOrderEditActionWorkflow = createWorkflow(
deleteOrderChangeActionsStep({ ids: [input.action_id] })
refreshOrderEditAdjustmentsWorkflow.runAsStep({
input: {
order: order,
},
})
return new WorkflowResponse(previewOrderChangeStep(order.id))
}
)

View File

@@ -13,7 +13,7 @@ import {
parallelize,
transform,
} from "@medusajs/framework/workflows-sdk"
import { useRemoteQueryStep } from "../../../common"
import { useQueryGraphStep } from "../../../common"
import { deleteOrderShippingMethods } from "../../steps"
import { deleteOrderChangeActionsStep } from "../../steps/delete-order-change-actions"
import { previewOrderChangeStep } from "../../steps/preview-order-change"
@@ -30,21 +30,24 @@ export type RemoveOrderEditShippingMethodValidationStepInput = {
/**
* The details of the shipping method to be removed.
*/
input: Pick<OrderWorkflow.DeleteOrderEditShippingMethodWorkflowInput, "order_id" | "action_id">
input: Pick<
OrderWorkflow.DeleteOrderEditShippingMethodWorkflowInput,
"order_id" | "action_id"
>
}
/**
* This step validates that a shipping method can be removed from an order edit.
* If the order change is not active, the shipping method isn't in the exchange,
* or the action doesn't add a shipping method, the step will throw an error.
*
*
* :::note
*
*
* You can retrieve an order change details using [Query](https://docs.medusajs.com/learn/fundamentals/module-links/query),
* or [useQueryGraphStep](https://docs.medusajs.com/resources/references/medusa-workflows/steps/useQueryGraphStep).
*
*
* :::
*
*
* @example
* const data = removeOrderEditShippingMethodValidationStep({
* orderChange: {
@@ -84,12 +87,12 @@ export const removeOrderEditShippingMethodValidationStep = createStep(
export const removeOrderEditShippingMethodWorkflowId =
"remove-order-edit-shipping-method"
/**
* This workflow removes a shipping method of an order edit. It's used by the
* This workflow removes a shipping method of an order edit. It's used by the
* [Remove Shipping Method Admin API Route](https://docs.medusajs.com/api/admin#order-edits_deleteordereditsidshippingmethodaction_id).
*
* You can use this workflow within your customizations or your own custom workflows, allowing you to remove a
*
* You can use this workflow within your customizations or your own custom workflows, allowing you to remove a
* shipping method from an order edit in your custom flows.
*
*
* @example
* const { result } = await removeOrderEditShippingMethodWorkflow(container)
* .run({
@@ -98,9 +101,9 @@ export const removeOrderEditShippingMethodWorkflowId =
* action_id: "orchact_123",
* }
* })
*
*
* @summary
*
*
* Remove a shipping method from an order edit.
*/
export const removeOrderEditShippingMethodWorkflow = createWorkflow(
@@ -108,18 +111,22 @@ export const removeOrderEditShippingMethodWorkflow = createWorkflow(
function (
input: WorkflowData<OrderWorkflow.DeleteOrderEditShippingMethodWorkflowInput>
): WorkflowResponse<OrderPreviewDTO> {
const orderChange: OrderChangeDTO = useRemoteQueryStep({
entry_point: "order_change",
const orderChangeResult = useQueryGraphStep({
entity: "order_change",
fields: ["id", "status", "version", "actions.*"],
variables: {
filters: {
order_id: input.order_id,
status: [OrderChangeStatus.PENDING, OrderChangeStatus.REQUESTED],
},
filters: {
order_id: input.order_id,
status: [OrderChangeStatus.PENDING, OrderChangeStatus.REQUESTED],
},
list: false,
}).config({ name: "order-change-query" })
const orderChange = transform(
{ orderChangeResult },
({ orderChangeResult }) => {
return orderChangeResult.data[0]
}
)
removeOrderEditShippingMethodValidationStep({
orderChange,
input,

View File

@@ -13,13 +13,15 @@ import {
createWorkflow,
transform,
} from "@medusajs/framework/workflows-sdk"
import { emitEventStep, useRemoteQueryStep } from "../../../common"
import { emitEventStep, useQueryGraphStep } from "../../../common"
import { previewOrderChangeStep } from "../../steps"
import { updateOrderChangesStep } from "../../steps/update-order-changes"
import {
throwIfIsCancelled,
throwIfOrderChangeIsNotActive,
} from "../../utils/order-validation"
import { refreshOrderEditAdjustmentsWorkflow } from "./refresh-order-edit-adjustments"
import { fieldsToRefreshOrderEdit } from "./utils/fields"
function getOrderChangesData({
input,
@@ -127,26 +129,35 @@ export const requestOrderEditRequestWorkflow = createWorkflow(
function (
input: OrderEditRequestWorkflowInput
): WorkflowResponse<OrderPreviewDTO> {
const order: OrderDTO = useRemoteQueryStep({
entry_point: "orders",
fields: ["id", "version", "canceled_at"],
variables: { id: input.order_id },
list: false,
throw_if_key_not_found: true,
const orderResult = useQueryGraphStep({
entity: "order",
fields: fieldsToRefreshOrderEdit,
filters: { id: input.order_id },
options: {
throwIfKeyNotFound: true,
},
}).config({ name: "order-query" })
const orderChange: OrderChangeDTO = useRemoteQueryStep({
entry_point: "order_change",
fields: ["id", "canceled_at", "actions.*"],
variables: {
filters: {
order_id: input.order_id,
status: [OrderChangeStatus.PENDING, OrderChangeStatus.REQUESTED],
},
const order = transform({ orderResult }, ({ orderResult }) => {
return orderResult.data[0]
})
const orderChangeResult = useQueryGraphStep({
entity: "order_change",
fields: ["id", "status", "version", "actions.*"],
filters: {
order_id: input.order_id,
status: [OrderChangeStatus.PENDING, OrderChangeStatus.REQUESTED],
},
list: false,
}).config({ name: "order-change-query" })
const orderChange = transform(
{ orderChangeResult },
({ orderChangeResult }) => {
return orderChangeResult.data[0]
}
)
requestOrderEditRequestValidationStep({
order,
orderChange,
@@ -165,6 +176,12 @@ export const requestOrderEditRequestWorkflow = createWorkflow(
}
)
refreshOrderEditAdjustmentsWorkflow.runAsStep({
input: {
order: order,
},
})
emitEventStep({
eventName: OrderEditWorkflowEvents.REQUESTED,
data: eventData,

View File

@@ -13,7 +13,7 @@ import {
createWorkflow,
transform,
} from "@medusajs/framework/workflows-sdk"
import { useRemoteQueryStep } from "../../../common"
import { useQueryGraphStep } from "../../../common"
import {
previewOrderChangeStep,
updateOrderChangeActionsStep,
@@ -22,6 +22,8 @@ import {
throwIfIsCancelled,
throwIfOrderChangeIsNotActive,
} from "../../utils/order-validation"
import { refreshOrderEditAdjustmentsWorkflow } from "./refresh-order-edit-adjustments"
import { fieldsToRefreshOrderEdit } from "./utils/fields"
/**
* The data to validate that a new item can be updated in an order edit.
@@ -43,17 +45,17 @@ export type UpdateOrderEditAddItemValidationStepInput = {
/**
* This step validates that a new item can be updated in an order edit.
* If the order is canceled, the order change is not active,
* If the order is canceled, the order change is not active,
* the item isn't in the order edit, or the action isn't adding an item,
* the step will throw an error.
*
*
* :::note
*
*
* You can retrieve an order and order change details using [Query](https://docs.medusajs.com/learn/fundamentals/module-links/query),
* or [useQueryGraphStep](https://docs.medusajs.com/resources/references/medusa-workflows/steps/useQueryGraphStep).
*
*
* :::
*
*
* @example
* const data = updateOrderEditAddItemValidationStep({
* order: {
@@ -76,11 +78,7 @@ export type UpdateOrderEditAddItemValidationStepInput = {
export const updateOrderEditAddItemValidationStep = createStep(
"update-order-edit-add-item-validation",
async function (
{
order,
orderChange,
input,
}: UpdateOrderEditAddItemValidationStepInput,
{ order, orderChange, input }: UpdateOrderEditAddItemValidationStepInput,
context
) {
throwIfIsCancelled(order, "Order")
@@ -104,10 +102,10 @@ export const updateOrderEditAddItemWorkflowId = "update-order-edit-add-item"
/**
* This workflow updates a new item in an order edit. It's used by the
* [Update Item Admin API Route](https://docs.medusajs.com/api/admin#order-edits_postordereditsiditemsaction_id).
*
*
* You can use this workflow within your customizations or your own custom workflows, allowing you to update a new item in an order edit
* in your custom flows.
*
*
* @example
* const { result } = await updateOrderEditAddItemWorkflow(container)
* .run({
@@ -119,9 +117,9 @@ export const updateOrderEditAddItemWorkflowId = "update-order-edit-add-item"
* }
* }
* })
*
*
* @summary
*
*
* Update a new item in an order edit.
*/
export const updateOrderEditAddItemWorkflow = createWorkflow(
@@ -129,26 +127,35 @@ export const updateOrderEditAddItemWorkflow = createWorkflow(
function (
input: WorkflowData<OrderWorkflow.UpdateOrderEditAddNewItemWorkflowInput>
): WorkflowResponse<OrderPreviewDTO> {
const order: OrderDTO = useRemoteQueryStep({
entry_point: "orders",
fields: ["id", "status", "canceled_at", "items.*"],
variables: { id: input.order_id },
list: false,
throw_if_key_not_found: true,
const orderResult = useQueryGraphStep({
entity: "order",
fields: fieldsToRefreshOrderEdit,
filters: { id: input.order_id },
options: {
throwIfKeyNotFound: true,
},
}).config({ name: "order-query" })
const orderChange: OrderChangeDTO = useRemoteQueryStep({
entry_point: "order_change",
const order = transform({ orderResult }, ({ orderResult }) => {
return orderResult.data[0]
})
const orderChangeResult = useQueryGraphStep({
entity: "order_change",
fields: ["id", "status", "version", "actions.*"],
variables: {
filters: {
order_id: input.order_id,
status: [OrderChangeStatus.PENDING, OrderChangeStatus.REQUESTED],
},
filters: {
order_id: input.order_id,
status: [OrderChangeStatus.PENDING, OrderChangeStatus.REQUESTED],
},
list: false,
}).config({ name: "order-change-query" })
const orderChange = transform(
{ orderChangeResult },
({ orderChangeResult }) => {
return orderChangeResult.data[0]
}
)
updateOrderEditAddItemValidationStep({
order,
input,
@@ -179,6 +186,12 @@ export const updateOrderEditAddItemWorkflow = createWorkflow(
updateOrderChangeActionsStep([updateData])
refreshOrderEditAdjustmentsWorkflow.runAsStep({
input: {
order: order,
},
})
return new WorkflowResponse(previewOrderChangeStep(order.id))
}
)

View File

@@ -13,7 +13,7 @@ import {
createWorkflow,
transform,
} from "@medusajs/framework/workflows-sdk"
import { useRemoteQueryStep } from "../../../common"
import { useQueryGraphStep } from "../../../common"
import {
previewOrderChangeStep,
updateOrderChangeActionsStep,
@@ -22,6 +22,8 @@ import {
throwIfIsCancelled,
throwIfOrderChangeIsNotActive,
} from "../../utils/order-validation"
import { refreshOrderEditAdjustmentsWorkflow } from "./refresh-order-edit-adjustments"
import { fieldsToRefreshOrderEdit } from "./utils/fields"
/**
* The data to validate that an existing order item can be updated in an order edit.
@@ -46,14 +48,14 @@ export type UpdateOrderEditItemQuantityValidationStepInput = {
* If the order is canceled, the order change is not active,
* the item isn't in the order edit, or the action isn't updating an existing item,
* the step will throw an error.
*
*
* :::note
*
*
* You can retrieve an order and order change details using [Query](https://docs.medusajs.com/learn/fundamentals/module-links/query),
* or [useQueryGraphStep](https://docs.medusajs.com/resources/references/medusa-workflows/steps/useQueryGraphStep).
*
*
* :::
*
*
* @example
* const data = updateOrderEditItemQuantityValidationStep({
* order: {
@@ -104,10 +106,10 @@ export const updateOrderEditItemQuantityWorkflowId =
"update-order-edit-update-quantity"
/**
* This workflow updates an existing order item that was previously added to the order edit.
*
* You can use this workflow within your customizations or your own custom workflows, allowing you to update the quantity
*
* You can use this workflow within your customizations or your own custom workflows, allowing you to update the quantity
* of an existing item in an order edit in your custom flows.
*
*
* @example
* const { result } = await updateOrderEditItemQuantityWorkflow(container)
* .run({
@@ -119,9 +121,9 @@ export const updateOrderEditItemQuantityWorkflowId =
* }
* }
* })
*
*
* @summary
*
*
* Update an existing order item previously added to an order edit.
*/
export const updateOrderEditItemQuantityWorkflow = createWorkflow(
@@ -129,26 +131,35 @@ export const updateOrderEditItemQuantityWorkflow = createWorkflow(
function (
input: WorkflowData<OrderWorkflow.UpdateOrderEditItemQuantityWorkflowInput>
): WorkflowResponse<OrderPreviewDTO> {
const order: OrderDTO = useRemoteQueryStep({
entry_point: "orders",
fields: ["id", "status", "canceled_at", "items.*"],
variables: { id: input.order_id },
list: false,
throw_if_key_not_found: true,
const orderResult = useQueryGraphStep({
entity: "order",
fields: fieldsToRefreshOrderEdit,
filters: { id: input.order_id },
options: {
throwIfKeyNotFound: true,
},
}).config({ name: "order-query" })
const orderChange: OrderChangeDTO = useRemoteQueryStep({
entry_point: "order_change",
const order = transform({ orderResult }, ({ orderResult }) => {
return orderResult.data[0]
})
const orderChangeResult = useQueryGraphStep({
entity: "order_change",
fields: ["id", "status", "version", "actions.*"],
variables: {
filters: {
order_id: input.order_id,
status: [OrderChangeStatus.PENDING, OrderChangeStatus.REQUESTED],
},
filters: {
order_id: input.order_id,
status: [OrderChangeStatus.PENDING, OrderChangeStatus.REQUESTED],
},
list: false,
}).config({ name: "order-change-query" })
const orderChange = transform(
{ orderChangeResult },
({ orderChangeResult }) => {
return orderChangeResult.data[0]
}
)
updateOrderEditItemQuantityValidationStep({
order,
input,
@@ -175,6 +186,12 @@ export const updateOrderEditItemQuantityWorkflow = createWorkflow(
updateOrderChangeActionsStep([updateData])
refreshOrderEditAdjustmentsWorkflow.runAsStep({
input: {
order: order,
},
})
return new WorkflowResponse(previewOrderChangeStep(order.id))
}
)

View File

@@ -2,7 +2,6 @@ import {
AdditionalData,
OrderChangeActionDTO,
OrderChangeDTO,
OrderDTO,
OrderPreviewDTO,
OrderWorkflow,
} from "@medusajs/framework/types"
@@ -17,7 +16,8 @@ import {
transform,
when,
} from "@medusajs/framework/workflows-sdk"
import { useRemoteQueryStep } from "../../../common"
import { pricingContextResult } from "../../../cart/utils/schemas"
import { useQueryGraphStep, useRemoteQueryStep } from "../../../common"
import {
updateOrderChangeActionsStep,
updateOrderShippingMethodsStep,
@@ -25,7 +25,7 @@ import {
import { previewOrderChangeStep } from "../../steps/preview-order-change"
import { throwIfOrderChangeIsNotActive } from "../../utils/order-validation"
import { prepareShippingMethodUpdate } from "../../utils/prepare-shipping-method"
import { pricingContextResult } from "../../../cart/utils/schemas"
import { fieldsToRefreshOrderEdit } from "./utils/fields"
/**
* The data to validate that an order edit's shipping method can be updated.
@@ -119,11 +119,11 @@ export const updateOrderEditShippingMethodWorkflowId =
* @summary
*
* Update a shipping method of an order edit.
*
*
* @property hooks.setPricingContext - This hook is executed before the shipping method's option is retrieved. You can consume this hook to return any custom context useful for the prices retrieval of shipping method's option.
*
*
* For example, assuming you have the following custom pricing rule:
*
*
* ```json
* {
* "attribute": "location_id",
@@ -131,13 +131,13 @@ export const updateOrderEditShippingMethodWorkflowId =
* "value": "sloc_123",
* }
* ```
*
*
* You can consume the `setPricingContext` hook to add the `location_id` context to the prices calculation:
*
*
* ```ts
* import { updateOrderEditShippingMethodWorkflow } from "@medusajs/medusa/core-flows";
* import { StepResponse } from "@medusajs/workflows-sdk";
*
*
* updateOrderEditShippingMethodWorkflow.hooks.setPricingContext((
* { order, order_change, additional_data }, { container }
* ) => {
@@ -146,13 +146,13 @@ export const updateOrderEditShippingMethodWorkflowId =
* });
* });
* ```
*
*
* The price of the shipping method's option will now be retrieved using the context you return.
*
*
* :::note
*
*
* Learn more about prices calculation context in the [Prices Calculation](https://docs.medusajs.com/resources/commerce-modules/pricing/price-calculation) documentation.
*
*
* :::
*/
export const updateOrderEditShippingMethodWorkflow = createWorkflow(
@@ -162,26 +162,35 @@ export const updateOrderEditShippingMethodWorkflow = createWorkflow(
OrderWorkflow.UpdateOrderEditShippingMethodWorkflowInput & AdditionalData
>
) {
const order: OrderDTO = useRemoteQueryStep({
entry_point: "order_claim",
fields: ["id", "currency_code"],
variables: { id: input.order_id },
list: false,
throw_if_key_not_found: true,
const orderResult = useQueryGraphStep({
entity: "order",
fields: fieldsToRefreshOrderEdit,
filters: { id: input.order_id },
options: {
throwIfKeyNotFound: true,
},
}).config({ name: "order-query" })
const order = transform({ orderResult }, ({ orderResult }) => {
return orderResult.data[0]
})
const orderChange: OrderChangeDTO = useRemoteQueryStep({
entry_point: "order_change",
const orderChangeResult = useQueryGraphStep({
entity: "order_change",
fields: ["id", "status", "version", "actions.*"],
variables: {
filters: {
order_id: input.order_id,
status: [OrderChangeStatus.PENDING, OrderChangeStatus.REQUESTED],
},
filters: {
order_id: input.order_id,
status: [OrderChangeStatus.PENDING, OrderChangeStatus.REQUESTED],
},
list: false,
}).config({ name: "order-change-query" })
const orderChange = transform(
{ orderChangeResult },
({ orderChangeResult }) => {
return orderChangeResult.data[0]
}
)
const setPricingContext = createHook(
"setPricingContext",
{

View File

@@ -0,0 +1,11 @@
export const fieldsToRefreshOrderEdit = [
"id",
"status",
"version",
"currency_code",
"canceled_at",
"items.*",
"items.product.id",
"promotions.*",
"shipping_address.*",
]