From d63ca002142f1f0ac946076aeb08398b9ccc17e2 Mon Sep 17 00:00:00 2001 From: "Carlos R. L. Rodrigues" <37986729+carlos-r-l-rodrigues@users.noreply.github.com> Date: Sat, 27 Jul 2024 10:20:48 -0300 Subject: [PATCH] chore(core-flows): return fulfillment link (#8304) --- .../workflows/create-complete-return.spec.ts | 21 +-- .../return/confirm-return-request.ts | 162 +++++++++++++++++- .../return/create-complete-return.ts | 27 +-- .../src/fulfillment/mutations/fulfillment.ts | 2 +- .../fulfillment/create-fulfillment.ts | 2 +- .../src/workflow/order/request-item-return.ts | 2 + packages/core/utils/src/link/links.ts | 6 + .../services/fulfillment-module-service.ts | 24 +-- .../link-modules/src/definitions/index.ts | 1 + .../definitions/order-return-fulfillment.ts | 67 ++++++++ 10 files changed, 261 insertions(+), 53 deletions(-) create mode 100644 packages/modules/link-modules/src/definitions/order-return-fulfillment.ts diff --git a/integration-tests/modules/__tests__/order/workflows/create-complete-return.spec.ts b/integration-tests/modules/__tests__/order/workflows/create-complete-return.spec.ts index 7e7bd8c1cb..26665aa197 100644 --- a/integration-tests/modules/__tests__/order/workflows/create-complete-return.spec.ts +++ b/integration-tests/modules/__tests__/order/workflows/create-complete-return.spec.ts @@ -428,14 +428,7 @@ medusaIntegrationTestRunner({ variables: { id: order.id, }, - fields: [ - "*", - "items.*", - "shipping_methods.*", - "total", - "item_total", - "fulfillments.*", - ], + fields: ["*", "items.*", "shipping_methods.*", "total", "item_total"], }) const [returnOrder] = await remoteQuery(remoteQueryObject) @@ -501,18 +494,6 @@ medusaIntegrationTestRunner({ order_id: expect.any(String), }), ]), - fulfillments: [ - expect.objectContaining({ - id: expect.any(String), - location_id: location.id, - provider_id: providerId, - shipping_option_id: shippingOption.id, - // TODO: Validate the address once we are fixed on it - /*delivery_address: { - id: "fuladdr_01HY0RTAP0P1EEAFK7BXJ0BKBN", - },*/ - }), - ], }) ) }) 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 88763d9923..9ab960ef1c 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,12 +1,24 @@ -import { OrderChangeDTO, OrderDTO, ReturnDTO } from "@medusajs/types" -import { ChangeActionType, OrderChangeStatus } from "@medusajs/utils" +import { + FulfillmentWorkflow, + OrderChangeDTO, + OrderDTO, + ReturnDTO, +} from "@medusajs/types" +import { + ChangeActionType, + MedusaError, + Modules, + OrderChangeStatus, +} from "@medusajs/utils" import { WorkflowData, createStep, createWorkflow, transform, + when, } from "@medusajs/workflows-sdk" -import { useRemoteQueryStep } from "../../../common" +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 { createReturnItemsStep } from "../../steps/create-return-items" @@ -36,13 +48,76 @@ const validationStep = createStep( } ) +function prepareFulfillmentData({ + order, + items, + returnShippingOption, +}: { + order: OrderDTO + items: any[] + returnShippingOption: { + id: string + provider_id: string + service_zone: { + fulfillment_set: { + location?: { + id: string + address: 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 = + returnShippingOption.service_zone.fulfillment_set.location?.id + + // delivery address is the stock location address + const address = + returnShippingOption.service_zone.fulfillment_set.location?.address ?? {} + + delete address.id + + if (!locationId) { + throw new MedusaError( + MedusaError.Types.INVALID_DATA, + `Cannot create return without stock location, either provide a location or you should link the shipping option ${returnShippingOption.id} to a stock location.` + ) + } + + return { + input: { + location_id: locationId, + provider_id: returnShippingOption.provider_id, + shipping_option_id: returnShippingOption.id, + items: fulfillmentItems, + delivery_address: address, + order: order, + }, + } +} + export const confirmReturnRequestWorkflowId = "confirm-return-request" export const confirmReturnRequestWorkflow = createWorkflow( confirmReturnRequestWorkflowId, function (input: WorkflowInput): WorkflowData { const orderReturn: ReturnDTO = useRemoteQueryStep({ entry_point: "return", - fields: ["id", "status", "order_id", "canceled_at"], + fields: ["id", "status", "order_id", "location_id", "canceled_at"], variables: { id: input.return_id }, list: false, throw_if_key_not_found: true, @@ -50,7 +125,16 @@ export const confirmReturnRequestWorkflow = createWorkflow( const order: OrderDTO = useRemoteQueryStep({ entry_point: "orders", - fields: ["id", "version", "canceled_at"], + fields: [ + "id", + "version", + "canceled_at", + "items.id", + "items.title", + "items.variant_title", + "items.variant_sku", + "items.variant_barcode", + ], variables: { id: orderReturn.order_id }, list: false, throw_if_key_not_found: true, @@ -85,13 +169,79 @@ export const confirmReturnRequestWorkflow = createWorkflow( validationStep({ order, orderReturn, orderChange }) - createReturnItemsStep({ + const createdReturnItems = createReturnItemsStep({ returnId: orderReturn.id, changes: returnItemActions, }) confirmOrderChanges({ changes: [orderChange], orderId: order.id }) + const returnModified = useRemoteQueryStep({ + entry_point: "return", + fields: [ + "id", + "status", + "order_id", + "canceled_at", + "shipping_methods.shipping_option_id", + ], + variables: { id: input.return_id }, + list: false, + throw_if_key_not_found: true, + }).config({ name: "return-query" }) + + const returnShippingOptionId = transform( + { returnModified }, + ({ returnModified }) => { + if (!returnModified.shipping_methods?.length) { + return + } + + return returnModified.shipping_methods[0].shipping_option_id + } + ) + + when({ returnShippingOptionId }, ({ returnShippingOptionId }) => { + return !!returnShippingOptionId + }).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: returnShippingOptionId, + }, + list: false, + throw_if_key_not_found: true, + }).config({ name: "return-shipping-option" }) + + const fulfillmentData = transform( + { order, items: createdReturnItems, returnShippingOption }, + prepareFulfillmentData + ) + + const returnFulfillment = + createReturnFulfillmentWorkflow.runAsStep(fulfillmentData) + + const link = transform( + { orderReturn, fulfillment: returnFulfillment }, + (data) => { + return [ + { + [Modules.ORDER]: { return_id: data.orderReturn.id }, + [Modules.FULFILLMENT]: { fulfillment_id: data.fulfillment.id }, + }, + ] + } + ) + + createRemoteLinkStep(link) + }) + return previewOrderChangeStep(order.id) } ) 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 8012431d11..047a88e683 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 @@ -12,7 +12,6 @@ import { WorkflowData, createStep, createWorkflow, - parallelize, transform, } from "@medusajs/workflows-sdk" import { createRemoteLinkStep, useRemoteQueryStep } from "../../../common" @@ -50,7 +49,10 @@ function prepareShippingMethodData({ adjustments: [], } - if (isDefined(inputShippingOption.price) && inputShippingOption.price >= 0) { + if ( + isDefined(inputShippingOption.price) && + MathBN.gte(inputShippingOption.price, 0) + ) { obj.amount = inputShippingOption.price } else { if (returnShippingOption.price_type === "calculated") { @@ -288,27 +290,26 @@ export const createAndCompleteReturnOrderWorkflow = createWorkflow( const returnFulfillment = createReturnFulfillmentWorkflow.runAsStep(fulfillmentData) + const returnCreated = createCompleteReturnStep({ + order_id: input.order_id, + items: input.items, + shipping_method: shippingMethodData, + created_by: input.created_by, + }) + const link = transform( - { order_id: input.order_id, fulfillment: returnFulfillment }, + { returnCreated, fulfillment: returnFulfillment }, (data) => { return [ { - [Modules.ORDER]: { order_id: data.order_id }, + [Modules.ORDER]: { return_id: data.returnCreated.id }, [Modules.FULFILLMENT]: { fulfillment_id: data.fulfillment.id }, }, ] } ) - const [returnCreated] = parallelize( - createCompleteReturnStep({ - order_id: input.order_id, - items: input.items, - shipping_method: shippingMethodData, - created_by: input.created_by, - }), - createRemoteLinkStep(link) - ) + createRemoteLinkStep(link) const receiveItems = transform( { diff --git a/packages/core/types/src/fulfillment/mutations/fulfillment.ts b/packages/core/types/src/fulfillment/mutations/fulfillment.ts index 74df0dfd2c..843fe3acd2 100644 --- a/packages/core/types/src/fulfillment/mutations/fulfillment.ts +++ b/packages/core/types/src/fulfillment/mutations/fulfillment.ts @@ -65,7 +65,7 @@ export interface CreateFulfillmentDTO { /** * The labels associated with the fulfillment. */ - labels: Omit[] + labels?: Omit[] /** * The associated order to be sent to the provider. diff --git a/packages/core/types/src/workflow/fulfillment/create-fulfillment.ts b/packages/core/types/src/workflow/fulfillment/create-fulfillment.ts index 65d50cc2bd..a186c9e8d3 100644 --- a/packages/core/types/src/workflow/fulfillment/create-fulfillment.ts +++ b/packages/core/types/src/workflow/fulfillment/create-fulfillment.ts @@ -174,7 +174,7 @@ export type CreateFulfillmentWorkflowInput = { /** * The labels associated with the fulfillment. */ - labels: CreateFulfillmentLabelWorkflowDTO[] + labels?: CreateFulfillmentLabelWorkflowDTO[] /** * The associated fulfillment order to be sent to the provider. diff --git a/packages/core/types/src/workflow/order/request-item-return.ts b/packages/core/types/src/workflow/order/request-item-return.ts index bf8cb1fd73..a64ebb3756 100644 --- a/packages/core/types/src/workflow/order/request-item-return.ts +++ b/packages/core/types/src/workflow/order/request-item-return.ts @@ -14,6 +14,8 @@ export interface DeleteRequestItemReturnWorkflowInput { export interface UpdateRequestItemReturnWorkflowInput { return_id: string + claim_id?: string + exchange_id?: string action_id: string data: { quantity?: BigNumberInput diff --git a/packages/core/utils/src/link/links.ts b/packages/core/utils/src/link/links.ts index d579963772..4e12863586 100644 --- a/packages/core/utils/src/link/links.ts +++ b/packages/core/utils/src/link/links.ts @@ -110,4 +110,10 @@ export const LINKS = { Modules.FULFILLMENT, "fulfillment_id" ), + ReturnFulfillment: composeLinkName( + Modules.ORDER, + "return_id", + Modules.FULFILLMENT, + "fulfillment_id" + ), } diff --git a/packages/modules/fulfillment/src/services/fulfillment-module-service.ts b/packages/modules/fulfillment/src/services/fulfillment-module-service.ts index cf95dcaddd..f4c0df2710 100644 --- a/packages/modules/fulfillment/src/services/fulfillment-module-service.ts +++ b/packages/modules/fulfillment/src/services/fulfillment-module-service.ts @@ -14,18 +14,18 @@ import { UpdateServiceZoneDTO, } from "@medusajs/types" import { - arrayDifference, - deepEqualObj, EmitEvents, - getSetDifference, InjectManager, InjectTransactionManager, - isDefined, - isPresent, - isString, MedusaContext, MedusaError, ModulesSdkUtils, + arrayDifference, + deepEqualObj, + getSetDifference, + isDefined, + isPresent, + isString, promiseAll, } from "@medusajs/utils" import { @@ -617,9 +617,8 @@ export default class FulfillmentModuleService ...fulfillmentRest } = fulfillment - let fulfillmentThirdPartyData!: any try { - fulfillmentThirdPartyData = + const providerResult = await this.fulfillmentProviderService_.createFulfillment( provider_id, fulfillmentData || {}, @@ -630,7 +629,8 @@ export default class FulfillmentModuleService await this.fulfillmentService_.update( { id: fulfillment.id, - data: fulfillmentThirdPartyData ?? {}, + data: providerResult.data ?? {}, + labels: providerResult.labels ?? [], }, sharedContext ) @@ -662,9 +662,8 @@ export default class FulfillmentModuleService sharedContext ) - let fulfillmentThirdPartyData!: any try { - fulfillmentThirdPartyData = + const providerResult = await this.fulfillmentProviderService_.createReturn( fulfillment.provider_id, fulfillment as Record @@ -672,7 +671,8 @@ export default class FulfillmentModuleService await this.fulfillmentService_.update( { id: fulfillment.id, - data: fulfillmentThirdPartyData ?? {}, + data: providerResult.data ?? {}, + labels: providerResult.labels ?? [], }, sharedContext ) diff --git a/packages/modules/link-modules/src/definitions/index.ts b/packages/modules/link-modules/src/definitions/index.ts index b5c61e4333..00fdf9f07b 100644 --- a/packages/modules/link-modules/src/definitions/index.ts +++ b/packages/modules/link-modules/src/definitions/index.ts @@ -6,6 +6,7 @@ export * from "./order-cart" export * from "./order-fulfillment" export * from "./order-payment-collection" export * from "./order-promotion" +export * from "./order-return-fulfillment" export * from "./product-sales-channel" export * from "./product-variant-inventory-item" export * from "./product-variant-price-set" diff --git a/packages/modules/link-modules/src/definitions/order-return-fulfillment.ts b/packages/modules/link-modules/src/definitions/order-return-fulfillment.ts new file mode 100644 index 0000000000..b4f75569a2 --- /dev/null +++ b/packages/modules/link-modules/src/definitions/order-return-fulfillment.ts @@ -0,0 +1,67 @@ +import { ModuleJoinerConfig } from "@medusajs/types" +import { LINKS, Modules } from "@medusajs/utils" + +export const ReturnFulfillment: ModuleJoinerConfig = { + serviceName: LINKS.ReturnFulfillment, + isLink: true, + databaseConfig: { + tableName: "return_fulfillment", + idPrefix: "retful", + }, + alias: [ + { + name: ["return_fulfillment", "return_fulfillments"], + args: { + entity: "LinkReturnFulfillment", + }, + }, + ], + primaryKeys: ["id", "return_id", "fulfillment_id"], + relationships: [ + { + serviceName: Modules.ORDER, + primaryKey: "id", + foreignKey: "return_id", + alias: "return", + args: { + methodSuffix: "Returns", + }, + }, + { + serviceName: Modules.FULFILLMENT, + primaryKey: "id", + foreignKey: "fulfillment_id", + alias: "fulfillments", + args: { + methodSuffix: "Fulfillments", + }, + }, + ], + extends: [ + { + serviceName: Modules.ORDER, + fieldAlias: { + return_fulfillments: { + path: "return_fulfillment_link.fulfillments", + isList: true, + }, + }, + relationship: { + serviceName: LINKS.OrderFulfillment, + primaryKey: "return_id", + foreignKey: "id", + alias: "return_fulfillment_link", + isList: true, + }, + }, + { + serviceName: Modules.FULFILLMENT, + relationship: { + serviceName: LINKS.OrderFulfillment, + primaryKey: "fulfillment_id", + foreignKey: "id", + alias: "return_link", + }, + }, + ], +}