feat(tax): adds getItemTaxLines (#6440)

**What**
- Selects the correct tax line for an item given a calculation context.

**For later PR**
- Consider optimizations. Some thoughts:
  - Even with global sales the number of rates in the DB is not likely to grow beyond ~1000.
  - Can large orders with hundreds of items optimize somehow?
  - Does it make sense to write a custom SQL query to do this?
- Support combined rate.

**Test cases covered**
The selection of tax rates take the following priority:

1. specific product rules - province
2. specific product type rules - province
3. default province rules
4. specific product rules - country
5. specific product type rules - country
6. default country rules

There are test cases for each of them under the following data seed structure:

### **US** 
- **Default Rate**: 2%
- **Sub-Regions**
  - CA 
    - Default Rate: 5%
    - Overrides
      - Reduced rate (for 3 product ids): 3%
      - Reduced rate (for product type): 1%
  - NY 
    - Default rate: 6%
  - FL 
    - Default rate: 4%
- **Overrides**
  - None

### **Denmark** 
- **Default rate:** 25% 
- **Sub-Regions**
  - None
- **Overrides**
  -  None

### **Germany** 
- **Default Rate:** 19%
- **Sub-Regions**
  - None
- **Overrides:**
  - Reduced Rate (for product type) - 7%

### **Canada** 
- **Default rate**: 5%
- **Sub-Regions**
  - QC 
    - Default rate: 2%
    - Overrides:
      - Reduced rate (for same product type as country reduced rate): 1%
  - BC 
    - Default rate: 2%
- **Overrides**
  - Reduced rate (for product id) - 3%
  - Reduced rate (for product type) - 3.5%
This commit is contained in:
Sebastian Rindom
2024-02-22 16:28:55 +00:00
committed by GitHub
parent 58943e83fd
commit 598ee6f49c
13 changed files with 824 additions and 201 deletions
+52
View File
@@ -99,3 +99,55 @@ export interface FilterableTaxRateRuleProps
updated_at?: OperatorMap<string>
created_by?: string | string[] | OperatorMap<string>
}
export interface TaxableItemDTO {
id: string
product_id: string
product_name?: string
product_category_id?: string
product_categories?: string[]
product_sku?: string
product_type?: string
product_type_id?: string
quantity?: number
unit_price?: number
currency_code?: string
}
export interface TaxableShippingDTO {
id: string
shipping_option_id: string
unit_price?: number
currency_code?: string
}
export interface TaxCalculationContext {
address: {
country_code: string
province_code?: string | null
address_1?: string
address_2?: string | null
city?: string
postal_code?: string
}
customer?: {
id: string
email: string
customer_groups: string[]
}
is_return?: boolean
}
interface TaxLineDTO {
rate_id: string
rate: number | null
code: string | null
name: string
}
export interface ItemTaxLineDTO extends TaxLineDTO {
line_item_id: string
}
export interface ShippingTaxLineDTO extends TaxLineDTO {
shipping_line_id: string
}
+11
View File
@@ -8,6 +8,11 @@ import {
TaxRegionDTO,
TaxRateRuleDTO,
FilterableTaxRateRuleProps,
TaxableItemDTO,
TaxCalculationContext,
ItemTaxLineDTO,
ShippingTaxLineDTO,
TaxableShippingDTO,
} from "./common"
import {
CreateTaxRateRuleDTO,
@@ -64,4 +69,10 @@ export interface ITaxModuleService extends IModuleService {
config?: FindConfig<TaxRateRuleDTO>,
sharedContext?: Context
): Promise<TaxRateRuleDTO[]>
getTaxLines(
item: (TaxableItemDTO | TaxableShippingDTO)[],
calculationContext: TaxCalculationContext,
sharedContext?: Context
): Promise<(ItemTaxLineDTO | ShippingTaxLineDTO)[]>
}