Tax Rate Documentation¶
Overview¶
The Tax Rate module (account.tax.rate) manages tax configurations for sales and purchases, supporting complex multi-component tax structures including VAT/SST, withholding tax (WHT), deferred VAT, and tax exemptions. Tax rates are built from individual tax components, allowing flexible and accurate tax calculations for various business scenarios and compliance requirements.
Model Information¶
Model Name: account.tax.rate
Display Name: Tax Rate
Name Field: name
Key Fields: name (tax rate name must be unique)
Features¶
- ✅ Audit logging enabled
- ✅ Multi-component tax support
- ✅ VAT/SST calculation
- ✅ Withholding tax (WHT) support
- ✅ Deferred and pending VAT handling
- ✅ Tax-inclusive and tax-exclusive pricing
- ✅ E-invoicing integration
- ✅ UUID for external system integration
Understanding Tax Rates¶
What is a Tax Rate?¶
A Tax Rate is a named collection of tax components that together define the complete tax treatment for a transaction. Examples: - "VAT 7%" - Standard VAT - "VAT 0%" - Zero-rated VAT - "WHT 3%" - Withholding tax - "VAT 7% + WHT 3%" - Combined taxes
Tax Components¶
Tax rates are composed of one or more components (account.tax.component), each representing:
- A specific tax type (VAT, WHT, exempt, deferred)
- A tax percentage
- GL accounts for posting
- Transaction type (sale/purchase)
Example Structure:
Tax Rate: "VAT 7% + WHT 3%"
├─ Component 1: "SST" (type: vat, rate: 7%)
└─ Component 2: "WHT" (type: wht, rate: 3%)
Tax Types¶
| Type | Description | Usage |
|---|---|---|
| vat | Standard VAT/SST | Normal taxable sales/purchases |
| vat_exempt | VAT Exempt | Exempt goods/services |
| vat_defer | Deferred VAT | Cash basis accounting |
| vat_pending | Pending VAT | Tax date accounting |
| wht | Withholding Tax | Income tax withholding |
Tax Computation Timing¶
The when parameter controls when taxes are computed:
| When | Description | Use Case |
|---|---|---|
| invoice | Invoice creation | Standard VAT on invoice |
| invoice_tax_date | Tax date reached | Pending VAT recognition |
| invoice_payment | Payment received | Deferred VAT on cash basis |
| invoice_payment_inv | Reverse deferred VAT | Clear deferred account |
| invoice_payment_pmt | Payment VAT | Recognize deferred VAT |
| direct_payment | Direct payment | Payment without invoice |
| payment | Payment withholding | WHT deduction |
Understanding Key Fields¶
What are Key Fields?¶
For the account.tax.rate model, the key field is:
This means the tax rate name must be unique.
Examples:
Key Fields Reference¶
Core Fields¶
| Field | Type | Required | Description |
|---|---|---|---|
name |
Char | ✅ | Unique tax rate name (e.g., "VAT 7%") |
code |
Char | ❌ | Short code for reporting |
uuid |
Char | ❌ | UUID for external system integration (auto-generated) |
active |
Boolean | ❌ | Active status (default: True) |
instructions |
Text | ❌ | Payment instructions for tax payments |
Computed Fields¶
| Field | Type | Description |
|---|---|---|
rate |
Decimal | Total VAT/SST rate (sum of VAT components) |
wht_rate |
Decimal | Total withholding tax rate (sum of WHT components) |
Relationship Fields¶
| Field | Type | Description |
|---|---|---|
components |
One2Many | Tax components (account.tax.component) |
comments |
One2Many | Comments and notes |
logs |
One2Many | Audit log entries |
API Methods¶
1. Create Tax Rate¶
Method: create(vals, context)
Creates a new tax rate with components.
Parameters:
vals = {
"name": "VAT 7%", # Required, unique
"code": "VAT7", # Optional
"active": True, # Default: True
"components": [ # Tax components
("create", {
"name": "SST",
"type": "vat",
"rate": 7.0,
"account_id": vat_account_id,
"trans_type": "out"
})
]
}
Returns: int - New tax rate ID
Example:
# Create standard VAT rate
vat_rate_id = get_model("account.tax.rate").create({
"name": "VAT 7%",
"code": "VAT7",
"components": [
("create", {
"name": "Standard SST",
"type": "vat",
"rate": 7.0,
"account_id": vat_output_account_id,
"trans_type": "out"
})
]
})
# Create combined VAT + WHT rate
combined_id = get_model("account.tax.rate").create({
"name": "VAT 7% + WHT 3%",
"code": "VAT7WHT3",
"components": [
("create", {
"name": "SST",
"type": "vat",
"rate": 7.0,
"account_id": vat_output_account_id,
"trans_type": "out"
}),
("create", {
"name": "WHT",
"type": "wht",
"rate": 3.0,
"account_id": wht_account_id,
"trans_type": "out"
})
]
})
2. Get Rate (Computed)¶
Method: get_rate(ids, context={})
Computes total VAT and WHT rates from components.
Parameters:
- ids (list): Tax rate IDs
- context (dict): Optional context
Returns: dict - Rates for each tax rate
Example:
tax_rate = get_model("account.tax.rate").browse([tax_rate_id])[0]
print(f"VAT Rate: {tax_rate.rate}%")
print(f"WHT Rate: {tax_rate.wht_rate}%")
3. Compute Base Amount¶
Method: compute_base(tax_id, amt, tax_type="tax_ex")
Calculates base amount from total amount based on tax treatment.
Parameters:
- tax_id (int or BrowseRecord): Tax rate ID or object
- amt (Decimal): Total amount
- tax_type (str): "tax_ex" (exclusive), "tax_in" (inclusive), or "no_tax"
Returns: Decimal - Base amount before tax
Formula:
# Tax exclusive (default)
base = amount # Tax not included in amount
# Tax inclusive
base = amount / (1 + rate/100) # Extract base from tax-inclusive amount
# No tax
base = amount # No tax adjustment
Example:
# Tax-exclusive: $100 + 7% = $107
base = get_model("account.tax.rate").compute_base(
tax_id=vat_7_id,
amt=100.00,
tax_type="tax_ex"
)
print(base) # Output: 100.00
# Tax-inclusive: $107 includes 7% tax
base = get_model("account.tax.rate").compute_base(
tax_id=vat_7_id,
amt=107.00,
tax_type="tax_in"
)
print(base) # Output: 100.00
4. Compute Taxes¶
Method: compute_taxes(tax_id, base, when="invoice")
Computes tax amounts for all components based on timing.
Parameters:
- tax_id (int or BrowseRecord): Tax rate ID or object
- base (Decimal): Base amount (before tax)
- when (str): When to compute taxes (see Tax Computation Timing table)
Returns: dict - Tax amount for each component
Example:
# Compute invoice VAT
taxes = get_model("account.tax.rate").compute_taxes(
tax_id=vat_rate_id,
base=100.00,
when="invoice"
)
for comp_id, tax_amt in taxes.items():
comp = get_model("account.tax.component").browse([comp_id])[0]
print(f"{comp.name}: ${tax_amt:.2f}")
# Output: Standard SST: $7.00
# Compute withholding tax on payment
wht_taxes = get_model("account.tax.rate").compute_taxes(
tax_id=wht_rate_id,
base=100.00,
when="payment"
)
# Only returns WHT components
5. Has Deferred VAT¶
Method: has_defer_vat(ids, context={})
Checks if tax rate has deferred VAT component.
Parameters:
- ids (list): Tax rate IDs
- context (dict): Optional context
Returns: bool - True if has deferred VAT
Example:
if get_model("account.tax.rate").has_defer_vat([tax_rate_id]):
print("This tax uses cash basis accounting")
# Apply different accounting treatment
6. Update Total (UI Event)¶
Method: update_total(context={})
Recalculates total rate when components change in UI.
Behavior: - Sums rates from all components - Updates in real-time during data entry
Search Functions¶
Find Tax Rates by Name¶
# Find VAT 7% rate
tax_rates = get_model("account.tax.rate").search_browse([
["name", "=", "VAT 7%"]
])
if tax_rates:
rate = tax_rates[0]
print(f"{rate.name}: {rate.rate}% VAT, {rate.wht_rate}% WHT")
Find Active Tax Rates¶
# Get all active tax rates
active_rates = get_model("account.tax.rate").search_browse([
["active", "=", True]
], order="name")
print("Active Tax Rates:")
for rate in active_rates:
print(f" {rate.name}: {rate.rate}%")
Find Rates with WHT¶
# Find rates that include withholding tax
wht_rates = get_model("account.tax.rate").search_browse([
["components.type", "=", "wht"]
])
for rate in wht_rates:
print(f"{rate.name}: WHT {rate.wht_rate}%")
Search by Code¶
Best Practices¶
1. Use Descriptive Names¶
# Good: Clear and descriptive
name = "VAT 7% (Standard Rate)"
name = "VAT 0% (Zero-Rated)"
name = "VAT Exempt"
# Less clear: Ambiguous
name = "Tax 1"
name = "Standard"
2. Organize by Transaction Type¶
# Create separate rates for sales and purchases
sales_vat = get_model("account.tax.rate").create({
"name": "Output VAT 7%",
"components": [
("create", {
"name": "SST Output",
"type": "vat",
"rate": 7.0,
"account_id": vat_output_account_id,
"trans_type": "out" # For sales
})
]
})
purchase_vat = get_model("account.tax.rate").create({
"name": "Input VAT 7%",
"components": [
("create", {
"name": "SST Input",
"type": "vat",
"rate": 7.0,
"account_id": vat_input_account_id,
"trans_type": "in" # For purchases
})
]
})
3. Use Correct Tax Type¶
# Invoice creation - use "invoice"
taxes = get_model("account.tax.rate").compute_taxes(
tax_id,
base=1000.00,
when="invoice"
)
# Payment withholding - use "payment"
wht = get_model("account.tax.rate").compute_taxes(
tax_id,
base=1000.00,
when="payment"
)
4. Handle Tax-Inclusive Pricing¶
# Customer sees $107 (tax-inclusive)
total_amount = 107.00
# Extract base and tax
base = get_model("account.tax.rate").compute_base(
vat_7_id,
total_amount,
tax_type="tax_in"
)
taxes = get_model("account.tax.rate").compute_taxes(
vat_7_id,
base,
when="invoice"
)
print(f"Total: ${total_amount:.2f}")
print(f"Base: ${base:.2f}")
print(f"Tax: ${sum(taxes.values()):.2f}")
# Output:
# Total: $107.00
# Base: $100.00
# Tax: $7.00
Database Constraints¶
Unique Tax Rate Name¶
Implications: - Cannot create duplicate tax rate names - Use descriptive, unique names
Related Models¶
| Model | Relationship | Description |
|---|---|---|
account.tax.component |
One2Many | Individual tax components |
account.invoice.line |
Referenced | Invoice lines use tax rates |
account.invoice.tax |
Referenced | Computed invoice taxes |
product |
Referenced | Products have default tax rates |
Common Use Cases¶
Use Case 1: Setup Standard VAT System¶
# 1. Create VAT output account
vat_output_id = get_model("account.account").create({
"code": "2310",
"name": "VAT Output",
"type": "payable"
})
# 2. Create VAT input account
vat_input_id = get_model("account.account").create({
"code": "1410",
"name": "VAT Input",
"type": "receivable"
})
# 3. Create output VAT 7% (for sales)
get_model("account.tax.rate").create({
"name": "Output VAT 7%",
"code": "OVAT7",
"components": [
("create", {
"name": "SST Output",
"type": "vat",
"rate": 7.0,
"account_id": vat_output_id,
"trans_type": "out"
})
]
})
# 4. Create input VAT 7% (for purchases)
get_model("account.tax.rate").create({
"name": "Input VAT 7%",
"code": "IVAT7",
"components": [
("create", {
"name": "SST Input",
"type": "vat",
"rate": 7.0,
"account_id": vat_input_id,
"trans_type": "in"
})
]
})
# 5. Create zero-rated
get_model("account.tax.rate").create({
"name": "VAT 0% (Zero-Rated)",
"code": "VAT0",
"components": [
("create", {
"name": "Zero-Rated SST",
"type": "vat",
"rate": 0.0,
"account_id": vat_output_id,
"trans_type": "out"
})
]
})
# 6. Create exempt
get_model("account.tax.rate").create({
"name": "VAT Exempt",
"code": "EXEMPT",
"components": [
("create", {
"name": "SST Exempt",
"type": "vat_exempt",
"rate": 0.0,
"trans_type": "out"
})
]
})
print("✓ VAT system configured")
Use Case 2: Calculate Invoice Tax¶
# Calculate tax for invoice line
line_total = 1000.00 # Line total
tax_type = "tax_ex" # Tax exclusive pricing
tax_rate_id = vat_7_id
# 1. Compute base amount
base = get_model("account.tax.rate").compute_base(
tax_rate_id,
line_total,
tax_type
)
# 2. Compute taxes
taxes = get_model("account.tax.rate").compute_taxes(
tax_rate_id,
base,
when="invoice"
)
# 3. Calculate totals
tax_total = sum(taxes.values())
grand_total = base + tax_total
print(f"Base Amount: ${base:.2f}")
print(f"Tax Amount: ${tax_total:.2f}")
print(f"Total: ${grand_total:.2f}")
# Output:
# Base Amount: $1000.00
# Tax Amount: $70.00
# Total: $1070.00
Use Case 3: Handle Withholding Tax¶
# Setup WHT for service payments
# 1. Create WHT account
wht_account_id = get_model("account.account").create({
"code": "1420",
"name": "WHT Receivable",
"type": "receivable"
})
# 2. Create WHT 3% rate
wht_rate_id = get_model("account.tax.rate").create({
"name": "WHT 3%",
"code": "WHT3",
"components": [
("create", {
"name": "Withholding Tax 3%",
"type": "wht",
"rate": 3.0,
"account_id": wht_account_id,
"trans_type": "out",
"contact_type": "company"
})
]
})
# 3. Calculate WHT on payment
payment_amount = 10000.00
wht_taxes = get_model("account.tax.rate").compute_taxes(
wht_rate_id,
payment_amount,
when="payment"
)
wht_amount = sum(wht_taxes.values())
net_payment = payment_amount + wht_amount # WHT is negative
print(f"Gross Amount: ${payment_amount:.2f}")
print(f"WHT Withheld: ${abs(wht_amount):.2f}")
print(f"Net Payment: ${net_payment:.2f}")
# Output:
# Gross Amount: $10000.00
# WHT Withheld: $300.00
# Net Payment: $9700.00
Use Case 4: Deferred VAT (Cash Basis)¶
# Setup deferred VAT for cash basis accounting
# Create deferred VAT account
defer_vat_id = get_model("account.account").create({
"code": "1411",
"name": "Deferred VAT",
"type": "receivable"
})
# Create deferred VAT rate
defer_rate_id = get_model("account.tax.rate").create({
"name": "VAT 7% (Deferred)",
"code": "DVAT7",
"components": [
("create", {
"name": "Deferred SST",
"type": "vat_defer",
"rate": 7.0,
"account_id": defer_vat_id,
"trans_type": "out"
})
]
})
# Invoice creation - deferred
base = 1000.00
invoice_taxes = get_model("account.tax.rate").compute_taxes(
defer_rate_id,
base,
when="invoice"
)
print(f"At invoice: ${sum(invoice_taxes.values()):.2f}") # $70 to deferred
# Payment receipt - recognize VAT
payment_taxes = get_model("account.tax.rate").compute_taxes(
defer_rate_id,
base,
when="invoice_payment"
)
print(f"At payment: ${sum(payment_taxes.values()):.2f}") # Recognize VAT
Use Case 5: Tax Rate Report¶
# Generate tax rate configuration report
def generate_tax_report():
rates = get_model("account.tax.rate").search_browse([
["active", "=", True]
], order="name")
print("TAX RATE CONFIGURATION REPORT")
print("=" * 80)
for rate in rates:
print(f"\n{rate.name} ({rate.code or 'N/A'})")
print(f" Total VAT Rate: {rate.rate}%")
if rate.wht_rate:
print(f" Total WHT Rate: {rate.wht_rate}%")
print(f" Components:")
for comp in rate.components:
print(f" - {comp.name}")
print(f" Type: {comp.type}")
print(f" Rate: {comp.rate}%")
print(f" Account: {comp.account_id.code} - {comp.account_id.name}")
print(f" Trans Type: {comp.trans_type or 'N/A'}")
generate_tax_report()
Performance Tips¶
1. Use Browse Cache¶
# Good: Pass BrowseRecord for speed
tax_rate = get_model("account.tax.rate").browse([tax_rate_id])[0]
for i in range(1000):
base = get_model("account.tax.rate").compute_base(
tax_rate, # BrowseRecord (uses cache)
100.00
)
# Slower: Pass ID (looks up each time)
for i in range(1000):
base = get_model("account.tax.rate").compute_base(
tax_rate_id, # int (no cache)
100.00
)
2. Index on Common Fields¶
CREATE INDEX idx_tax_rate_name ON account_tax_rate(name);
CREATE INDEX idx_tax_rate_code ON account_tax_rate(code);
CREATE INDEX idx_tax_rate_active ON account_tax_rate(active);
Troubleshooting¶
"Tax rate name already exists"¶
Cause: Duplicate tax rate name Solution: Use unique names or update existing rate
"Tax calculation returns 0"¶
Cause: No components or wrong tax type
Solution: Verify components exist and use correct when parameter
"WHT not being calculated"¶
Cause: Using when="invoice" instead of when="payment"
Solution: Use correct timing:
# Wrong
taxes = compute_taxes(wht_rate_id, 1000, when="invoice") # Returns {}
# Correct
taxes = compute_taxes(wht_rate_id, 1000, when="payment") # Returns WHT
"Deferred VAT not working"¶
Cause: Using wrong when value
Solution: Use proper sequence:
# Invoice - to deferred account
invoice_taxes = compute_taxes(rate_id, base, when="invoice")
# Payment - reverse deferred, recognize VAT
payment_taxes = compute_taxes(rate_id, base, when="invoice_payment")
Version History¶
Last Updated: 2025-12-16 Model Version: account_tax_rate.py Framework: Netforce
Additional Resources¶
- Tax Component Documentation:
account.tax.component - Invoice Tax Documentation:
account.invoice.tax - Invoice Line Documentation:
account.invoice.line - E-Invoice Tax Type Documentation:
account.einvoice.taxtype
This documentation is generated for developer onboarding and reference purposes.