Chore/order claims 2 (#8312)

This commit is contained in:
Carlos R. L. Rodrigues
2024-07-29 10:15:35 -03:00
committed by GitHub
parent ebaf0eb53a
commit 42c80e4264
47 changed files with 1293 additions and 139 deletions
@@ -0,0 +1,59 @@
import { IOrderModuleService, OrderChangeActionDTO } from "@medusajs/types"
import { ChangeActionType, ModuleRegistrationName } from "@medusajs/utils"
import { StepResponse, createStep } from "@medusajs/workflows-sdk"
type CreateOrderClaimItemsInput = {
changes: OrderChangeActionDTO[]
claimId: string
}
export const createOrderClaimItemsStep = createStep(
"create-claim-items",
async (input: CreateOrderClaimItemsInput, { container }) => {
const orderModuleService = container.resolve<IOrderModuleService>(
ModuleRegistrationName.ORDER
)
const claimItems = input.changes.map((item) => {
let additionalFields
if (item.action === ChangeActionType.ITEM_ADD) {
additionalFields = {
is_additional_item: true,
}
} else if (item.action === ChangeActionType.WRITE_OFF_ITEM) {
additionalFields = {
reason: item.details?.reason,
}
}
return {
claim_id: input.claimId,
item_id: item.details?.reference_id! as string,
quantity: item.details?.quantity as number,
note: item.internal_note,
metadata: (item.details?.metadata as Record<string, unknown>) ?? {},
...additionalFields,
}
})
const createdClaimItems = await orderModuleService.createOrderClaimItems(
claimItems
)
return new StepResponse(
createdClaimItems,
createdClaimItems.map((i) => i.id)
)
},
async (ids, { container }) => {
if (!ids) {
return
}
const orderModuleService = container.resolve<IOrderModuleService>(
ModuleRegistrationName.ORDER
)
await orderModuleService.deleteOrderClaimItems(ids)
}
)
@@ -28,6 +28,7 @@ export const createReturnItemsStep = createStep(
metadata: (item.details?.metadata as Record<string, unknown>) ?? {},
} as CreateOrderReturnItemDTO
})
const createdReturnItems = await orderModuleService.createReturnItems(
returnItems
)
@@ -5,6 +5,7 @@ export * from "./cancel-order-change"
export * from "./cancel-orders"
export * from "./cancel-return"
export * from "./complete-orders"
export * from "./create-claim-items"
export * from "./create-claims"
export * from "./create-complete-return"
export * from "./create-exchanges"
@@ -45,7 +45,7 @@ export const cancelBeginOrderClaimWorkflow = createWorkflow(
cancelBeginOrderClaimWorkflowId,
function (input: WorkflowInput): WorkflowData<void> {
const orderClaim: OrderClaimDTO = useRemoteQueryStep({
entry_point: "claim",
entry_point: "order_claim",
fields: ["id", "status", "order_id", "return_id", "canceled_at"],
variables: { id: input.claim_id },
list: false,
@@ -100,7 +100,7 @@ export const orderClaimAddNewItemWorkflow = 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,
},
}))
@@ -91,6 +91,7 @@ export const orderClaimItemWorkflow = createWorkflow(
reference_id: orderClaim.id,
details: {
reference_id: item.id,
reason: item.reason,
quantity: item.quantity,
},
}))
@@ -156,6 +156,7 @@ export const orderClaimRequestItemReturnWorkflow = createWorkflow(
details: {
reference_id: item.id,
quantity: item.quantity,
reason_id: item.reason_id,
metadata: item.metadata,
},
}))
@@ -0,0 +1,361 @@
import {
FulfillmentWorkflow,
OrderChangeActionDTO,
OrderChangeDTO,
OrderClaimDTO,
OrderDTO,
} from "@medusajs/types"
import { ChangeActionType, Modules, OrderChangeStatus } from "@medusajs/utils"
import {
WorkflowData,
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 { createOrderClaimItemsStep } from "../../steps/create-claim-items"
import { createReturnItemsStep } from "../../steps/create-return-items"
import {
throwIfIsCancelled,
throwIfOrderChangeIsNotActive,
} from "../../utils/order-validation"
type WorkflowInput = {
claim_id: string
}
const validationStep = createStep(
"validate-confirm-claim-request",
async function ({
order,
orderChange,
orderClaim,
}: {
order: OrderDTO
orderClaim: OrderClaimDTO
orderChange: OrderChangeDTO
}) {
throwIfIsCancelled(order, "Order")
throwIfIsCancelled(orderClaim, "Claim")
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<string, any>
}
}
}
}
deliveryAddress?: Record<string, any>
}) {
const orderItemsMap = new Map<string, Required<OrderDTO>["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 claimItems: 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 ||
item.action === ChangeActionType.WRITE_OFF_ITEM
) {
claimItems.push(item)
}
})
return {
claimItems: {
changes: claimItems,
claimId: claimItems?.[0]?.claim_id!,
},
returnItems: {
changes: returnItems,
returnId: returnItems?.[0]?.return_id!,
},
}
}
function extractShippingOption({ orderPreview, orderClaim, returnId }) {
if (!orderPreview.shipping_methods?.length) {
return
}
let returnShippingMethod
let claimShippingMethod
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.claim_id === orderClaim.id) {
claimShippingMethod = shippingMethod
}
}
}
}
return {
returnShippingMethod,
claimShippingMethod,
}
}
export const confirmClaimRequestWorkflowId = "confirm-claim-request"
export const confirmClaimRequestWorkflow = createWorkflow(
confirmClaimRequestWorkflowId,
function (input: WorkflowInput): WorkflowData<OrderDTO> {
const orderClaim: OrderClaimDTO = useRemoteQueryStep({
entry_point: "order_claim",
fields: ["id", "status", "order_id", "canceled_at"],
variables: { id: input.claim_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: orderClaim.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.claim_id",
"actions.return_id",
"actions.action",
"actions.details",
"actions.reference",
"actions.reference_id",
"actions.internal_note",
],
variables: {
filters: {
order_id: orderClaim.order_id,
claim_id: orderClaim.id,
status: [OrderChangeStatus.PENDING, OrderChangeStatus.REQUESTED],
},
},
list: false,
}).config({ name: "order-change-query" })
validationStep({ order, orderClaim, orderChange })
const { claimItems, returnItems } = transform(
{ orderChange },
transformActionsToItems
)
const orderPreview = previewOrderChangeStep(order.id)
const [createClaimItems, createdReturnItems] = parallelize(
createOrderClaimItemsStep(claimItems),
createReturnItemsStep(returnItems),
confirmOrderChanges({ changes: [orderChange], orderId: order.id })
)
const returnId = transform(
{ createdReturnItems },
({ createdReturnItems }) => {
return createdReturnItems?.[0]?.return_id
}
)
const claimId = transform({ createClaimItems }, ({ createClaimItems }) => {
return createClaimItems?.[0]?.claim_id
})
const { returnShippingMethod, claimShippingMethod } = transform(
{ orderPreview, orderClaim, returnId },
extractShippingOption
)
when({ claimShippingMethod }, ({ claimShippingMethod }) => {
return !!claimShippingMethod
}).then(() => {
const claim: OrderClaimDTO = useRemoteQueryStep({
entry_point: "order_claim",
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: claimId },
list: false,
throw_if_key_not_found: true,
}).config({ name: "claim-query" })
const claimShippingOption = useRemoteQueryStep({
entry_point: "shipping_options",
fields: [
"id",
"provider_id",
"service_zone.fulfillment_set.location.id",
"service_zone.fulfillment_set.location.address.*",
],
variables: {
id: claimShippingMethod.shipping_option_id,
},
list: false,
throw_if_key_not_found: true,
}).config({ name: "claim-shipping-option" })
const fulfillmentData = transform(
{
order,
items: claim.additional_items! ?? [],
shippingOption: claimShippingOption,
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: "claim-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: "claim-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: "claim-return-shipping-fulfillment-link",
})
})
return orderPreview
}
)
@@ -48,7 +48,7 @@ export const createClaimShippingMethodWorkflow = createWorkflow(
custom_price?: BigNumberInput
}): WorkflowData<OrderDTO> {
const orderClaim: OrderClaimDTO = useRemoteQueryStep({
entry_point: "claim",
entry_point: "order_claim",
fields: ["id", "status", "order_id", "canceled_at"],
variables: { id: input.claim_id },
list: false,
@@ -115,8 +115,8 @@ export const createClaimShippingMethodWorkflow = createWorkflow(
name: option.name,
version: orderChange.version,
order_id: data.orderClaim.order_id,
return_id: data.orderClaim.id,
claim_id: data.input.claim_id,
return_id: input.return_id,
claim_id: data.orderClaim.id,
}
}
)
@@ -156,8 +156,8 @@ export const createClaimShippingMethodWorkflow = createWorkflow(
reference_id: createdMethod.id,
amount: methodPrice,
order_id: order.id,
return_id: orderClaim.id,
claim_id: input.claim_id,
return_id: input.return_id,
claim_id: orderClaim.id,
}
}
)
@@ -59,7 +59,7 @@ export const removeItemClaimActionWorkflow = createWorkflow(
input: WorkflowData<OrderWorkflow.DeleteOrderClaimItemActionWorkflowInput>
): WorkflowData<OrderDTO> {
const orderClaim: OrderClaimDTO = useRemoteQueryStep({
entry_point: "claim",
entry_point: "order_claim",
fields: ["id", "status", "order_id", "canceled_at"],
variables: { id: input.claim_id },
list: false,
@@ -59,7 +59,7 @@ export const removeClaimShippingMethodWorkflow = createWorkflow(
input: WorkflowData<OrderWorkflow.DeleteClaimShippingMethodWorkflowInput>
): WorkflowData {
const orderClaim: OrderClaimDTO = useRemoteQueryStep({
entry_point: "claim",
entry_point: "order_claim",
fields: ["id", "status", "order_id", "canceled_at"],
variables: { id: input.claim_id },
list: false,
@@ -63,7 +63,7 @@ export const updateClaimAddItemWorkflow = createWorkflow(
input: WorkflowData<OrderWorkflow.UpdateClaimAddNewItemWorkflowInput>
): WorkflowData<OrderDTO> {
const orderClaim: OrderClaimDTO = useRemoteQueryStep({
entry_point: "claim",
entry_point: "order_claim",
fields: ["id", "status", "order_id", "canceled_at"],
variables: { id: input.claim_id },
list: false,
@@ -63,7 +63,7 @@ export const updateClaimItemWorkflow = createWorkflow(
input: WorkflowData<OrderWorkflow.UpdateClaimItemWorkflowInput>
): WorkflowData<OrderDTO> {
const orderClaim: OrderClaimDTO = useRemoteQueryStep({
entry_point: "claim",
entry_point: "order_claim",
fields: ["id", "status", "order_id", "canceled_at"],
variables: { id: input.claim_id },
list: false,
@@ -61,7 +61,7 @@ export const updateClaimShippingMethodWorkflow = createWorkflow(
input: WorkflowData<OrderWorkflow.UpdateClaimShippingMethodWorkflowInput>
): WorkflowData {
const orderClaim: OrderClaimDTO = useRemoteQueryStep({
entry_point: "claim",
entry_point: "order_claim",
fields: ["id", "status", "order_id", "canceled_at"],
variables: { id: input.claim_id },
list: false,
@@ -8,6 +8,7 @@ export * from "./claim/cancel-begin-order-claim"
export * from "./claim/claim-add-new-item"
export * from "./claim/claim-item"
export * from "./claim/claim-request-item-return"
export * from "./claim/confirm-claim-request"
export * from "./claim/create-claim-shipping-method"
export * from "./claim/remove-claim-item-action"
export * from "./claim/remove-claim-shipping-method"
@@ -4,12 +4,7 @@ import {
OrderDTO,
ReturnDTO,
} from "@medusajs/types"
import {
ChangeActionType,
MedusaError,
Modules,
OrderChangeStatus,
} from "@medusajs/utils"
import { ChangeActionType, Modules, OrderChangeStatus } from "@medusajs/utils"
import {
WorkflowData,
createStep,
@@ -84,7 +79,7 @@ function prepareFulfillmentData({
})
const locationId =
returnShippingOption.service_zone.fulfillment_set.location?.id
returnShippingOption.service_zone.fulfillment_set.location?.id!
// delivery address is the stock location address
const address =
@@ -92,13 +87,6 @@ function prepareFulfillmentData({
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,
@@ -111,6 +99,31 @@ function prepareFulfillmentData({
}
}
function extractReturnShippingOptionId({ orderPreview, orderReturn }) {
if (!orderPreview.shipping_methods?.length) {
return
}
let returnShippingMethod
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 &&
action.return_id === orderReturn.id
) {
returnShippingMethod = shippingMethod
break
}
}
}
return returnShippingMethod.shipping_option_id
}
export const confirmReturnRequestWorkflowId = "confirm-return-request"
export const confirmReturnRequestWorkflow = createWorkflow(
confirmReturnRequestWorkflowId,
@@ -169,36 +182,16 @@ export const confirmReturnRequestWorkflow = createWorkflow(
validationStep({ order, orderReturn, orderChange })
const orderPreview = previewOrderChangeStep(order.id)
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
}
{ orderPreview, orderReturn },
extractReturnShippingOptionId
)
when({ returnShippingOptionId }, ({ returnShippingOptionId }) => {
@@ -242,6 +235,8 @@ export const confirmReturnRequestWorkflow = createWorkflow(
createRemoteLinkStep(link)
})
return previewOrderChangeStep(order.id)
confirmOrderChanges({ changes: [orderChange], orderId: order.id })
return orderPreview
}
)
@@ -97,7 +97,7 @@ export const updateRequestItemReturnWorkflow = createWorkflow(
variables: {
filters: {
order_id: orderReturn.order_id,
return_id: orderReturn.id,
claim_id: input.claim_id,
status: [OrderChangeStatus.PENDING, OrderChangeStatus.REQUESTED],
},
},