From ffd4b195eef99a3429db2f3bc4f307bf9196f92f Mon Sep 17 00:00:00 2001 From: Oli Juhl <59018053+olivermrbl@users.noreply.github.com> Date: Mon, 15 Jul 2024 22:04:20 +0200 Subject: [PATCH] feat: Add exchange return shipping (#8108) * wip * finalize tests * feat: Add exchange return shipping * add shipping to preview * test input * move utils and ignore already inserted shipping method * use custom price --------- Co-authored-by: Carlos R. L. Rodrigues --- .../http/__tests__/returns/returns.spec.ts | 18 +-- .../create-exchange-return-shipping.spec.ts | 126 +++++++++++++++ .../return/create-return-shipping.spec.ts | 59 +++---- .../order/workflows/confirm-return-request.ts | 7 +- .../create-exchange-return-shipping-method.ts | 147 ++++++++++++++++++ .../create-return-shipping-method.ts | 65 +++++--- .../core-flows/src/order/workflows/index.ts | 1 + packages/core/types/src/order/common.ts | 2 + packages/core/utils/src/order/index.ts | 1 + packages/core/utils/src/order/order-change.ts | 29 ++++ .../returns/[id]/shipping-method/route.ts | 25 +-- .../src/migrations/Migration20240715102100.ts | 12 ++ .../modules/order/src/models/order-change.ts | 6 +- packages/modules/order/src/models/return.ts | 3 + .../__tests__/util/actions/exchanges.ts | 8 +- .../src/services/actions/create-claim.ts | 2 +- .../src/services/actions/create-exchange.ts | 2 +- .../src/services/actions/create-return.ts | 2 +- .../src/services/actions/receive-return.ts | 2 +- .../src/services/order-module-service.ts | 85 +++++++--- .../modules/order/src/types/order-change.ts | 31 +--- .../modules/order/src/types/utils/index.ts | 2 +- .../order/src/utils/actions/shipping-add.ts | 2 +- .../src/utils/actions/shipping-remove.ts | 2 +- .../order/src/utils/apply-order-changes.ts | 37 ++++- 25 files changed, 511 insertions(+), 165 deletions(-) create mode 100644 integration-tests/modules/__tests__/order/workflows/return/create-exchange-return-shipping.spec.ts create mode 100644 packages/core/core-flows/src/order/workflows/create-exchange-return-shipping-method.ts create mode 100644 packages/core/utils/src/order/order-change.ts create mode 100644 packages/modules/order/src/migrations/Migration20240715102100.ts diff --git a/integration-tests/http/__tests__/returns/returns.spec.ts b/integration-tests/http/__tests__/returns/returns.spec.ts index e99ee6fcb0..d60d6e5d64 100644 --- a/integration-tests/http/__tests__/returns/returns.spec.ts +++ b/integration-tests/http/__tests__/returns/returns.spec.ts @@ -225,21 +225,11 @@ medusaIntegrationTestRunner({ adminHeaders ) - expect(result.data.return).toEqual( + expect(result.data.order.shipping_methods[1]).toEqual( expect.objectContaining({ - id: expect.any(String), - order_id: order.id, - display_id: 1, - order_version: 2, - status: "requested", - items: [], - shipping_methods: [ - expect.objectContaining({ - amount: 1000, - name: "Return shipping", - shipping_option_id: returnShippingOption.id, - }), - ], + amount: 1000, + name: "Return shipping", + shipping_option_id: returnShippingOption.id, }) ) 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 new file mode 100644 index 0000000000..25d5914b5b --- /dev/null +++ b/integration-tests/modules/__tests__/order/workflows/return/create-exchange-return-shipping.spec.ts @@ -0,0 +1,126 @@ +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/integration-tests/modules/__tests__/order/workflows/return/create-return-shipping.spec.ts b/integration-tests/modules/__tests__/order/workflows/return/create-return-shipping.spec.ts index ea352a248a..a1b4f1dc50 100644 --- a/integration-tests/modules/__tests__/order/workflows/return/create-return-shipping.spec.ts +++ b/integration-tests/modules/__tests__/order/workflows/return/create-return-shipping.spec.ts @@ -2,9 +2,10 @@ import { beginReturnOrderWorkflow, createReturnShippingMethodWorkflow, } from "@medusajs/core-flows" -import { OrderDTO, ReturnDTO } from "@medusajs/types" +import { IFulfillmentModuleService, OrderDTO, ReturnDTO } from "@medusajs/types" import { ContainerRegistrationKeys, + ModuleRegistrationName, remoteQueryObjectFromString, } from "@medusajs/utils" import { medusaIntegrationTestRunner } from "medusa-test-utils" @@ -23,6 +24,7 @@ medusaIntegrationTestRunner({ describe("Order change: Create return shipping", () => { let order: OrderDTO + let service: IFulfillmentModuleService let fixtures let returnOrder: ReturnDTO @@ -52,6 +54,7 @@ medusaIntegrationTestRunner({ fields: ["order_id", "id", "status", "order_change_id"], }) + service = container.resolve(ModuleRegistrationName.FULFILLMENT) ;[returnOrder] = await remoteQuery(remoteQueryObject) }) @@ -59,62 +62,50 @@ medusaIntegrationTestRunner({ it("should successfully add return shipping to order changes", async () => { const shippingOptionId = fixtures.shippingOption.id - const { result } = await createReturnShippingMethodWorkflow( - container - ).run({ - input: { - return_id: returnOrder.id, - shipping_option_id: shippingOptionId, - }, - }) + const { result: orderChangePreview } = + await createReturnShippingMethodWorkflow(container).run({ + input: { + return_id: returnOrder.id, + shipping_option_id: shippingOptionId, + }, + }) - const orderChange = result?.[0] - - expect(orderChange).toEqual( + expect(orderChangePreview.shipping_methods[1].actions).toEqual([ expect.objectContaining({ id: expect.any(String), reference: "order_shipping_method", reference_id: expect.any(String), - order_id: returnOrder.order_id, - return_id: returnOrder.id, - details: {}, 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 createReturnShippingMethodWorkflow( - container - ).run({ - input: { - return_id: returnOrder.id, - shipping_option_id: shippingOptionId, - custom_price: 20, - }, - }) + const { result: orderChangePreview } = + await createReturnShippingMethodWorkflow(container).run({ + input: { + return_id: returnOrder.id, + shipping_option_id: shippingOptionId, + custom_price: 20, + }, + }) - const orderChange = result?.[0] - - expect(orderChange).toEqual( + expect(orderChangePreview.shipping_methods[1].actions).toEqual([ expect.objectContaining({ id: expect.any(String), reference: "order_shipping_method", reference_id: expect.any(String), - order_id: returnOrder.order_id, - return_id: returnOrder.id, - details: {}, raw_amount: { value: "20", precision: 20 }, applied: false, action: "SHIPPING_ADD", amount: 20, - }) - ) + }), + ]) }) }) }) diff --git a/packages/core/core-flows/src/order/workflows/confirm-return-request.ts b/packages/core/core-flows/src/order/workflows/confirm-return-request.ts index 87d0100403..7ed1d0bc60 100644 --- a/packages/core/core-flows/src/order/workflows/confirm-return-request.ts +++ b/packages/core/core-flows/src/order/workflows/confirm-return-request.ts @@ -1,13 +1,12 @@ import { OrderChangeDTO, OrderDTO, ReturnDTO } from "@medusajs/types" import { ChangeActionType } from "@medusajs/utils" import { + WorkflowData, createStep, createWorkflow, transform, - WorkflowData, } from "@medusajs/workflows-sdk" import { useRemoteQueryStep } from "../../common" -import { previewOrderChangeStep } from "../steps" import { confirmOrderChanges } from "../steps/confirm-order-changes" import { createReturnItems } from "../steps/create-return-items" import { @@ -39,7 +38,7 @@ const validationStep = createStep( export const confirmReturnRequestWorkflowId = "confirm-return-request" export const confirmReturnRequestWorkflow = createWorkflow( confirmReturnRequestWorkflowId, - function (input: WorkflowInput): WorkflowData { + function (input: WorkflowInput): WorkflowData { const orderReturn: ReturnDTO = useRemoteQueryStep({ entry_point: "return", fields: ["id", "status", "order_id"], @@ -87,7 +86,5 @@ export const confirmReturnRequestWorkflow = createWorkflow( createReturnItems({ returnId: orderReturn.id, changes: returnItemActions }) confirmOrderChanges({ changes: [orderChange], orderId: order.id }) - - return previewOrderChangeStep(order.id) } ) diff --git a/packages/core/core-flows/src/order/workflows/create-exchange-return-shipping-method.ts b/packages/core/core-flows/src/order/workflows/create-exchange-return-shipping-method.ts new file mode 100644 index 0000000000..7843db7a6d --- /dev/null +++ b/packages/core/core-flows/src/order/workflows/create-exchange-return-shipping-method.ts @@ -0,0 +1,147 @@ +import { + BigNumberInput, + OrderChangeDTO, + OrderDTO, + OrderExchangeDTO, +} from "@medusajs/types" +import { ChangeActionType } from "@medusajs/utils" +import { + createStep, + createWorkflow, + transform, + WorkflowData, +} from "@medusajs/workflows-sdk" +import { useRemoteQueryStep } from "../../common" +import { createOrderChangeActionsStep } from "../steps/create-order-change-actions" +import { createOrderShippingMethods } from "../steps/create-order-shipping-methods" +import { + throwIfOrderChangeIsNotActive, + throwIfOrderIsCancelled, +} from "../utils/order-validation" + +const validationStep = createStep( + "validate-create-exchange-return-shipping-method", + async function ({ + order, + orderChange, + }: { + order: OrderDTO + orderChange: OrderChangeDTO + }) { + throwIfOrderIsCancelled({ order }) + throwIfOrderChangeIsNotActive({ orderChange }) + } +) + +export const createExchangeReturnShippingMethodWorkflowId = + "create-exchange-return-shipping-method" +export const createExchangeReturnShippingMethodWorkflow = createWorkflow( + createExchangeReturnShippingMethodWorkflowId, + function (input: { + exchangeId: string + shippingOptionId: string + customShippingPrice?: BigNumberInput + }): WorkflowData { + const orderExchange: OrderExchangeDTO = useRemoteQueryStep({ + entry_point: "order_exchange", + fields: ["id", "status", "order_id", "return_id"], + variables: { id: input.exchangeId }, + list: false, + throw_if_key_not_found: true, + }) + + const order: OrderDTO = useRemoteQueryStep({ + entry_point: "orders", + fields: ["id", "status", "currency_code"], + variables: { id: orderExchange.order_id }, + list: false, + throw_if_key_not_found: true, + }).config({ name: "order-query" }) + + const shippingOptions = useRemoteQueryStep({ + entry_point: "shipping_option", + fields: [ + "id", + "name", + "calculated_price.calculated_amount", + "calculated_price.is_calculated_price_tax_inclusive", + ], + variables: { + id: input.shippingOptionId, + 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"], + variables: { order_id: orderExchange.order_id }, + list: false, + }).config({ name: "order-change-query" }) + + validationStep({ order, orderChange }) + + const orderChangeActionInput = transform( + { + orderId: order.id, + returnId: orderExchange.return_id, + exchangeId: orderExchange.id, + shippingOption: shippingOptions[0], + methodId: createdMethods[0].id, + customPrice: input.customShippingPrice, + }, + ({ + shippingOption, + exchangeId, + returnId, + orderId, + methodId, + customPrice, + }) => { + const methodPrice = + customPrice ?? shippingOption.calculated_price.calculated_amount + + return { + action: ChangeActionType.SHIPPING_ADD, + reference: "order_shipping_method", + reference_id: methodId, + amount: methodPrice, + details: { + order_id: orderId, + return_id: returnId, + exchange_id: exchangeId, + }, + } + } + ) + + return createOrderChangeActionsStep([orderChangeActionInput]) + } +) diff --git a/packages/core/core-flows/src/order/workflows/create-return-shipping-method.ts b/packages/core/core-flows/src/order/workflows/create-return-shipping-method.ts index 32b75e886c..7a8ea59146 100644 --- a/packages/core/core-flows/src/order/workflows/create-return-shipping-method.ts +++ b/packages/core/core-flows/src/order/workflows/create-return-shipping-method.ts @@ -4,16 +4,17 @@ import { OrderDTO, ReturnDTO, } from "@medusajs/types" -import { ChangeActionType } from "@medusajs/utils" +import { ChangeActionType, OrderChangeStatus } from "@medusajs/utils" import { + WorkflowData, createStep, createWorkflow, transform, - WorkflowData, } from "@medusajs/workflows-sdk" import { useRemoteQueryStep } from "../../common" import { createOrderChangeActionsStep } from "../steps/create-order-change-actions" import { createOrderShippingMethods } from "../steps/create-order-shipping-methods" +import { previewOrderChangeStep } from "../steps/preview-order-change" import { throwIfIsCancelled, throwIfOrderChangeIsNotActive, @@ -77,10 +78,25 @@ export const createReturnShippingMethodWorkflow = createWorkflow( }, }).config({ name: "fetch-shipping-option" }) + const orderChange: OrderChangeDTO = useRemoteQueryStep({ + entry_point: "order_change", + fields: ["id", "status", "version"], + variables: { + filters: { + order_id: orderReturn.order_id, + status: [OrderChangeStatus.PENDING, OrderChangeStatus.REQUESTED], + }, + }, + list: false, + }).config({ name: "order-change-query" }) + + validationStep({ order, orderReturn, orderChange }) + const shippingMethodInput = transform( - { orderReturn, shippingOptions }, + { orderReturn, shippingOptions, orderChange }, (data) => { const option = data.shippingOptions[0] + const orderChange = data.orderChange return { shipping_option_id: option.id, @@ -89,6 +105,7 @@ export const createReturnShippingMethodWorkflow = createWorkflow( !!option.calculated_price.is_calculated_price_tax_inclusive, data: option.data ?? {}, name: option.name, + version: orderChange.version, order_id: data.orderReturn.order_id, return_id: data.orderReturn.id, } @@ -99,40 +116,42 @@ export const createReturnShippingMethodWorkflow = createWorkflow( shipping_methods: [shippingMethodInput], }) - const orderChange: OrderChangeDTO = useRemoteQueryStep({ - entry_point: "order_change", - fields: ["id", "status"], - variables: { - filters: { order_id: orderReturn.order_id, return_id: orderReturn.id }, - }, - list: false, - }).config({ name: "order-change-query" }) - - validationStep({ order, orderReturn, orderChange }) - const orderChangeActionInput = transform( { - orderId: order.id, - returnId: orderReturn.id, - shippingOption: shippingOptions[0], - methodId: createdMethods[0].id, + order, + orderReturn, + shippingOptions, + createdMethods, customPrice: input.custom_price, + orderChange, }, - ({ shippingOption, returnId, orderId, methodId, customPrice }) => { + ({ + shippingOptions, + orderReturn, + order, + createdMethods, + customPrice, + orderChange, + }) => { + 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, + reference_id: createdMethod.id, + order_change_id: orderChange.id, amount: methodPrice, - order_id: orderId, - return_id: returnId, + order_id: order.id, + return_id: orderReturn.id, } } ) - return createOrderChangeActionsStep([orderChangeActionInput]) + createOrderChangeActionsStep([orderChangeActionInput]) + + return previewOrderChangeStep(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 93e43c71eb..ed0a86dc76 100644 --- a/packages/core/core-flows/src/order/workflows/index.ts +++ b/packages/core/core-flows/src/order/workflows/index.ts @@ -11,6 +11,7 @@ export * from "./claim-request-item-return" export * from "./complete-orders" export * from "./confirm-return-request" export * from "./create-complete-return" +export * from "./create-exchange-return-shipping-method" export * from "./create-fulfillment" export * from "./create-order-change" export * from "./create-order-change-actions" diff --git a/packages/core/types/src/order/common.ts b/packages/core/types/src/order/common.ts index f7ccde7e01..9238dedee7 100644 --- a/packages/core/types/src/order/common.ts +++ b/packages/core/types/src/order/common.ts @@ -1161,6 +1161,8 @@ export interface OrderExchangeDTO no_notification?: boolean difference_due?: BigNumberValue return?: ReturnDTO + return_id?: string + order_id: string } export type PaymentStatus = diff --git a/packages/core/utils/src/order/index.ts b/packages/core/utils/src/order/index.ts index c9aad20dcc..a2fff682e9 100644 --- a/packages/core/utils/src/order/index.ts +++ b/packages/core/utils/src/order/index.ts @@ -1,3 +1,4 @@ export * from "./events" +export * from "./order-change" export * from "./order-change-action" export * from "./status" diff --git a/packages/core/utils/src/order/order-change.ts b/packages/core/utils/src/order/order-change.ts new file mode 100644 index 0000000000..635b71fe74 --- /dev/null +++ b/packages/core/utils/src/order/order-change.ts @@ -0,0 +1,29 @@ +export enum OrderChangeStatus { + /** + * The order change is confirmed. + */ + CONFIRMED = "confirmed", + /** + * The order change is declined. + */ + DECLINED = "declined", + /** + * The order change is requested. + */ + REQUESTED = "requested", + /** + * The order change is pending. + */ + PENDING = "pending", + /** + * The order change is canceled. + */ + CANCELED = "canceled", +} + +export enum OrderChangeType { + RETURN = "return", + EXCHANGE = "exchange", + CLAIM = "claim", + EDIT = "edit", +} diff --git a/packages/medusa/src/api/admin/returns/[id]/shipping-method/route.ts b/packages/medusa/src/api/admin/returns/[id]/shipping-method/route.ts index 62236b6eef..6acf15e648 100644 --- a/packages/medusa/src/api/admin/returns/[id]/shipping-method/route.ts +++ b/packages/medusa/src/api/admin/returns/[id]/shipping-method/route.ts @@ -1,8 +1,4 @@ import { createReturnShippingMethodWorkflow } from "@medusajs/core-flows" -import { - ContainerRegistrationKeys, - remoteQueryObjectFromString, -} from "@medusajs/utils" import { AuthenticatedMedusaRequest, MedusaResponse, @@ -15,26 +11,13 @@ export const POST = async ( ) => { const { id } = req.params - const remoteQuery = req.scope.resolve(ContainerRegistrationKeys.REMOTE_QUERY) - - await createReturnShippingMethodWorkflow(req.scope).run({ + const { result: orderPreview } = await createReturnShippingMethodWorkflow( + req.scope + ).run({ input: { ...req.validatedBody, return_id: id }, }) - const queryObject = remoteQueryObjectFromString({ - entryPoint: "return", - variables: { - id, - filters: { - ...req.filterableFields, - }, - }, - fields: req.remoteQueryConfig.fields, - }) - - const [orderReturn] = await remoteQuery(queryObject) - res.json({ - return: orderReturn, + order: orderPreview, }) } diff --git a/packages/modules/order/src/migrations/Migration20240715102100.ts b/packages/modules/order/src/migrations/Migration20240715102100.ts new file mode 100644 index 0000000000..e4e5b3186d --- /dev/null +++ b/packages/modules/order/src/migrations/Migration20240715102100.ts @@ -0,0 +1,12 @@ +import { Migration } from "@mikro-orm/migrations" + +export class Migration20240715102100 extends Migration { + async up(): Promise { + const sql = ` + ALTER TABLE "return" + ADD COLUMN if NOT exists "location_id" TEXT NULL; + ` + + this.addSql(sql) + } +} diff --git a/packages/modules/order/src/models/order-change.ts b/packages/modules/order/src/models/order-change.ts index 1fa271cac7..0132c5bd5f 100644 --- a/packages/modules/order/src/models/order-change.ts +++ b/packages/modules/order/src/models/order-change.ts @@ -2,6 +2,8 @@ import { DAL } from "@medusajs/types" import { createPsqlIndexStatementHelper, generateEntityId, + OrderChangeStatus, + OrderChangeType, } from "@medusajs/utils" import { BeforeCreate, @@ -10,14 +12,14 @@ import { Entity, Enum, ManyToOne, - OnInit, OneToMany, + OnInit, OptionalProps, PrimaryKey, Property, Rel, } from "@mikro-orm/core" -import { OrderChangeStatus, OrderChangeType } from "@types" +import {} from "@types" import OrderClaim from "./claim" import OrderExchange from "./exchange" import Order from "./order" diff --git a/packages/modules/order/src/models/return.ts b/packages/modules/order/src/models/return.ts index 887c891cdd..4e45804bc6 100644 --- a/packages/modules/order/src/models/return.ts +++ b/packages/modules/order/src/models/return.ts @@ -116,6 +116,9 @@ export default class Return { @Enum({ items: () => ReturnStatus, default: ReturnStatus.REQUESTED }) status: ReturnStatus = ReturnStatus.REQUESTED + @Property({ columnType: "text", nullable: true }) + location_id: string | null = null + @Property({ columnType: "boolean", nullable: true }) no_notification: boolean | null = null diff --git a/packages/modules/order/src/services/__tests__/util/actions/exchanges.ts b/packages/modules/order/src/services/__tests__/util/actions/exchanges.ts index d62b722cc1..2a0713bf2c 100644 --- a/packages/modules/order/src/services/__tests__/util/actions/exchanges.ts +++ b/packages/modules/order/src/services/__tests__/util/actions/exchanges.ts @@ -54,7 +54,7 @@ describe("Order Exchange - Actions", function () { shipping_methods: [ { id: "ship_123", - price: 0, + amount: 0, }, ], total: 270, @@ -188,11 +188,11 @@ describe("Order Exchange - Actions", function () { expect(changes.order.shipping_methods).toEqual([ { id: "ship_123", - price: 0, + amount: 0, }, { id: "shipping_345", - price: 5, + amount: 5, actions: [ { action: "SHIPPING_ADD", @@ -203,7 +203,7 @@ describe("Order Exchange - Actions", function () { }, { id: "return_shipping_345", - price: 7.5, + amount: 7.5, actions: [ { action: "SHIPPING_ADD", diff --git a/packages/modules/order/src/services/actions/create-claim.ts b/packages/modules/order/src/services/actions/create-claim.ts index ae711521c6..b9317c1ec2 100644 --- a/packages/modules/order/src/services/actions/create-claim.ts +++ b/packages/modules/order/src/services/actions/create-claim.ts @@ -6,13 +6,13 @@ import { import { ChangeActionType, ClaimType, + OrderChangeType, ReturnStatus, getShippingMethodsTotals, isString, promiseAll, } from "@medusajs/utils" import { ClaimItem, OrderClaim, Return, ReturnItem } from "@models" -import { OrderChangeType } from "@types" function createClaimAndReturnEntities(em, data, order) { const claimReference = em.create(OrderClaim, { diff --git a/packages/modules/order/src/services/actions/create-exchange.ts b/packages/modules/order/src/services/actions/create-exchange.ts index 04d8637dbf..f1cf263e59 100644 --- a/packages/modules/order/src/services/actions/create-exchange.ts +++ b/packages/modules/order/src/services/actions/create-exchange.ts @@ -5,13 +5,13 @@ import { } from "@medusajs/types" import { ChangeActionType, + OrderChangeType, ReturnStatus, getShippingMethodsTotals, isString, promiseAll, } from "@medusajs/utils" import { ExchangeItem, OrderExchange, Return, ReturnItem } from "@models" -import { OrderChangeType } from "@types" function createExchangeAndReturnEntities(em, data, order) { const exchangeReference = em.create(OrderExchange, { diff --git a/packages/modules/order/src/services/actions/create-return.ts b/packages/modules/order/src/services/actions/create-return.ts index 7058aeb075..5845b4d640 100644 --- a/packages/modules/order/src/services/actions/create-return.ts +++ b/packages/modules/order/src/services/actions/create-return.ts @@ -5,6 +5,7 @@ import { } from "@medusajs/types" import { ChangeActionType, + OrderChangeType, ReturnStatus, getShippingMethodsTotals, isDefined, @@ -12,7 +13,6 @@ import { promiseAll, } from "@medusajs/utils" import { Return, ReturnItem } from "@models" -import { OrderChangeType } from "@types" function createReturnReference(em, data, order) { return em.create(Return, { diff --git a/packages/modules/order/src/services/actions/receive-return.ts b/packages/modules/order/src/services/actions/receive-return.ts index 639723745a..6c74579d51 100644 --- a/packages/modules/order/src/services/actions/receive-return.ts +++ b/packages/modules/order/src/services/actions/receive-return.ts @@ -2,10 +2,10 @@ import { Context, OrderTypes } from "@medusajs/types" import { ChangeActionType, MathBN, + OrderChangeType, ReturnStatus, promiseAll, } from "@medusajs/utils" -import { OrderChangeType } from "@types" function createReturnItems(data) { return data.items.map((item) => ({ diff --git a/packages/modules/order/src/services/order-module-service.ts b/packages/modules/order/src/services/order-module-service.ts index 0dcc4f560c..d81c30998c 100644 --- a/packages/modules/order/src/services/order-module-service.ts +++ b/packages/modules/order/src/services/order-module-service.ts @@ -21,12 +21,14 @@ import { deduplicate, InjectManager, InjectTransactionManager, + isDefined, isObject, isString, MathBN, MedusaContext, MedusaError, ModulesSdkUtils, + OrderChangeStatus, OrderStatus, promiseAll, transformPropertiesToBigNumber, @@ -59,7 +61,6 @@ import { CreateOrderLineItemTaxLineDTO, CreateOrderShippingMethodDTO, CreateOrderShippingMethodTaxLineDTO, - OrderChangeStatus, UpdateOrderItemDTO, UpdateOrderLineItemDTO, UpdateOrderLineItemTaxLineDTO, @@ -1193,7 +1194,7 @@ export default class OrderModuleService< return_id: dt.return_id, claim_id: dt.claim_id, exchange_id: dt.exchange_id, - version: mapOrderVersion[dt.order_id], + version: dt.version ?? mapOrderVersion[dt.order_id], } }) @@ -1979,13 +1980,20 @@ export default class OrderModuleService< const calculated = calculatedOrders[order.id] const addedItems = {} + const addedShippingMethods = {} for (const item of calculated.order.items) { const isExistingItem = item.id === item.detail?.item_id - if (!isExistingItem) { addedItems[item.id] = item } } + + for (const sm of calculated.order.shipping_methods) { + if (!isDefined(sm.shipping_option_id)) { + addedShippingMethods[sm.id] = sm + } + } + if (Object.keys(addedItems).length > 0) { const addedItemDetails = await this.listLineItems( { id: Object.keys(addedItems) }, @@ -1996,22 +2004,61 @@ export default class OrderModuleService< ) calculated.order.items.forEach((item, idx) => { - if (addedItems[item.id]) { - const lineItem = addedItemDetails.find((d) => d.id === item.id) as any + if (!addedItems[item.id]) { + return + } - const actions = item.actions - delete item.actions + const lineItem = addedItemDetails.find((d) => d.id === item.id) as any - const newItem = itemsToUpsert.find((d) => d.item_id === item.id)! - calculated.order.items[idx] = { - ...lineItem, - actions, - quantity: newItem.quantity, - detail: { - ...newItem, - ...item, - }, - } + const actions = item.actions + delete item.actions + + const newItem = itemsToUpsert.find((d) => d.item_id === item.id)! + calculated.order.items[idx] = { + ...lineItem, + actions, + quantity: newItem.quantity, + detail: { + ...newItem, + ...item, + }, + } + }) + } + + if (Object.keys(addedShippingMethods).length > 0) { + const addedShippingDetails = await this.listShippingMethods( + { id: Object.keys(addedShippingMethods) }, + { + relations: ["adjustments", "tax_lines"], + }, + sharedContext + ) + + calculated.order.shipping_methods.forEach((sm, idx) => { + if (!addedShippingMethods[sm.id]) { + return + } + + const shippingMethod = addedShippingDetails.find( + (d) => d.id === sm.id + ) as any + + const actions = sm.actions + delete sm.actions + + const newItem = shippingMethodsToUpsert.find((d) => d.id === sm.id)! + + sm.shipping_method_id = sm.id + delete sm.id + + calculated.order.shipping_methods[idx] = { + ...shippingMethod, + actions, + detail: { + ...sm, + ...newItem, + }, } }) } @@ -2579,7 +2626,9 @@ export default class OrderModuleService< shippingMethodsToUpsert, summariesToUpsert, orderToUpdate, - } = applyChangesToOrder(orders, actionsMap) + } = applyChangesToOrder(orders, actionsMap, { + addActionReferenceToObject: true, + }) await promiseAll([ orderToUpdate.length diff --git a/packages/modules/order/src/types/order-change.ts b/packages/modules/order/src/types/order-change.ts index e4009570af..146ac29eb2 100644 --- a/packages/modules/order/src/types/order-change.ts +++ b/packages/modules/order/src/types/order-change.ts @@ -1,34 +1,5 @@ import { OrderTypes } from "@medusajs/types" - -export enum OrderChangeStatus { - /** - * The order change is confirmed. - */ - CONFIRMED = "confirmed", - /** - * The order change is declined. - */ - DECLINED = "declined", - /** - * The order change is requested. - */ - REQUESTED = "requested", - /** - * The order change is pending. - */ - PENDING = "pending", - /** - * The order change is canceled. - */ - CANCELED = "canceled", -} - -export enum OrderChangeType { - RETURN = "return", - EXCHANGE = "exchange", - CLAIM = "claim", - EDIT = "edit", -} +import { OrderChangeType } from "@medusajs/utils" export interface CreateOrderChangeDTO extends OrderTypes.CreateOrderChangeDTO { change_type?: OrderChangeType diff --git a/packages/modules/order/src/types/utils/index.ts b/packages/modules/order/src/types/utils/index.ts index 377815aefc..23aaac0773 100644 --- a/packages/modules/order/src/types/utils/index.ts +++ b/packages/modules/order/src/types/utils/index.ts @@ -47,7 +47,7 @@ export type VirtualOrder = { exchange_id?: string } - price: BigNumberInput + amount: BigNumberInput }[] total: BigNumberInput diff --git a/packages/modules/order/src/utils/actions/shipping-add.ts b/packages/modules/order/src/utils/actions/shipping-add.ts index 7807f8e37e..cdfcbb4e50 100644 --- a/packages/modules/order/src/utils/actions/shipping-add.ts +++ b/packages/modules/order/src/utils/actions/shipping-add.ts @@ -17,7 +17,7 @@ OrderChangeProcessing.registerActionType(ChangeActionType.SHIPPING_ADD, { return_id: action.return_id, claim_id: action.claim_id, exchange_id: action.exchange_id, - price: action.amount as number, + amount: action.amount as number, } shipping.push(existing) } diff --git a/packages/modules/order/src/utils/actions/shipping-remove.ts b/packages/modules/order/src/utils/actions/shipping-remove.ts index 6267e2e041..e51c5679ea 100644 --- a/packages/modules/order/src/utils/actions/shipping-remove.ts +++ b/packages/modules/order/src/utils/actions/shipping-remove.ts @@ -33,7 +33,7 @@ OrderChangeProcessing.registerActionType(ChangeActionType.SHIPPING_REMOVE, { return_id: action.return_id, claim_id: action.claim_id, exchange_id: action.exchange_id, - price: action.amount as number, + amount: action.amount as number, }) } }, diff --git a/packages/modules/order/src/utils/apply-order-changes.ts b/packages/modules/order/src/utils/apply-order-changes.ts index f3f3dafe1d..b023d8011b 100644 --- a/packages/modules/order/src/utils/apply-order-changes.ts +++ b/packages/modules/order/src/utils/apply-order-changes.ts @@ -1,5 +1,9 @@ import { OrderChangeActionDTO } from "@medusajs/types" -import { createRawPropertiesFromBigNumber } from "@medusajs/utils" +import { + ChangeActionType, + createRawPropertiesFromBigNumber, + isDefined, +} from "@medusajs/utils" import { OrderItem, OrderShippingMethod } from "@models" import { calculateOrderChange } from "./calculate-order-change" @@ -35,7 +39,7 @@ export function applyChangesToOrder( calculatedOrders[order.id] = calculated - const version = actionsMap[order.id][0].version ?? 1 + const version = actionsMap[order.id]?.[0]?.version ?? order.version for (const item of calculated.order.items) { const isExistingItem = item.id === item.detail?.item_id @@ -68,17 +72,36 @@ export function applyChangesToOrder( if (version > order.version) { for (const shippingMethod of calculated.order.shipping_methods ?? []) { - if (!shippingMethod) { + const shippingMethod_ = shippingMethod as any + const isNewShippingMethod = !isDefined(shippingMethod_?.detail) + if (!shippingMethod_) { continue } - const sm = { - ...((shippingMethod as any).detail ?? shippingMethod), - version, + let associatedMethodId + let hasShippingMethod = false + if (isNewShippingMethod) { + associatedMethodId = shippingMethod_.actions?.find((sm) => { + return ( + sm.action === ChangeActionType.SHIPPING_ADD && sm.reference_id + ) + }) + hasShippingMethod = !!associatedMethodId + } else { + associatedMethodId = shippingMethod_?.detail?.shipping_method_id } + const sm = { + ...(isNewShippingMethod ? shippingMethod_ : shippingMethod_.detail), + version, + shipping_method_id: associatedMethodId, + } as any + delete sm.id - shippingMethodsToUpsert.push(sm) + + if (!hasShippingMethod) { + shippingMethodsToUpsert.push(sm) + } } orderToUpdate.push({