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