Skip to content

Commit 91d62c1

Browse files
committed
feat: refactor edits and exchanges to have common flag toggle flow
1 parent 7d7a250 commit 91d62c1

18 files changed

+549
-554
lines changed

integration-tests/http/__tests__/exchanges/exchanges.spec.ts

Lines changed: 0 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1584,34 +1584,6 @@ medusaIntegrationTestRunner({
15841584
])
15851585
)
15861586
})
1587-
1588-
it("should validate that order change is an exchange", async () => {
1589-
// start order edit instead of an exchange
1590-
await api.post(
1591-
`/admin/order-edits`,
1592-
{ order_id: order.id },
1593-
adminHeaders
1594-
)
1595-
1596-
const orderEditOrderChange = (
1597-
await api.get(`/admin/orders/${order.id}/preview`, adminHeaders)
1598-
).data.order.order_change
1599-
1600-
const { response } = await api
1601-
.post(
1602-
`/admin/order-changes/${orderEditOrderChange.id}`,
1603-
{
1604-
carry_over_promotions: true,
1605-
},
1606-
adminHeaders
1607-
)
1608-
.catch((e) => e)
1609-
1610-
expect(response.status).toBe(400)
1611-
expect(response.data.message).toContain(
1612-
`Order change ${orderEditOrderChange.id} is not an exchange.`
1613-
)
1614-
})
16151587
})
16161588
})
16171589
},

integration-tests/http/__tests__/order-edits/order-edits.spec.ts

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1297,6 +1297,16 @@ medusaIntegrationTestRunner({
12971297
adminHeaders
12981298
)
12991299

1300+
// allow carry over promotions flag on the edit
1301+
const orderChangeId = result.data.order_change.id
1302+
await api.post(
1303+
`/admin/order-changes/${orderChangeId}`,
1304+
{
1305+
carry_over_promotions: true,
1306+
},
1307+
adminHeaders
1308+
)
1309+
13001310
const orderId = result.data.order_change.order_id
13011311

13021312
result = (await api.get(`/admin/orders/${orderId}`, adminHeaders)).data
@@ -1375,6 +1385,16 @@ medusaIntegrationTestRunner({
13751385

13761386
const orderId = result.data.order_change.order_id
13771387

1388+
// allow carry over promotions flag on the edit
1389+
const orderChangeId = result.data.order_change.id
1390+
await api.post(
1391+
`/admin/order-changes/${orderChangeId}`,
1392+
{
1393+
carry_over_promotions: true,
1394+
},
1395+
adminHeaders
1396+
)
1397+
13781398
const item = order.items[0]
13791399

13801400
result = (await api.get(`/admin/orders/${orderId}`, adminHeaders)).data
@@ -1451,6 +1471,16 @@ medusaIntegrationTestRunner({
14511471

14521472
const orderId = result.data.order_change.order_id
14531473

1474+
// allow carry over promotions flag on the edit
1475+
const orderChangeId = result.data.order_change.id
1476+
await api.post(
1477+
`/admin/order-changes/${orderChangeId}`,
1478+
{
1479+
carry_over_promotions: true,
1480+
},
1481+
adminHeaders
1482+
)
1483+
14541484
const item = order.items[0]
14551485

14561486
result = (await api.get(`/admin/orders/${orderId}`, adminHeaders)).data
@@ -1559,6 +1589,16 @@ medusaIntegrationTestRunner({
15591589
)
15601590
const orderChange1 = response.data.order_change
15611591

1592+
// allow carry over promotions flag on the edit
1593+
const orderChangeId = response.data.order_change.id
1594+
await api.post(
1595+
`/admin/order-changes/${orderChangeId}`,
1596+
{
1597+
carry_over_promotions: true,
1598+
},
1599+
adminHeaders
1600+
)
1601+
15621602
// 2. Add a new item in the first edit
15631603
response = await api.post(
15641604
`/admin/order-edits/${orderChange1.order_id}/items`,
@@ -1648,6 +1688,13 @@ medusaIntegrationTestRunner({
16481688
adminHeaders
16491689
)
16501690
const orderChange2 = response.data.order_change
1691+
await api.post(
1692+
`/admin/order-changes/${orderChange2.id}`,
1693+
{
1694+
carry_over_promotions: true,
1695+
},
1696+
adminHeaders
1697+
)
16511698

16521699
// 5. Add another productExtra item
16531700
response = await api.post(
@@ -1943,6 +1990,17 @@ medusaIntegrationTestRunner({
19431990
},
19441991
adminHeaders
19451992
)
1993+
1994+
// allow carry over promotions flag on the edit
1995+
const orderChangeId = editRes.data.order_change.id
1996+
await api.post(
1997+
`/admin/order-changes/${orderChangeId}`,
1998+
{
1999+
carry_over_promotions: true,
2000+
},
2001+
adminHeaders
2002+
)
2003+
19462004
const editOrderId = editRes.data.order_change.order_id
19472005
const extraVariantId = productExtra.variants[0].id
19482006

@@ -2038,6 +2096,16 @@ medusaIntegrationTestRunner({
20382096
const orderId = result.data.order_change.order_id
20392097
const originalItem = order.items[0]
20402098

2099+
// allow carry over promotions flag on the edit
2100+
const orderChangeId = result.data.order_change.id
2101+
await api.post(
2102+
`/admin/order-changes/${orderChangeId}`,
2103+
{
2104+
carry_over_promotions: true,
2105+
},
2106+
adminHeaders
2107+
)
2108+
20412109
// Add a new item
20422110
result = (
20432111
await api.post(
@@ -2154,6 +2222,16 @@ medusaIntegrationTestRunner({
21542222
adminHeaders
21552223
)
21562224

2225+
// allow carry over promotions flag on the edit
2226+
const orderChangeId = result.data.order_change.id
2227+
await api.post(
2228+
`/admin/order-changes/${orderChangeId}`,
2229+
{
2230+
carry_over_promotions: true,
2231+
},
2232+
adminHeaders
2233+
)
2234+
21572235
const orderId = result.data.order_change.order_id
21582236

21592237
result = (await api.get(`/admin/orders/${orderId}`, adminHeaders)).data
@@ -2332,6 +2410,16 @@ medusaIntegrationTestRunner({
23322410
adminHeaders
23332411
)
23342412

2413+
// allow carry over promotions flag on the edit
2414+
const orderChangeId = result.data.order_change.id
2415+
await api.post(
2416+
`/admin/order-changes/${orderChangeId}`,
2417+
{
2418+
carry_over_promotions: true,
2419+
},
2420+
adminHeaders
2421+
)
2422+
23352423
const orderId = result.data.order_change.order_id
23362424

23372425
result = (await api.get(`/admin/orders/${orderId}`, adminHeaders)).data

packages/core/core-flows/src/order/steps/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ export * from "./delete-order-change-actions"
1717
export * from "./delete-order-changes"
1818
export * from "./delete-order-shipping-methods"
1919
export * from "./exchange/cancel-exchange"
20+
export * from "./list-order-change-actions-by-type"
2021
export * from "./exchange/create-exchange"
2122
export * from "./exchange/create-exchange-items-from-actions"
2223
export * from "./exchange/delete-exchanges"
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import { IOrderModuleService } from "@medusajs/framework/types"
2+
import { ChangeActionType, Modules } from "@medusajs/framework/utils"
3+
import { StepResponse, createStep } from "@medusajs/framework/workflows-sdk"
4+
5+
/**
6+
* This step lists order change actions filtered by action type.
7+
*/
8+
export const listOrderChangeActionsByTypeStep = createStep(
9+
"list-order-change-actions-by-type",
10+
async function (
11+
{
12+
order_change_id,
13+
action_type,
14+
}: {
15+
order_change_id: string
16+
action_type: ChangeActionType
17+
},
18+
{ container }
19+
) {
20+
const service = container.resolve<IOrderModuleService>(Modules.ORDER)
21+
22+
const actions = await service.listOrderChangeActions(
23+
{
24+
order_change_id,
25+
},
26+
{
27+
select: ["id", "action"],
28+
}
29+
)
30+
31+
const filteredActions = actions.filter(
32+
(action) => action.action === action_type
33+
)
34+
35+
return new StepResponse(filteredActions.map((action) => action.id))
36+
}
37+
)
Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
import {
2+
ComputeActionContext,
3+
OrderChangeDTO,
4+
OrderDTO,
5+
PromotionDTO,
6+
} from "@medusajs/framework/types"
7+
import { ChangeActionType } from "@medusajs/framework/utils"
8+
import {
9+
createWorkflow,
10+
transform,
11+
when,
12+
WorkflowData,
13+
} from "@medusajs/framework/workflows-sdk"
14+
import {
15+
getActionsToComputeFromPromotionsStep,
16+
prepareAdjustmentsFromPromotionActionsStep,
17+
} from "../../cart"
18+
import { previewOrderChangeStep } from "../steps/preview-order-change"
19+
import { createOrderChangeActionsWorkflow } from "./create-order-change-actions"
20+
import {
21+
deleteOrderChangeActionsStep,
22+
listOrderChangeActionsByTypeStep,
23+
} from "../steps"
24+
25+
/**
26+
* The data to compute adjustments for an order edit, exchange, claim, or return.
27+
*/
28+
export type ComputeAdjustmentsForPreviewWorkflowInput = {
29+
/**
30+
* The order's details.
31+
*/
32+
order: OrderDTO & { promotions: PromotionDTO[] }
33+
/**
34+
* The order change's details.
35+
*/
36+
orderChange: OrderChangeDTO
37+
}
38+
39+
export const computeAdjustmentsForPreviewWorkflowId =
40+
"compute-adjustments-for-preview"
41+
/**
42+
* This workflow computes adjustments for an order change if the carry over promotions flag is true on the order change.
43+
* If the flag is false, it deletes the existing adjustments replacement actions.
44+
*
45+
* It is currently used as a part of the order edit and exchange flows.
46+
* It's used by the [Add Items to Order Edit Admin API Route](https://docs.medusajs.com/api/admin#order-edits_postordereditsiditems),
47+
* [Add Outbound Items Admin API Route](https://docs.medusajs.com/api/admin#exchanges_postexchangesidoutbounditems),
48+
* and [Add Inbound Items Admin API Route](https://docs.medusajs.com/api/admin#exchanges_postexchangesidinbounditems).
49+
*
50+
* You can use this workflow within your customizations or your own custom workflows, allowing you to compute adjustments
51+
* in your custom flows.
52+
*
53+
* @example
54+
* const { result } = await computeAdjustmentsForPreviewWorkflow(container)
55+
* .run({
56+
* input: {
57+
* order: {
58+
* id: "order_123",
59+
* // other order details...
60+
* },
61+
* orderChange: {
62+
* id: "orch_123",
63+
* // other order change details...
64+
* },
65+
* exchange_id: "exchange_123", // optional, for exchanges
66+
* }
67+
* })
68+
*
69+
* @summary
70+
*
71+
* Compute adjustments for an order edit, exchange, claim, or return.
72+
*/
73+
export const computeAdjustmentsForPreviewWorkflow = createWorkflow(
74+
computeAdjustmentsForPreviewWorkflowId,
75+
function (input: WorkflowData<ComputeAdjustmentsForPreviewWorkflowInput>) {
76+
const previewedOrder = previewOrderChangeStep(input.order.id)
77+
78+
when(
79+
{ order: input.order },
80+
({ order }) =>
81+
/**
82+
* Compute adjustments only if the flag on the order change is true
83+
*/
84+
!!order.promotions.length && !!input.orderChange.carry_over_promotions
85+
).then(() => {
86+
const actionsToComputeItemsInput = transform(
87+
{ previewedOrder, order: input.order },
88+
({ previewedOrder, order }) => {
89+
return {
90+
currency_code: order.currency_code,
91+
items: previewedOrder.items.map((item) => ({
92+
...item,
93+
// Buy-Get promotions rely on the product ID, so we need to manually set it before refreshing adjustments
94+
product: { id: item.product_id },
95+
})),
96+
} as ComputeActionContext
97+
}
98+
)
99+
100+
const orderPromotions = transform({ order: input.order }, ({ order }) => {
101+
return order.promotions
102+
.map((p) => p.code)
103+
.filter((p) => p !== undefined)
104+
})
105+
106+
const actions = getActionsToComputeFromPromotionsStep({
107+
computeActionContext: actionsToComputeItemsInput,
108+
promotionCodesToApply: orderPromotions,
109+
})
110+
111+
const { lineItemAdjustmentsToCreate } =
112+
prepareAdjustmentsFromPromotionActionsStep({ actions })
113+
114+
const orderChangeActionAdjustmentsInput = transform(
115+
{
116+
order: input.order,
117+
previewedOrder,
118+
orderChange: input.orderChange,
119+
lineItemAdjustmentsToCreate,
120+
},
121+
({
122+
order,
123+
previewedOrder,
124+
orderChange,
125+
lineItemAdjustmentsToCreate,
126+
}) => {
127+
return previewedOrder.items.map((item) => {
128+
const itemAdjustments = lineItemAdjustmentsToCreate.filter(
129+
(adjustment) => adjustment.item_id === item.id
130+
)
131+
132+
return {
133+
order_change_id: orderChange.id,
134+
order_id: order.id,
135+
exchange_id: orderChange.exchange_id ?? undefined,
136+
claim_id: orderChange.claim_id ?? undefined,
137+
return_id: orderChange.return_id ?? undefined,
138+
version: orderChange.version,
139+
action: ChangeActionType.ITEM_ADJUSTMENTS_REPLACE,
140+
details: {
141+
reference_id: item.id,
142+
adjustments: itemAdjustments,
143+
},
144+
}
145+
})
146+
}
147+
)
148+
149+
createOrderChangeActionsWorkflow
150+
.runAsStep({ input: orderChangeActionAdjustmentsInput })
151+
.config({ name: "order-change-action-adjustments-input" })
152+
})
153+
154+
when(
155+
{ order: previewedOrder },
156+
({ order }) => !order.order_change.carry_over_promotions
157+
).then(() => {
158+
const actionIds = listOrderChangeActionsByTypeStep({
159+
order_change_id: input.orderChange.id,
160+
action_type: ChangeActionType.ITEM_ADJUSTMENTS_REPLACE,
161+
})
162+
163+
deleteOrderChangeActionsStep({ ids: actionIds })
164+
})
165+
}
166+
)

0 commit comments

Comments
 (0)