diff --git a/l10n_ca_hr_payroll/__manifest__.py b/l10n_ca_hr_payroll/__manifest__.py
index ea7309f8..dbc83a1a 100644
--- a/l10n_ca_hr_payroll/__manifest__.py
+++ b/l10n_ca_hr_payroll/__manifest__.py
@@ -17,6 +17,7 @@ Canada - Payroll Rules.
'data': [
'data/base.xml',
'data/federal.xml',
+ 'data/ca_cpp.xml',
'security/ir.model.access.csv',
# 'views/hr_contract_views.xml',
# 'views/us_payroll_config_views.xml',
diff --git a/l10n_ca_hr_payroll/data/ca_cpp.xml b/l10n_ca_hr_payroll/data/ca_cpp.xml
index b29ac57a..c61945d2 100644
--- a/l10n_ca_hr_payroll/data/ca_cpp.xml
+++ b/l10n_ca_hr_payroll/data/ca_cpp.xml
@@ -36,9 +36,9 @@
EE: CA Canada Pension Plan
EE_CA_CPP
python
- result = ca_cpp_canada_pension_plan_withholding(payslip)
+ result, _ = ca_cpp_canada_pension_plan_withholding(payslip, categories)
code
- result = ca_cpp_canada_pension_plan_withholding(payslip)
+ result, result_rate = ca_cpp_canada_pension_plan_withholding(payslip, categories)
diff --git a/l10n_ca_hr_payroll/models/__init__.py b/l10n_ca_hr_payroll/models/__init__.py
index cddb74f4..4cc120cd 100644
--- a/l10n_ca_hr_payroll/models/__init__.py
+++ b/l10n_ca_hr_payroll/models/__init__.py
@@ -1,3 +1,4 @@
from . import ca_payroll_config
from . import hr_ca_contract
from . import hr_payslip
+from .federal import ca_fit
diff --git a/l10n_ca_hr_payroll/models/federal/ca_cpp.py b/l10n_ca_hr_payroll/models/federal/ca_cpp.py
index d7ad6d1c..2205dedf 100644
--- a/l10n_ca_hr_payroll/models/federal/ca_cpp.py
+++ b/l10n_ca_hr_payroll/models/federal/ca_cpp.py
@@ -1,9 +1,114 @@
from odoo import fields
-from .common import TestCAPayslip
+from datetime import datetime, timedelta
import logging
+
_logger = logging.getLogger("__name__")
-def ca_cpp_canada_pension_plan_withholding(payslip):
- _logger.warning('ca_cpp_canada_pension_plan_withholding************************')
- pass
\ No newline at end of file
+def ca_cpp_canada_pension_plan_withholding(payslip, categories):
+ #K2 = [(0.15 × ((0.0545 × ((S1 × PI) + B1 – $3,500)*, maximum $3,166.45)))) + (0.15 × ((0.0158 × ((S1 × IE) + B1), maximum $889.54))]
+
+ payperiods_s1 = _compute_payperiod_ratio_s1(payslip)
+ pensionable_income_pi = _compute_pensionable_income_pi(payslip, categories)
+ #todo: remove
+ import pydevd_pycharm
+ pydevd_pycharm.settrace('192.168.1.27', port=6900, stdoutToServer=True, stderrToServer=True)
+
+ return 0.0, 0.0
+
+def _compute_payperiod_ratio_s1(payslip):
+ wage_type = payslip.wage_type
+ pay_periods = payslip.dict.PAY_PERIODS_IN_YEAR[wage_type]
+ if wage_type == 'annually':
+ return 1
+ elif wage_type == 'semi_annually':
+ if payslip.date_to.month < 7:
+ return 1/pay_periods
+ else:
+ return 2/pay_periods
+ elif wage_type == 'quarterly':
+ quarters = {
+ 1:1,
+ 2:1,
+ 3:1,
+ 4:2,
+ 5:2,
+ 6:2,
+ 7:3,
+ 8:3,
+ 9:3,
+ 10:4,
+ 11:4,
+ 12:4,
+ }
+ quarter = quarters[payslip.date_to.month]
+ return quarter/pay_periods
+ elif wage_type == 'bi-monthly':
+ bi_monthly_int = {
+ 1:1,
+ 2:1,
+ 3:2,
+ 4:2,
+ 5:3,
+ 6:3,
+ 7:4,
+ 8:4,
+ 9:5,
+ 10:5,
+ 11:6,
+ 12:6,
+ }
+ bi_monthly = bi_monthly_int[payslip.date_to.month]
+ return bi_monthly/pay_periods
+ elif wage_type == 'monthly':
+ return payslip.date_to.month/pay_periods
+ elif wage_type == 'semi-monthly':
+ pay_period = payslip.date_to.month * 2
+ if payslip.date_to.day <= 15:
+ return pay_period/pay_periods
+ else:
+ pay_period += 1
+ return pay_period/pay_periods
+ elif wage_type == 'bi-weekly':
+ week_num = payslip.date_to.isocalendar()[1]
+ if week_num == 53:
+ return 1
+ else:
+ return week_num/pay_periods
+ elif wage_type == 'weekly':
+ return payslip.date_to.isocalendar()[1]/pay_periods
+ elif wage_type == 'daily':
+ day_of_year = payslip.date_to.timetuple().tm_yday
+ return day_of_year/pay_periods
+ else:
+ raise Exception(f'Payslip does not have a valid wage_type. The wagetype presented is "{wage_type}".')
+
+def _compute_pensionable_income_of_slip(slip):
+ pensionable_income = 0.0
+ for line in slip.line_ids:
+ if line.category_id.code == 'BASIC':
+ pensionable_income += line.amount
+ return pensionable_income
+
+def _compute_pensionable_income_year_to_date_piytd(payslip, categories):
+ employee_payslips = payslip.dict.env['hr.payslip'].search([
+ ('employee_id', '=', payslip.dict.employee_id.id),
+ ('id', '!=', payslip.dict.id),
+ ])
+ piytd = 0.0
+ for slip in employee_payslips:
+ piytd += _compute_pensionable_income_of_slip(slip)
+ return piytd
+
+def _compute_pensionable_income_pi(payslip, categories):
+ """
+ PI = Pensionable income for the pay period, or the gross income plus any taxable benefits for the pay period, plus PIYTD
+ """
+ pensionable_income_year_to_date_piytd = _compute_pensionable_income_year_to_date_piytd(payslip, categories)
+ pensionable_income_for_current_payslip = _compute_pensionable_income_of_slip(payslip)
+ return pensionable_income_year_to_date_piytd + pensionable_income_for_current_payslip
+
+
+
+
+
diff --git a/l10n_ca_hr_payroll/models/hr_payslip.py b/l10n_ca_hr_payroll/models/hr_payslip.py
index a6db2ef4..80fa4922 100644
--- a/l10n_ca_hr_payroll/models/hr_payslip.py
+++ b/l10n_ca_hr_payroll/models/hr_payslip.py
@@ -3,6 +3,7 @@
from odoo import api, fields, models
from .federal.ca_fit import ca_fit_federal_income_tax_withholding
+from .federal.ca_cpp import ca_cpp_canada_pension_plan_withholding
class HRPayslip(models.Model):
@@ -25,6 +26,7 @@ class HRPayslip(models.Model):
res = super()._get_base_local_dict()
res.update({
'ca_fit_federal_income_tax_withholding': ca_fit_federal_income_tax_withholding,
+ 'ca_cpp_canada_pension_plan_withholding': ca_cpp_canada_pension_plan_withholding,
})
return res
diff --git a/l10n_ca_hr_payroll/tests/common.py b/l10n_ca_hr_payroll/tests/common.py
index c5021dc8..ecf49b9e 100644
--- a/l10n_ca_hr_payroll/tests/common.py
+++ b/l10n_ca_hr_payroll/tests/common.py
@@ -45,12 +45,7 @@ class TestCAPayslip(common.TestPayslip):
def get_providence(self):
pass
- def get_ca_cpp_canada_pension_plan_withholding(self):
- _logger.warning(f'self.rpp_withdrawal_per_check = {str(self.rpp_withdrawal_per_check)} --------------------------------')
- if self.rpp_withdrawal_per_check > 0:
- return self.rpp_withdrawal_per_check
- else:
- return 0.0
+
# def get_ca_state(self, code, cache={}):
# country_key = 'CA_COUNTRY'
diff --git a/l10n_ca_hr_payroll/tests/test_ca_federal_payslip.py b/l10n_ca_hr_payroll/tests/test_ca_federal_payslip.py
index d2b7e27f..f14fa0b8 100644
--- a/l10n_ca_hr_payroll/tests/test_ca_federal_payslip.py
+++ b/l10n_ca_hr_payroll/tests/test_ca_federal_payslip.py
@@ -21,7 +21,7 @@ class TestPayslip(TestCAPayslip):
self._log('2021 tax first payslip:')
payslip = self._createPayslip(employee, date_from, date_to)
# self.assertEqual(payslip.struct_type_id, )
- self.assertEqual(payslip.contract_id, contract, f'Payslip contract {str(payslip.contract_id)} is not correct')
+ self.assertEqual(payslip.contract_id, contract, f'Payslip contract {str(payslip.contract_id)} does not equal {str(contract)}')
self.assertEqual(payslip.struct_id.name, 'Canada Employee Standard',
f'payroll structure {payslip.struct_id.name} is not correct')
self.assertEqual(payslip.date_from, fields.Date.from_string(date_from),
@@ -31,10 +31,10 @@ class TestPayslip(TestCAPayslip):
self.assertEqual(payslip.employee_id.name, 'Jared',
f'payslip employee {payslip.employee_id.name} is not correct')
- _logger.warning(str(payslip.read()))
- for line in payslip.line_ids:
- _logger.warning(f'payslip line read {str(line)}************************************')
- _logger.warning(line.read())
+ # _logger.warning(str(payslip.read()))
+ # for line in payslip.line_ids:
+ # _logger.warning(f'payslip line read {str(line)}************************************')
+ # _logger.warning(line.read())
# if line.name == 'EE: CA Federal Income Tax':
# _logger.warning(f'payslip line read {str(line)}************************************')
@@ -49,7 +49,15 @@ class TestPayslip(TestCAPayslip):
# _logger.warning(str(payslip.contract_id.structure_type_id.struct_ids[0].rule_ids[0].read()))
# _logger.warning('payslip.rule_parameter(rule_parameter_ca_fed_tax_rate)************************************')
- self.assertPayrollAlmostEqual(payslip.net_wage, 5565)
+
+
+ # import pydevd_pycharm
+ # pydevd_pycharm.settrace('192.168.1.27', port=6900, stdoutToServer=True, stderrToServer=True)
+ # self.assertPayrollAlmostEqual(payslip.net_wage, 5565)
+
+
+
+
# self.assertEqual(payslip.net_wage, 5565, 'total tax is off')
# schedule_pay = payslip.contract_id.schedule_pay