feat(tax): normalize country and province code (#6513)

**What**
- Ensures that country and province codes are always stored as lower case.
- Ensures that calculation context normalizes input before getting region rates.
This commit is contained in:
Sebastian Rindom
2024-02-27 10:12:05 +01:00
committed by GitHub
parent be8122bc0d
commit d03b72ecdd
3 changed files with 68 additions and 29 deletions

View File

@@ -34,14 +34,14 @@ moduleIntegrationTestRunner({
expect.arrayContaining([
expect.objectContaining({
id: region.id,
country_code: "US",
country_code: "us",
province_code: null,
parent_id: null,
}),
expect.objectContaining({
id: provinceRegion.id,
country_code: "US",
province_code: "CA",
country_code: "us",
province_code: "ca",
parent_id: region.id,
}),
])
@@ -397,6 +397,7 @@ moduleIntegrationTestRunner({
expect(taxRegions).toEqual([
expect.objectContaining({
id: region.id,
country_code: "us",
deleted_at: expect.any(Date),
}),
])

View File

@@ -160,28 +160,10 @@ export default class TaxModuleService<
data: TaxTypes.CreateTaxRegionDTO | TaxTypes.CreateTaxRegionDTO[],
@MedusaContext() sharedContext: Context = {}
) {
const input = Array.isArray(data) ? data : [data]
await this.verifyProvinceToCountryMatch(input, sharedContext)
const [defaultRates, regionData] = input.reduce(
(acc, region) => {
const { default_tax_rate, ...rest } = region
if (!default_tax_rate) {
acc[0].push(null)
} else {
acc[0].push({
...default_tax_rate,
is_default: true,
created_by: region.created_by,
})
}
acc[1].push(rest)
return acc
},
[[], []] as [
(Omit<TaxTypes.CreateTaxRateDTO, "tax_region_id"> | null)[],
Partial<TaxTypes.CreateTaxRegionDTO>[]
]
)
const { defaultRates, regionData } =
this.prepareTaxRegionInputForCreate(data)
await this.verifyProvinceToCountryMatch(regionData, sharedContext)
const regions = await this.taxRegionService_.create(
regionData,
@@ -251,16 +233,18 @@ export default class TaxModuleService<
calculationContext: TaxTypes.TaxCalculationContext,
@MedusaContext() sharedContext: Context = {}
): Promise<(TaxTypes.ItemTaxLineDTO | TaxTypes.ShippingTaxLineDTO)[]> {
const normalizedContext =
this.normalizeTaxCalculationContext(calculationContext)
const regions = await this.taxRegionService_.list(
{
$or: [
{
country_code: calculationContext.address.country_code,
country_code: normalizedContext.address.country_code,
province_code: null,
},
{
country_code: calculationContext.address.country_code,
province_code: calculationContext.address.province_code,
country_code: normalizedContext.address.country_code,
province_code: normalizedContext.address.province_code,
},
],
},
@@ -355,6 +339,56 @@ export default class TaxModuleService<
return itemTaxLines
}
private normalizeTaxCalculationContext(
context: TaxTypes.TaxCalculationContext
): TaxTypes.TaxCalculationContext {
return {
...context,
address: {
...context.address,
country_code: this.normalizeRegionCodes(context.address.country_code),
province_code: context.address.province_code
? this.normalizeRegionCodes(context.address.province_code)
: null,
},
}
}
private prepareTaxRegionInputForCreate(
data: TaxTypes.CreateTaxRegionDTO | TaxTypes.CreateTaxRegionDTO[]
) {
const regionsWithDefaultRate = Array.isArray(data) ? data : [data]
const defaultRates: (Omit<
TaxTypes.CreateTaxRateDTO,
"tax_region_id"
> | null)[] = []
const regionData: TaxTypes.CreateTaxRegionDTO[] = []
for (const region of regionsWithDefaultRate) {
const { default_tax_rate, ...rest } = region
if (!default_tax_rate) {
defaultRates.push(null)
} else {
defaultRates.push({
...default_tax_rate,
is_default: true,
created_by: region.created_by,
})
}
regionData.push({
...rest,
province_code: rest.province_code
? this.normalizeRegionCodes(rest.province_code)
: null,
country_code: this.normalizeRegionCodes(rest.country_code),
})
}
return { defaultRates, regionData }
}
private async verifyProvinceToCountryMatch(
regionsToVerify: TaxTypes.CreateTaxRegionDTO[],
sharedContext: Context = {}
@@ -531,4 +565,8 @@ export default class TaxModuleService<
(a, b) => (a as any).priority_score - (b as any).priority_score
)
}
private normalizeRegionCodes(code: string) {
return code.toLowerCase()
}
}

View File

@@ -15,7 +15,7 @@ export interface CreateTaxRegionDTO {
parent_id?: string | null
metadata?: Record<string, unknown>
created_by?: string
default_tax_rate: {
default_tax_rate?: {
rate?: number | null
code?: string | null
name: string