Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore(cart, core-flows): Improve tax lines algo management #11715

Merged
merged 18 commits into from
Mar 9, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .changeset/afraid-hotels-jam.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"@medusajs/core-flows": patch
"@medusajs/cart": patch
"@medusajs/types": patch
---

chore: improve tax lines
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
ItemTaxLineDTO,
ShippingTaxLineDTO,
} from "@medusajs/framework/types"
import { Modules } from "@medusajs/framework/utils"
import { Modules, promiseAll } from "@medusajs/framework/utils"
import { StepResponse, createStep } from "@medusajs/framework/workflows-sdk"

/**
Expand All @@ -30,13 +30,13 @@ export interface SetTaxLinesForItemsStepInput {
export const setTaxLinesForItemsStepId = "set-tax-lines-for-items"
/**
* This step sets the tax lines of shipping methods and line items in a cart.
*
*
* :::tip
*
*
* You can use the {@link retrieveCartStep} to retrieve a cart's details.
*
*
* :::
*
*
* @example
* const data = setTaxLinesForItemsStep({
* // retrieve the details of the cart from another workflow
Expand Down Expand Up @@ -64,21 +64,31 @@ export const setTaxLinesForItemsStep = createStep(
const { cart, item_tax_lines, shipping_tax_lines } = data
const cartService = container.resolve<ICartModuleService>(Modules.CART)

const existingShippingMethodTaxLines =
await cartService.listShippingMethodTaxLines({
shipping_method_id: shipping_tax_lines.map((t) => t.shipping_line_id),
})
const [existingShippingMethodTaxLines, existingLineItemTaxLines] =
await promiseAll([
shipping_tax_lines.length
? cartService.listShippingMethodTaxLines({
shipping_method_id: shipping_tax_lines.map(
(t) => t.shipping_line_id
),
})
: [],

const existingLineItemTaxLines = await cartService.listLineItemTaxLines({
item_id: item_tax_lines.map((t) => t.line_item_id),
})
item_tax_lines.length
? cartService.listLineItemTaxLines({
item_id: item_tax_lines.map((t) => t.line_item_id),
})
: [],
])

const itemsTaxLinesData = normalizeItemTaxLinesForCart(item_tax_lines)
await cartService.setLineItemTaxLines(cart.id, itemsTaxLinesData)

const shippingTaxLinesData =
normalizeShippingTaxLinesForCart(shipping_tax_lines)
await cartService.setShippingMethodTaxLines(cart.id, shippingTaxLinesData)

await promiseAll([
cartService.setLineItemTaxLines(cart.id, itemsTaxLinesData),
cartService.setShippingMethodTaxLines(cart.id, shippingTaxLinesData),
])

return new StepResponse(null, {
cart,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
import {
CartWorkflowDTO,
CreateLineItemTaxLineDTO,
CreateShippingMethodTaxLineDTO,
ICartModuleService,
ItemTaxLineDTO,
LineItemTaxLineDTO,
ShippingMethodTaxLineDTO,
ShippingTaxLineDTO,
} from "@medusajs/framework/types"
import { Modules, promiseAll } from "@medusajs/framework/utils"
import { StepResponse, createStep } from "@medusajs/framework/workflows-sdk"

/**
* The details of the tax lines to set in a cart.
*/
export interface SetTaxLinesForItemsStepInput {
/**
* The cart's details.
*/
cart: CartWorkflowDTO
/**
* The tax lines to set for line items.
*/
item_tax_lines: ItemTaxLineDTO[]
/**
* The tax lines to set for shipping methods.
*/
shipping_tax_lines: ShippingTaxLineDTO[]
}

export const upsertTaxLinesForItemsStepId = "set-tax-lines-for-items"
/**
* This step sets the tax lines of shipping methods and line items in a cart.
*
* :::tip
*
* You can use the {@link retrieveCartStep} to retrieve a cart's details.
*
* :::
*
* @example
* const data = upsertTaxLinesForItemsStep({
* // retrieve the details of the cart from another workflow
* // or in another step using the Cart Module's service
* cart,
* "item_tax_lines": [{
* "rate": 48,
* "code": "CODE123",
* "name": "Tax rate 2",
* "provider_id": "provider_1",
* "line_item_id": "litem_123"
* }],
* "shipping_tax_lines": [{
* "rate": 49,
* "code": "CODE456",
* "name": "Tax rate 1",
* "provider_id": "provider_1",
* "shipping_line_id": "sm_123"
* }]
* })
*/
export const upsertTaxLinesForItemsStep = createStep(
upsertTaxLinesForItemsStepId,
async (data: SetTaxLinesForItemsStepInput, { container }) => {
const { cart, item_tax_lines, shipping_tax_lines } = data
const cartService = container.resolve<ICartModuleService>(Modules.CART)

const [existingShippingMethodTaxLines, existingLineItemTaxLines] =
await promiseAll([
shipping_tax_lines.length
? cartService.listShippingMethodTaxLines({
shipping_method_id: shipping_tax_lines.map(
(t) => t.shipping_line_id
),
})
: [],

item_tax_lines.length
? cartService.listLineItemTaxLines({
item_id: item_tax_lines.map((t) => t.line_item_id),
})
: [],
])

const itemsTaxLinesData = normalizeItemTaxLinesForCart(
item_tax_lines,
existingLineItemTaxLines
)
const shippingTaxLinesData = normalizeShippingTaxLinesForCart(
shipping_tax_lines,
existingShippingMethodTaxLines
)

await promiseAll([
itemsTaxLinesData.length
? cartService.upsertLineItemTaxLines(itemsTaxLinesData)
: [],
shippingTaxLinesData.length
? cartService.upsertShippingMethodTaxLines(shippingTaxLinesData)
: [],
])

return new StepResponse(null, {
cart,
existingLineItemTaxLines,
existingShippingMethodTaxLines,
})
},
async (revertData, { container }) => {
if (!revertData) {
return
}

const { existingLineItemTaxLines, existingShippingMethodTaxLines } =
revertData

const cartService = container.resolve<ICartModuleService>(Modules.CART)

if (existingLineItemTaxLines) {
await cartService.upsertLineItemTaxLines(
existingLineItemTaxLines.map((taxLine) => ({
description: taxLine.description,
tax_rate_id: taxLine.tax_rate_id,
code: taxLine.code,
rate: taxLine.rate,
provider_id: taxLine.provider_id,
item_id: taxLine.item_id,
}))
)
}

await cartService.upsertShippingMethodTaxLines(
existingShippingMethodTaxLines.map((taxLine) => ({
description: taxLine.description,
tax_rate_id: taxLine.tax_rate_id,
code: taxLine.code,
rate: taxLine.rate,
provider_id: taxLine.provider_id,
shipping_method_id: taxLine.shipping_method_id,
}))
)
}
)

function normalizeItemTaxLinesForCart(
taxLines: ItemTaxLineDTO[],
existingTaxLines: LineItemTaxLineDTO[]
): CreateLineItemTaxLineDTO[] {
return taxLines.map((taxLine: ItemTaxLineDTO & { id?: string }) => ({
id: existingTaxLines.find((t) => t.item_id === taxLine.line_item_id)?.id,
description: taxLine.name,
tax_rate_id: taxLine.rate_id,
code: taxLine.code!,
rate: taxLine.rate!,
provider_id: taxLine.provider_id,
item_id: taxLine.line_item_id,
}))
}

function normalizeShippingTaxLinesForCart(
taxLines: ShippingTaxLineDTO[],
existingTaxLines: ShippingMethodTaxLineDTO[]
): CreateShippingMethodTaxLineDTO[] {
return taxLines.map((taxLine: ShippingTaxLineDTO & { id?: string }) => ({
id: existingTaxLines.find(
(t) => t.shipping_method_id === taxLine.shipping_line_id
)?.id,
description: taxLine.name,
tax_rate_id: taxLine.rate_id,
code: taxLine.code!,
rate: taxLine.rate!,
provider_id: taxLine.provider_id,
shipping_method_id: taxLine.shipping_line_id,
}))
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ export interface AddShippingMethodToCartWorkflowInput {
id: string
/**
* Custom data useful for the fulfillment provider processing the shipping option or method.
*
*
* Learn more in [this documentation](https://docs.medusajs.com/resources/commerce-modules/fulfillment/shipping-option#data-property).
*/
data?: Record<string, unknown>
Expand All @@ -48,11 +48,11 @@ export interface AddShippingMethodToCartWorkflowInput {

export const addShippingMethodToCartWorkflowId = "add-shipping-method-to-cart"
/**
* This workflow adds a shipping method to a cart. It's executed by the
* This workflow adds a shipping method to a cart. It's executed by the
* [Add Shipping Method Store API Route](https://docs.medusajs.com/api/store#carts_postcartsidshippingmethods).
*
*
* 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.
*
*
* @example
* const { result } = await addShippingMethodToCartWorkflow(container)
* .run({
Expand All @@ -71,11 +71,11 @@ export const addShippingMethodToCartWorkflowId = "add-shipping-method-to-cart"
* ]
* }
* })
*
*
* @summary
*
*
* Add a shipping method to a cart.
*
*
* @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.
*/
export const addShippingMethodToCartWorkflow = createWorkflow(
Expand Down Expand Up @@ -186,7 +186,7 @@ export const addShippingMethodToCartWorkflow = createWorkflow(
cart.shipping_methods.map((sm) => sm.id)
)

parallelize(
const [, createdShippingMethods] = parallelize(
removeShippingMethodFromCartStep({
shipping_method_ids: currentShippingMethods,
}),
Expand All @@ -200,7 +200,7 @@ export const addShippingMethodToCartWorkflow = createWorkflow(
)

refreshCartItemsWorkflow.runAsStep({
input: { cart_id: cart.id },
input: { cart_id: cart.id, shipping_methods: createdShippingMethods },
})

return new WorkflowResponse(void 0, {
Expand Down
11 changes: 9 additions & 2 deletions packages/core/core-flows/src/cart/workflows/add-to-cart.ts
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ export const addToCartWorkflow = createWorkflow(
},
})

parallelize(
const [createdLineItems, updatedLineItems] = parallelize(
createLineItemsStep({
id: cart.id,
items: itemsToCreate,
Expand All @@ -184,8 +184,15 @@ export const addToCartWorkflow = createWorkflow(
})
)

const allItems = transform(
{ createdLineItems, updatedLineItems },
({ createdLineItems = [], updatedLineItems = [] }) => {
return createdLineItems.concat(updatedLineItems)
}
)

refreshCartItemsWorkflow.runAsStep({
input: { cart_id: cart.id },
input: { cart_id: cart.id, items: allItems },
})

emitEventStep({
Expand Down
Loading
Loading