feat(core-flows,types,order,cart): assign tax lines only to regular products (#11994)

what:

- assign tax lines only to regular products
This commit is contained in:
Riqwan Thamir authored and GitHub committed 2025-03-26 22:26:34 +00:00
1 parent e950e2b2d2
commit 1f8fab3636
18 files changed
+375 -131

No files matched your search

+8
View File
@@ -0,0 +1,8 @@
---
"@medusajs/core-flows": patch
"@medusajs/order": patch
"@medusajs/cart": patch
"@medusajs/types": patch
---
feat(core-flows,types,order,cart): assign tax lines only to regular products
@@ -2001,6 +2001,72 @@ medusaIntegrationTestRunner({
) )
}) })
it("should not generate tax lines for gift card products", async () => {
const giftCardProduct = (
await api.post(
`/admin/products`,
{
title: "Gift Card",
description: "test",
is_giftcard: true,
options: [
{
title: "Denomination",
values: ["10", "20", "50", "100"],
},
],
variants: [
{
title: "10",
sku: "special-shirt",
options: {
Denomination: "10",
},
manage_inventory: false,
prices: [
{
amount: 1000,
currency_code: "usd",
},
],
},
],
},
adminHeaders
)
).data.product
let updated = await api.post(
`/store/carts/${cart.id}/line-items?fields=+items.is_giftcard`,
{ variant_id: giftCardProduct.variants[0].id, quantity: 1 },
storeHeaders
)
expect(updated.status).toEqual(200)
expect(updated.data.cart).toEqual(
expect.objectContaining({
id: cart.id,
items: expect.arrayContaining([
expect.objectContaining({
is_giftcard: false,
tax_lines: [
expect.objectContaining({
description: "CA Default Rate",
code: "CADEFAULT",
rate: 5,
provider_id: "system",
}),
],
}),
expect.objectContaining({
is_giftcard: true,
tax_lines: [],
}),
]),
})
)
})
it("should update a cart's region, sales channel, customer data and tax lines", async () => { it("should update a cart's region, sales channel, customer data and tax lines", async () => {
const newSalesChannel = ( const newSalesChannel = (
await api.post( await api.post(
@@ -820,6 +820,7 @@ medusaIntegrationTestRunner({
deleted_at: null, deleted_at: null,
id: expect.any(String), id: expect.any(String),
is_discountable: false, is_discountable: false,
is_giftcard: false,
is_tax_inclusive: false, is_tax_inclusive: false,
is_custom_price: true, is_custom_price: true,
metadata: { metadata: {
@@ -1179,6 +1180,7 @@ medusaIntegrationTestRunner({
// Custom line item // Custom line item
id: expect.any(String), id: expect.any(String),
is_discountable: false, is_discountable: false,
is_giftcard: false,
is_tax_inclusive: false, is_tax_inclusive: false,
is_custom_price: true, is_custom_price: true,
quantity: 1, quantity: 1,
@@ -1415,6 +1417,7 @@ medusaIntegrationTestRunner({
deleted_at: null, deleted_at: null,
id: expect.any(String), id: expect.any(String),
is_discountable: false, is_discountable: false,
is_giftcard: false,
is_tax_inclusive: false, is_tax_inclusive: false,
is_custom_price: true, is_custom_price: true,
metadata: { metadata: {
@@ -1876,6 +1879,7 @@ medusaIntegrationTestRunner({
deleted_at: null, deleted_at: null,
id: expect.any(String), id: expect.any(String),
is_discountable: false, is_discountable: false,
is_giftcard: false,
is_tax_inclusive: false, is_tax_inclusive: false,
is_custom_price: true, is_custom_price: true,
metadata: { metadata: {
@@ -1937,6 +1941,7 @@ medusaIntegrationTestRunner({
deleted_at: null, deleted_at: null,
id: expect.any(String), id: expect.any(String),
is_discountable: false, is_discountable: false,
is_giftcard: false,
is_tax_inclusive: false, is_tax_inclusive: false,
is_custom_price: true, is_custom_price: true,
metadata: { metadata: {
@@ -172,6 +172,7 @@ medusaIntegrationTestRunner({
variant_option_values: null, variant_option_values: null,
requires_shipping: true, requires_shipping: true,
is_discountable: true, is_discountable: true,
is_giftcard: false,
is_tax_inclusive: false, is_tax_inclusive: false,
raw_compare_at_unit_price: null, raw_compare_at_unit_price: null,
raw_unit_price: { raw_unit_price: {
@@ -16,6 +16,7 @@ export const cartFieldsForRefreshSteps = [
"region.*", "region.*",
"items.*", "items.*",
"items.product.id", "items.product.id",
"items.product.is_giftcard",
"items.product.collection_id", "items.product.collection_id",
"items.product.categories.id", "items.product.categories.id",
"items.product.tags.id", "items.product.tags.id",
@@ -105,6 +106,7 @@ export const completeCartFields = [
"payment_collection.payment_sessions.*", "payment_collection.payment_sessions.*",
"items.variant.id", "items.variant.id",
"items.variant.product.id", "items.variant.product.id",
"items.variant.product.is_giftcard",
"items.variant.product.shipping_profile.id", "items.variant.product.shipping_profile.id",
"items.variant.manage_inventory", "items.variant.manage_inventory",
"items.variant.allow_backorder", "items.variant.allow_backorder",
@@ -157,6 +159,7 @@ export const productVariantsFields = [
"product.collection.title", "product.collection.title",
"product.handle", "product.handle",
"product.discountable", "product.discountable",
"product.is_giftcard",
"product.shipping_profile.id", "product.shipping_profile.id",
"calculated_price.*", "calculated_price.*",
"inventory_items.inventory_item_id", "inventory_items.inventory_item_id",
@@ -150,6 +150,7 @@ export function prepareLineItemData(data: PrepareLineItemDataInput) {
variant_option_values: item?.variant_option_values, variant_option_values: item?.variant_option_values,
is_discountable: variant?.product?.discountable ?? item?.is_discountable, is_discountable: variant?.product?.discountable ?? item?.is_discountable,
is_giftcard: variant?.product?.is_giftcard ?? false,
requires_shipping: requiresShipping, requires_shipping: requiresShipping,
unit_price: unitPrice, unit_price: unitPrice,
@@ -21,6 +21,7 @@ const cartFields = [
"items.id", "items.id",
"items.variant_id", "items.variant_id",
"items.product_id", "items.product_id",
"items.product.is_giftcard",
"items.product_title", "items.product_title",
"items.product_description", "items.product_description",
"items.product_subtitle", "items.product_subtitle",
@@ -17,6 +17,7 @@ const completeOrderFields = [
"region.automatic_taxes", "region.automatic_taxes",
"items.id", "items.id",
"items.is_tax_inclusive", "items.is_tax_inclusive",
"items.is_giftcard",
"items.variant_id", "items.variant_id",
"items.product_id", "items.product_id",
"items.product_title", "items.product_title",
@@ -101,6 +102,7 @@ const lineItemFields = [
"variant_id", "variant_id",
"product_id", "product_id",
"is_tax_inclusive", "is_tax_inclusive",
"is_giftcard",
"product_title", "product_title",
"product_description", "product_description",
"product_subtitle", "product_subtitle",
@@ -12,7 +12,7 @@ import {
TaxableShippingDTO, TaxableShippingDTO,
TaxCalculationContext, TaxCalculationContext,
} from "@medusajs/framework/types" } from "@medusajs/framework/types"
import { MedusaError, Modules } from "@medusajs/framework/utils" import { isDefined, MedusaError, Modules } from "@medusajs/framework/utils"
import { createStep, StepResponse } from "@medusajs/framework/workflows-sdk" import { createStep, StepResponse } from "@medusajs/framework/workflows-sdk"
/** /**
@@ -168,6 +168,11 @@ export const getItemTaxLinesStep = createStep(
is_return: isReturn = false, is_return: isReturn = false,
shipping_address: shippingAddress, shipping_address: shippingAddress,
} = data } = data
const filteredItems = items.filter(
(item) => !item.is_giftcard || !isDefined(item.is_giftcard)
) as OrderLineItemDTO[] | CartLineItemDTO[]
const taxService = container.resolve<ITaxModuleService>(Modules.TAX) const taxService = container.resolve<ITaxModuleService>(Modules.TAX)
const taxContext = normalizeTaxModuleContext( const taxContext = normalizeTaxModuleContext(
@@ -188,7 +193,7 @@ export const getItemTaxLinesStep = createStep(
if (items.length) { if (items.length) {
stepResponseData.lineItemTaxLines = (await taxService.getTaxLines( stepResponseData.lineItemTaxLines = (await taxService.getTaxLines(
normalizeLineItemsForTax(orderOrCart, items), normalizeLineItemsForTax(orderOrCart, filteredItems),
taxContext taxContext
)) as ItemTaxLineDTO[] )) as ItemTaxLineDTO[]
} }
+5
View File
@@ -658,6 +658,11 @@ export interface CartLineItemDTO extends CartLineItemTotalsDTO {
*/ */
is_discountable: boolean is_discountable: boolean
/**
* Whether the line item is a gift card.
*/
is_giftcard: boolean
/** /**
* Whether the line item price is tax inclusive. * Whether the line item price is tax inclusive.
*/ */
+5
View File
@@ -789,6 +789,11 @@ export interface OrderLineItemDTO extends OrderLineItemTotalsDTO {
*/ */
is_discountable: boolean is_discountable: boolean
/**
* Indicates whether the line item is a gift card.
*/
is_giftcard: boolean
/** /**
* Indicates whether the line item price is tax inclusive. * Indicates whether the line item price is tax inclusive.
*/ */
@@ -2886,6 +2886,7 @@ moduleIntegrationTestRunner<ICartModuleService>({
variant_option_values: null, variant_option_values: null,
requires_shipping: true, requires_shipping: true,
is_discountable: true, is_discountable: true,
is_giftcard: false,
is_tax_inclusive: false, is_tax_inclusive: false,
is_custom_price: false, is_custom_price: false,
raw_compare_at_unit_price: null, raw_compare_at_unit_price: null,
@@ -2992,6 +2993,7 @@ moduleIntegrationTestRunner<ICartModuleService>({
variant_option_values: null, variant_option_values: null,
requires_shipping: true, requires_shipping: true,
is_discountable: true, is_discountable: true,
is_giftcard: false,
is_tax_inclusive: false, is_tax_inclusive: false,
is_custom_price: false, is_custom_price: false,
raw_compare_at_unit_price: null, raw_compare_at_unit_price: null,
@@ -757,6 +757,16 @@
"default": "true", "default": "true",
"mappedType": "boolean" "mappedType": "boolean"
}, },
"is_giftcard": {
"name": "is_giftcard",
"type": "boolean",
"unsigned": false,
"autoincrement": false,
"primary": false,
"nullable": false,
"default": "false",
"mappedType": "boolean"
},
"is_tax_inclusive": { "is_tax_inclusive": {
"name": "is_tax_inclusive", "name": "is_tax_inclusive",
"type": "boolean", "type": "boolean",
@@ -0,0 +1,15 @@
import { Migration } from "@mikro-orm/migrations"
export class Migration20250326151602 extends Migration {
override async up(): Promise<void> {
this.addSql(
`alter table if exists "cart_line_item" add column if not exists "is_giftcard" boolean not null default false;`
)
}
override async down(): Promise<void> {
this.addSql(
`alter table if exists "cart_line_item" drop column if exists "is_giftcard";`
)
}
}
@@ -27,6 +27,7 @@ const LineItem = model
variant_option_values: model.json().nullable(), variant_option_values: model.json().nullable(),
requires_shipping: model.boolean().default(true), requires_shipping: model.boolean().default(true),
is_discountable: model.boolean().default(true), is_discountable: model.boolean().default(true),
is_giftcard: model.boolean().default(false),
is_tax_inclusive: model.boolean().default(false), is_tax_inclusive: model.boolean().default(false),
is_custom_price: model.boolean().default(false), is_custom_price: model.boolean().default(false),
compare_at_unit_price: model.bigNumber().nullable(), compare_at_unit_price: model.bigNumber().nullable(),
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,15 @@
import { Migration } from "@mikro-orm/migrations"
export class Migration20250326151554 extends Migration {
override async up(): Promise<void> {
this.addSql(
`alter table if exists "order_line_item" add column if not exists "is_giftcard" boolean not null default false;`
)
}
override async down(): Promise<void> {
this.addSql(
`alter table if exists "order_line_item" drop column if exists "is_giftcard";`
)
}
}
@@ -22,6 +22,7 @@ const _OrderLineItem = model
variant_title: model.text().nullable(), variant_title: model.text().nullable(),
variant_option_values: model.json().nullable(), variant_option_values: model.json().nullable(),
requires_shipping: model.boolean().default(true), requires_shipping: model.boolean().default(true),
is_giftcard: model.boolean().default(false),
is_discountable: model.boolean().default(true), is_discountable: model.boolean().default(true),
is_tax_inclusive: model.boolean().default(false), is_tax_inclusive: model.boolean().default(false),
compare_at_unit_price: model.bigNumber().nullable(), compare_at_unit_price: model.bigNumber().nullable(),