Skip to content

Commit b767898

Browse files
chore(cart, core-flows): Improve tax lines algo management (#11715)
Co-authored-by: Adrien de Peretti <25098370+adrien2p@users.noreply.github.com>
1 parent 4b3869e commit b767898

File tree

12 files changed

+1047
-140
lines changed

12 files changed

+1047
-140
lines changed

.changeset/afraid-hotels-jam.md

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
"@medusajs/core-flows": patch
3+
"@medusajs/cart": patch
4+
"@medusajs/types": patch
5+
---
6+
7+
chore: improve tax lines

packages/core/core-flows/src/cart/steps/set-tax-lines-for-items.ts

+25-15
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import {
66
ItemTaxLineDTO,
77
ShippingTaxLineDTO,
88
} from "@medusajs/framework/types"
9-
import { Modules } from "@medusajs/framework/utils"
9+
import { Modules, promiseAll } from "@medusajs/framework/utils"
1010
import { StepResponse, createStep } from "@medusajs/framework/workflows-sdk"
1111

1212
/**
@@ -30,13 +30,13 @@ export interface SetTaxLinesForItemsStepInput {
3030
export const setTaxLinesForItemsStepId = "set-tax-lines-for-items"
3131
/**
3232
* This step sets the tax lines of shipping methods and line items in a cart.
33-
*
33+
*
3434
* :::tip
35-
*
35+
*
3636
* You can use the {@link retrieveCartStep} to retrieve a cart's details.
37-
*
37+
*
3838
* :::
39-
*
39+
*
4040
* @example
4141
* const data = setTaxLinesForItemsStep({
4242
* // retrieve the details of the cart from another workflow
@@ -64,21 +64,31 @@ export const setTaxLinesForItemsStep = createStep(
6464
const { cart, item_tax_lines, shipping_tax_lines } = data
6565
const cartService = container.resolve<ICartModuleService>(Modules.CART)
6666

67-
const existingShippingMethodTaxLines =
68-
await cartService.listShippingMethodTaxLines({
69-
shipping_method_id: shipping_tax_lines.map((t) => t.shipping_line_id),
70-
})
67+
const [existingShippingMethodTaxLines, existingLineItemTaxLines] =
68+
await promiseAll([
69+
shipping_tax_lines.length
70+
? cartService.listShippingMethodTaxLines({
71+
shipping_method_id: shipping_tax_lines.map(
72+
(t) => t.shipping_line_id
73+
),
74+
})
75+
: [],
7176

72-
const existingLineItemTaxLines = await cartService.listLineItemTaxLines({
73-
item_id: item_tax_lines.map((t) => t.line_item_id),
74-
})
77+
item_tax_lines.length
78+
? cartService.listLineItemTaxLines({
79+
item_id: item_tax_lines.map((t) => t.line_item_id),
80+
})
81+
: [],
82+
])
7583

7684
const itemsTaxLinesData = normalizeItemTaxLinesForCart(item_tax_lines)
77-
await cartService.setLineItemTaxLines(cart.id, itemsTaxLinesData)
78-
7985
const shippingTaxLinesData =
8086
normalizeShippingTaxLinesForCart(shipping_tax_lines)
81-
await cartService.setShippingMethodTaxLines(cart.id, shippingTaxLinesData)
87+
88+
await promiseAll([
89+
cartService.setLineItemTaxLines(cart.id, itemsTaxLinesData),
90+
cartService.setShippingMethodTaxLines(cart.id, shippingTaxLinesData),
91+
])
8292

8393
return new StepResponse(null, {
8494
cart,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
import {
2+
CartWorkflowDTO,
3+
CreateLineItemTaxLineDTO,
4+
CreateShippingMethodTaxLineDTO,
5+
ICartModuleService,
6+
ItemTaxLineDTO,
7+
LineItemTaxLineDTO,
8+
ShippingMethodTaxLineDTO,
9+
ShippingTaxLineDTO,
10+
} from "@medusajs/framework/types"
11+
import { Modules, promiseAll } from "@medusajs/framework/utils"
12+
import { StepResponse, createStep } from "@medusajs/framework/workflows-sdk"
13+
14+
/**
15+
* The details of the tax lines to set in a cart.
16+
*/
17+
export interface SetTaxLinesForItemsStepInput {
18+
/**
19+
* The cart's details.
20+
*/
21+
cart: CartWorkflowDTO
22+
/**
23+
* The tax lines to set for line items.
24+
*/
25+
item_tax_lines: ItemTaxLineDTO[]
26+
/**
27+
* The tax lines to set for shipping methods.
28+
*/
29+
shipping_tax_lines: ShippingTaxLineDTO[]
30+
}
31+
32+
export const upsertTaxLinesForItemsStepId = "set-tax-lines-for-items"
33+
/**
34+
* This step sets the tax lines of shipping methods and line items in a cart.
35+
*
36+
* :::tip
37+
*
38+
* You can use the {@link retrieveCartStep} to retrieve a cart's details.
39+
*
40+
* :::
41+
*
42+
* @example
43+
* const data = upsertTaxLinesForItemsStep({
44+
* // retrieve the details of the cart from another workflow
45+
* // or in another step using the Cart Module's service
46+
* cart,
47+
* "item_tax_lines": [{
48+
* "rate": 48,
49+
* "code": "CODE123",
50+
* "name": "Tax rate 2",
51+
* "provider_id": "provider_1",
52+
* "line_item_id": "litem_123"
53+
* }],
54+
* "shipping_tax_lines": [{
55+
* "rate": 49,
56+
* "code": "CODE456",
57+
* "name": "Tax rate 1",
58+
* "provider_id": "provider_1",
59+
* "shipping_line_id": "sm_123"
60+
* }]
61+
* })
62+
*/
63+
export const upsertTaxLinesForItemsStep = createStep(
64+
upsertTaxLinesForItemsStepId,
65+
async (data: SetTaxLinesForItemsStepInput, { container }) => {
66+
const { cart, item_tax_lines, shipping_tax_lines } = data
67+
const cartService = container.resolve<ICartModuleService>(Modules.CART)
68+
69+
const [existingShippingMethodTaxLines, existingLineItemTaxLines] =
70+
await promiseAll([
71+
shipping_tax_lines.length
72+
? cartService.listShippingMethodTaxLines({
73+
shipping_method_id: shipping_tax_lines.map(
74+
(t) => t.shipping_line_id
75+
),
76+
})
77+
: [],
78+
79+
item_tax_lines.length
80+
? cartService.listLineItemTaxLines({
81+
item_id: item_tax_lines.map((t) => t.line_item_id),
82+
})
83+
: [],
84+
])
85+
86+
const itemsTaxLinesData = normalizeItemTaxLinesForCart(
87+
item_tax_lines,
88+
existingLineItemTaxLines
89+
)
90+
const shippingTaxLinesData = normalizeShippingTaxLinesForCart(
91+
shipping_tax_lines,
92+
existingShippingMethodTaxLines
93+
)
94+
95+
await promiseAll([
96+
itemsTaxLinesData.length
97+
? cartService.upsertLineItemTaxLines(itemsTaxLinesData)
98+
: [],
99+
shippingTaxLinesData.length
100+
? cartService.upsertShippingMethodTaxLines(shippingTaxLinesData)
101+
: [],
102+
])
103+
104+
return new StepResponse(null, {
105+
cart,
106+
existingLineItemTaxLines,
107+
existingShippingMethodTaxLines,
108+
})
109+
},
110+
async (revertData, { container }) => {
111+
if (!revertData) {
112+
return
113+
}
114+
115+
const { existingLineItemTaxLines, existingShippingMethodTaxLines } =
116+
revertData
117+
118+
const cartService = container.resolve<ICartModuleService>(Modules.CART)
119+
120+
if (existingLineItemTaxLines) {
121+
await cartService.upsertLineItemTaxLines(
122+
existingLineItemTaxLines.map((taxLine) => ({
123+
description: taxLine.description,
124+
tax_rate_id: taxLine.tax_rate_id,
125+
code: taxLine.code,
126+
rate: taxLine.rate,
127+
provider_id: taxLine.provider_id,
128+
item_id: taxLine.item_id,
129+
}))
130+
)
131+
}
132+
133+
await cartService.upsertShippingMethodTaxLines(
134+
existingShippingMethodTaxLines.map((taxLine) => ({
135+
description: taxLine.description,
136+
tax_rate_id: taxLine.tax_rate_id,
137+
code: taxLine.code,
138+
rate: taxLine.rate,
139+
provider_id: taxLine.provider_id,
140+
shipping_method_id: taxLine.shipping_method_id,
141+
}))
142+
)
143+
}
144+
)
145+
146+
function normalizeItemTaxLinesForCart(
147+
taxLines: ItemTaxLineDTO[],
148+
existingTaxLines: LineItemTaxLineDTO[]
149+
): CreateLineItemTaxLineDTO[] {
150+
return taxLines.map((taxLine: ItemTaxLineDTO & { id?: string }) => ({
151+
id: existingTaxLines.find((t) => t.item_id === taxLine.line_item_id)?.id,
152+
description: taxLine.name,
153+
tax_rate_id: taxLine.rate_id,
154+
code: taxLine.code!,
155+
rate: taxLine.rate!,
156+
provider_id: taxLine.provider_id,
157+
item_id: taxLine.line_item_id,
158+
}))
159+
}
160+
161+
function normalizeShippingTaxLinesForCart(
162+
taxLines: ShippingTaxLineDTO[],
163+
existingTaxLines: ShippingMethodTaxLineDTO[]
164+
): CreateShippingMethodTaxLineDTO[] {
165+
return taxLines.map((taxLine: ShippingTaxLineDTO & { id?: string }) => ({
166+
id: existingTaxLines.find(
167+
(t) => t.shipping_method_id === taxLine.shipping_line_id
168+
)?.id,
169+
description: taxLine.name,
170+
tax_rate_id: taxLine.rate_id,
171+
code: taxLine.code!,
172+
rate: taxLine.rate!,
173+
provider_id: taxLine.provider_id,
174+
shipping_method_id: taxLine.shipping_line_id,
175+
}))
176+
}

packages/core/core-flows/src/cart/workflows/add-shipping-method-to-cart.ts

+9-9
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ export interface AddShippingMethodToCartWorkflowInput {
3939
id: string
4040
/**
4141
* Custom data useful for the fulfillment provider processing the shipping option or method.
42-
*
42+
*
4343
* Learn more in [this documentation](https://docs.medusajs.com/resources/commerce-modules/fulfillment/shipping-option#data-property).
4444
*/
4545
data?: Record<string, unknown>
@@ -48,11 +48,11 @@ export interface AddShippingMethodToCartWorkflowInput {
4848

4949
export const addShippingMethodToCartWorkflowId = "add-shipping-method-to-cart"
5050
/**
51-
* This workflow adds a shipping method to a cart. It's executed by the
51+
* This workflow adds a shipping method to a cart. It's executed by the
5252
* [Add Shipping Method Store API Route](https://docs.medusajs.com/api/store#carts_postcartsidshippingmethods).
53-
*
53+
*
5454
* You can use this workflow within your own customizations or custom workflows, allowing you to wrap custom logic around adding a shipping method to the cart.
55-
*
55+
*
5656
* @example
5757
* const { result } = await addShippingMethodToCartWorkflow(container)
5858
* .run({
@@ -71,11 +71,11 @@ export const addShippingMethodToCartWorkflowId = "add-shipping-method-to-cart"
7171
* ]
7272
* }
7373
* })
74-
*
74+
*
7575
* @summary
76-
*
76+
*
7777
* Add a shipping method to a cart.
78-
*
78+
*
7979
* @property hooks.validate - This hook is executed before all operations. You can consume this hook to perform any custom validation. If validation fails, you can throw an error to stop the workflow execution.
8080
*/
8181
export const addShippingMethodToCartWorkflow = createWorkflow(
@@ -186,7 +186,7 @@ export const addShippingMethodToCartWorkflow = createWorkflow(
186186
cart.shipping_methods.map((sm) => sm.id)
187187
)
188188

189-
parallelize(
189+
const [, createdShippingMethods] = parallelize(
190190
removeShippingMethodFromCartStep({
191191
shipping_method_ids: currentShippingMethods,
192192
}),
@@ -200,7 +200,7 @@ export const addShippingMethodToCartWorkflow = createWorkflow(
200200
)
201201

202202
refreshCartItemsWorkflow.runAsStep({
203-
input: { cart_id: cart.id },
203+
input: { cart_id: cart.id, shipping_methods: createdShippingMethods },
204204
})
205205

206206
return new WorkflowResponse(void 0, {

packages/core/core-flows/src/cart/workflows/add-to-cart.ts

+9-2
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@ export const addToCartWorkflow = createWorkflow(
173173
},
174174
})
175175

176-
parallelize(
176+
const [createdLineItems, updatedLineItems] = parallelize(
177177
createLineItemsStep({
178178
id: cart.id,
179179
items: itemsToCreate,
@@ -184,8 +184,15 @@ export const addToCartWorkflow = createWorkflow(
184184
})
185185
)
186186

187+
const allItems = transform(
188+
{ createdLineItems, updatedLineItems },
189+
({ createdLineItems = [], updatedLineItems = [] }) => {
190+
return createdLineItems.concat(updatedLineItems)
191+
}
192+
)
193+
187194
refreshCartItemsWorkflow.runAsStep({
188-
input: { cart_id: cart.id },
195+
input: { cart_id: cart.id, items: allItems },
189196
})
190197

191198
emitEventStep({

0 commit comments

Comments
 (0)