diff --git a/l10n_ca_hr_payroll/__manifest__.py b/l10n_ca_hr_payroll/__manifest__.py
index 6de3594b..a5f1e7c0 100644
--- a/l10n_ca_hr_payroll/__manifest__.py
+++ b/l10n_ca_hr_payroll/__manifest__.py
@@ -17,6 +17,7 @@ Canada - Payroll Rules.
'data': [
'security/ir.model.access.csv',
'data/base.xml',
+ 'data/ded.xml',
'data/federal.xml',
'data/ca_cpp.xml',
# 'views/hr_contract_views.xml',
diff --git a/l10n_ca_hr_payroll/data/base.xml b/l10n_ca_hr_payroll/data/base.xml
index e2af112a..37d84bc0 100644
--- a/l10n_ca_hr_payroll/data/base.xml
+++ b/l10n_ca_hr_payroll/data/base.xml
@@ -21,10 +21,33 @@
+
+ EE: Canada Pension Plan
+ EE_CA_CPP
+
+
+
+ EE: CA Employment Insurance
+ EE_CA_EI
+
+
-
-
+
+ EE: Federal Income Tax Withholding
+ EE_CA_FIT
+
+
+
+ ALW: FIT Exempt
+ ALW_FIT_EXEMPT
+
+
+
+ DED: FIT Exempt
+ DED_FIT_EXEMPT
+
+
diff --git a/l10n_ca_hr_payroll/data/ca_al_alberta.xml b/l10n_ca_hr_payroll/data/ca_al_alberta.xml
deleted file mode 100644
index 5476f60c..00000000
--- a/l10n_ca_hr_payroll/data/ca_al_alberta.xml
+++ /dev/null
@@ -1,49 +0,0 @@
-
-
-
-
- CA Federal Tax Rate
- ca_fed_tax_rate
-
-
-
-
-
- {
- 'annually': (
- ( 0, 0.1500, 0.00),
- ( 49029, 0.2050, 2696.00),
- ( 98040, 0.2600, 8088.00),
- ( 151978, 0.2900, 12648.00),
- ( 216511, 0.3300, 21308.00),
- ( 'inf', 0.3300, 21308.00),
- ),
- }
-
-
-
-
-
-
- CA Federal - Canada Revenue Agency - Federal Income Tax
-
-
-
-
-
-
-
- EE: CA Federal Income Tax
- EE_CA_FIT
- python
- result, _ = ca_fit_federal_income_tax_withholding(payslip)
- code
- result, result_rate = ca_fit_federal_income_tax_withholding(payslip)
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/l10n_ca_hr_payroll/data/ded.xml b/l10n_ca_hr_payroll/data/ded.xml
new file mode 100644
index 00000000..1e9c9a77
--- /dev/null
+++ b/l10n_ca_hr_payroll/data/ded.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/l10n_ca_hr_payroll/data/federal.xml b/l10n_ca_hr_payroll/data/federal.xml
index 08cee3b0..bef9313f 100644
--- a/l10n_ca_hr_payroll/data/federal.xml
+++ b/l10n_ca_hr_payroll/data/federal.xml
@@ -6,45 +6,191 @@
ca_fed_tax_rate
+
+ [
+ ( 0, 0.1500, 0.00),
+ ( 49020, 0.2050, 2696.00),
+ ( 98040, 0.2600, 8088.00),
+ ( 151978, 0.2900, 12648.00),
+ ( 216511, 0.3300, 21308.00),
+ ( 'inf', 0.3300, 21308.00),
+ ]
+
+
+
-
-
- [
- ( 0, 0.1500, 0.00),
- ( 49020, 0.2050, 2696.00),
- ( 98040, 0.2600, 8088.00),
- ( 151978, 0.2900, 12648.00),
- ( 216511, 0.3300, 21308.00),
- ( 'inf', 0.3300, 21308.00),
- ]
-
-
-
-
+
+ CA Federal Personal Tax Credit Rate (K1)
+ ca_fed_k1
+
+
+
+ 0.15
+
+
+
+
+ CA Federal Pension & EI Credit Rate (K1)
+ ca_fed_k2
+
+
+
+ 0.15
+
+
+
+
+
+ CA Federal Pension Credit Maximum (K2)
+ ca_fed_k2_pc_max
+
+
+
+ 3166.45
+
+
+
+
+
+ CA Federal Pension Credit Maximum (K2)
+ ca_fed_k2_pei_max
+
+
+
+ 889.54
+
+
+
+
+
+ CA Quebec Federal Pension Credit Maximum (K2Q)
+ ca_fed_k2q_pc_max
+
+
+
+ 3427.90
+
+
+
+
+
+ CA Quebec Federal Pension Credit Maximum (K2Q)
+ ca_fed_k2q_pei_max
+
+
+
+ 664.34
+
+
+
+
+
+ CA Quebec Insurable Earnings Credit Rate (K2Q)
+ ca_fed_k2q_pie
+
+
+
+ 0.00494
+
+
+
+
+
+ CA Quebec Insurable Earnings Credit Maximum (K2Q)
+ ca_fed_k2q_pie_max
+
+
+
+ 412.49
+
+
+
+
+
+ CA Nonrefundable Tax Credit Rate (K4)
+ ca_fed_k4
+
+
+
+ 0.15
+
+
+
+
+
+
+ CA Employment Amount Rate (K4)
+ ca_fed_k4
+
+
+
+ 0.15
+
+
+
+
+
+ CA Employment Amount (CEA)
+ ca_fed_cea
+
+
+
+ 1257.0
+
+
+
+
+
+ CA LCF Max
+ ca_fed_lcf_max
+
+
+
+ 750.0
+
+
+
+
+
+ CA LCF Rate
+ ca_fed_lcf_rate
+
+
+
+ 15.0
+
+
+
+
+
+ CA T1 Quebec Rate
+ ca_fed_t1q
+
+
+
+ 0.165
+
+
+
+
+
+ CA T1 Outside Rate
+ ca_fed_t1_outside
+
+
+
+ 0.48
+
+
+
+
+
+
CA Federal - Canada Revenue Agency - Federal Income Tax
-
-
- EE: Canada Pension Plan
- EE_CA_CPP
-
-
-
-
- EE: CA Employment Insurance
- EE_CA_EI
-
-
-
-
- EE: Federal Income Tax Withholding
- EE_CA_FIT
-
-
-
diff --git a/l10n_ca_hr_payroll/models/ca_payroll_config.py b/l10n_ca_hr_payroll/models/ca_payroll_config.py
index e9b43db5..43b15ac2 100644
--- a/l10n_ca_hr_payroll/models/ca_payroll_config.py
+++ b/l10n_ca_hr_payroll/models/ca_payroll_config.py
@@ -74,8 +74,12 @@ class HRContractCanadaPayrollConfig(models.Model):
# fed_td1_6_disability_amount = fields.Float()
# fed_td1_7_spouse_amount = fields.Float()
# fed_td1_8_dependant_amount = fields.Float()
+
+
fed_td1_total_claim_amount = fields.Float()
fed_td1_deduction_prescribed_zone = fields.Float()
fed_td1_additional = fields.Float()
+
is_cpp_exempt = fields.Boolean()
is_ei_exempt = fields.Boolean()
+ is_outside_ca = fields.Boolean(string='Outside Canada or beyond limits of province/territory')
diff --git a/l10n_ca_hr_payroll/models/federal/ca_fit.py b/l10n_ca_hr_payroll/models/federal/ca_fit.py
index 7034c65b..1a81d397 100644
--- a/l10n_ca_hr_payroll/models/federal/ca_fit.py
+++ b/l10n_ca_hr_payroll/models/federal/ca_fit.py
@@ -1,5 +1,7 @@
# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details.
+from ..state.general import _state_applies
+
def _compute_annual_taxable_income(payslip, categories):
"""
@@ -8,16 +10,107 @@ def _compute_annual_taxable_income(payslip, categories):
"""
P = payslip.dict.get_pay_periods_in_year()
I = categories.GROSS \
- - categories.ALW_FIT_EXEMPT \
- + categories.DED_FIT_EXEMPT
- F = 0.0 # Payroll deductions for RPP or RRSP ...
- F2 = 0.0
- U1 = 0.0 # Union Dues
+ - categories.ALW_FIT_EXEMPT
+ # F = 0.0 # Payroll deductions for RPP or RRSP ...
+ # F2 = 0.0 # Annual Alimony or maintenance payments
+ # U1 = 0.0 # Union Dues
+ I += categories.DED_FIT_EXEMPT
+
HD = 0.0 # Annual deduction for living in a prescribed zone Form TD1
F1 = 0.0 # Annual deductions such as child care and authorized
- A = (P * (I - F - F2 - U1)) - HD - F1
+ # A = (P * (I - F - F2 - U1)) - HD - F1
+ A = (P * I) - HD - F1
return A
+def ca_fit_k1_personal_tax_credit(payslip, categories, worked_days, inputs):
+ TC = payslip.contract_id.ca_payroll_config_value('fed_td1_total_claim_amount')
+ k1 = payslip.rule_parameter('ca_fed_k1')
+ return k1 * TC
+
+def ca_fit_k2_cpp_ei_tax_credit(payslip, categories, worked_days, inputs):
+ P = payslip.dict.get_pay_periods_in_year()
+ C = -categories.EE_CA_CPP
+ EI = -categories.EE_CA_EI
+ k2 = payslip.rule_parameter('ca_fed_k2')
+ result = 0.0
+ if _state_applies(payslip, 'QC'):
+ pc_max = payslip.rule_parameter('ca_fed_k2q_pc_max')
+ pei_max = payslip.rule_parameter('ca_fed_k2q_pei_max')
+ pie = payslip.rule_parameter('ca_fed_k2q_pie')
+ pie_max = payslip.rule_parameter('ca_fed_k2q_pie_max')
+ IE = 0.0 # TODO get IE
+ result = k2 * min(P * IE * pie, pie_max)
+ else:
+ pc_max = payslip.rule_parameter('ca_fed_k2_pc_max')
+ pei_max = payslip.rule_parameter('ca_fed_k2_pei_max')
+
+ if not payslip.contract_id.ca_payroll_config_value('is_cpp_exempt'):
+ result += k2 * min(P * C, pc_max)
+
+ if not payslip.contract_id.ca_payroll_config_value('is_ei_exempt'):
+ result += k2 * min(P * EI, pei_max)
+
+ return result
+
+def ca_fit_k3_other_tax_credits(payslip, categories, worked_days, inputs):
+ # this could be a category (if it were a dummy category)
+ # this could be a contract field, but what would it truely mean?
+ # How would we know if we implemented this after the first pay period?
+ # adjust (P * K3) / PR
+ return 0.0
+
+def ca_fit_k4_non_refunable_tax_credit(payslip, categories, worked_days, inputs):
+ k4 = payslip.rule_parameter('ca_fed_k4')
+ A = _compute_annual_taxable_income(payslip, categories)
+ cea = payslip.rule_parameter('ca_fed_cea')
+ return min(k4 * A, k4 * cea)
+
+def ca_fit_t3_annual_basic_federal_tax(payslip, categories, worked_days, inputs):
+ """
+ T3 = Annual basic federal tax
+ = (R × A) – K – K1 – K2 – K3 – K4
+ If the result is negative, T3 = $0.
+ """
+ A = _compute_annual_taxable_income(payslip, categories)
+ rates = payslip.rule_parameter('ca_fed_tax_rate')
+ for annual_taxable_income, rate, federal_constant in rates:
+ annual_taxable_income = float(annual_taxable_income)
+ if A < annual_taxable_income:
+ break
+ R, K = rate, federal_constant
+
+ T3 = (R * A) - K
+ T3 -= ca_fit_k1_personal_tax_credit(payslip, categories, worked_days, inputs)
+ T3 -= ca_fit_k2_cpp_ei_tax_credit(payslip, categories, worked_days, inputs)
+ T3 -= ca_fit_k3_other_tax_credits(payslip, categories, worked_days, inputs)
+ T3 -= ca_fit_k4_non_refunable_tax_credit(payslip, categories, worked_days, inputs)
+ if T3 < 0.0:
+ return 0.0
+ return T3
+
+def ca_fit_t1_federal_income_tax_payable(payslip, categories, worked_days, inputs):
+ T3 = ca_fit_t3_annual_basic_federal_tax(payslip, categories, worked_days, inputs)
+ # Short out as it can only go down..
+ if T3 <= 0.0:
+ return 0.0
+
+ amount_deducted_stock = 0.0
+ # amount deducted or withheld during the year for the acquisition by the employee of approved shares of the capital stock of a prescribed labour-sponsored venture capital corporation
+ # this amount could be a category, but it would need to be year to date.
+ LCF = min(750.0, 0.15 * amount_deducted_stock) # 0.0 => amount deducted or withheld during the year for the acquisition by the employee of approved shares of the capital stock of a prescribed labour-sponsored venture capital corporation
+
+ if _state_applies(payslip, 'QC'):
+ t1q = payslip.rule_parameter('ca_fed_t1q')
+ T1 = (T3 - LCF) - (t1q * T3)
+ elif payslip.contract_id.ca_payroll_config_value('is_outside_ca'):
+ t1_outside = payslip.rule_parameter('ca_fed_t1_outside')
+ T1 = T3 + (t1_outside * T3) - LCF
+ else:
+ T1 = T3 - LCF
+
+ if T1 < 0.0:
+ return 0.0
+ return T1
def ca_fit_federal_income_tax_withholding(payslip, categories, worked_days, inputs):
L = payslip.contract_id.ca_payroll_config_value('fed_td1_additional')
@@ -27,42 +120,14 @@ def ca_fit_federal_income_tax_withholding(payslip, categories, worked_days, inpu
return -L, 100.0
elif A <= 0.0:
return 0.0, 0.0
-
- TC = payslip.contract_id.ca_payroll_config_value('fed_td1_total_claim_amount')
+
+ T1 = ca_fit_t1_federal_income_tax_payable(payslip, categories, worked_days, inputs)
+ if T1 <= 0.0 and L:
+ return -L, 100.0
+ elif T1 <= 0.0:
+ return 0.0, 0.0
+
P = payslip.dict.get_pay_periods_in_year()
-
- """
- T3 = Annual basic federal tax
- = (R × A) – K – K1 – K2 – K3 – K4
- If the result is negative, T3 = $0.
- """
- rates = payslip.rule_parameter('ca_fed_tax_rate')
- for annual_taxable_income, rate, federal_constant in rates:
- annual_taxable_income = float(annual_taxable_income)
- if A < annual_taxable_income:
- break
- R, K = rate, federal_constant
-
- K1 = 0.15 * TC
-
- K2 = 0.0
- if not payslip.contract_id.ca_payroll_config_value('is_cpp_exempt'):
- C = -categories.EE_CA_CPP
- K2 += 0.15 * min(P * C, 3166.45) # min because we can only have up to
- if not payslip.contract_id.ca_payroll_config_value('is_ei_exempt'):
- EI = -categories.EE_CA_EI
- K2 += 0.15 * min(P * EI, 889.54)
- K3 = 0.0 # medical
- CEA = 1257.0 # TODO this is an indexed parameter
- K4 = min(0.15 * A, 0.15 * CEA)
-
- T3 = (R * A) - K - K1 - K2 - K3 - K4
-
- LCF = min(750.0, 0.15 * 0.0) # 0.0 => amount deducted or withheld during the year for the acquisition by the employee of approved shares of the capital stock of a prescribed labour-sponsored venture capital corporation
- T1 = T3 - LCF
- if T1 < 0.0:
- T1 = 0.0
-
T = (T1 / P) + L
if T > 0.0:
T = round(T, 2)
diff --git a/l10n_ca_hr_payroll/models/quebec/__init__.py b/l10n_ca_hr_payroll/models/state/__init__.py
similarity index 100%
rename from l10n_ca_hr_payroll/models/quebec/__init__.py
rename to l10n_ca_hr_payroll/models/state/__init__.py
diff --git a/l10n_ca_hr_payroll/models/state/general.py b/l10n_ca_hr_payroll/models/state/general.py
new file mode 100644
index 00000000..baef4f72
--- /dev/null
+++ b/l10n_ca_hr_payroll/models/state/general.py
@@ -0,0 +1,6 @@
+def _state_applies(payslip, state_code):
+ return state_code == payslip.contract_id.ca_payroll_config_value('state_code')
+
+
+# Export for eval context
+is_ca_state = _state_applies
diff --git a/l10n_ca_hr_payroll/models/territory/__init__.py b/l10n_ca_hr_payroll/models/territory/__init__.py
deleted file mode 100644
index e69de29b..00000000
diff --git a/l10n_ca_hr_payroll/models/territory/ca_al_alberta.py b/l10n_ca_hr_payroll/models/territory/ca_al_alberta.py
deleted file mode 100644
index e69de29b..00000000
diff --git a/l10n_ca_hr_payroll/models/territory/ca_bc_british_columbia.py b/l10n_ca_hr_payroll/models/territory/ca_bc_british_columbia.py
deleted file mode 100644
index e69de29b..00000000
diff --git a/l10n_ca_hr_payroll/models/territory/ca_mb_manitoba.py b/l10n_ca_hr_payroll/models/territory/ca_mb_manitoba.py
deleted file mode 100644
index e69de29b..00000000
diff --git a/l10n_ca_hr_payroll/models/territory/ca_nl_newfoundand_and_labrador.py b/l10n_ca_hr_payroll/models/territory/ca_nl_newfoundand_and_labrador.py
deleted file mode 100644
index e69de29b..00000000
diff --git a/l10n_ca_hr_payroll/models/territory/ca_ns_nova_scotia.py b/l10n_ca_hr_payroll/models/territory/ca_ns_nova_scotia.py
deleted file mode 100644
index e69de29b..00000000
diff --git a/l10n_ca_hr_payroll/models/territory/ca_nt_northwest_territories.py b/l10n_ca_hr_payroll/models/territory/ca_nt_northwest_territories.py
deleted file mode 100644
index e69de29b..00000000
diff --git a/l10n_ca_hr_payroll/models/territory/ca_nu_nunavut.py b/l10n_ca_hr_payroll/models/territory/ca_nu_nunavut.py
deleted file mode 100644
index e69de29b..00000000
diff --git a/l10n_ca_hr_payroll/models/territory/ca_on_ontario.py b/l10n_ca_hr_payroll/models/territory/ca_on_ontario.py
deleted file mode 100644
index e69de29b..00000000
diff --git a/l10n_ca_hr_payroll/models/territory/ca_pe_prince_edward_island.py b/l10n_ca_hr_payroll/models/territory/ca_pe_prince_edward_island.py
deleted file mode 100644
index e69de29b..00000000
diff --git a/l10n_ca_hr_payroll/models/territory/ca_sk_saskatchewan.py b/l10n_ca_hr_payroll/models/territory/ca_sk_saskatchewan.py
deleted file mode 100644
index e69de29b..00000000
diff --git a/l10n_ca_hr_payroll/models/territory/ca_yt_yukon.py b/l10n_ca_hr_payroll/models/territory/ca_yt_yukon.py
deleted file mode 100644
index e69de29b..00000000
diff --git a/l10n_ca_hr_payroll/tests/__init__.py b/l10n_ca_hr_payroll/tests/__init__.py
index a1d77f73..4a6e8d47 100644
--- a/l10n_ca_hr_payroll/tests/__init__.py
+++ b/l10n_ca_hr_payroll/tests/__init__.py
@@ -4,6 +4,3 @@ from . import common
# Tests moved to `l10n_ca_hr_payroll_params`
# common remains for site specific tests
-
-from . import test_ca_fed_2021_1
-# from . import test_ca_province_payslip