From accf884bb1706cb383993e08f7bed3f94a0d366e Mon Sep 17 00:00:00 2001 From: "Carlos R. L. Rodrigues" <37986729+carlos-r-l-rodrigues@users.noreply.github.com> Date: Thu, 1 Aug 2024 07:27:06 -0300 Subject: [PATCH] chore(core-flows): Order Exchange - initial workflows (#8374) PR: 1:n This is the first PR with a initial skeleton for Order exchange workflows. This is not yet to be considered functional or reflecting the exact behavior of Order Exchanges. What: * organize folder structure of order-related steps and workflows * initial worklows for Order exchange - This first draft is just a copy of Claims behavior --- .../create-exchange-return-shipping.spec.ts | 125 ------ .../order/steps/{ => claim}/cancel-claim.ts | 0 .../create-claim-items-from-actions.ts | 0 .../order/steps/{ => claim}/create-claims.ts | 0 .../order/steps/{ => claim}/delete-claims.ts | 0 .../steps/{ => claim}/update-order-claims.ts | 0 .../steps/{ => exchange}/cancel-exchange.ts | 0 .../create-exchange-items-from-actions.ts | 50 +++ .../create-exchange.ts} | 0 .../order/steps/exchange/delete-exchanges.ts | 28 ++ .../steps/exchange/update-order-exchanges.ts | 55 +++ .../core/core-flows/src/order/steps/index.ts | 26 +- .../order/steps/{ => return}/cancel-return.ts | 0 .../{ => return}/create-complete-return.ts | 0 .../create-return-items-from-actions.ts | 0 .../steps/{ => return}/create-returns.ts | 0 .../steps/{ => return}/delete-returns.ts | 0 .../steps/{ => return}/receive-return.ts | 0 .../steps/{ => return}/update-return-items.ts | 0 .../steps/{ => return}/update-returns.ts | 0 .../workflows/claim/begin-order-claim.ts | 2 +- .../claim/claim-request-item-return.ts | 4 +- .../workflows/claim/confirm-claim-request.ts | 5 +- .../exchange/begin-order-exchange.ts | 2 +- .../exchange/cancel-begin-order-exchange.ts | 94 +++++ .../workflows/exchange/cancel-exchange.ts | 82 ++++ .../exchange/confirm-exchange-request.ts | 361 ++++++++++++++++++ ....ts => create-exchange-shipping-method.ts} | 139 ++++--- .../exchange/exchange-add-new-item.ts | 5 +- .../exchange/exchange-request-item-return.ts | 17 +- .../remove-exchange-shipping-method.ts | 107 ++++++ .../exchange/update-exchange-add-item.ts | 119 ++++++ .../update-exchange-shipping-method.ts | 122 ++++++ .../core-flows/src/order/workflows/index.ts | 8 +- .../return/confirm-return-request.ts | 3 +- .../return/create-complete-return.ts | 4 +- .../return/receive-complete-return.ts | 2 +- .../core/types/src/workflow/order/items.ts | 19 + 38 files changed, 1156 insertions(+), 223 deletions(-) delete mode 100644 integration-tests/modules/__tests__/order/workflows/return/create-exchange-return-shipping.spec.ts rename packages/core/core-flows/src/order/steps/{ => claim}/cancel-claim.ts (100%) rename packages/core/core-flows/src/order/steps/{ => claim}/create-claim-items-from-actions.ts (100%) rename packages/core/core-flows/src/order/steps/{ => claim}/create-claims.ts (100%) rename packages/core/core-flows/src/order/steps/{ => claim}/delete-claims.ts (100%) rename packages/core/core-flows/src/order/steps/{ => claim}/update-order-claims.ts (100%) rename packages/core/core-flows/src/order/steps/{ => exchange}/cancel-exchange.ts (100%) create mode 100644 packages/core/core-flows/src/order/steps/exchange/create-exchange-items-from-actions.ts rename packages/core/core-flows/src/order/steps/{create-exchanges.ts => exchange/create-exchange.ts} (100%) create mode 100644 packages/core/core-flows/src/order/steps/exchange/delete-exchanges.ts create mode 100644 packages/core/core-flows/src/order/steps/exchange/update-order-exchanges.ts rename packages/core/core-flows/src/order/steps/{ => return}/cancel-return.ts (100%) rename packages/core/core-flows/src/order/steps/{ => return}/create-complete-return.ts (100%) rename packages/core/core-flows/src/order/steps/{ => return}/create-return-items-from-actions.ts (100%) rename packages/core/core-flows/src/order/steps/{ => return}/create-returns.ts (100%) rename packages/core/core-flows/src/order/steps/{ => return}/delete-returns.ts (100%) rename packages/core/core-flows/src/order/steps/{ => return}/receive-return.ts (100%) rename packages/core/core-flows/src/order/steps/{ => return}/update-return-items.ts (100%) rename packages/core/core-flows/src/order/steps/{ => return}/update-returns.ts (100%) create mode 100644 packages/core/core-flows/src/order/workflows/exchange/cancel-begin-order-exchange.ts create mode 100644 packages/core/core-flows/src/order/workflows/exchange/cancel-exchange.ts create mode 100644 packages/core/core-flows/src/order/workflows/exchange/confirm-exchange-request.ts rename packages/core/core-flows/src/order/workflows/exchange/{create-exchange-return-shipping-method.ts => create-exchange-shipping-method.ts} (60%) create mode 100644 packages/core/core-flows/src/order/workflows/exchange/remove-exchange-shipping-method.ts create mode 100644 packages/core/core-flows/src/order/workflows/exchange/update-exchange-add-item.ts create mode 100644 packages/core/core-flows/src/order/workflows/exchange/update-exchange-shipping-method.ts diff --git a/integration-tests/modules/__tests__/order/workflows/return/create-exchange-return-shipping.spec.ts b/integration-tests/modules/__tests__/order/workflows/return/create-exchange-return-shipping.spec.ts deleted file mode 100644 index dc3ed435e9..0000000000 --- a/integration-tests/modules/__tests__/order/workflows/return/create-exchange-return-shipping.spec.ts +++ /dev/null @@ -1,125 +0,0 @@ -import { - beginExchangeOrderWorkflow, - createExchangeReturnShippingMethodWorkflow, -} from "@medusajs/core-flows" -import { OrderDTO, OrderExchangeDTO } from "@medusajs/types" -import { - ContainerRegistrationKeys, - remoteQueryObjectFromString, -} from "@medusajs/utils" -import { medusaIntegrationTestRunner } from "medusa-test-utils" -import { createOrderFixture, prepareDataFixtures } from "../__fixtures__" - -jest.setTimeout(50000) - -medusaIntegrationTestRunner({ - env: { MEDUSA_FF_MEDUSA_V2: true }, - testSuite: ({ getContainer }) => { - let container - - beforeAll(() => { - container = getContainer() - }) - - describe("Order change: Create exchange return shipping", () => { - let order: OrderDTO - let fixtures - - let exchangeOrder: OrderExchangeDTO - - beforeEach(async () => { - fixtures = await prepareDataFixtures({ container }) - order = await createOrderFixture({ - container, - product: fixtures.product, - location: fixtures.location, - inventoryItem: fixtures.inventoryItem, - }) - - await beginExchangeOrderWorkflow(container).run({ - input: { order_id: order.id }, - throwOnError: true, - }) - - const remoteQuery = container.resolve( - ContainerRegistrationKeys.REMOTE_QUERY - ) - - const remoteQueryObject = remoteQueryObjectFromString({ - entryPoint: "order_exchange", - variables: { order_id: order.id }, - fields: ["order_id", "id", "status", "order_change_id", "return_id"], - }) - - ;[exchangeOrder] = await remoteQuery(remoteQueryObject) - }) - - describe("createExchangeReturnShippingMethodWorkflow", () => { - it("should successfully add exchange return shipping to order changes", async () => { - const shippingOptionId = fixtures.shippingOption.id - - const { result } = await createExchangeReturnShippingMethodWorkflow( - container - ).run({ - input: { - exchangeId: exchangeOrder.id, - shippingOptionId: shippingOptionId, - }, - }) - - const orderChange = result?.[0] - - expect(orderChange).toEqual( - expect.objectContaining({ - id: expect.any(String), - reference: "order_shipping_method", - reference_id: expect.any(String), - details: { - exchange_id: exchangeOrder.id, - order_id: exchangeOrder.order_id, - return_id: exchangeOrder.return_id, - }, - raw_amount: { value: "10", precision: 20 }, - applied: false, - action: "SHIPPING_ADD", - amount: 10, - }) - ) - }) - - it("should successfully add return shipping with custom price to order changes", async () => { - const shippingOptionId = fixtures.shippingOption.id - - const { result } = await createExchangeReturnShippingMethodWorkflow( - container - ).run({ - input: { - exchangeId: exchangeOrder.id, - shippingOptionId: shippingOptionId, - customShippingPrice: 20, - }, - }) - - const orderChange = result?.[0] - - expect(orderChange).toEqual( - expect.objectContaining({ - id: expect.any(String), - reference: "order_shipping_method", - reference_id: expect.any(String), - details: { - exchange_id: exchangeOrder.id, - order_id: exchangeOrder.order_id, - return_id: exchangeOrder.return_id, - }, - raw_amount: { value: "20", precision: 20 }, - applied: false, - action: "SHIPPING_ADD", - amount: 20, - }) - ) - }) - }) - }) - }, -}) diff --git a/packages/core/core-flows/src/order/steps/cancel-claim.ts b/packages/core/core-flows/src/order/steps/claim/cancel-claim.ts similarity index 100% rename from packages/core/core-flows/src/order/steps/cancel-claim.ts rename to packages/core/core-flows/src/order/steps/claim/cancel-claim.ts diff --git a/packages/core/core-flows/src/order/steps/create-claim-items-from-actions.ts b/packages/core/core-flows/src/order/steps/claim/create-claim-items-from-actions.ts similarity index 100% rename from packages/core/core-flows/src/order/steps/create-claim-items-from-actions.ts rename to packages/core/core-flows/src/order/steps/claim/create-claim-items-from-actions.ts diff --git a/packages/core/core-flows/src/order/steps/create-claims.ts b/packages/core/core-flows/src/order/steps/claim/create-claims.ts similarity index 100% rename from packages/core/core-flows/src/order/steps/create-claims.ts rename to packages/core/core-flows/src/order/steps/claim/create-claims.ts diff --git a/packages/core/core-flows/src/order/steps/delete-claims.ts b/packages/core/core-flows/src/order/steps/claim/delete-claims.ts similarity index 100% rename from packages/core/core-flows/src/order/steps/delete-claims.ts rename to packages/core/core-flows/src/order/steps/claim/delete-claims.ts diff --git a/packages/core/core-flows/src/order/steps/update-order-claims.ts b/packages/core/core-flows/src/order/steps/claim/update-order-claims.ts similarity index 100% rename from packages/core/core-flows/src/order/steps/update-order-claims.ts rename to packages/core/core-flows/src/order/steps/claim/update-order-claims.ts diff --git a/packages/core/core-flows/src/order/steps/cancel-exchange.ts b/packages/core/core-flows/src/order/steps/exchange/cancel-exchange.ts similarity index 100% rename from packages/core/core-flows/src/order/steps/cancel-exchange.ts rename to packages/core/core-flows/src/order/steps/exchange/cancel-exchange.ts diff --git a/packages/core/core-flows/src/order/steps/exchange/create-exchange-items-from-actions.ts b/packages/core/core-flows/src/order/steps/exchange/create-exchange-items-from-actions.ts new file mode 100644 index 0000000000..e451833c23 --- /dev/null +++ b/packages/core/core-flows/src/order/steps/exchange/create-exchange-items-from-actions.ts @@ -0,0 +1,50 @@ +import { + CreateOrderExchangeItemDTO, + IOrderModuleService, + OrderChangeActionDTO, +} from "@medusajs/types" +import { ModuleRegistrationName } from "@medusajs/utils" +import { StepResponse, createStep } from "@medusajs/workflows-sdk" + +type CreateOrderExchangeItemsFromActionsInput = { + changes: OrderChangeActionDTO[] + exchangeId: string +} + +export const createOrderExchangeItemsFromActionsStep = createStep( + "create-exchange-items-from-change-actions", + async (input: CreateOrderExchangeItemsFromActionsInput, { container }) => { + const orderModuleService = container.resolve( + ModuleRegistrationName.ORDER + ) + + const exchangeItems = input.changes.map((item) => { + return { + exchange_id: input.exchangeId, + item_id: item.details?.reference_id! as string, + quantity: item.details?.quantity as number, + note: item.internal_note, + metadata: (item.details?.metadata as Record) ?? {}, + } + }) as CreateOrderExchangeItemDTO[] + + const createdExchangeItems = + await orderModuleService.createOrderExchangeItems(exchangeItems) + + return new StepResponse( + createdExchangeItems, + createdExchangeItems.map((i) => i.id) + ) + }, + async (ids, { container }) => { + if (!ids) { + return + } + + const orderModuleService = container.resolve( + ModuleRegistrationName.ORDER + ) + + await orderModuleService.deleteOrderExchangeItems(ids) + } +) diff --git a/packages/core/core-flows/src/order/steps/create-exchanges.ts b/packages/core/core-flows/src/order/steps/exchange/create-exchange.ts similarity index 100% rename from packages/core/core-flows/src/order/steps/create-exchanges.ts rename to packages/core/core-flows/src/order/steps/exchange/create-exchange.ts diff --git a/packages/core/core-flows/src/order/steps/exchange/delete-exchanges.ts b/packages/core/core-flows/src/order/steps/exchange/delete-exchanges.ts new file mode 100644 index 0000000000..353dd26a89 --- /dev/null +++ b/packages/core/core-flows/src/order/steps/exchange/delete-exchanges.ts @@ -0,0 +1,28 @@ +import { IOrderModuleService } from "@medusajs/types" +import { ModuleRegistrationName } from "@medusajs/utils" +import { createStep, StepResponse } from "@medusajs/workflows-sdk" + +export const deleteExchangesStepId = "delete-exchanges" +export const deleteExchangesStep = createStep( + deleteExchangesStepId, + async (data: { ids: string[] }, { container }) => { + const service = container.resolve( + ModuleRegistrationName.ORDER + ) + + const deleted = await service.softDeleteOrderExchanges(data.ids) + + return new StepResponse(deleted, data.ids) + }, + async (ids, { container }) => { + if (!ids) { + return + } + + const service = container.resolve( + ModuleRegistrationName.ORDER + ) + + await service.restoreOrderExchanges(ids) + } +) diff --git a/packages/core/core-flows/src/order/steps/exchange/update-order-exchanges.ts b/packages/core/core-flows/src/order/steps/exchange/update-order-exchanges.ts new file mode 100644 index 0000000000..b949b5d860 --- /dev/null +++ b/packages/core/core-flows/src/order/steps/exchange/update-order-exchanges.ts @@ -0,0 +1,55 @@ +import { IOrderModuleService, UpdateOrderExchangeDTO } from "@medusajs/types" +import { + ModuleRegistrationName, + getSelectsAndRelationsFromObjectArray, +} from "@medusajs/utils" +import { StepResponse, createStep } from "@medusajs/workflows-sdk" + +export const updateOrderExchangesStepId = "update-order-exchange" +export const updateOrderExchangesStep = createStep( + updateOrderExchangesStepId, + async (data: UpdateOrderExchangeDTO[], { container }) => { + const service = container.resolve( + ModuleRegistrationName.ORDER + ) + + const { selects, relations } = getSelectsAndRelationsFromObjectArray(data, { + objectFields: ["metadata"], + }) + const dataBeforeUpdate = await service.listOrderExchanges( + { id: data.map((d) => d.id) }, + { relations, select: selects } + ) + + const updated = await service.updateOrderExchanges( + data.map((dt) => { + const { id, ...rest } = dt + return { + selector: { id }, + data: rest, + } + }) + ) + + return new StepResponse(updated, dataBeforeUpdate) + }, + async (dataBeforeUpdate, { container }) => { + if (!dataBeforeUpdate?.length) { + return + } + + const service = container.resolve( + ModuleRegistrationName.ORDER + ) + + await service.updateOrderExchanges( + dataBeforeUpdate.map((dt) => { + const { id, ...rest } = dt + return { + selector: { id }, + data: rest, + } + }) + ) + } +) diff --git a/packages/core/core-flows/src/order/steps/index.ts b/packages/core/core-flows/src/order/steps/index.ts index 68254d28a9..38fa3a6589 100644 --- a/packages/core/core-flows/src/order/steps/index.ts +++ b/packages/core/core-flows/src/order/steps/index.ts @@ -1,34 +1,36 @@ export * from "./archive-orders" -export * from "./cancel-claim" -export * from "./cancel-exchange" export * from "./cancel-order-change" export * from "./cancel-orders" -export * from "./cancel-return" +export * from "./claim/cancel-claim" +export * from "./claim/create-claim-items-from-actions" +export * from "./claim/create-claims" +export * from "./claim/delete-claims" export * from "./complete-orders" -export * from "./create-claim-items-from-actions" -export * from "./create-claims" -export * from "./create-complete-return" -export * from "./create-exchanges" export * from "./create-line-items" export * from "./create-order-change" export * from "./create-order-change-actions" export * from "./create-orders" -export * from "./create-returns" export * from "./decline-order-change" -export * from "./delete-claims" export * from "./delete-line-items" export * from "./delete-order-change-actions" export * from "./delete-order-changes" export * from "./delete-order-shipping-methods" -export * from "./delete-returns" +export * from "./exchange/cancel-exchange" +export * from "./exchange/create-exchange" +export * from "./exchange/create-exchange-items-from-actions" +export * from "./exchange/delete-exchanges" export * from "./get-item-tax-lines" export * from "./preview-order-change" export * from "./register-fulfillment" export * from "./register-shipment" +export * from "./return/cancel-return" +export * from "./return/create-complete-return" +export * from "./return/create-returns" +export * from "./return/delete-returns" +export * from "./return/update-return-items" +export * from "./return/update-returns" export * from "./set-tax-lines-for-items" export * from "./update-order-change-actions" export * from "./update-order-exchanges" -export * from "./update-return-items" -export * from "./update-returns" export * from "./update-shipping-methods" export * from "./update-tax-lines" diff --git a/packages/core/core-flows/src/order/steps/cancel-return.ts b/packages/core/core-flows/src/order/steps/return/cancel-return.ts similarity index 100% rename from packages/core/core-flows/src/order/steps/cancel-return.ts rename to packages/core/core-flows/src/order/steps/return/cancel-return.ts diff --git a/packages/core/core-flows/src/order/steps/create-complete-return.ts b/packages/core/core-flows/src/order/steps/return/create-complete-return.ts similarity index 100% rename from packages/core/core-flows/src/order/steps/create-complete-return.ts rename to packages/core/core-flows/src/order/steps/return/create-complete-return.ts diff --git a/packages/core/core-flows/src/order/steps/create-return-items-from-actions.ts b/packages/core/core-flows/src/order/steps/return/create-return-items-from-actions.ts similarity index 100% rename from packages/core/core-flows/src/order/steps/create-return-items-from-actions.ts rename to packages/core/core-flows/src/order/steps/return/create-return-items-from-actions.ts diff --git a/packages/core/core-flows/src/order/steps/create-returns.ts b/packages/core/core-flows/src/order/steps/return/create-returns.ts similarity index 100% rename from packages/core/core-flows/src/order/steps/create-returns.ts rename to packages/core/core-flows/src/order/steps/return/create-returns.ts diff --git a/packages/core/core-flows/src/order/steps/delete-returns.ts b/packages/core/core-flows/src/order/steps/return/delete-returns.ts similarity index 100% rename from packages/core/core-flows/src/order/steps/delete-returns.ts rename to packages/core/core-flows/src/order/steps/return/delete-returns.ts diff --git a/packages/core/core-flows/src/order/steps/receive-return.ts b/packages/core/core-flows/src/order/steps/return/receive-return.ts similarity index 100% rename from packages/core/core-flows/src/order/steps/receive-return.ts rename to packages/core/core-flows/src/order/steps/return/receive-return.ts diff --git a/packages/core/core-flows/src/order/steps/update-return-items.ts b/packages/core/core-flows/src/order/steps/return/update-return-items.ts similarity index 100% rename from packages/core/core-flows/src/order/steps/update-return-items.ts rename to packages/core/core-flows/src/order/steps/return/update-return-items.ts diff --git a/packages/core/core-flows/src/order/steps/update-returns.ts b/packages/core/core-flows/src/order/steps/return/update-returns.ts similarity index 100% rename from packages/core/core-flows/src/order/steps/update-returns.ts rename to packages/core/core-flows/src/order/steps/return/update-returns.ts diff --git a/packages/core/core-flows/src/order/workflows/claim/begin-order-claim.ts b/packages/core/core-flows/src/order/workflows/claim/begin-order-claim.ts index 7aba30071f..8bf61dd37f 100644 --- a/packages/core/core-flows/src/order/workflows/claim/begin-order-claim.ts +++ b/packages/core/core-flows/src/order/workflows/claim/begin-order-claim.ts @@ -7,7 +7,7 @@ import { transform, } from "@medusajs/workflows-sdk" import { useRemoteQueryStep } from "../../../common" -import { createOrderClaimsStep } from "../../steps/create-claims" +import { createOrderClaimsStep } from "../../steps/claim/create-claims" import { createOrderChangeStep } from "../../steps/create-order-change" import { throwIfIsCancelled } from "../../utils/order-validation" diff --git a/packages/core/core-flows/src/order/workflows/claim/claim-request-item-return.ts b/packages/core/core-flows/src/order/workflows/claim/claim-request-item-return.ts index b47f7f4d16..3f4e75a72f 100644 --- a/packages/core/core-flows/src/order/workflows/claim/claim-request-item-return.ts +++ b/packages/core/core-flows/src/order/workflows/claim/claim-request-item-return.ts @@ -15,10 +15,10 @@ import { when, } from "@medusajs/workflows-sdk" import { useRemoteQueryStep } from "../../../common" +import { updateOrderClaimsStep } from "../../steps/claim/update-order-claims" import { createOrderChangeActionsStep } from "../../steps/create-order-change-actions" -import { createReturnsStep } from "../../steps/create-returns" import { previewOrderChangeStep } from "../../steps/preview-order-change" -import { updateOrderClaimsStep } from "../../steps/update-order-claims" +import { createReturnsStep } from "../../steps/return/create-returns" import { throwIfIsCancelled, throwIfItemsDoesNotExistsInOrder, diff --git a/packages/core/core-flows/src/order/workflows/claim/confirm-claim-request.ts b/packages/core/core-flows/src/order/workflows/claim/confirm-claim-request.ts index fba5dc014e..c5a6bcb8ff 100644 --- a/packages/core/core-flows/src/order/workflows/claim/confirm-claim-request.ts +++ b/packages/core/core-flows/src/order/workflows/claim/confirm-claim-request.ts @@ -7,7 +7,6 @@ import { } from "@medusajs/types" import { ChangeActionType, Modules, OrderChangeStatus } from "@medusajs/utils" import { - WorkflowData, WorkflowResponse, createStep, createWorkflow, @@ -19,9 +18,9 @@ import { createRemoteLinkStep, useRemoteQueryStep } from "../../../common" import { createFulfillmentWorkflow } from "../../../fulfillment/workflows/create-fulfillment" import { createReturnFulfillmentWorkflow } from "../../../fulfillment/workflows/create-return-fulfillment" import { previewOrderChangeStep } from "../../steps" +import { createOrderClaimItemsFromActionsStep } from "../../steps/claim/create-claim-items-from-actions" import { confirmOrderChanges } from "../../steps/confirm-order-changes" -import { createOrderClaimItemsFromActionsStep } from "../../steps/create-claim-items-from-actions" -import { createReturnItemsFromActionsStep } from "../../steps/create-return-items-from-actions" +import { createReturnItemsFromActionsStep } from "../../steps/return/create-return-items-from-actions" import { throwIfIsCancelled, throwIfOrderChangeIsNotActive, diff --git a/packages/core/core-flows/src/order/workflows/exchange/begin-order-exchange.ts b/packages/core/core-flows/src/order/workflows/exchange/begin-order-exchange.ts index d53453ae64..8990891ad7 100644 --- a/packages/core/core-flows/src/order/workflows/exchange/begin-order-exchange.ts +++ b/packages/core/core-flows/src/order/workflows/exchange/begin-order-exchange.ts @@ -7,8 +7,8 @@ import { transform, } from "@medusajs/workflows-sdk" import { useRemoteQueryStep } from "../../../common" -import { createOrderExchangesStep } from "../../steps/create-exchanges" import { createOrderChangeStep } from "../../steps/create-order-change" +import { createOrderExchangesStep } from "../../steps/exchange/create-exchange" import { throwIfOrderIsCancelled } from "../../utils/order-validation" const validationStep = createStep( diff --git a/packages/core/core-flows/src/order/workflows/exchange/cancel-begin-order-exchange.ts b/packages/core/core-flows/src/order/workflows/exchange/cancel-begin-order-exchange.ts new file mode 100644 index 0000000000..1407d8c2f2 --- /dev/null +++ b/packages/core/core-flows/src/order/workflows/exchange/cancel-begin-order-exchange.ts @@ -0,0 +1,94 @@ +import { OrderChangeDTO, OrderDTO, OrderExchangeDTO } from "@medusajs/types" +import { ChangeActionType, OrderChangeStatus } from "@medusajs/utils" +import { + WorkflowData, + createStep, + createWorkflow, + parallelize, + transform, +} from "@medusajs/workflows-sdk" +import { useRemoteQueryStep } from "../../../common" +import { + deleteExchangesStep, + deleteOrderChangesStep, + deleteOrderShippingMethods, + deleteReturnsStep, +} from "../../steps" +import { + throwIfIsCancelled, + throwIfOrderChangeIsNotActive, +} from "../../utils/order-validation" + +type WorkflowInput = { + exchange_id: string +} + +const validationStep = createStep( + "validate-cancel-begin-order-exchange", + async function ({ + order, + orderChange, + orderExchange, + }: { + order: OrderDTO + orderExchange: OrderExchangeDTO + orderChange: OrderChangeDTO + }) { + throwIfIsCancelled(order, "Order") + throwIfIsCancelled(orderExchange, "Exchange") + throwIfOrderChangeIsNotActive({ orderChange }) + } +) + +export const cancelBeginOrderExchangeWorkflowId = "cancel-begin-order-exchange" +export const cancelBeginOrderExchangeWorkflow = createWorkflow( + cancelBeginOrderExchangeWorkflowId, + function (input: WorkflowInput): WorkflowData { + const orderExchange: OrderExchangeDTO = useRemoteQueryStep({ + entry_point: "order_exchange", + fields: ["id", "status", "order_id", "return_id", "canceled_at"], + variables: { id: input.exchange_id }, + list: false, + throw_if_key_not_found: true, + }) + + const order: OrderDTO = useRemoteQueryStep({ + entry_point: "orders", + fields: ["id", "version", "canceled_at"], + variables: { id: orderExchange.order_id }, + list: false, + throw_if_key_not_found: true, + }).config({ name: "order-query" }) + + const orderChange: OrderChangeDTO = useRemoteQueryStep({ + entry_point: "order_change", + fields: ["id", "status", "version", "actions.*"], + variables: { + filters: { + order_id: orderExchange.order_id, + exchange_id: orderExchange.id, + status: [OrderChangeStatus.PENDING, OrderChangeStatus.REQUESTED], + }, + }, + list: false, + }).config({ name: "order-change-query" }) + + validationStep({ order, orderExchange, orderChange }) + + const shippingToRemove = transform( + { orderChange, input }, + ({ orderChange, input }) => { + return (orderChange.actions ?? []) + .filter((a) => a.action === ChangeActionType.SHIPPING_ADD) + .map(({ id }) => id) + } + ) + + parallelize( + deleteReturnsStep({ ids: [orderExchange.return_id!] }), + deleteExchangesStep({ ids: [orderExchange.id] }), + deleteOrderChangesStep({ ids: [orderChange.id] }), + deleteOrderShippingMethods({ ids: shippingToRemove }) + ) + } +) diff --git a/packages/core/core-flows/src/order/workflows/exchange/cancel-exchange.ts b/packages/core/core-flows/src/order/workflows/exchange/cancel-exchange.ts new file mode 100644 index 0000000000..ec62d60b58 --- /dev/null +++ b/packages/core/core-flows/src/order/workflows/exchange/cancel-exchange.ts @@ -0,0 +1,82 @@ +import { + FulfillmentDTO, + OrderExchangeDTO, + OrderWorkflow, +} from "@medusajs/types" +import { MedusaError } from "@medusajs/utils" +import { + WorkflowData, + createStep, + createWorkflow, + when, +} from "@medusajs/workflows-sdk" +import { useRemoteQueryStep } from "../../../common" +import { cancelOrderExchangeStep } from "../../steps" +import { throwIfIsCancelled } from "../../utils/order-validation" +import { cancelReturnWorkflow } from "../return/cancel-return" + +const validateOrder = createStep( + "validate-exchange", + ({ + orderExchange, + }: { + orderExchange: OrderExchangeDTO + input: OrderWorkflow.CancelOrderExchangeWorkflowInput + }) => { + const orderExchange_ = orderExchange as OrderExchangeDTO & { + fulfillments: FulfillmentDTO[] + } + + throwIfIsCancelled(orderExchange, "Exchange") + + const throwErrorIf = ( + arr: unknown[], + pred: (obj: any) => boolean, + message: string + ) => { + if (arr?.some(pred)) { + throw new MedusaError(MedusaError.Types.NOT_ALLOWED, message) + } + } + + const notCanceled = (o) => !o.canceled_at + + throwErrorIf( + orderExchange_.fulfillments, + notCanceled, + "All fulfillments must be canceled before canceling am exchange" + ) + } +) + +export const cancelOrderExchangeWorkflowId = "cancel-exchange" +export const cancelOrderExchangeWorkflow = createWorkflow( + cancelOrderExchangeWorkflowId, + ( + input: WorkflowData + ): WorkflowData => { + const orderExchange: OrderExchangeDTO & { fulfillments: FulfillmentDTO[] } = + useRemoteQueryStep({ + entry_point: "order_exchange", + fields: ["id", "return_id", "canceled_at", "fulfillments.canceled_at"], + variables: { id: input.exchange_id }, + list: false, + throw_if_key_not_found: true, + }) + + validateOrder({ orderExchange, input }) + + cancelOrderExchangeStep({ exchange_id: orderExchange.id }) + + when({ orderExchange }, ({ orderExchange }) => { + return !!orderExchange.return_id + }).then(() => { + cancelReturnWorkflow.runAsStep({ + input: { + return_id: orderExchange.return_id!, + no_notification: input.no_notification, + }, + }) + }) + } +) diff --git a/packages/core/core-flows/src/order/workflows/exchange/confirm-exchange-request.ts b/packages/core/core-flows/src/order/workflows/exchange/confirm-exchange-request.ts new file mode 100644 index 0000000000..5ef3fd1674 --- /dev/null +++ b/packages/core/core-flows/src/order/workflows/exchange/confirm-exchange-request.ts @@ -0,0 +1,361 @@ +import { + FulfillmentWorkflow, + OrderChangeActionDTO, + OrderChangeDTO, + OrderDTO, + OrderExchangeDTO, +} from "@medusajs/types" +import { ChangeActionType, Modules, OrderChangeStatus } from "@medusajs/utils" +import { + WorkflowResponse, + createStep, + createWorkflow, + parallelize, + transform, + when, +} from "@medusajs/workflows-sdk" +import { createRemoteLinkStep, useRemoteQueryStep } from "../../../common" +import { createFulfillmentWorkflow } from "../../../fulfillment/workflows/create-fulfillment" +import { createReturnFulfillmentWorkflow } from "../../../fulfillment/workflows/create-return-fulfillment" +import { previewOrderChangeStep } from "../../steps" +import { confirmOrderChanges } from "../../steps/confirm-order-changes" +import { createOrderExchangeItemsFromActionsStep } from "../../steps/exchange/create-exchange-items-from-actions" +import { createReturnItemsFromActionsStep } from "../../steps/return/create-return-items-from-actions" +import { + throwIfIsCancelled, + throwIfOrderChangeIsNotActive, +} from "../../utils/order-validation" + +type WorkflowInput = { + exchange_id: string +} + +const validationStep = createStep( + "validate-confirm-exchange-request", + async function ({ + order, + orderChange, + orderExchange, + }: { + order: OrderDTO + orderExchange: OrderExchangeDTO + orderChange: OrderChangeDTO + }) { + throwIfIsCancelled(order, "Order") + throwIfIsCancelled(orderExchange, "Exchange") + throwIfOrderChangeIsNotActive({ orderChange }) + } +) + +function prepareFulfillmentData({ + order, + items, + shippingOption, + deliveryAddress, +}: { + order: OrderDTO + items: any[] + shippingOption: { + id: string + provider_id: string + service_zone: { + fulfillment_set: { + location?: { + id: string + address: Record + } + } + } + } + deliveryAddress?: Record +}) { + const orderItemsMap = new Map["items"][0]>( + order.items!.map((i) => [i.id, i]) + ) + const fulfillmentItems = items.map((i) => { + const orderItem = orderItemsMap.get(i.item_id)! + return { + line_item_id: i.item_id, + quantity: i.quantity, + return_quantity: i.quantity, + title: orderItem.variant_title ?? orderItem.title, + sku: orderItem.variant_sku || "", + barcode: orderItem.variant_barcode || "", + } as FulfillmentWorkflow.CreateFulfillmentItemWorkflowDTO + }) + + const locationId = shippingOption.service_zone.fulfillment_set.location?.id! + + // delivery address is the stock location address + const address = + deliveryAddress ?? + shippingOption.service_zone.fulfillment_set.location?.address ?? + {} + + delete address.id + + return { + input: { + location_id: locationId, + provider_id: shippingOption.provider_id, + shipping_option_id: shippingOption.id, + items: fulfillmentItems, + delivery_address: address, + order: order, + }, + } +} + +function transformActionsToItems({ orderChange }) { + const exchangeItems: OrderChangeActionDTO[] = [] + const returnItems: OrderChangeActionDTO[] = [] + + const actions = orderChange.actions ?? [] + actions.forEach((item) => { + if (item.action === ChangeActionType.RETURN_ITEM) { + returnItems.push(item) + } else if (item.action === ChangeActionType.ITEM_ADD) { + exchangeItems.push(item) + } + }) + + return { + exchangeItems: { + changes: exchangeItems, + exchangeId: exchangeItems?.[0]?.exchange_id!, + }, + returnItems: { + changes: returnItems, + returnId: returnItems?.[0]?.return_id!, + }, + } +} + +function extractShippingOption({ orderPreview, orderExchange, returnId }) { + if (!orderPreview.shipping_methods?.length) { + return + } + + let returnShippingMethod + let exchangeShippingMethod + for (const shippingMethod of orderPreview.shipping_methods) { + const modifiedShippingMethod_ = shippingMethod as any + if (!modifiedShippingMethod_.actions) { + continue + } + + for (const action of modifiedShippingMethod_.actions) { + if (action.action === ChangeActionType.SHIPPING_ADD) { + if (action.return_id === returnId) { + returnShippingMethod = shippingMethod + } else if (action.exchange_id === orderExchange.id) { + exchangeShippingMethod = shippingMethod + } + } + } + } + + return { + returnShippingMethod, + exchangeShippingMethod, + } +} + +export const confirmExchangeRequestWorkflowId = "confirm-exchange-request" +export const confirmExchangeRequestWorkflow = createWorkflow( + confirmExchangeRequestWorkflowId, + function (input: WorkflowInput): WorkflowResponse { + const orderExchange: OrderExchangeDTO = useRemoteQueryStep({ + entry_point: "order_exchange", + fields: ["id", "status", "order_id", "canceled_at"], + variables: { id: input.exchange_id }, + list: false, + throw_if_key_not_found: true, + }) + + 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: orderExchange.order_id }, + list: false, + throw_if_key_not_found: true, + }).config({ name: "order-query" }) + + const orderChange: OrderChangeDTO = useRemoteQueryStep({ + entry_point: "order_change", + fields: [ + "id", + "actions.id", + "actions.exchange_id", + "actions.return_id", + "actions.action", + "actions.details", + "actions.reference", + "actions.reference_id", + "actions.internal_note", + ], + variables: { + filters: { + order_id: orderExchange.order_id, + exchange_id: orderExchange.id, + status: [OrderChangeStatus.PENDING, OrderChangeStatus.REQUESTED], + }, + }, + list: false, + }).config({ name: "order-change-query" }) + + validationStep({ order, orderExchange, orderChange }) + + const { exchangeItems, returnItems } = transform( + { orderChange }, + transformActionsToItems + ) + + const orderPreview = previewOrderChangeStep(order.id) + + const [createExchangeItems, createdReturnItems] = parallelize( + createOrderExchangeItemsFromActionsStep(exchangeItems), + createReturnItemsFromActionsStep(returnItems), + confirmOrderChanges({ changes: [orderChange], orderId: order.id }) + ) + + const returnId = transform( + { createdReturnItems }, + ({ createdReturnItems }) => { + return createdReturnItems?.[0]?.return_id + } + ) + + const exchangeId = transform( + { createExchangeItems }, + ({ createExchangeItems }) => { + return createExchangeItems?.[0]?.exchange_id + } + ) + + const { returnShippingMethod, exchangeShippingMethod } = transform( + { orderPreview, orderExchange, returnId }, + extractShippingOption + ) + + when({ exchangeShippingMethod }, ({ exchangeShippingMethod }) => { + return !!exchangeShippingMethod + }).then(() => { + const exchange: OrderExchangeDTO = useRemoteQueryStep({ + entry_point: "order_exchange", + fields: [ + "id", + "version", + "canceled_at", + "additional_items.id", + "additional_items.title", + "additional_items.variant_title", + "additional_items.variant_sku", + "additional_items.variant_barcode", + ], + variables: { id: exchangeId }, + list: false, + throw_if_key_not_found: true, + }).config({ name: "exchange-query" }) + + const exchangeShippingOption = useRemoteQueryStep({ + entry_point: "shipping_options", + fields: [ + "id", + "provider_id", + "service_zone.fulfillment_set.location.id", + "service_zone.fulfillment_set.location.address.*", + ], + variables: { + id: exchangeShippingMethod.shipping_option_id, + }, + list: false, + throw_if_key_not_found: true, + }).config({ name: "exchange-shipping-option" }) + + const fulfillmentData = transform( + { + order, + items: exchange.additional_items! ?? [], + shippingOption: exchangeShippingOption, + deliveryAddress: order.shipping_address, + }, + prepareFulfillmentData + ) + + const fulfillment = createFulfillmentWorkflow.runAsStep(fulfillmentData) + + const link = transform({ fulfillment, order }, (data) => { + return [ + { + [Modules.ORDER]: { order_id: data.order.id }, + [Modules.FULFILLMENT]: { fulfillment_id: data.fulfillment.id }, + }, + ] + }) + + createRemoteLinkStep(link).config({ + name: "exchange-shipping-fulfillment-link", + }) + }) + + when({ returnShippingMethod }, ({ returnShippingMethod }) => { + return !!returnShippingMethod + }).then(() => { + const returnShippingOption = useRemoteQueryStep({ + entry_point: "shipping_options", + fields: [ + "id", + "provider_id", + "service_zone.fulfillment_set.location.id", + "service_zone.fulfillment_set.location.address.*", + ], + variables: { + id: returnShippingMethod.shipping_option_id, + }, + list: false, + throw_if_key_not_found: true, + }).config({ name: "exchange-return-shipping-option" }) + + const fulfillmentData = transform( + { + order, + items: order.items!, + shippingOption: returnShippingOption, + }, + prepareFulfillmentData + ) + + const returnFulfillment = + createReturnFulfillmentWorkflow.runAsStep(fulfillmentData) + + const returnLink = transform( + { returnId, fulfillment: returnFulfillment }, + (data) => { + return [ + { + [Modules.ORDER]: { return_id: data.returnId }, + [Modules.FULFILLMENT]: { fulfillment_id: data.fulfillment.id }, + }, + ] + } + ) + + createRemoteLinkStep(returnLink).config({ + name: "exchange-return-shipping-fulfillment-link", + }) + }) + + return new WorkflowResponse(orderPreview) + } +) diff --git a/packages/core/core-flows/src/order/workflows/exchange/create-exchange-return-shipping-method.ts b/packages/core/core-flows/src/order/workflows/exchange/create-exchange-shipping-method.ts similarity index 60% rename from packages/core/core-flows/src/order/workflows/exchange/create-exchange-return-shipping-method.ts rename to packages/core/core-flows/src/order/workflows/exchange/create-exchange-shipping-method.ts index a7ca8ea521..78e95b08ff 100644 --- a/packages/core/core-flows/src/order/workflows/exchange/create-exchange-return-shipping-method.ts +++ b/packages/core/core-flows/src/order/workflows/exchange/create-exchange-shipping-method.ts @@ -1,60 +1,63 @@ import { BigNumberInput, - OrderChangeActionDTO, OrderChangeDTO, OrderDTO, OrderExchangeDTO, } from "@medusajs/types" import { ChangeActionType, OrderChangeStatus } from "@medusajs/utils" import { - WorkflowData, WorkflowResponse, createStep, createWorkflow, transform, } from "@medusajs/workflows-sdk" import { useRemoteQueryStep } from "../../../common" +import { previewOrderChangeStep } from "../../steps" import { createOrderChangeActionsStep } from "../../steps/create-order-change-actions" import { createOrderShippingMethods } from "../../steps/create-order-shipping-methods" import { + throwIfIsCancelled, throwIfOrderChangeIsNotActive, - throwIfOrderIsCancelled, } from "../../utils/order-validation" const validationStep = createStep( - "validate-create-exchange-return-shipping-method", + "validate-create-exchange-shipping-method", async function ({ order, orderChange, + orderExchange, }: { order: OrderDTO + orderExchange: OrderExchangeDTO orderChange: OrderChangeDTO }) { - throwIfOrderIsCancelled({ order }) + throwIfIsCancelled(order, "Order") + throwIfIsCancelled(orderExchange, "Exchange") throwIfOrderChangeIsNotActive({ orderChange }) } ) -export const createExchangeReturnShippingMethodWorkflowId = - "create-exchange-return-shipping-method" -export const createExchangeReturnShippingMethodWorkflow = createWorkflow( - createExchangeReturnShippingMethodWorkflowId, +export const createExchangeShippingMethodWorkflowId = + "create-exchange-shipping-method" +export const createExchangeShippingMethodWorkflow = createWorkflow( + createExchangeShippingMethodWorkflowId, function (input: { - exchangeId: string - shippingOptionId: string - customShippingPrice?: BigNumberInput - }): WorkflowResponse { + return_id?: string + exchange_id?: string + shipping_option_id: string + custom_price?: BigNumberInput + }): WorkflowResponse { const orderExchange: OrderExchangeDTO = useRemoteQueryStep({ entry_point: "order_exchange", - fields: ["id", "status", "order_id", "return_id"], - variables: { id: input.exchangeId }, + fields: ["id", "status", "order_id", "canceled_at"], + variables: { id: input.exchange_id }, list: false, throw_if_key_not_found: true, }) const order: OrderDTO = useRemoteQueryStep({ entry_point: "orders", - fields: ["id", "status", "currency_code"], + fields: ["id", "status", "currency_code", "canceled_at"], variables: { id: orderExchange.order_id }, list: false, throw_if_key_not_found: true, @@ -69,41 +72,16 @@ export const createExchangeReturnShippingMethodWorkflow = createWorkflow( "calculated_price.is_calculated_price_tax_inclusive", ], variables: { - id: input.shippingOptionId, + id: input.shipping_option_id, calculated_price: { context: { currency_code: order.currency_code }, }, }, }).config({ name: "fetch-shipping-option" }) - const shippingMethodInput = transform( - { orderExchange, shippingOptions, input }, - (data) => { - const option = data.shippingOptions[0] - - return { - shipping_option_id: option.id, - amount: - data.input.customShippingPrice ?? - option.calculated_price.calculated_amount, - is_tax_inclusive: - !!option.calculated_price.is_calculated_price_tax_inclusive, - data: option.data ?? {}, - name: option.name, - order_id: data.orderExchange.order_id, - return_id: data.orderExchange.return_id, - exchange_id: data.orderExchange.id, - } - } - ) - - const createdMethods = createOrderShippingMethods({ - shipping_methods: [shippingMethodInput], - }) - const orderChange: OrderChangeDTO = useRemoteQueryStep({ entry_point: "order_change", - fields: ["id", "status"], + fields: ["id", "status", "version"], variables: { filters: { order_id: orderExchange.order_id, @@ -114,43 +92,78 @@ export const createExchangeReturnShippingMethodWorkflow = createWorkflow( list: false, }).config({ name: "order-change-query" }) - validationStep({ order, orderChange }) + validationStep({ order, orderExchange, orderChange }) + + const shippingMethodInput = transform( + { + orderExchange, + shippingOptions, + customPrice: input.custom_price, + orderChange, + input, + }, + (data) => { + const option = data.shippingOptions[0] + const orderChange = data.orderChange + + return { + shipping_option_id: option.id, + amount: data.customPrice ?? option.calculated_price.calculated_amount, + is_tax_inclusive: + !!option.calculated_price.is_calculated_price_tax_inclusive, + data: option.data ?? {}, + name: option.name, + version: orderChange.version, + order_id: data.orderExchange.order_id, + return_id: input.return_id, + exchange_id: data.orderExchange.id, + } + } + ) + + const createdMethods = createOrderShippingMethods({ + shipping_methods: [shippingMethodInput], + }) const orderChangeActionInput = transform( { - orderId: order.id, - returnId: orderExchange.return_id, - exchangeId: orderExchange.id, - shippingOption: shippingOptions[0], - methodId: createdMethods[0].id, - customPrice: input.customShippingPrice, + order, + orderExchange, + shippingOptions, + createdMethods, + customPrice: input.custom_price, + orderChange, + input, }, ({ - shippingOption, - exchangeId, - returnId, - orderId, - methodId, + shippingOptions, + orderExchange, + order, + createdMethods, customPrice, + orderChange, + input, }) => { + const shippingOption = shippingOptions[0] + const createdMethod = createdMethods[0] const methodPrice = customPrice ?? shippingOption.calculated_price.calculated_amount return { action: ChangeActionType.SHIPPING_ADD, reference: "order_shipping_method", - reference_id: methodId, + order_change_id: orderChange.id, + reference_id: createdMethod.id, amount: methodPrice, - details: { - order_id: orderId, - return_id: returnId, - exchange_id: exchangeId, - }, + order_id: order.id, + return_id: input.return_id, + exchange_id: orderExchange.id, } } ) - const response = createOrderChangeActionsStep([orderChangeActionInput]) - return new WorkflowResponse(response) + createOrderChangeActionsStep([orderChangeActionInput]) + + return new WorkflowResponse(previewOrderChangeStep(order.id)) } ) diff --git a/packages/core/core-flows/src/order/workflows/exchange/exchange-add-new-item.ts b/packages/core/core-flows/src/order/workflows/exchange/exchange-add-new-item.ts index b2c1b11c65..0a90f58d73 100644 --- a/packages/core/core-flows/src/order/workflows/exchange/exchange-add-new-item.ts +++ b/packages/core/core-flows/src/order/workflows/exchange/exchange-add-new-item.ts @@ -18,7 +18,6 @@ import { previewOrderChangeStep } from "../../steps/preview-order-change" import { throwIfIsCancelled, throwIfOrderChangeIsNotActive, - throwIfOrderIsCancelled, } from "../../utils/order-validation" import { addOrderLineItemsWorkflow } from "../add-line-items" @@ -33,7 +32,7 @@ const validationStep = createStep( orderExchange: OrderExchangeDTO orderChange: OrderChangeDTO }) { - throwIfOrderIsCancelled({ order }) + throwIfIsCancelled(order, "Order") throwIfIsCancelled(orderExchange, "Exchange") throwIfOrderChangeIsNotActive({ orderChange }) } @@ -102,7 +101,7 @@ export const orderExchangeAddNewItemWorkflow = createWorkflow( details: { reference_id: lineItems[index].id, quantity: item.quantity, - unit_price: item.unit_price, + unit_price: item.unit_price ?? lineItems[index].unit_price, metadata: item.metadata, }, })) diff --git a/packages/core/core-flows/src/order/workflows/exchange/exchange-request-item-return.ts b/packages/core/core-flows/src/order/workflows/exchange/exchange-request-item-return.ts index ea8d2697d7..ce720e8509 100644 --- a/packages/core/core-flows/src/order/workflows/exchange/exchange-request-item-return.ts +++ b/packages/core/core-flows/src/order/workflows/exchange/exchange-request-item-return.ts @@ -7,23 +7,22 @@ import { } from "@medusajs/types" import { ChangeActionType, OrderChangeStatus } from "@medusajs/utils" import { + WorkflowData, + WorkflowResponse, createStep, createWorkflow, transform, when, - WorkflowData, - WorkflowResponse, } from "@medusajs/workflows-sdk" import { useRemoteQueryStep } from "../../../common" import { createOrderChangeActionsStep } from "../../steps/create-order-change-actions" -import { createReturnsStep } from "../../steps/create-returns" +import { updateOrderExchangesStep } from "../../steps/exchange/update-order-exchanges" import { previewOrderChangeStep } from "../../steps/preview-order-change" -import { updateOrderExchangesStep } from "../../steps/update-order-exchanges" +import { createReturnsStep } from "../../steps/return/create-returns" import { throwIfIsCancelled, throwIfItemsDoesNotExistsInOrder, throwIfOrderChangeIsNotActive, - throwIfOrderIsCancelled, } from "../../utils/order-validation" const validationStep = createStep( @@ -41,7 +40,7 @@ const validationStep = createStep( orderChange: OrderChangeDTO items: OrderWorkflow.OrderExchangeRequestItemReturnWorkflowInput["items"] }) { - throwIfOrderIsCancelled({ order }) + throwIfIsCancelled(order, "Order") throwIfIsCancelled(orderExchange, "Exchange") throwIfIsCancelled(orderReturn, "Return") throwIfOrderChangeIsNotActive({ orderChange }) @@ -113,7 +112,10 @@ export const orderExchangeRequestItemReturnWorkflow = createWorkflow( }, }, list: false, - }).config({ name: "order-change-query" }) + }).config({ + name: "order-change-query", + status: [OrderChangeStatus.PENDING, OrderChangeStatus.REQUESTED], + }) validationStep({ order, @@ -156,6 +158,7 @@ export const orderExchangeRequestItemReturnWorkflow = createWorkflow( details: { reference_id: item.id, quantity: item.quantity, + reason_id: item.reason_id, metadata: item.metadata, }, })) diff --git a/packages/core/core-flows/src/order/workflows/exchange/remove-exchange-shipping-method.ts b/packages/core/core-flows/src/order/workflows/exchange/remove-exchange-shipping-method.ts new file mode 100644 index 0000000000..0c92221a40 --- /dev/null +++ b/packages/core/core-flows/src/order/workflows/exchange/remove-exchange-shipping-method.ts @@ -0,0 +1,107 @@ +import { + OrderChangeActionDTO, + OrderChangeDTO, + OrderDTO, + OrderExchangeDTO, + OrderWorkflow, +} from "@medusajs/types" +import { ChangeActionType, OrderChangeStatus } from "@medusajs/utils" +import { + WorkflowData, + WorkflowResponse, + createStep, + createWorkflow, + parallelize, + transform, +} from "@medusajs/workflows-sdk" +import { useRemoteQueryStep } from "../../../common" +import { deleteOrderShippingMethods } from "../../steps" +import { deleteOrderChangeActionsStep } from "../../steps/delete-order-change-actions" +import { previewOrderChangeStep } from "../../steps/preview-order-change" +import { + throwIfIsCancelled, + throwIfOrderChangeIsNotActive, +} from "../../utils/order-validation" + +const validationStep = createStep( + "validate-remove-exchange-shipping-method", + async function ({ + orderChange, + orderExchange, + input, + }: { + input: { exchange_id: string; action_id: string } + orderExchange: OrderExchangeDTO + orderChange: OrderChangeDTO + }) { + throwIfIsCancelled(orderExchange, "Exchange") + throwIfOrderChangeIsNotActive({ orderChange }) + + const associatedAction = (orderChange.actions ?? []).find( + (a) => a.id === input.action_id + ) as OrderChangeActionDTO + + if (!associatedAction) { + throw new Error( + `No shipping method found for exchange ${input.exchange_id} in order change ${orderChange.id}` + ) + } else if (associatedAction.action !== ChangeActionType.SHIPPING_ADD) { + throw new Error( + `Action ${associatedAction.id} is not adding a shipping method` + ) + } + } +) + +export const removeExchangeShippingMethodWorkflowId = + "remove-exchange-shipping-method" +export const removeExchangeShippingMethodWorkflow = createWorkflow( + removeExchangeShippingMethodWorkflowId, + function ( + input: WorkflowData + ): WorkflowResponse { + const orderExchange: OrderExchangeDTO = useRemoteQueryStep({ + entry_point: "order_exchange", + fields: ["id", "status", "order_id", "canceled_at"], + variables: { id: input.exchange_id }, + list: false, + throw_if_key_not_found: true, + }) + + const orderChange: OrderChangeDTO = useRemoteQueryStep({ + entry_point: "order_change", + fields: ["id", "status", "version", "actions.*"], + variables: { + filters: { + order_id: orderExchange.order_id, + exchange_id: orderExchange.id, + status: [OrderChangeStatus.PENDING, OrderChangeStatus.REQUESTED], + }, + }, + list: false, + }).config({ name: "order-change-query" }) + + validationStep({ orderExchange, orderChange, input }) + + const dataToRemove = transform( + { orderChange, input }, + ({ orderChange, input }) => { + const associatedAction = (orderChange.actions ?? []).find( + (a) => a.id === input.action_id + ) as OrderChangeActionDTO + + return { + actionId: associatedAction.id, + shippingMethodId: associatedAction.reference_id, + } + } + ) + + parallelize( + deleteOrderChangeActionsStep({ ids: [dataToRemove.actionId] }), + deleteOrderShippingMethods({ ids: [dataToRemove.shippingMethodId] }) + ) + + return new WorkflowResponse(previewOrderChangeStep(orderExchange.order_id)) + } +) diff --git a/packages/core/core-flows/src/order/workflows/exchange/update-exchange-add-item.ts b/packages/core/core-flows/src/order/workflows/exchange/update-exchange-add-item.ts new file mode 100644 index 0000000000..c6c93e45e9 --- /dev/null +++ b/packages/core/core-flows/src/order/workflows/exchange/update-exchange-add-item.ts @@ -0,0 +1,119 @@ +import { + OrderChangeActionDTO, + OrderChangeDTO, + OrderDTO, + OrderExchangeDTO, + OrderWorkflow, +} from "@medusajs/types" +import { ChangeActionType, OrderChangeStatus } from "@medusajs/utils" +import { + WorkflowData, + WorkflowResponse, + createStep, + createWorkflow, + transform, +} from "@medusajs/workflows-sdk" +import { useRemoteQueryStep } from "../../../common" +import { + previewOrderChangeStep, + updateOrderChangeActionsStep, +} from "../../steps" +import { + throwIfIsCancelled, + throwIfOrderChangeIsNotActive, +} from "../../utils/order-validation" + +const validationStep = createStep( + "update-exchange-add-item-validation", + async function ( + { + order, + orderChange, + orderExchange, + input, + }: { + order: OrderDTO + orderExchange: OrderExchangeDTO + orderChange: OrderChangeDTO + input: OrderWorkflow.UpdateExchangeAddNewItemWorkflowInput + }, + context + ) { + throwIfIsCancelled(order, "Order") + throwIfIsCancelled(orderExchange, "Exchange") + throwIfOrderChangeIsNotActive({ orderChange }) + + const associatedAction = (orderChange.actions ?? []).find( + (a) => a.id === input.action_id + ) as OrderChangeActionDTO + + if (!associatedAction) { + throw new Error( + `No request to add item for exchange ${input.exchange_id} in order change ${orderChange.id}` + ) + } else if (associatedAction.action !== ChangeActionType.ITEM_ADD) { + throw new Error(`Action ${associatedAction.id} is not adding an item`) + } + } +) + +export const updateExchangeAddItemWorkflowId = "update-exchange-add-item" +export const updateExchangeAddItemWorkflow = createWorkflow( + updateExchangeAddItemWorkflowId, + function ( + input: WorkflowData + ): WorkflowResponse { + const orderExchange: OrderExchangeDTO = useRemoteQueryStep({ + entry_point: "order_exchange", + fields: ["id", "status", "order_id", "canceled_at"], + variables: { id: input.exchange_id }, + list: false, + throw_if_key_not_found: true, + }) + + const order: OrderDTO = useRemoteQueryStep({ + entry_point: "orders", + fields: ["id", "status", "canceled_at", "items.*"], + variables: { id: orderExchange.order_id }, + list: false, + throw_if_key_not_found: true, + }).config({ name: "order-query" }) + + const orderChange: OrderChangeDTO = useRemoteQueryStep({ + entry_point: "order_change", + fields: ["id", "status", "version", "actions.*"], + variables: { + filters: { + order_id: orderExchange.order_id, + exchange_id: orderExchange.id, + status: [OrderChangeStatus.PENDING, OrderChangeStatus.REQUESTED], + }, + }, + list: false, + }).config({ name: "order-change-query" }) + + validationStep({ order, input, orderExchange, orderChange }) + + const updateData = transform( + { orderChange, input }, + ({ input, orderChange }) => { + const originalAction = (orderChange.actions ?? []).find( + (a) => a.id === input.action_id + ) as OrderChangeActionDTO + + const data = input.data + return { + id: input.action_id, + details: { + quantity: data.quantity ?? originalAction.details?.quantity, + }, + internal_note: data.internal_note, + } + } + ) + + updateOrderChangeActionsStep([updateData]) + + return new WorkflowResponse(previewOrderChangeStep(order.id)) + } +) diff --git a/packages/core/core-flows/src/order/workflows/exchange/update-exchange-shipping-method.ts b/packages/core/core-flows/src/order/workflows/exchange/update-exchange-shipping-method.ts new file mode 100644 index 0000000000..9e19551337 --- /dev/null +++ b/packages/core/core-flows/src/order/workflows/exchange/update-exchange-shipping-method.ts @@ -0,0 +1,122 @@ +import { + OrderChangeActionDTO, + OrderChangeDTO, + OrderDTO, + OrderExchangeDTO, + OrderWorkflow, +} from "@medusajs/types" +import { ChangeActionType, OrderChangeStatus } from "@medusajs/utils" +import { + WorkflowData, + WorkflowResponse, + createStep, + createWorkflow, + parallelize, + transform, +} from "@medusajs/workflows-sdk" +import { useRemoteQueryStep } from "../../../common" +import { + updateOrderChangeActionsStep, + updateOrderShippingMethodsStep, +} from "../../steps" +import { previewOrderChangeStep } from "../../steps/preview-order-change" +import { + throwIfIsCancelled, + throwIfOrderChangeIsNotActive, +} from "../../utils/order-validation" + +const validationStep = createStep( + "validate-update-exchange-shipping-method", + async function ({ + orderChange, + orderExchange, + input, + }: { + input: { exchange_id: string; action_id: string } + orderExchange: OrderExchangeDTO + orderChange: OrderChangeDTO + }) { + throwIfIsCancelled(orderExchange, "Exchange") + throwIfOrderChangeIsNotActive({ orderChange }) + + const associatedAction = (orderChange.actions ?? []).find( + (a) => a.id === input.action_id + ) as OrderChangeActionDTO + + if (!associatedAction) { + throw new Error( + `No shipping method found for exchange ${input.exchange_id} in order change ${orderChange.id}` + ) + } else if (associatedAction.action !== ChangeActionType.SHIPPING_ADD) { + throw new Error( + `Action ${associatedAction.id} is not adding a shipping method` + ) + } + } +) + +export const updateExchangeShippingMethodWorkflowId = + "update-exchange-shipping-method" +export const updateExchangeShippingMethodWorkflow = createWorkflow( + updateExchangeShippingMethodWorkflowId, + function ( + input: WorkflowData + ): WorkflowResponse { + const orderExchange: OrderExchangeDTO = useRemoteQueryStep({ + entry_point: "order_exchange", + fields: ["id", "status", "order_id", "canceled_at"], + variables: { id: input.exchange_id }, + list: false, + throw_if_key_not_found: true, + }) + + const orderChange: OrderChangeDTO = useRemoteQueryStep({ + entry_point: "order_change", + fields: ["id", "status", "version", "actions.*"], + variables: { + filters: { + order_id: orderExchange.order_id, + exchange_id: orderExchange.id, + status: [OrderChangeStatus.PENDING, OrderChangeStatus.REQUESTED], + }, + }, + list: false, + }).config({ name: "order-change-query" }) + + validationStep({ orderExchange, orderChange, input }) + + const updateData = transform( + { orderChange, input }, + ({ input, orderChange }) => { + const originalAction = (orderChange.actions ?? []).find( + (a) => a.id === input.action_id + ) as OrderChangeActionDTO + + const data = input.data + + const action = { + id: originalAction.id, + internal_note: data.internal_note, + } + + const shippingMethod = { + id: originalAction.reference_id, + amount: data.custom_price, + metadata: data.metadata, + } + + return { + action, + shippingMethod, + } + } + ) + + parallelize( + updateOrderChangeActionsStep([updateData.action]), + updateOrderShippingMethodsStep([updateData.shippingMethod!]) + ) + + return new WorkflowResponse(previewOrderChangeStep(orderExchange.order_id)) + } +) diff --git a/packages/core/core-flows/src/order/workflows/index.ts b/packages/core/core-flows/src/order/workflows/index.ts index 43f8fd076b..577eb55c7b 100644 --- a/packages/core/core-flows/src/order/workflows/index.ts +++ b/packages/core/core-flows/src/order/workflows/index.ts @@ -26,9 +26,15 @@ export * from "./decline-order-change" export * from "./delete-order-change" export * from "./delete-order-change-actions" export * from "./exchange/begin-order-exchange" -export * from "./exchange/create-exchange-return-shipping-method" +export * from "./exchange/cancel-begin-order-exchange" +export * from "./exchange/cancel-exchange" +export * from "./exchange/confirm-exchange-request" +export * from "./exchange/create-exchange-shipping-method" export * from "./exchange/exchange-add-new-item" export * from "./exchange/exchange-request-item-return" +export * from "./exchange/remove-exchange-shipping-method" +export * from "./exchange/update-exchange-add-item" +export * from "./exchange/update-exchange-shipping-method" export * from "./get-order-detail" export * from "./get-orders-list" export * from "./return/begin-receive-return" diff --git a/packages/core/core-flows/src/order/workflows/return/confirm-return-request.ts b/packages/core/core-flows/src/order/workflows/return/confirm-return-request.ts index 0bfb512cfb..700df8c3da 100644 --- a/packages/core/core-flows/src/order/workflows/return/confirm-return-request.ts +++ b/packages/core/core-flows/src/order/workflows/return/confirm-return-request.ts @@ -6,7 +6,6 @@ import { } from "@medusajs/types" import { ChangeActionType, Modules, OrderChangeStatus } from "@medusajs/utils" import { - WorkflowData, WorkflowResponse, createStep, createWorkflow, @@ -17,7 +16,7 @@ import { createRemoteLinkStep, useRemoteQueryStep } from "../../../common" import { createReturnFulfillmentWorkflow } from "../../../fulfillment/workflows/create-return-fulfillment" import { previewOrderChangeStep } from "../../steps" import { confirmOrderChanges } from "../../steps/confirm-order-changes" -import { createReturnItemsFromActionsStep } from "../../steps/create-return-items-from-actions" +import { createReturnItemsFromActionsStep } from "../../steps/return/create-return-items-from-actions" import { throwIfIsCancelled, throwIfOrderChangeIsNotActive, diff --git a/packages/core/core-flows/src/order/workflows/return/create-complete-return.ts b/packages/core/core-flows/src/order/workflows/return/create-complete-return.ts index 047a88e683..e884596422 100644 --- a/packages/core/core-flows/src/order/workflows/return/create-complete-return.ts +++ b/packages/core/core-flows/src/order/workflows/return/create-complete-return.ts @@ -16,8 +16,8 @@ import { } from "@medusajs/workflows-sdk" import { createRemoteLinkStep, useRemoteQueryStep } from "../../../common" import { createReturnFulfillmentWorkflow } from "../../../fulfillment" -import { createCompleteReturnStep } from "../../steps/create-complete-return" -import { receiveReturnStep } from "../../steps/receive-return" +import { createCompleteReturnStep } from "../../steps/return/create-complete-return" +import { receiveReturnStep } from "../../steps/return/receive-return" import { throwIfItemsDoesNotExistsInOrder, throwIfOrderIsCancelled, diff --git a/packages/core/core-flows/src/order/workflows/return/receive-complete-return.ts b/packages/core/core-flows/src/order/workflows/return/receive-complete-return.ts index 8a62b198ed..0a86f423b8 100644 --- a/packages/core/core-flows/src/order/workflows/return/receive-complete-return.ts +++ b/packages/core/core-flows/src/order/workflows/return/receive-complete-return.ts @@ -8,7 +8,7 @@ import { import { useRemoteQueryStep } from "../../../common" import { ReturnDTO } from "@medusajs/types" -import { receiveReturnStep } from "../../steps/receive-return" +import { receiveReturnStep } from "../../steps/return/receive-return" import { throwIfIsCancelled, throwIfItemsDoesNotExistsInReturn, diff --git a/packages/core/types/src/workflow/order/items.ts b/packages/core/types/src/workflow/order/items.ts index f27ee206f5..3890883d92 100644 --- a/packages/core/types/src/workflow/order/items.ts +++ b/packages/core/types/src/workflow/order/items.ts @@ -25,6 +25,11 @@ export interface OrderClaimAddNewItemWorkflowInput { items: NewItem[] } +export interface OrderExchangeAddNewItemWorkflowInput { + exchange_id: string + items: NewItem[] +} + export interface OrderAddLineItemWorkflowInput { order_id: string items: NewItem[] @@ -48,6 +53,15 @@ export interface UpdateClaimAddNewItemWorkflowInput { } } +export interface UpdateExchangeAddNewItemWorkflowInput { + exchange_id: string + action_id: string + data: { + quantity?: BigNumberInput + internal_note?: string | null + } +} + export interface OrderExchangeItemWorkflowInput { exchange_id: string items: ExistingItem[] @@ -86,3 +100,8 @@ export interface DeleteOrderClaimItemActionWorkflowInput { claim_id: string action_id: string } + +export interface DeleteOrderExchangeItemActionWorkflowInput { + exchange_id: string + action_id: string +}