From 4daf57dc1fce3b20f39526940cc38574fab95180 Mon Sep 17 00:00:00 2001 From: "Carlos R. L. Rodrigues" <37986729+carlos-r-l-rodrigues@users.noreply.github.com> Date: Wed, 9 Oct 2024 08:50:50 -0300 Subject: [PATCH] fix(order): undo order change (#9497) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit FIXES: CC-573 Co-authored-by: Frane Polić <16856471+fPolic@users.noreply.github.com> --- .../src/order/steps/confirm-order-changes.ts | 31 ++- .../workflows/claim/confirm-claim-request.ts | 7 +- .../exchange/confirm-exchange-request.ts | 7 +- .../order-edit/confirm-order-edit-request.ts | 6 +- .../return/confirm-receive-return-request.ts | 1 + .../return/confirm-return-request.ts | 1 + packages/core/types/src/order/service.ts | 19 +- .../src/services/order-module-service.ts | 205 ++++++++++++++++-- 8 files changed, 240 insertions(+), 37 deletions(-) diff --git a/packages/core/core-flows/src/order/steps/confirm-order-changes.ts b/packages/core/core-flows/src/order/steps/confirm-order-changes.ts index 18c8ac4b91..7c2002273b 100644 --- a/packages/core/core-flows/src/order/steps/confirm-order-changes.ts +++ b/packages/core/core-flows/src/order/steps/confirm-order-changes.ts @@ -15,21 +15,36 @@ export const confirmOrderChanges = createStep( "confirm-order-changes", async (input: ConfirmOrderChangesInput, { container }) => { const orderModuleService = container.resolve(Modules.ORDER) + + const currentChanges: Partial[] = [] await orderModuleService.confirmOrderChange( - input.changes.map((action) => ({ - id: action.id, - confirmed_by: input.confirmed_by, - })) + input.changes.map((action) => { + const update = { + id: action.id, + confirmed_by: input.confirmed_by, + } + + currentChanges.push({ + ...update, + order_id: input.orderId, + status: action.status, + }) + + return update + }) ) - return new StepResponse(null, input.orderId) + return new StepResponse(null, currentChanges) }, - async (orderId, { container }) => { - if (!orderId) { + async (currentChanges, { container }) => { + if (!currentChanges?.length) { return } const orderModuleService = container.resolve(Modules.ORDER) - await orderModuleService.revertLastVersion(orderId) + await orderModuleService.undoLastChange( + currentChanges[0].order_id!, + currentChanges[0] + ) } ) 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 9097c4f372..4391ea64c3 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 @@ -246,6 +246,7 @@ export const confirmClaimRequestWorkflow = createWorkflow( entry_point: "order_change", fields: [ "id", + "status", "actions.id", "actions.claim_id", "actions.return_id", @@ -291,7 +292,11 @@ export const confirmClaimRequestWorkflow = createWorkflow( } ) - confirmOrderChanges({ changes: [orderChange], orderId: order.id }) + confirmOrderChanges({ + changes: [orderChange], + orderId: order.id, + confirmed_by: input.confirmed_by, + }) when({ returnId }, ({ returnId }) => { return !!returnId 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 index 29533c8806..adba4a3f8e 100644 --- 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 @@ -234,6 +234,7 @@ export const confirmExchangeRequestWorkflow = createWorkflow( entry_point: "order_change", fields: [ "id", + "status", "actions.id", "actions.exchange_id", "actions.return_id", @@ -272,7 +273,11 @@ export const confirmExchangeRequestWorkflow = createWorkflow( returnItems: createdReturnItems, }) - confirmOrderChanges({ changes: [orderChange], orderId: order.id }) + confirmOrderChanges({ + changes: [orderChange], + orderId: order.id, + confirmed_by: input.confirmed_by, + }) const returnId = transform( { createdReturnItems }, diff --git a/packages/core/core-flows/src/order/workflows/order-edit/confirm-order-edit-request.ts b/packages/core/core-flows/src/order/workflows/order-edit/confirm-order-edit-request.ts index 431f340710..1a68ec5315 100644 --- a/packages/core/core-flows/src/order/workflows/order-edit/confirm-order-edit-request.ts +++ b/packages/core/core-flows/src/order/workflows/order-edit/confirm-order-edit-request.ts @@ -18,6 +18,7 @@ import { import { reserveInventoryStep } from "../../../cart/steps/reserve-inventory" import { prepareConfirmInventoryInput } from "../../../cart/utils/prepare-confirm-inventory-input" import { useRemoteQueryStep } from "../../../common" +import { deleteReservationsByLineItemsStep } from "../../../reservation" import { previewOrderChangeStep } from "../../steps" import { confirmOrderChanges } from "../../steps/confirm-order-changes" import { @@ -25,7 +26,6 @@ import { throwIfOrderChangeIsNotActive, } from "../../utils/order-validation" import { createOrUpdateOrderPaymentCollectionWorkflow } from "../create-or-update-order-payment-collection" -import { deleteReservationsByLineItemsStep } from "../../../reservation" export type ConfirmOrderEditRequestWorkflowInput = { order_id: string @@ -80,6 +80,7 @@ export const confirmOrderEditRequestWorkflow = createWorkflow( entry_point: "order_change", fields: [ "id", + "status", "actions.id", "actions.order_id", "actions.return_id", @@ -162,7 +163,6 @@ export const confirmOrderEditRequestWorkflow = createWorkflow( const unitPrice: BigNumberInput = itemAction.raw_unit_price ?? itemAction.unit_price - const updateAction = itemAction.actions!.find( (a) => a.action === ChangeActionType.ITEM_UPDATE ) @@ -187,7 +187,7 @@ export const confirmOrderEditRequestWorkflow = createWorkflow( id: ordItem.id, variant_id: ordItem.variant_id, quantity: reservationQuantity, - unit_price: unitPrice + unit_price: unitPrice, }) allVariants.push(ordItem.variant) }) diff --git a/packages/core/core-flows/src/order/workflows/return/confirm-receive-return-request.ts b/packages/core/core-flows/src/order/workflows/return/confirm-receive-return-request.ts index 28a8373986..3b3709bff7 100644 --- a/packages/core/core-flows/src/order/workflows/return/confirm-receive-return-request.ts +++ b/packages/core/core-flows/src/order/workflows/return/confirm-receive-return-request.ts @@ -171,6 +171,7 @@ export const confirmReturnReceiveWorkflow = createWorkflow( entry_point: "order_change", fields: [ "id", + "status", "actions.id", "actions.action", "actions.details", 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 7bb5494fb0..a0fa976746 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 @@ -191,6 +191,7 @@ export const confirmReturnRequestWorkflow = createWorkflow( entry_point: "order_change", fields: [ "id", + "status", "actions.id", "actions.action", "actions.details", diff --git a/packages/core/types/src/order/service.ts b/packages/core/types/src/order/service.ts index 99a00d8757..48dc2ba4ed 100644 --- a/packages/core/types/src/order/service.ts +++ b/packages/core/types/src/order/service.ts @@ -3380,7 +3380,7 @@ export interface IOrderModuleService extends IModuleService { ): Promise | void> /** - * This method reverts an order to its last version. + * This method reverts an order to its last version and cleanup data related to the changes. * * @param {string} orderId - The order's ID. * @param {Context} sharedContext - A context used to share resources, such as transaction manager, between the application and the module. @@ -3391,6 +3391,23 @@ export interface IOrderModuleService extends IModuleService { */ revertLastVersion(orderId: string, sharedContext?: Context): Promise + /** + * This method reverts an order to its last change and keep the order changes and actions not applied. + * + * @param {string} orderId - The order's ID. + * @param {Partial} lastOrderChange - The last order change status to revert to. + * @param {Context} sharedContext - A context used to share resources, such as transaction manager, between the application and the module. + * @returns {Promise} Resolves when the order is undone. + * + * @example + * await orderModuleService.revertLastChange("123") + */ + undoLastChange( + orderId: string, + lastOrderChange?: Partial, + sharedContext?: Context + ): Promise + /** * This method retrieves a paginated list of transactions based on optional filters and configuration. * diff --git a/packages/modules/order/src/services/order-module-service.ts b/packages/modules/order/src/services/order-module-service.ts index e77e290d26..b5fab5b78d 100644 --- a/packages/modules/order/src/services/order-module-service.ts +++ b/packages/modules/order/src/services/order-module-service.ts @@ -8,6 +8,7 @@ import { IOrderModuleService, ModuleJoinerConfig, ModulesSdkTypes, + OrderChangeDTO, OrderDTO, OrderReturnReasonDTO, OrderShippingMethodDTO, @@ -2302,13 +2303,39 @@ export default class OrderModuleService< return await this.revertLastChange_(order, sharedContext) } + @InjectManager() + async undoLastChange( + orderId: string, + lastOrderChange?: Partial, + @MedusaContext() sharedContext?: Context + ) { + const order = await super.retrieveOrder( + orderId, + { + select: ["id", "version"], + }, + sharedContext + ) + + if (order.version < 2) { + throw new MedusaError( + MedusaError.Types.INVALID_DATA, + `Order with id ${orderId} has no previous versions` + ) + } + + return await this.undoLastChange_(order, lastOrderChange, sharedContext) + } + @InjectTransactionManager() - protected async revertLastChange_( + protected async undoLastChange_( order: OrderDTO, + lastOrderChange?: Partial, sharedContext?: Context ): Promise { const currentVersion = order.version + const updatePromises: Promise[] = [] // Order Changes const orderChanges = await this.orderChangeService_.list( { @@ -2318,9 +2345,18 @@ export default class OrderModuleService< { select: ["id", "version"] }, sharedContext ) - const orderChangesIds = orderChanges.map((change) => change.id) - await this.orderChangeService_.softDelete(orderChangesIds, sharedContext) + const orderChangesIds = orderChanges.map((change) => { + return { + id: change.id, + status: lastOrderChange?.status ?? OrderChangeStatus.PENDING, + confirmed_at: null, + } + }) + + updatePromises.push( + this.orderChangeService_.update(orderChangesIds, sharedContext) + ) // Order Changes Actions const orderChangesActions = await this.orderChangeActionService_.list( @@ -2331,11 +2367,18 @@ export default class OrderModuleService< { select: ["id", "version"] }, sharedContext ) - const orderChangeActionsIds = orderChangesActions.map((action) => action.id) + const orderChangeActionsIds = orderChangesActions.map((action) => { + return { + id: action.id, + applied: false, + } + }) - await this.orderChangeActionService_.softDelete( - orderChangeActionsIds, - sharedContext + updatePromises.push( + this.orderChangeActionService_.update( + orderChangeActionsIds, + sharedContext + ) ) // Order Summary @@ -2349,7 +2392,9 @@ export default class OrderModuleService< ) const orderSummaryIds = orderSummary.map((summary) => summary.id) - await this.orderSummaryService_.softDelete(orderSummaryIds, sharedContext) + updatePromises.push( + this.orderSummaryService_.softDelete(orderSummaryIds, sharedContext) + ) // Order Items const orderItems = await this.orderItemService_.list( @@ -2362,7 +2407,9 @@ export default class OrderModuleService< ) const orderItemIds = orderItems.map((summary) => summary.id) - await this.orderItemService_.softDelete(orderItemIds, sharedContext) + updatePromises.push( + this.orderItemService_.softDelete(orderItemIds, sharedContext) + ) // Order Shipping const orderShippings = await this.orderShippingService_.list( @@ -2375,29 +2422,141 @@ export default class OrderModuleService< ) const orderShippingIds = orderShippings.map((sh) => sh.id) - await this.orderShippingService_.softDelete(orderShippingIds, sharedContext) + updatePromises.push( + this.orderShippingService_.softDelete(orderShippingIds, sharedContext) + ) // Order - await this.orderService_.update( + updatePromises.push( + this.orderService_.update( + { + selector: { + id: order.id, + }, + data: { + version: order.version - 1, + }, + }, + sharedContext + ) + ) + + await promiseAll(updatePromises) + } + + @InjectTransactionManager() + protected async revertLastChange_( + order: OrderDTO, + sharedContext?: Context + ): Promise { + const currentVersion = order.version + + const updatePromises: Promise[] = [] + // Order Changes + const orderChanges = await this.orderChangeService_.list( { - selector: { - id: order.id, - }, - data: { - version: order.version - 1, - }, + order_id: order.id, + version: currentVersion, }, + { select: ["id", "version"] }, sharedContext ) + const orderChangesIds = orderChanges.map((change) => change.id) + + updatePromises.push( + this.orderChangeService_.softDelete(orderChangesIds, sharedContext) + ) + + // Order Changes Actions + const orderChangesActions = await this.orderChangeActionService_.list( + { + order_id: order.id, + version: currentVersion, + }, + { select: ["id", "version"] }, + sharedContext + ) + const orderChangeActionsIds = orderChangesActions.map((action) => action.id) + + updatePromises.push( + this.orderChangeActionService_.softDelete( + orderChangeActionsIds, + sharedContext + ) + ) + + // Order Summary + const orderSummary = await this.orderSummaryService_.list( + { + order_id: order.id, + version: currentVersion, + }, + { select: ["id", "version"] }, + sharedContext + ) + const orderSummaryIds = orderSummary.map((summary) => summary.id) + + updatePromises.push( + this.orderSummaryService_.softDelete(orderSummaryIds, sharedContext) + ) + + // Order Items + const orderItems = await this.orderItemService_.list( + { + order_id: order.id, + version: currentVersion, + }, + { select: ["id", "version"] }, + sharedContext + ) + const orderItemIds = orderItems.map((summary) => summary.id) + + updatePromises.push( + this.orderItemService_.softDelete(orderItemIds, sharedContext) + ) + + // Order Shipping + const orderShippings = await this.orderShippingService_.list( + { + order_id: order.id, + version: currentVersion, + }, + { select: ["id", "version"] }, + sharedContext + ) + const orderShippingIds = orderShippings.map((sh) => sh.id) + + updatePromises.push( + this.orderShippingService_.softDelete(orderShippingIds, sharedContext) + ) + + // Order + updatePromises.push( + this.orderService_.update( + { + selector: { + id: order.id, + }, + data: { + version: order.version - 1, + }, + }, + sharedContext + ) + ) // Returns - await this.returnService_.delete( - { - order_id: order.id, - order_version: currentVersion, - }, - sharedContext + updatePromises.push( + this.returnService_.delete( + { + order_id: order.id, + order_version: currentVersion, + }, + sharedContext + ) ) + + await promiseAll(updatePromises) } private async getActiveOrderChange_(