diff --git a/integration-tests/http/__tests__/returns/returns.spec.ts b/integration-tests/http/__tests__/returns/returns.spec.ts index 9b037b9aab..5e23a4cf77 100644 --- a/integration-tests/http/__tests__/returns/returns.spec.ts +++ b/integration-tests/http/__tests__/returns/returns.spec.ts @@ -531,6 +531,53 @@ medusaIntegrationTestRunner({ }) ) }) + + it("should cancel a return request", async () => { + let result = await api.post( + "/admin/returns", + { + order_id: order.id, + description: "Test", + }, + adminHeaders + ) + + const returnId = result.data.return.id + + const item = order.items[0] + await api.post( + `/admin/returns/${returnId}/request-items`, + { + items: [ + { + id: item.id, + quantity: 2, + reason_id: returnReason.id, + }, + ], + }, + adminHeaders + ) + + await api.post( + `/admin/returns/${returnId}/shipping-method`, + { + shipping_option_id: returnShippingOption.id, + }, + adminHeaders + ) + + await api.delete(`/admin/returns/${returnId}/request`, adminHeaders) + + result = await api + .post(`/admin/returns/${returnId}/request`, {}, adminHeaders) + .catch((e) => e) + + expect(result.response.status).toEqual(404) + expect(result.response.data.message).toEqual( + `Return id not found: ${returnId}` + ) + }) }) }, }) diff --git a/integration-tests/modules/__tests__/cart/store/cart.workflows.spec.ts b/integration-tests/modules/__tests__/cart/store/cart.workflows.spec.ts index 8f99661ee0..6f2e2e0338 100644 --- a/integration-tests/modules/__tests__/cart/store/cart.workflows.spec.ts +++ b/integration-tests/modules/__tests__/cart/store/cart.workflows.spec.ts @@ -778,8 +778,7 @@ medusaIntegrationTestRunner({ action: "use-remote-query", handlerType: "invoke", error: expect.objectContaining({ - // TODO: Implement error message handler for Remote Query throw_if_key_not_found - message: `productService id not found: prva_foo`, + message: `ProductVariant id not found: prva_foo`, }), }, ]) diff --git a/integration-tests/modules/__tests__/modules/remote-query.spec.ts b/integration-tests/modules/__tests__/modules/remote-query.spec.ts index bc9fae48c5..809429d058 100644 --- a/integration-tests/modules/__tests__/modules/remote-query.spec.ts +++ b/integration-tests/modules/__tests__/modules/remote-query.spec.ts @@ -71,7 +71,7 @@ medusaIntegrationTestRunner({ ) await expect(getNonExistingRegion).rejects.toThrow( - "region id not found: region_123" + "Region id not found: region_123" ) }) diff --git a/integration-tests/modules/__tests__/order/workflows/return/items.spec.ts b/integration-tests/modules/__tests__/order/workflows/return/items.spec.ts index fb833a7ae7..b092d81392 100644 --- a/integration-tests/modules/__tests__/order/workflows/return/items.spec.ts +++ b/integration-tests/modules/__tests__/order/workflows/return/items.spec.ts @@ -120,7 +120,7 @@ medusaIntegrationTestRunner({ }) expect(error.error.message).toEqual( - "order id not found: does-not-exist" + "Return id not found: does-not-exist" ) }) @@ -145,7 +145,7 @@ medusaIntegrationTestRunner({ throwOnError: false, }) - expect(error.error.message).toEqual(`order id not found: ${order.id}`) + expect(error.error.message).toEqual(`Order id not found: ${order.id}`) }) it("should throw an error if order change does not exist", async () => { @@ -206,7 +206,7 @@ medusaIntegrationTestRunner({ }) expect(error.error.message).toEqual( - `Order Change cannot be modified: ${orderChange.id}.` + `An active Order Change is required to proceed` ) }) diff --git a/packages/core/core-flows/src/order/steps/delete-return.ts b/packages/core/core-flows/src/order/steps/delete-return.ts new file mode 100644 index 0000000000..26e760dbe8 --- /dev/null +++ b/packages/core/core-flows/src/order/steps/delete-return.ts @@ -0,0 +1,28 @@ +import { IOrderModuleService } from "@medusajs/types" +import { ModuleRegistrationName } from "@medusajs/utils" +import { createStep, StepResponse } from "@medusajs/workflows-sdk" + +export const deleteReturnsStepId = "delete-return" +export const deleteReturnsStep = createStep( + deleteReturnsStepId, + async (data: { ids: string[] }, { container }) => { + const service = container.resolve( + ModuleRegistrationName.ORDER + ) + + const deleted = await service.softDeleteReturns(data.ids) + + return new StepResponse(deleted, data.ids) + }, + async (ids, { container }) => { + if (!ids) { + return + } + + const service = container.resolve( + ModuleRegistrationName.ORDER + ) + + await service.restoreReturns(ids) + } +) diff --git a/packages/core/core-flows/src/order/steps/index.ts b/packages/core/core-flows/src/order/steps/index.ts index 9c6aff59ee..1ee4143fff 100644 --- a/packages/core/core-flows/src/order/steps/index.ts +++ b/packages/core/core-flows/src/order/steps/index.ts @@ -18,6 +18,7 @@ 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-return" export * from "./get-item-tax-lines" export * from "./preview-order-change" export * from "./register-fulfillment" diff --git a/packages/core/core-flows/src/order/workflows/claim/claim-add-new-item.ts b/packages/core/core-flows/src/order/workflows/claim/claim-add-new-item.ts index 53b59bd670..8fb491974f 100644 --- a/packages/core/core-flows/src/order/workflows/claim/claim-add-new-item.ts +++ b/packages/core/core-flows/src/order/workflows/claim/claim-add-new-item.ts @@ -4,7 +4,7 @@ import { OrderDTO, OrderWorkflow, } from "@medusajs/types" -import { ChangeActionType } from "@medusajs/utils" +import { ChangeActionType, OrderChangeStatus } from "@medusajs/utils" import { WorkflowData, createStep, @@ -63,7 +63,13 @@ export const orderClaimAddNewItemWorkflow = createWorkflow( const orderChange: OrderChangeDTO = useRemoteQueryStep({ entry_point: "order_change", fields: ["id", "status"], - variables: { order_id: orderClaim.order_id }, + variables: { + filters: { + order_id: orderClaim.order_id, + claim_id: orderClaim.id, + status: [OrderChangeStatus.PENDING, OrderChangeStatus.REQUESTED], + }, + }, list: false, }).config({ name: "order-change-query" }) 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 7b9c72b1a2..a3468019f4 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 @@ -5,7 +5,7 @@ import { OrderWorkflow, ReturnDTO, } from "@medusajs/types" -import { ChangeActionType } from "@medusajs/utils" +import { ChangeActionType, OrderChangeStatus } from "@medusajs/utils" import { WorkflowData, createStep, @@ -103,9 +103,18 @@ export const orderClaimRequestItemReturnWorkflow = createWorkflow( const orderChange: OrderChangeDTO = useRemoteQueryStep({ entry_point: "order_change", fields: ["id", "status"], - variables: { order_id: orderClaim.order_id }, + variables: { + filters: { + order_id: orderClaim.order_id, + claim_id: orderClaim.id, + status: [OrderChangeStatus.PENDING, OrderChangeStatus.REQUESTED], + }, + }, list: false, - }).config({ name: "order-change-query" }) + }).config({ + name: "order-change-query", + status: [OrderChangeStatus.PENDING, OrderChangeStatus.REQUESTED], + }) validationStep({ order, 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-return-shipping-method.ts index d31bd91ffa..342fd81c25 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-return-shipping-method.ts @@ -4,7 +4,7 @@ import { OrderDTO, OrderExchangeDTO, } from "@medusajs/types" -import { ChangeActionType } from "@medusajs/utils" +import { ChangeActionType, OrderChangeStatus } from "@medusajs/utils" import { WorkflowData, createStep, @@ -102,7 +102,13 @@ export const createExchangeReturnShippingMethodWorkflow = createWorkflow( const orderChange: OrderChangeDTO = useRemoteQueryStep({ entry_point: "order_change", fields: ["id", "status"], - variables: { order_id: orderExchange.order_id }, + variables: { + filters: { + order_id: orderExchange.order_id, + exchange_id: orderExchange.id, + status: [OrderChangeStatus.PENDING, OrderChangeStatus.REQUESTED], + }, + }, list: false, }).config({ name: "order-change-query" }) 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 da97a3de31..5490489137 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 @@ -4,7 +4,7 @@ import { OrderExchangeDTO, OrderWorkflow, } from "@medusajs/types" -import { ChangeActionType } from "@medusajs/utils" +import { ChangeActionType, OrderChangeStatus } from "@medusajs/utils" import { WorkflowData, createStep, @@ -63,7 +63,13 @@ export const orderExchangeAddNewItemWorkflow = createWorkflow( const orderChange: OrderChangeDTO = useRemoteQueryStep({ entry_point: "order_change", fields: ["id", "status"], - variables: { order_id: orderExchange.order_id }, + variables: { + filters: { + order_id: orderExchange.order_id, + exchange_id: orderExchange.id, + status: [OrderChangeStatus.PENDING, OrderChangeStatus.REQUESTED], + }, + }, list: false, }).config({ name: "order-change-query" }) 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 f2932368f9..7699af1f04 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 @@ -5,7 +5,7 @@ import { OrderWorkflow, ReturnDTO, } from "@medusajs/types" -import { ChangeActionType } from "@medusajs/utils" +import { ChangeActionType, OrderChangeStatus } from "@medusajs/utils" import { WorkflowData, createStep, @@ -104,7 +104,13 @@ export const orderExchangeRequestItemReturnWorkflow = createWorkflow( const orderChange: OrderChangeDTO = useRemoteQueryStep({ entry_point: "order_change", fields: ["id", "status"], - variables: { order_id: orderExchange.order_id }, + variables: { + filters: { + order_id: orderExchange.order_id, + exchange_id: orderExchange.id, + status: [OrderChangeStatus.PENDING, OrderChangeStatus.REQUESTED], + }, + }, list: false, }).config({ name: "order-change-query" }) diff --git a/packages/core/core-flows/src/order/workflows/index.ts b/packages/core/core-flows/src/order/workflows/index.ts index 8ebcff46ab..c43ccdce57 100644 --- a/packages/core/core-flows/src/order/workflows/index.ts +++ b/packages/core/core-flows/src/order/workflows/index.ts @@ -22,6 +22,7 @@ export * from "./exchange/exchange-request-item-return" export * from "./get-order-detail" export * from "./get-orders-list" export * from "./return/begin-return" +export * from "./return/cancel-request-return" export * from "./return/cancel-return" export * from "./return/confirm-return-request" export * from "./return/create-return-shipping-method" diff --git a/packages/core/core-flows/src/order/workflows/return/cancel-request-return.ts b/packages/core/core-flows/src/order/workflows/return/cancel-request-return.ts new file mode 100644 index 0000000000..9681782d25 --- /dev/null +++ b/packages/core/core-flows/src/order/workflows/return/cancel-request-return.ts @@ -0,0 +1,92 @@ +import { OrderChangeDTO, OrderDTO, ReturnDTO } from "@medusajs/types" +import { ChangeActionType, OrderChangeStatus } from "@medusajs/utils" +import { + WorkflowData, + createStep, + createWorkflow, + parallelize, + transform, +} from "@medusajs/workflows-sdk" +import { useRemoteQueryStep } from "../../../common" +import { + deleteOrderChangesStep, + deleteOrderShippingMethods, + deleteReturnsStep, +} from "../../steps" +import { + throwIfIsCancelled, + throwIfOrderChangeIsNotActive, +} from "../../utils/order-validation" + +type WorkflowInput = { + return_id: string +} + +const validationStep = createStep( + "validate-cancel-return-shipping-method", + async function ({ + order, + orderChange, + orderReturn, + }: { + order: OrderDTO + orderReturn: ReturnDTO + orderChange: OrderChangeDTO + }) { + throwIfIsCancelled(order, "Order") + throwIfIsCancelled(orderReturn, "Return") + throwIfOrderChangeIsNotActive({ orderChange }) + } +) + +export const cancelReturnRequestWorkflowId = "cancel-return-request" +export const cancelReturnRequestWorkflow = createWorkflow( + cancelReturnRequestWorkflowId, + function (input: WorkflowInput): WorkflowData { + const orderReturn: ReturnDTO = useRemoteQueryStep({ + entry_point: "return", + fields: ["id", "status", "order_id"], + variables: { id: input.return_id }, + list: false, + throw_if_key_not_found: true, + }) + + const order: OrderDTO = useRemoteQueryStep({ + entry_point: "orders", + fields: ["id", "version", "items"], + variables: { id: orderReturn.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: orderReturn.order_id, + return_id: orderReturn.id, + status: [OrderChangeStatus.PENDING, OrderChangeStatus.REQUESTED], + }, + }, + list: false, + }).config({ name: "order-change-query" }) + + validationStep({ order, orderReturn, orderChange }) + + const shippingToRemove = transform( + { orderChange, input }, + ({ orderChange, input }) => { + return (orderChange.actions ?? []) + .filter((a) => a.action === ChangeActionType.SHIPPING_ADD) + .map(({ id }) => id) + } + ) + + parallelize( + deleteReturnsStep({ ids: [orderReturn.id] }), + deleteOrderChangesStep({ ids: [orderChange.id] }), + deleteOrderShippingMethods({ ids: shippingToRemove }) + ) + } +) 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 39a5359bb1..b6c77d87bd 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 @@ -1,5 +1,5 @@ import { OrderChangeDTO, OrderDTO, ReturnDTO } from "@medusajs/types" -import { ChangeActionType } from "@medusajs/utils" +import { ChangeActionType, OrderChangeStatus } from "@medusajs/utils" import { WorkflowData, createStep, @@ -71,6 +71,7 @@ export const confirmReturnRequestWorkflow = createWorkflow( filters: { order_id: orderReturn.order_id, return_id: orderReturn.id, + status: [OrderChangeStatus.PENDING, OrderChangeStatus.REQUESTED], }, }, list: false, diff --git a/packages/core/core-flows/src/order/workflows/return/create-return-shipping-method.ts b/packages/core/core-flows/src/order/workflows/return/create-return-shipping-method.ts index b1500ed48a..4784f43143 100644 --- a/packages/core/core-flows/src/order/workflows/return/create-return-shipping-method.ts +++ b/packages/core/core-flows/src/order/workflows/return/create-return-shipping-method.ts @@ -84,6 +84,7 @@ export const createReturnShippingMethodWorkflow = createWorkflow( variables: { filters: { order_id: orderReturn.order_id, + return_id: orderReturn.id, status: [OrderChangeStatus.PENDING, OrderChangeStatus.REQUESTED], }, }, diff --git a/packages/core/core-flows/src/order/workflows/return/request-item-return.ts b/packages/core/core-flows/src/order/workflows/return/request-item-return.ts index 43c0141fd3..9e3143d7a6 100644 --- a/packages/core/core-flows/src/order/workflows/return/request-item-return.ts +++ b/packages/core/core-flows/src/order/workflows/return/request-item-return.ts @@ -4,7 +4,7 @@ import { OrderWorkflow, ReturnDTO, } from "@medusajs/types" -import { ChangeActionType } from "@medusajs/utils" +import { ChangeActionType, OrderChangeStatus } from "@medusajs/utils" import { WorkflowData, createStep, @@ -75,7 +75,11 @@ export const requestItemReturnWorkflow = createWorkflow( entry_point: "order_change", fields: ["id", "status", "order_id", "return_id"], variables: { - filters: { order_id: orderReturn.order_id, return_id: orderReturn.id }, + filters: { + order_id: orderReturn.order_id, + return_id: orderReturn.id, + status: [OrderChangeStatus.PENDING, OrderChangeStatus.REQUESTED], + }, }, list: false, }).config({ name: "order-change-query" }) diff --git a/packages/core/orchestration/src/joiner/remote-joiner.ts b/packages/core/orchestration/src/joiner/remote-joiner.ts index d54da54db9..0dd670f4d5 100644 --- a/packages/core/orchestration/src/joiner/remote-joiner.ts +++ b/packages/core/orchestration/src/joiner/remote-joiner.ts @@ -434,11 +434,14 @@ export class RemoteJoiner { }) if (notFound.size > 0) { - // TODO: This should say "entryPoint" resource not found and not "serviceName" resource not found + const entityName = + expand.serviceConfig.args?.entity ?? + expand.serviceConfig.args?.methodSuffix ?? + expand.serviceConfig.serviceName + throw new MedusaError( MedusaError.Types.NOT_FOUND, - `${expand.serviceConfig.serviceName} ${pkField} not found: ` + - Array.from(notFound).join(", ") + `${entityName} ${pkField} not found: ` + Array.from(notFound).join(", ") ) } } diff --git a/packages/medusa/src/api/admin/returns/[id]/request/route.ts b/packages/medusa/src/api/admin/returns/[id]/request/route.ts index 99856daeb7..a24123a075 100644 --- a/packages/medusa/src/api/admin/returns/[id]/request/route.ts +++ b/packages/medusa/src/api/admin/returns/[id]/request/route.ts @@ -1,4 +1,7 @@ -import { confirmReturnRequestWorkflow } from "@medusajs/core-flows" +import { + cancelReturnRequestWorkflow, + confirmReturnRequestWorkflow, +} from "@medusajs/core-flows" import { ContainerRegistrationKeys, remoteQueryObjectFromString, @@ -39,3 +42,22 @@ export const POST = async ( return: orderReturn, }) } + +export const DELETE = async ( + req: AuthenticatedMedusaRequest, + res: MedusaResponse +) => { + const { id } = req.params + + await cancelReturnRequestWorkflow(req.scope).run({ + input: { + return_id: id, + }, + }) + + res.status(200).json({ + id, + object: "return", + deleted: true, + }) +} diff --git a/packages/medusa/src/api/admin/returns/middlewares.ts b/packages/medusa/src/api/admin/returns/middlewares.ts index d65aa2ac72..fa1aa36b38 100644 --- a/packages/medusa/src/api/admin/returns/middlewares.ts +++ b/packages/medusa/src/api/admin/returns/middlewares.ts @@ -120,4 +120,9 @@ export const adminReturnRoutesMiddlewares: MiddlewareRoute[] = [ ), ], }, + { + method: ["DELETE"], + matcher: "/admin/returns/:id/request", + middlewares: [], + }, ] diff --git a/packages/modules/order/src/models/claim.ts b/packages/modules/order/src/models/claim.ts index 1008e9b1f7..693508d432 100644 --- a/packages/modules/order/src/models/claim.ts +++ b/packages/modules/order/src/models/claim.ts @@ -77,7 +77,6 @@ export default class OrderClaim { @OneToOne({ entity: () => Return, mappedBy: (ret) => ret.claim, - cascade: ["soft-remove"] as any, fieldName: "return_id", nullable: true, owner: true, diff --git a/packages/modules/order/src/models/exchange.ts b/packages/modules/order/src/models/exchange.ts index b5b8150f56..14e376d15c 100644 --- a/packages/modules/order/src/models/exchange.ts +++ b/packages/modules/order/src/models/exchange.ts @@ -74,7 +74,6 @@ export default class OrderExchange { @OneToOne({ entity: () => Return, mappedBy: (ret) => ret.exchange, - cascade: ["soft-remove"] as any, fieldName: "return_id", nullable: true, owner: true, diff --git a/packages/modules/order/src/models/return.ts b/packages/modules/order/src/models/return.ts index 4e45804bc6..10b58216a9 100644 --- a/packages/modules/order/src/models/return.ts +++ b/packages/modules/order/src/models/return.ts @@ -82,7 +82,6 @@ export default class Return { @OneToOne({ entity: () => Exchange, - cascade: ["soft-remove"] as any, fieldName: "exchange_id", nullable: true, }) @@ -94,7 +93,6 @@ export default class Return { @OneToOne({ entity: () => Claim, - cascade: ["soft-remove"] as any, fieldName: "claim_id", nullable: true, }) diff --git a/packages/modules/order/src/utils/base-repository-find.ts b/packages/modules/order/src/utils/base-repository-find.ts index e99d69cd01..8999a4e177 100644 --- a/packages/modules/order/src/utils/base-repository-find.ts +++ b/packages/modules/order/src/utils/base-repository-find.ts @@ -31,6 +31,8 @@ export function setFindMethods(klass: Constructor, entity: any) { const isRelatedEntity = entity !== Order const config = mapRepositoryToOrderModel(findOptions_, isRelatedEntity) + config.options ??= {} + config.options.populate ??= [] let orderAlias = "o0" if (isRelatedEntity) {