feat(core-flows): request return on order exchanges and claims (#8107)

FIXES: CC-92, CC-87
This commit is contained in:
Carlos R. L. Rodrigues authored and GitHub committed 2024-07-12 15:48:24 +00:00
1 parent 136da3f3ce
commit 4321241553
25 files changed
+695 -69

No files matched your search

@@ -60,7 +60,7 @@ medusaIntegrationTestRunner({
describe("Orders - Admin", () => { describe("Orders - Admin", () => {
it("should get an order", async () => { it("should get an order", async () => {
const created = await orderModule.createOrders({ const created = await orderModule.createOrders({
region_id: "test_region_idclear", region_id: "test_region_id",
email: "foo@bar.com", email: "foo@bar.com",
items: [ items: [
{ {
@@ -205,7 +205,7 @@ export async function createOrderFixture({
) )
let order = await orderService.createOrders({ let order = await orderService.createOrders({
region_id: "test_region_idclear", region_id: "test_region_id",
email: "foo@bar.com", email: "foo@bar.com",
items: [ items: [
{ {
@@ -1,6 +1,7 @@
import { import {
beginClaimOrderWorkflow, beginClaimOrderWorkflow,
createShippingOptionsWorkflow, createShippingOptionsWorkflow,
orderClaimRequestItemReturnWorkflow,
} from "@medusajs/core-flows" } from "@medusajs/core-flows"
import { import {
FulfillmentWorkflow, FulfillmentWorkflow,
@@ -232,7 +233,7 @@ async function createOrderFixture({ container, product }) {
ModuleRegistrationName.ORDER ModuleRegistrationName.ORDER
) )
let order = await orderService.createOrders({ let order = await orderService.createOrders({
region_id: "test_region_idclear", region_id: "test_region_id",
email: "foo@bar.com", email: "foo@bar.com",
items: [ items: [
{ {
@@ -382,11 +383,56 @@ medusaIntegrationTestRunner({
fields: ["order_id", "id", "type"], fields: ["order_id", "id", "type"],
}) })
const [returnOrder] = await remoteQuery(remoteQueryObject) const [claimOrder] = await remoteQuery(remoteQueryObject)
expect(returnOrder.order_id).toEqual(order.id) expect(claimOrder.order_id).toEqual(order.id)
expect(returnOrder.type).toEqual("refund") expect(claimOrder.type).toEqual("refund")
expect(returnOrder.id).toBeDefined() expect(claimOrder.id).toBeDefined()
// Request itemm to return
const { result: preview } =
await orderClaimRequestItemReturnWorkflow.run({
throwOnError: true,
container,
input: {
claim_id: claimOrder.id,
items: [
{
id: order.items![0].id,
quantity: 1,
},
],
},
})
expect(preview.items[0]).toEqual(
expect.objectContaining({
quantity: 1,
id: order.items![0].id,
detail: expect.objectContaining({
quantity: 1,
fulfilled_quantity: 1,
return_requested_quantity: 1,
}),
actions: [
expect.objectContaining({
order_id: order.id,
claim_id: claimOrder.id,
version: 2,
order_change_id: expect.any(String),
reference: "return",
reference_id: expect.stringContaining("return_"),
action: "RETURN_ITEM",
details: expect.objectContaining({
quantity: 1,
return_id: expect.stringContaining("return_"),
claim_id: claimOrder.id,
reference_id: order.items![0].id,
}),
}),
],
})
)
}) })
}) })
}, },
@@ -1,10 +1,10 @@
import { import {
beginExchangeOrderWorkflow, beginExchangeOrderWorkflow,
createShippingOptionsWorkflow, createShippingOptionsWorkflow,
orderExchangeRequestItemReturnWorkflow,
} from "@medusajs/core-flows" } from "@medusajs/core-flows"
import { import {
FulfillmentWorkflow, FulfillmentWorkflow,
IOrderModuleService,
IRegionModuleService, IRegionModuleService,
IStockLocationService, IStockLocationService,
OrderWorkflow, OrderWorkflow,
@@ -227,18 +227,16 @@ async function prepareDataFixtures({ container }) {
} }
async function createOrderFixture({ container, product }) { async function createOrderFixture({ container, product }) {
const orderService: IOrderModuleService = container.resolve( const orderService = container.resolve(ModuleRegistrationName.ORDER)
ModuleRegistrationName.ORDER
)
let order = await orderService.createOrders({ let order = await orderService.createOrders({
region_id: "test_region_idclear", region_id: "test_region_id",
email: "foo@bar.com", email: "foo@bar.com",
items: [ items: [
{ {
title: "Custom Item 2", title: "Custom Item 2",
variant_sku: product.variants[0].sku, variant_sku: product.variants[0].sku,
variant_title: product.variants[0].title, variant_title: product.variants[0].title,
quantity: 1, quantity: 5,
unit_price: 50, unit_price: 50,
adjustments: [ adjustments: [
{ {
@@ -251,12 +249,6 @@ async function createOrderFixture({ container, product }) {
], ],
} as any, } as any,
], ],
transactions: [
{
amount: 50,
currency_code: "usd",
},
],
sales_channel_id: "test", sales_channel_id: "test",
shipping_address: { shipping_address: {
first_name: "Test", first_name: "Test",
@@ -311,7 +303,7 @@ async function createOrderFixture({ container, product }) {
reference_id: "fulfill_123", reference_id: "fulfill_123",
details: { details: {
reference_id: order.items![0].id, reference_id: order.items![0].id,
quantity: 1, quantity: 3,
}, },
}, },
{ {
@@ -356,7 +348,7 @@ medusaIntegrationTestRunner({
product = fixtures.product product = fixtures.product
}) })
it("should begin an exchange order", async () => { it("should begin an exchange order, request item return", async () => {
const order = await createOrderFixture({ container, product }) const order = await createOrderFixture({ container, product })
const createExchangeOrderData: OrderWorkflow.beginOrderExchangeWorkflowInput = const createExchangeOrderData: OrderWorkflow.beginOrderExchangeWorkflowInput =
@@ -369,9 +361,9 @@ medusaIntegrationTestRunner({
}, },
} }
await beginExchangeOrderWorkflow(container).run({ await beginExchangeOrderWorkflow.run({
container,
input: createExchangeOrderData, input: createExchangeOrderData,
throwOnError: true,
}) })
const remoteQuery = container.resolve( const remoteQuery = container.resolve(
@@ -385,15 +377,119 @@ medusaIntegrationTestRunner({
fields: ["order_id", "id", "metadata"], fields: ["order_id", "id", "metadata"],
}) })
const [returnOrder] = await remoteQuery(remoteQueryObject) const [exchangeOrder] = await remoteQuery(remoteQueryObject)
expect(returnOrder.order_id).toEqual(order.id) expect(exchangeOrder.order_id).toEqual(order.id)
expect(returnOrder.metadata).toEqual({ expect(exchangeOrder.metadata).toEqual({
reason: "test", reason: "test",
extra: "data", extra: "data",
value: 1234, value: 1234,
}) })
expect(returnOrder.id).toBeDefined() expect(exchangeOrder.id).toBeDefined()
// Request itemm to return
const { result: preview } =
await orderExchangeRequestItemReturnWorkflow.run({
throwOnError: true,
container,
input: {
exchange_id: exchangeOrder.id,
items: [
{
id: order.items![0].id,
quantity: 1,
},
],
},
})
expect(preview.items[0]).toEqual(
expect.objectContaining({
quantity: 5,
id: order.items![0].id,
detail: expect.objectContaining({
quantity: 5,
fulfilled_quantity: 3,
return_requested_quantity: 1,
}),
actions: [
expect.objectContaining({
order_id: order.id,
exchange_id: exchangeOrder.id,
version: 2,
order_change_id: expect.any(String),
reference: "return",
reference_id: expect.stringContaining("return_"),
action: "RETURN_ITEM",
details: expect.objectContaining({
quantity: 1,
return_id: expect.stringContaining("return_"),
exchange_id: exchangeOrder.id,
reference_id: order.items![0].id,
}),
}),
],
})
)
const { errors } = await orderExchangeRequestItemReturnWorkflow.run({
throwOnError: false,
container,
input: {
exchange_id: exchangeOrder.id,
items: [
{
id: order.items![0].id,
quantity: 3,
},
],
},
})
expect(errors[0].error.message).toEqual(
`Cannot request to return more items than what was fulfilled for item ${
order.items![0].id
}.`
)
const { result: anotherPreview } =
await orderExchangeRequestItemReturnWorkflow.run({
container,
input: {
exchange_id: exchangeOrder.id,
items: [
{
id: order.items![0].id,
quantity: 2,
},
],
},
})
expect(anotherPreview.items[0]).toEqual(
expect.objectContaining({
detail: expect.objectContaining({
quantity: 5,
fulfilled_quantity: 3,
return_requested_quantity: 3,
}),
actions: [
expect.objectContaining({
reference_id: preview.items[0].actions[0].reference_id,
action: "RETURN_ITEM",
details: expect.objectContaining({
quantity: 1,
}),
}),
expect.objectContaining({
reference_id: preview.items[0].actions[0].reference_id,
action: "RETURN_ITEM",
details: expect.objectContaining({
quantity: 2,
}),
}),
],
})
)
}) })
}) })
}, },
@@ -231,7 +231,7 @@ async function createOrderFixture({ container, product }) {
ModuleRegistrationName.ORDER ModuleRegistrationName.ORDER
) )
let order = await orderService.createOrders({ let order = await orderService.createOrders({
region_id: "test_region_idclear", region_id: "test_region_id",
email: "foo@bar.com", email: "foo@bar.com",
items: [ items: [
{ {
@@ -235,7 +235,7 @@ async function createOrderFixture({ container, product }) {
ModuleRegistrationName.ORDER ModuleRegistrationName.ORDER
) )
let order = await orderService.createOrders({ let order = await orderService.createOrders({
region_id: "test_region_idclear", region_id: "test_region_id",
email: "foo@bar.com", email: "foo@bar.com",
items: [ items: [
{ {
@@ -434,7 +434,7 @@ medusaIntegrationTestRunner({
expect.objectContaining({ expect.objectContaining({
id: expect.any(String), id: expect.any(String),
display_id: 1, display_id: 1,
region_id: "test_region_idclear", region_id: "test_region_id",
customer_id: "joe", customer_id: "joe",
version: 2, version: 2,
sales_channel_id: "test", // TODO: What about order with a sales channel but a shipping option link to a stock from another channel? sales_channel_id: "test", // TODO: What about order with a sales channel but a shipping option link to a stock from another channel?
@@ -217,7 +217,7 @@ async function createOrderFixture({ container, product, location }) {
ModuleRegistrationName.ORDER ModuleRegistrationName.ORDER
) )
let order = await orderService.createOrders({ let order = await orderService.createOrders({
region_id: "test_region_idclear", region_id: "test_region_id",
email: "foo@bar.com", email: "foo@bar.com",
items: [ items: [
{ {
@@ -220,7 +220,7 @@ async function createOrderFixture({ container, product, location }) {
ModuleRegistrationName.ORDER ModuleRegistrationName.ORDER
) )
let order = await orderService.createOrders({ let order = await orderService.createOrders({
region_id: "test_region_idclear", region_id: "test_region_id",
email: "foo@bar.com", email: "foo@bar.com",
items: [ items: [
{ {
@@ -16,8 +16,10 @@ export * from "./decline-order-change"
export * from "./delete-order-change" export * from "./delete-order-change"
export * from "./delete-order-change-actions" export * from "./delete-order-change-actions"
export * from "./get-item-tax-lines" export * from "./get-item-tax-lines"
export * from "./preview-order-change"
export * from "./register-fulfillment" export * from "./register-fulfillment"
export * from "./register-shipment" export * from "./register-shipment"
export * from "./set-tax-lines-for-items" export * from "./set-tax-lines-for-items"
export * from "./update-order-change-actions" export * from "./update-order-change-actions"
export * from "./update-order-exchanges"
export * from "./update-tax-lines" export * from "./update-tax-lines"
@@ -0,0 +1,17 @@
import { IOrderModuleService } from "@medusajs/types"
import { ModuleRegistrationName } from "@medusajs/utils"
import { StepResponse, createStep } from "@medusajs/workflows-sdk"
export const previewOrderChangeStepId = "preview-order-change"
export const previewOrderChangeStep = createStep(
previewOrderChangeStepId,
async (orderId: string, { container }) => {
const service = container.resolve<IOrderModuleService>(
ModuleRegistrationName.ORDER
)
const preview = await service.previewOrderChange(orderId)
return new StepResponse(preview)
}
)
@@ -0,0 +1,55 @@
import { IOrderModuleService, UpdateOrderClaimDTO } from "@medusajs/types"
import {
ModuleRegistrationName,
getSelectsAndRelationsFromObjectArray,
} from "@medusajs/utils"
import { StepResponse, createStep } from "@medusajs/workflows-sdk"
export const updateOrderClaimsStepId = "update-order-claim"
export const updateOrderClaimsStep = createStep(
updateOrderClaimsStepId,
async (data: UpdateOrderClaimDTO[], { container }) => {
const service = container.resolve<IOrderModuleService>(
ModuleRegistrationName.ORDER
)
const { selects, relations } = getSelectsAndRelationsFromObjectArray(data, {
objectFields: ["metadata"],
})
const dataBeforeUpdate = await service.listOrderClaims(
{ id: data.map((d) => d.id) },
{ relations, select: selects }
)
const updated = await service.updateOrderClaims(
data.map((dt) => {
const { id, ...rest } = dt
return {
selector: { id },
data: rest,
}
})
)
return new StepResponse(updated, dataBeforeUpdate)
},
async (dataBeforeUpdate, { container }) => {
if (!dataBeforeUpdate?.length) {
return
}
const service = container.resolve<IOrderModuleService>(
ModuleRegistrationName.ORDER
)
await service.updateOrderClaims(
dataBeforeUpdate.map((dt) => {
const { id, ...rest } = dt
return {
selector: { id },
data: rest,
}
})
)
}
)
@@ -0,0 +1,55 @@
import { IOrderModuleService, UpdateOrderExchangeDTO } from "@medusajs/types"
import {
ModuleRegistrationName,
getSelectsAndRelationsFromObjectArray,
} from "@medusajs/utils"
import { StepResponse, createStep } from "@medusajs/workflows-sdk"
export const updateOrderExchangesStepId = "update-order-exchange"
export const updateOrderExchangesStep = createStep(
updateOrderExchangesStepId,
async (data: UpdateOrderExchangeDTO[], { container }) => {
const service = container.resolve<IOrderModuleService>(
ModuleRegistrationName.ORDER
)
const { selects, relations } = getSelectsAndRelationsFromObjectArray(data, {
objectFields: ["metadata"],
})
const dataBeforeUpdate = await service.listOrderExchanges(
{ id: data.map((d) => d.id) },
{ relations, select: selects }
)
const updated = await service.updateOrderExchanges(
data.map((dt) => {
const { id, ...rest } = dt
return {
selector: { id },
data: rest,
}
})
)
return new StepResponse(updated, dataBeforeUpdate)
},
async (dataBeforeUpdate, { container }) => {
if (!dataBeforeUpdate?.length) {
return
}
const service = container.resolve<IOrderModuleService>(
ModuleRegistrationName.ORDER
)
await service.updateOrderExchanges(
dataBeforeUpdate.map((dt) => {
const { id, ...rest } = dt
return {
selector: { id },
data: rest,
}
})
)
}
)
@@ -41,15 +41,14 @@ export function throwIfItemsDoesNotExistsInOrder({
} }
} }
export function throwIfReturnIsCancelled({ export function throwIfIsCancelled(
orderReturn, obj: unknown & { id: string; canceled_at?: any },
}: { type: string
orderReturn: ReturnDTO ) {
}) { if (obj.canceled_at) {
if (orderReturn.canceled_at) {
throw new MedusaError( throw new MedusaError(
MedusaError.Types.INVALID_DATA, MedusaError.Types.INVALID_DATA,
`return with id ${orderReturn.id} has been canceled.` `${type} with id ${obj.id} has been canceled.`
) )
} }
} }
@@ -12,7 +12,7 @@ import {
} from "@medusajs/workflows-sdk" } from "@medusajs/workflows-sdk"
import { useRemoteQueryStep } from "../../common" import { useRemoteQueryStep } from "../../common"
import { cancelOrderReturnStep } from "../steps" import { cancelOrderReturnStep } from "../steps"
import { throwIfReturnIsCancelled } from "../utils/order-validation" import { throwIfIsCancelled } from "../utils/order-validation"
const validateOrder = createStep( const validateOrder = createStep(
"validate-return", "validate-return",
@@ -27,7 +27,7 @@ const validateOrder = createStep(
fulfillments: FulfillmentDTO[] fulfillments: FulfillmentDTO[]
} }
throwIfReturnIsCancelled({ orderReturn }) throwIfIsCancelled(orderReturn, "Return")
const throwErrorIf = ( const throwErrorIf = (
arr: unknown[], arr: unknown[],
@@ -0,0 +1,163 @@
import {
OrderChangeDTO,
OrderClaimDTO,
OrderDTO,
OrderWorkflow,
ReturnDTO,
} from "@medusajs/types"
import { ChangeActionType } from "@medusajs/utils"
import {
WorkflowData,
createStep,
createWorkflow,
transform,
when,
} from "@medusajs/workflows-sdk"
import { useRemoteQueryStep } from "../../common"
import { createOrderChangeActionsStep } from "../steps/create-order-change-actions"
import { createReturnsStep } from "../steps/create-returns"
import { previewOrderChangeStep } from "../steps/preview-order-change"
import { updateOrderClaimsStep } from "../steps/update-order-claims"
import {
throwIfIsCancelled,
throwIfItemsDoesNotExistsInOrder,
throwIfOrderChangeIsNotActive,
throwIfOrderIsCancelled,
} from "../utils/order-validation"
const validationStep = createStep(
"claim-request-item-return-validation",
async function ({
order,
orderChange,
orderReturn,
orderClaim,
items,
}: {
order: OrderDTO
orderReturn: ReturnDTO
orderClaim: OrderClaimDTO
orderChange: OrderChangeDTO
items: OrderWorkflow.OrderClaimRequestItemReturnWorkflowInput["items"]
}) {
throwIfOrderIsCancelled({ order })
throwIfIsCancelled(orderClaim, "Claim")
throwIfIsCancelled(orderReturn, "Return")
throwIfOrderChangeIsNotActive({ orderChange })
throwIfItemsDoesNotExistsInOrder({ order, inputItems: items })
}
)
export const orderClaimRequestItemReturnWorkflowId = "claim-request-item-return"
export const orderClaimRequestItemReturnWorkflow = createWorkflow(
orderClaimRequestItemReturnWorkflowId,
function (
input: WorkflowData<OrderWorkflow.OrderClaimRequestItemReturnWorkflowInput>
): WorkflowData<OrderDTO> {
const orderClaim = useRemoteQueryStep({
entry_point: "order_claim",
fields: ["id", "order_id", "return_id"],
variables: { id: input.claim_id },
list: false,
throw_if_key_not_found: true,
}).config({ name: "claim-query" })
const existingOrderReturn = when({ orderClaim }, ({ orderClaim }) => {
return orderClaim.return_id
}).then(() => {
return useRemoteQueryStep({
entry_point: "return",
fields: ["id", "status", "order_id"],
variables: { id: orderClaim.return_id },
list: false,
throw_if_key_not_found: true,
}).config({ name: "return-query" }) as ReturnDTO
})
const createdReturn = when({ orderClaim }, ({ orderClaim }) => {
return !orderClaim.return_id
}).then(() => {
return createReturnsStep([
{
order_id: orderClaim.order_id,
claim_id: orderClaim.id,
},
])
})
const orderReturn: ReturnDTO = transform(
{ createdReturn, existingOrderReturn, orderClaim },
({ createdReturn, existingOrderReturn, orderClaim }) => {
return existingOrderReturn ?? (createdReturn[0] as ReturnDTO)
}
)
const order: OrderDTO = useRemoteQueryStep({
entry_point: "orders",
fields: ["id", "status", "items.*"],
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", "status"],
variables: { order_id: orderClaim.order_id },
list: false,
}).config({ name: "order-change-query" })
validationStep({
order,
items: input.items,
orderClaim,
orderReturn,
orderChange,
})
when({ orderClaim }, ({ orderClaim }) => {
return !orderClaim.return_id
}).then(() => {
const createdReturnId = transform(
{ createdReturn },
({ createdReturn }) => {
return createdReturn[0]!.id
}
)
updateOrderClaimsStep([
{
id: orderClaim.id,
return_id: createdReturnId,
},
])
})
const orderChangeActionInput = transform(
{ order, orderChange, orderClaim, orderReturn, items: input.items },
({ order, orderChange, orderClaim, orderReturn, items }) => {
return items.map((item) => ({
order_change_id: orderChange.id,
order_id: order.id,
claim_id: orderClaim.id,
return_id: orderReturn.id,
version: orderChange.version,
action: ChangeActionType.RETURN_ITEM,
internal_note: item.internal_note,
reference: "return",
reference_id: orderReturn.id,
details: {
reference_id: item.id,
claim_id: orderClaim.id,
return_id: orderReturn.id,
quantity: item.quantity,
metadata: item.metadata,
},
}))
}
)
createOrderChangeActionsStep(orderChangeActionInput)
return previewOrderChangeStep(orderClaim.order_id)
}
)
@@ -0,0 +1,164 @@
import {
OrderChangeDTO,
OrderDTO,
OrderExchangeDTO,
OrderWorkflow,
ReturnDTO,
} from "@medusajs/types"
import { ChangeActionType } from "@medusajs/utils"
import {
WorkflowData,
createStep,
createWorkflow,
transform,
when,
} from "@medusajs/workflows-sdk"
import { useRemoteQueryStep } from "../../common"
import { createOrderChangeActionsStep } from "../steps/create-order-change-actions"
import { createReturnsStep } from "../steps/create-returns"
import { previewOrderChangeStep } from "../steps/preview-order-change"
import { updateOrderExchangesStep } from "../steps/update-order-exchanges"
import {
throwIfIsCancelled,
throwIfItemsDoesNotExistsInOrder,
throwIfOrderChangeIsNotActive,
throwIfOrderIsCancelled,
} from "../utils/order-validation"
const validationStep = createStep(
"exchange-request-item-return-validation",
async function ({
order,
orderChange,
orderReturn,
orderExchange,
items,
}: {
order: OrderDTO
orderReturn: ReturnDTO
orderExchange: OrderExchangeDTO
orderChange: OrderChangeDTO
items: OrderWorkflow.OrderExchangeRequestItemReturnWorkflowInput["items"]
}) {
throwIfOrderIsCancelled({ order })
throwIfIsCancelled(orderExchange, "Exchange")
throwIfIsCancelled(orderReturn, "Return")
throwIfOrderChangeIsNotActive({ orderChange })
throwIfItemsDoesNotExistsInOrder({ order, inputItems: items })
}
)
export const orderExchangeRequestItemReturnWorkflowId =
"exchange-request-item-return"
export const orderExchangeRequestItemReturnWorkflow = createWorkflow(
orderExchangeRequestItemReturnWorkflowId,
function (
input: WorkflowData<OrderWorkflow.OrderExchangeRequestItemReturnWorkflowInput>
): WorkflowData<OrderDTO> {
const orderExchange = useRemoteQueryStep({
entry_point: "order_exchange",
fields: ["id", "order_id", "return_id"],
variables: { id: input.exchange_id },
list: false,
throw_if_key_not_found: true,
}).config({ name: "exchange-query" })
const existingOrderReturn = when({ orderExchange }, ({ orderExchange }) => {
return orderExchange.return_id
}).then(() => {
return useRemoteQueryStep({
entry_point: "return",
fields: ["id", "status", "order_id"],
variables: { id: orderExchange.return_id },
list: false,
throw_if_key_not_found: true,
}).config({ name: "return-query" }) as ReturnDTO
})
const createdReturn = when({ orderExchange }, ({ orderExchange }) => {
return !orderExchange.return_id
}).then(() => {
return createReturnsStep([
{
order_id: orderExchange.order_id,
exchange_id: orderExchange.id,
},
])
})
const orderReturn: ReturnDTO = transform(
{ createdReturn, existingOrderReturn, orderExchange },
({ createdReturn, existingOrderReturn, orderExchange }) => {
return existingOrderReturn ?? (createdReturn[0] as ReturnDTO)
}
)
const order: OrderDTO = useRemoteQueryStep({
entry_point: "orders",
fields: ["id", "status", "items.*"],
variables: { id: orderExchange.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"],
variables: { order_id: orderExchange.order_id },
list: false,
}).config({ name: "order-change-query" })
validationStep({
order,
items: input.items,
orderExchange,
orderReturn,
orderChange,
})
when({ orderExchange }, ({ orderExchange }) => {
return !orderExchange.return_id
}).then(() => {
const createdReturnId = transform(
{ createdReturn },
({ createdReturn }) => {
return createdReturn[0]!.id
}
)
updateOrderExchangesStep([
{
id: orderExchange.id,
return_id: createdReturnId,
},
])
})
const orderChangeActionInput = transform(
{ order, orderChange, orderExchange, orderReturn, items: input.items },
({ order, orderChange, orderExchange, orderReturn, items }) => {
return items.map((item) => ({
order_change_id: orderChange.id,
order_id: order.id,
exchange_id: orderExchange.id,
return_id: orderReturn.id,
version: orderChange.version,
action: ChangeActionType.RETURN_ITEM,
internal_note: item.internal_note,
reference: "return",
reference_id: orderReturn.id,
details: {
reference_id: item.id,
exchange_id: orderExchange.id,
return_id: orderReturn.id,
quantity: item.quantity,
metadata: item.metadata,
},
}))
}
)
createOrderChangeActionsStep(orderChangeActionInput)
return previewOrderChangeStep(orderExchange.order_id)
}
)
@@ -6,6 +6,7 @@ export * from "./cancel-order"
export * from "./cancel-order-change" export * from "./cancel-order-change"
export * from "./cancel-order-fulfillment" export * from "./cancel-order-fulfillment"
export * from "./cancel-return" export * from "./cancel-return"
export * from "./claim-request-item-return"
export * from "./complete-orders" export * from "./complete-orders"
export * from "./create-complete-return" export * from "./create-complete-return"
export * from "./create-fulfillment" export * from "./create-fulfillment"
@@ -16,6 +17,7 @@ export * from "./create-shipment"
export * from "./decline-order-change" export * from "./decline-order-change"
export * from "./delete-order-change" export * from "./delete-order-change"
export * from "./delete-order-change-actions" export * from "./delete-order-change-actions"
export * from "./exchange-request-item-return"
export * from "./get-order-detail" export * from "./get-order-detail"
export * from "./get-orders-list" export * from "./get-orders-list"
export * from "./receive-return" export * from "./receive-return"
@@ -9,8 +9,8 @@ import { useRemoteQueryStep } from "../../common"
import { ReturnDTO } from "@medusajs/types" import { ReturnDTO } from "@medusajs/types"
import { receiveReturnStep } from "../steps/receive-return" import { receiveReturnStep } from "../steps/receive-return"
import { import {
throwIfIsCancelled,
throwIfItemsDoesNotExistsInReturn, throwIfItemsDoesNotExistsInReturn,
throwIfReturnIsCancelled,
} from "../utils/order-validation" } from "../utils/order-validation"
const validationStep = createStep( const validationStep = createStep(
@@ -25,7 +25,7 @@ const validationStep = createStep(
}, },
context context
) { ) {
throwIfReturnIsCancelled({ orderReturn }) throwIfIsCancelled(orderReturn, "Return")
throwIfItemsDoesNotExistsInReturn({ orderReturn, inputItems: input.items }) throwIfItemsDoesNotExistsInReturn({ orderReturn, inputItems: input.items })
} }
) )
@@ -15,10 +15,10 @@ import {
import { useRemoteQueryStep } from "../../common" import { useRemoteQueryStep } from "../../common"
import { createOrderChangeActionsStep } from "../steps/create-order-change-actions" import { createOrderChangeActionsStep } from "../steps/create-order-change-actions"
import { import {
throwIfIsCancelled,
throwIfItemsDoesNotExistsInOrder, throwIfItemsDoesNotExistsInOrder,
throwIfOrderChangeIsNotActive, throwIfOrderChangeIsNotActive,
throwIfOrderIsCancelled, throwIfOrderIsCancelled,
throwIfReturnIsCancelled,
} from "../utils/order-validation" } from "../utils/order-validation"
const validationStep = createStep( const validationStep = createStep(
@@ -35,7 +35,7 @@ const validationStep = createStep(
items: OrderWorkflow.RequestItemReturnWorkflowInput["items"] items: OrderWorkflow.RequestItemReturnWorkflowInput["items"]
}) { }) {
throwIfOrderIsCancelled({ order }) throwIfOrderIsCancelled({ order })
throwIfReturnIsCancelled({ orderReturn }) throwIfIsCancelled(orderReturn, "Return")
throwIfOrderChangeIsNotActive({ orderChange }) throwIfOrderChangeIsNotActive({ orderChange })
throwIfItemsDoesNotExistsInOrder({ order, inputItems: items }) throwIfItemsDoesNotExistsInOrder({ order, inputItems: items })
} }
@@ -49,7 +49,7 @@ export const requestItemReturnWorkflow = createWorkflow(
): WorkflowData<OrderChangeActionDTO[]> { ): WorkflowData<OrderChangeActionDTO[]> {
const orderReturn: ReturnDTO = useRemoteQueryStep({ const orderReturn: ReturnDTO = useRemoteQueryStep({
entry_point: "return", entry_point: "return",
fields: ["id", "status", "refund_amount", "order_id", "items.*"], fields: ["id", "status", "order_id"],
variables: { id: input.return_id }, variables: { id: input.return_id },
list: false, list: false,
throw_if_key_not_found: true, throw_if_key_not_found: true,
+6 -2
View File
@@ -326,6 +326,7 @@ export interface CreateOrderChangeActionDTO {
export interface UpdateOrderChangeActionDTO { export interface UpdateOrderChangeActionDTO {
id: string id: string
internal_note?: string | null internal_note?: string | null
metadata?: Record<string, unknown> | null
} }
/** ORDER TRANSACTION START */ /** ORDER TRANSACTION START */
@@ -436,7 +437,8 @@ export interface CreateOrderReturnDTO extends BaseOrderBundledActionsDTO {
exchange_id?: string exchange_id?: string
} }
export interface UpdateOrderReturnDTO { export interface UpdateReturnDTO {
id: string
refund_amount?: BigNumberInput refund_amount?: BigNumberInput
no_notification?: boolean no_notification?: boolean
claim_id?: string claim_id?: string
@@ -445,6 +447,7 @@ export interface UpdateOrderReturnDTO {
} }
export interface UpdateOrderClaimDTO { export interface UpdateOrderClaimDTO {
id: string
refund_amount?: BigNumberInput refund_amount?: BigNumberInput
no_notification?: boolean no_notification?: boolean
return_id?: string return_id?: string
@@ -453,6 +456,7 @@ export interface UpdateOrderClaimDTO {
} }
export interface UpdateOrderExchangeDTO { export interface UpdateOrderExchangeDTO {
id: string
difference_due?: BigNumberInput difference_due?: BigNumberInput
no_notification?: boolean no_notification?: boolean
return_id?: string return_id?: string
@@ -462,7 +466,7 @@ export interface UpdateOrderExchangeDTO {
export interface UpdateOrderReturnWithSelectorDTO { export interface UpdateOrderReturnWithSelectorDTO {
selector: Partial<ReturnDTO> selector: Partial<ReturnDTO>
data: Partial<UpdateOrderReturnDTO> data: Partial<UpdateReturnDTO>
} }
export interface UpdateOrderClaimWithSelectorDTO { export interface UpdateOrderClaimWithSelectorDTO {
+3 -3
View File
@@ -75,12 +75,12 @@ import {
UpdateOrderLineItemDTO, UpdateOrderLineItemDTO,
UpdateOrderLineItemTaxLineDTO, UpdateOrderLineItemTaxLineDTO,
UpdateOrderLineItemWithSelectorDTO, UpdateOrderLineItemWithSelectorDTO,
UpdateOrderReturnDTO,
UpdateOrderReturnReasonDTO, UpdateOrderReturnReasonDTO,
UpdateOrderReturnReasonWithSelectorDTO, UpdateOrderReturnReasonWithSelectorDTO,
UpdateOrderReturnWithSelectorDTO, UpdateOrderReturnWithSelectorDTO,
UpdateOrderShippingMethodAdjustmentDTO, UpdateOrderShippingMethodAdjustmentDTO,
UpdateOrderShippingMethodTaxLineDTO, UpdateOrderShippingMethodTaxLineDTO,
UpdateReturnDTO,
UpsertOrderLineItemAdjustmentDTO, UpsertOrderLineItemAdjustmentDTO,
} from "./mutations" } from "./mutations"
@@ -1899,12 +1899,12 @@ export interface IOrderModuleService extends IModuleService {
updateReturns( updateReturns(
selector: Partial<FilterableReturnProps>, selector: Partial<FilterableReturnProps>,
data: Partial<UpdateOrderReturnDTO>, data: Partial<UpdateReturnDTO>,
sharedContext?: Context sharedContext?: Context
): Promise<ReturnDTO[]> ): Promise<ReturnDTO[]>
updateReturns( updateReturns(
id: string, id: string,
data: Partial<UpdateOrderReturnDTO>, data: Partial<UpdateReturnDTO>,
sharedContext?: Context sharedContext?: Context
): Promise<ReturnDTO> ): Promise<ReturnDTO>
@@ -4,3 +4,13 @@ export interface RequestItemReturnWorkflowInput {
return_id: string return_id: string
items: CreateReturnItem[] items: CreateReturnItem[]
} }
export interface OrderExchangeRequestItemReturnWorkflowInput {
exchange_id: string
items: CreateReturnItem[]
}
export interface OrderClaimRequestItemReturnWorkflowInput {
claim_id: string
items: CreateReturnItem[]
}
@@ -120,9 +120,17 @@ describe("Workflow composer", () => {
} }
) )
const { result } = await workflow.run({ input: { callSubFlow: true } }) const { result } = await workflow.run({
input: { callSubFlow: true },
})
expect(result).toEqual({ result: "hi from outside" }) expect(result).toEqual({ result: "hi from outside" })
const { result: res2 } = await workflow.run({
input: { callSubFlow: false },
})
expect(res2).toEqual({ result: "default response" })
}) })
it("should revert the workflow and sub workflow on failure", async function () { it("should revert the workflow and sub workflow on failure", async function () {
@@ -1932,9 +1932,28 @@ export default class OrderModuleService<
return await this.orderChangeService_.create(input, sharedContext) return await this.orderChangeService_.create(input, sharedContext)
} }
async previewOrderChange(orderChangeId: string, sharedContext?: Context) { @InjectManager("baseRepository_")
async previewOrderChange(orderId: string, sharedContext?: Context) {
const order = await this.retrieveOrder(
orderId,
{
select: ["id", "version", "items.detail", "summary", "total"],
relations: [
"transactions",
"items",
"items.detail",
"shipping_methods",
],
},
sharedContext
)
if (!order.order_change) {
return order
}
const orderChange = await super.retrieveOrderChange( const orderChange = await super.retrieveOrderChange(
orderChangeId, order.order_change.id,
{ relations: ["actions"] }, { relations: ["actions"] },
sharedContext sharedContext
) )
@@ -1950,20 +1969,6 @@ export default class OrderModuleService<
} }
}) })
const order = await this.retrieveOrder(
orderChange.order_id,
{
select: ["id", "version", "items.detail", "summary", "total"],
relations: [
"transactions",
"items",
"items.detail",
"shipping_methods",
],
},
sharedContext
)
const calculated = calculateOrderChange({ const calculated = calculateOrderChange({
order: order as any, order: order as any,
actions: orderChange.actions, actions: orderChange.actions,
@@ -97,7 +97,7 @@ function cleanNestedRelations(obj) {
} }
function formatOrderReturn(orderReturn, mainOrder) { function formatOrderReturn(orderReturn, mainOrder) {
orderReturn.items.forEach((orderItem) => { orderReturn.items?.forEach((orderItem) => {
const item = mainOrder.items?.find((item) => item.id === orderItem.item_id) const item = mainOrder.items?.find((item) => item.id === orderItem.item_id)
orderItem.detail = item?.detail orderItem.detail = item?.detail