mirror of
https://gitlab.com/hibou-io/hibou-odoo/suite.git
synced 2025-01-20 12:37:31 +02:00
#31 Merge branch 'mig/12.0/l10n_us_ca_hr_payroll' into mig/12.0/us_payroll
This commit is contained in:
65
l10n_us_ca_hr_payroll/README.rst
Normal file
65
l10n_us_ca_hr_payroll/README.rst
Normal file
@@ -0,0 +1,65 @@
|
||||
*************************************
|
||||
Hibou - US Payroll - California State
|
||||
*************************************
|
||||
|
||||
Calculations and contribution registers for California State Payroll.
|
||||
|
||||
For more information and add-ons, visit `Hibou.io <https://hibou.io/>`_.
|
||||
|
||||
=============
|
||||
Main Features
|
||||
=============
|
||||
|
||||
* Contribution registers and partners for:
|
||||
* California Department of Taxation - Unemployment Insurance Tax
|
||||
* California Department of Taxation - Income Tax Withholding
|
||||
* California Department of Taxation - Employee Training Tax
|
||||
* California Department of Taxation - State Disability Insurance
|
||||
|
||||
* Contract level California Exemptions and California State Disability Insurance
|
||||
* Company level California Unemployment Insurance Tax and California Employee Training Tax
|
||||
|
||||
.. image:: https://user-images.githubusercontent.com/15882954/41482877-d1311214-708b-11e8-9400-3bc5c134b836.png
|
||||
:alt: 'Employee Contract Detail'
|
||||
:width: 988
|
||||
:align: left
|
||||
|
||||
USA California Employee Added to Contract Salary Structure Menu
|
||||
|
||||
.. image:: https://user-images.githubusercontent.com/15882954/41482910-ef25bbd0-708b-11e8-8720-d2065149f953.png
|
||||
:alt: 'Computed Pay Slip Detail'
|
||||
:width: 988
|
||||
:align: left
|
||||
|
||||
New Payslip Categories for:
|
||||
|
||||
* California Income Withholding
|
||||
* California State Disability Insurance - Wages
|
||||
* California State Disability Insurance
|
||||
* California Employee Training Tax - Wages
|
||||
* California Unemployment Insurance Tax - Wages
|
||||
* California Unemployment Insurance Tax
|
||||
* California Employee Training Tax
|
||||
|
||||
Upgrading to 11.0.2018.1.0
|
||||
==========================
|
||||
|
||||
If you were using this prior to November 2018, then you have more Contribution registers
|
||||
and partners than you need! Simply run the following before installing the new code and upgrading.
|
||||
|
||||
Odoo Shell code::
|
||||
|
||||
main_cr = env.ref('l10n_us_ca_hr_payroll.contrib_register_cador_uit')
|
||||
old_1 = env.ref('l10n_us_ca_hr_payroll.contrib_register_cador_withhold')
|
||||
old_2 = env.ref('l10n_us_ca_hr_payroll.contrib_register_cador_ett')
|
||||
old_3 = env.ref('l10n_us_ca_hr_payroll.contrib_register_cador_sdi')
|
||||
lines = env['hr.payslip.line'].search([('register_id', 'in', [old_1.id, old_2.id, old_3.id])])
|
||||
lines.write({'register_id': main_cr.id})
|
||||
env.cr.commit()
|
||||
|
||||
|
||||
=======
|
||||
License
|
||||
=======
|
||||
Please see `LICENSE <https://github.com/hibou-io/hibou-odoo-suite/blob/master/LICENSE>`_.
|
||||
Copyright Hibou Corp. 2018
|
||||
1
l10n_us_ca_hr_payroll/__init__.py
Executable file
1
l10n_us_ca_hr_payroll/__init__.py
Executable file
@@ -0,0 +1 @@
|
||||
from . import models
|
||||
32
l10n_us_ca_hr_payroll/__manifest__.py
Executable file
32
l10n_us_ca_hr_payroll/__manifest__.py
Executable file
@@ -0,0 +1,32 @@
|
||||
{
|
||||
'name': 'USA - California - Payroll',
|
||||
'author': 'Hibou Corp. <hello@hibou.io>',
|
||||
'license': 'AGPL-3',
|
||||
'category': 'Localization',
|
||||
'depends': ['l10n_us_hr_payroll'],
|
||||
'version': '12.0.2019.0.0',
|
||||
'description': """
|
||||
USA::California Payroll Rules.
|
||||
==============================
|
||||
|
||||
* Contribution register and partner for California Department of Taxation - Unemployment Insurance Tax
|
||||
* Contribution register and partner for California Department of Taxation - Income Tax Withholding
|
||||
* Contribution register and partner for Califronia Department of Taxation - Employee Training Tax
|
||||
* Contribution register and partner for Califronia Department of Taxation - State Disability Insurance
|
||||
* Contract level California Exemptions
|
||||
* Contract level California State Disability Insurance
|
||||
* Company level California Unemployment Insurance Tax
|
||||
* Company level California Employee Training Tax
|
||||
""",
|
||||
|
||||
'auto_install': False,
|
||||
'website': 'https://hibou.io/',
|
||||
'data': [
|
||||
'views/hr_payroll_views.xml',
|
||||
'data/base.xml',
|
||||
'data/rates.xml',
|
||||
'data/rules.xml',
|
||||
'data/final.xml',
|
||||
],
|
||||
'installable': True
|
||||
}
|
||||
75
l10n_us_ca_hr_payroll/data/base.xml
Executable file
75
l10n_us_ca_hr_payroll/data/base.xml
Executable file
@@ -0,0 +1,75 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<data>
|
||||
<!-- CONTRIBUTION REGISTERS -->
|
||||
<record id="res_partner_cador_uit" model="res.partner">
|
||||
<field name="name">California Department of Taxation (CA DE88)</field>
|
||||
<field name="supplier">1</field>
|
||||
<field eval="0" name="customer"/>
|
||||
</record>
|
||||
<record id="res_partner_cador_withhold" model="res.partner">
|
||||
<field name="name">California Department of Taxation - Income Tax Withholding</field>
|
||||
<field name="supplier">1</field>
|
||||
<field eval="0" name="customer"/>
|
||||
<field eval="False" name="active"/>
|
||||
</record>
|
||||
<record id="res_partner_cador_ett" model="res.partner">
|
||||
<field name="name">California Department of Taxation - Employment Training Tax</field>
|
||||
<field name="supplier">1</field>
|
||||
<field eval="0" name="customer"/>
|
||||
<field eval="False" name="active"/>
|
||||
</record>
|
||||
<record id="res_partner_cador_sdi" model="res.partner">
|
||||
<field name="name">California Department of Taxation - State Disability Insurance</field>
|
||||
<field name="supplier">1</field>
|
||||
<field eval="0" name="customer"/>
|
||||
<field eval="False" name="active"/>
|
||||
</record>
|
||||
|
||||
<record id="contrib_register_cador_uit" model="hr.contribution.register">
|
||||
<field name="name">California (CA DE88)</field>
|
||||
<field name="note">California Department of Taxation (CA DE88)</field>
|
||||
<field name="partner_id" ref="res_partner_cador_uit"/>
|
||||
</record>
|
||||
|
||||
<!-- HR SALARY RULE CATEGORIES-->
|
||||
<record id="hr_payroll_ca_uit_wages" model="hr.salary.rule.category">
|
||||
<field name="name">Wage: US-CA Unemployment Insurance</field>
|
||||
<field name="code">WAGE_US_CA_UNEMP</field>
|
||||
</record>
|
||||
|
||||
<record id="hr_payroll_ca_uit" model="hr.salary.rule.category">
|
||||
<field name="name">ER: US-CA Unemployment Insurance</field>
|
||||
<field name="code">ER_US_CA_UNEMP</field>
|
||||
<field name="parent_id" ref="hr_payroll.COMP"/>
|
||||
</record>
|
||||
|
||||
<record id="hr_payroll_ca_ett_wages" model="hr.salary.rule.category">
|
||||
<field name="name">Wage: US-CA Employee Training Tax</field>
|
||||
<field name="code">WAGE_US_CA_ETT</field>
|
||||
</record>
|
||||
|
||||
<record id="hr_payroll_ca_ett" model="hr.salary.rule.category">
|
||||
<field name="name">ER: US-CA Employee Training Tax</field>
|
||||
<field name="code">ER_US_CA_ETT</field>
|
||||
<field name="parent_id" ref="hr_payroll.COMP"/>
|
||||
</record>
|
||||
|
||||
<record id="hr_payroll_ca_sdi_wages" model="hr.salary.rule.category">
|
||||
<field name="name">Wage: US-CA State Disability Insurance</field>
|
||||
<field name="code">WAGE_US_CA_SDI</field>
|
||||
</record>
|
||||
|
||||
<record id="hr_payroll_ca_sdi" model="hr.salary.rule.category">
|
||||
<field name="name">EE: US-CA State Disability Insurance</field>
|
||||
<field name="code">EE_US_CA_SDI</field>
|
||||
<field name="parent_id" ref="hr_payroll.DED"/>
|
||||
</record>
|
||||
|
||||
<record id="hr_payroll_ca_income_withhold" model="hr.salary.rule.category">
|
||||
<field name="name">EE: US-CA Income Withholding</field>
|
||||
<field name="code">EE_US_CA_INC_WITHHOLD</field>
|
||||
<field name="parent_id" ref="hr_payroll.DED"/>
|
||||
</record>
|
||||
</data>
|
||||
</odoo>
|
||||
23
l10n_us_ca_hr_payroll/data/final.xml
Executable file
23
l10n_us_ca_hr_payroll/data/final.xml
Executable file
@@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<data>
|
||||
|
||||
<!-- HR PAYROLL STRUCTURE -->
|
||||
<record id="hr_payroll_salary_structure_us_ca_employee" model="hr.payroll.structure">
|
||||
<field name="code">US_CA_EMP</field>
|
||||
<field name="name">USA California Employee</field>
|
||||
<field eval="[(6, 0, [
|
||||
ref('hr_payroll_rules_ca_uit_wages_2018'),
|
||||
ref('hr_payroll_rules_ca_uit_2018'),
|
||||
ref('hr_payroll_rules_ca_ett_wages_2018'),
|
||||
ref('hr_payroll_rules_ca_ett_2018'),
|
||||
ref('hr_payroll_rules_ca_sdi_wages_2018'),
|
||||
ref('hr_payroll_rules_ca_sdi_2018'),
|
||||
ref('hr_payroll_rules_ca_inc_withhold_2018'),
|
||||
])]" name="rule_ids"/>
|
||||
<field name="company_id" ref="base.main_company"/>
|
||||
<field name="parent_id" ref="l10n_us_hr_payroll.hr_payroll_salary_structure_us_employee"/>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</odoo>
|
||||
46
l10n_us_ca_hr_payroll/data/rates.xml
Executable file
46
l10n_us_ca_hr_payroll/data/rates.xml
Executable file
@@ -0,0 +1,46 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<record id="hr_payroll_rates_ca_unemp_2018" model="hr.payroll.rate">
|
||||
<field name="name">US California Unemployment</field>
|
||||
<field name="code">US_CA_UNEMP</field>
|
||||
<field name="rate">2.6</field>
|
||||
<field name="date_from">2018-01-01</field>
|
||||
<field name="wage_limit_year" eval="7000"/>
|
||||
</record>
|
||||
<record id="hr_payroll_rates_ca_ett_2018" model="hr.payroll.rate">
|
||||
<field name="name">US California Employment Training Tax</field>
|
||||
<field name="code">US_CA_ETT</field>
|
||||
<field name="rate">0.1</field>
|
||||
<field name="date_from">2018-01-01</field>
|
||||
<field name="wage_limit_year" eval="7000"/>
|
||||
</record>
|
||||
<record id="hr_payroll_rates_ca_sdi_2018" model="hr.payroll.rate">
|
||||
<field name="name">US California State Disability Insurance</field>
|
||||
<field name="code">US_CA_SDI</field>
|
||||
<field name="rate">1.0</field>
|
||||
<field name="date_from">2018-01-01</field>
|
||||
<field name="wage_limit_year" eval="114967.0"/>
|
||||
</record>
|
||||
|
||||
<record id="hr_payroll_rates_ca_unemp_2019" model="hr.payroll.rate">
|
||||
<field name="name">US California Unemployment</field>
|
||||
<field name="code">US_CA_UNEMP</field>
|
||||
<field name="rate">3.4</field>
|
||||
<field name="date_from">2019-01-01</field>
|
||||
<field name="wage_limit_year" eval="7000"/>
|
||||
</record>
|
||||
<record id="hr_payroll_rates_ca_ett_2019" model="hr.payroll.rate">
|
||||
<field name="name">US California Employment Training Tax</field>
|
||||
<field name="code">US_CA_ETT</field>
|
||||
<field name="rate">0.1</field>
|
||||
<field name="date_from">2019-01-01</field>
|
||||
<field name="wage_limit_year" eval="7000"/>
|
||||
</record>
|
||||
<record id="hr_payroll_rates_ca_sdi_2019" model="hr.payroll.rate">
|
||||
<field name="name">US California State Disability Insurance</field>
|
||||
<field name="code">US_CA_SDI</field>
|
||||
<field name="rate">1.0</field>
|
||||
<field name="date_from">2019-01-01</field>
|
||||
<field name="wage_limit_year" eval="18371.0"/>
|
||||
</record>
|
||||
</odoo>
|
||||
1005
l10n_us_ca_hr_payroll/data/rules.xml
Executable file
1005
l10n_us_ca_hr_payroll/data/rules.xml
Executable file
File diff suppressed because it is too large
Load Diff
1
l10n_us_ca_hr_payroll/models/__init__.py
Normal file
1
l10n_us_ca_hr_payroll/models/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from . import hr_payroll
|
||||
16
l10n_us_ca_hr_payroll/models/hr_payroll.py
Executable file
16
l10n_us_ca_hr_payroll/models/hr_payroll.py
Executable file
@@ -0,0 +1,16 @@
|
||||
from odoo import models, fields, api
|
||||
|
||||
|
||||
class USCAHrContract(models.Model):
|
||||
_inherit = 'hr.contract'
|
||||
|
||||
ca_de4_allowances = fields.Integer(string="California CA-4 Allowances",
|
||||
default=0,
|
||||
help="Estimated Deductions claimed on DE-4")
|
||||
ca_additional_allowances = fields.Integer(string="Additional Allowances", default=0)
|
||||
ca_de4_filing_status = fields.Selection([
|
||||
('exempt', 'Exempt'),
|
||||
('single', 'Single'),
|
||||
('married', 'Married'),
|
||||
('head_household', 'Head of Household')
|
||||
], string='CA Filing Status', default='single')
|
||||
2
l10n_us_ca_hr_payroll/tests/__init__.py
Executable file
2
l10n_us_ca_hr_payroll/tests/__init__.py
Executable file
@@ -0,0 +1,2 @@
|
||||
from . import test_us_ca_payslip_2018
|
||||
from . import test_us_ca_payslip_2019
|
||||
419
l10n_us_ca_hr_payroll/tests/test_us_ca_payslip_2018.py
Executable file
419
l10n_us_ca_hr_payroll/tests/test_us_ca_payslip_2018.py
Executable file
@@ -0,0 +1,419 @@
|
||||
from odoo.addons.l10n_us_hr_payroll.tests.test_us_payslip import TestUsPayslip, process_payslip
|
||||
|
||||
|
||||
class TestUsCAPayslip(TestUsPayslip):
|
||||
###
|
||||
# Taxes and Rates
|
||||
###
|
||||
CA_UIT_MAX_WAGE = 7000
|
||||
CA_UIT_MAX_WAGE = 7000
|
||||
CA_SDI_MAX_WAGE = 114967
|
||||
|
||||
CA_UIT = -2.6 / 100.0
|
||||
CA_ETT = -0.1 / 100.0
|
||||
CA_SDI = -1.0 / 100.0
|
||||
|
||||
# Examples from http://www.edd.ca.gov/pdf_pub_ctr/18methb.pdf
|
||||
def test_example_a(self):
|
||||
salary = 210
|
||||
schedule_pay = 'weekly'
|
||||
allowances = 1
|
||||
additional_allowances = 0
|
||||
|
||||
wh = 0.00
|
||||
|
||||
employee = self._createEmployee()
|
||||
|
||||
contract = self._createContract(employee,
|
||||
salary,
|
||||
struct_id=self.ref(
|
||||
'l10n_us_ca_hr_payroll.hr_payroll_salary_structure_us_ca_employee'),
|
||||
schedule_pay=schedule_pay)
|
||||
contract.ca_c4_exemptions = allowances
|
||||
contract.ca_additional_allowances = additional_allowances
|
||||
contract.ca_de4_filing_status = 'single'
|
||||
|
||||
self.assertEqual(contract.schedule_pay, 'weekly')
|
||||
|
||||
self._log('2017 California tax last payslip:')
|
||||
payslip = self._createPayslip(employee, '2017-12-01', '2017-12-31')
|
||||
payslip.compute_sheet()
|
||||
process_payslip(payslip)
|
||||
|
||||
self._log('2018 California tax first payslip:')
|
||||
payslip = self._createPayslip(employee, '2018-01-01', '2018-01-31')
|
||||
|
||||
payslip.compute_sheet()
|
||||
|
||||
cats = self._getCategories(payslip)
|
||||
|
||||
self.assertPayrollEqual(cats['WAGE_US_CA_UNEMP'], salary)
|
||||
self.assertPayrollEqual(cats['ER_US_CA_UNEMP'], cats['WAGE_US_CA_UNEMP'] * self.CA_UIT)
|
||||
self.assertPayrollEqual(cats['WAGE_US_CA_ETT'], salary)
|
||||
self.assertPayrollEqual(cats['ER_US_CA_ETT'], cats['WAGE_US_CA_ETT'] * self.CA_ETT)
|
||||
self.assertPayrollEqual(cats['WAGE_US_CA_SDI'], salary)
|
||||
self.assertPayrollEqual(cats['EE_US_CA_SDI'], cats['WAGE_US_CA_SDI'] * self.CA_SDI)
|
||||
self.assertPayrollEqual(cats['EE_US_CA_INC_WITHHOLD'], wh)
|
||||
|
||||
process_payslip(payslip)
|
||||
|
||||
# Make a new payslip, this one will have maximums
|
||||
|
||||
remaining_ca_uit_wages = self.CA_UIT_MAX_WAGE - salary if (self.CA_UIT_MAX_WAGE - 2 * salary < salary) \
|
||||
else salary
|
||||
|
||||
self._log('2018 California tax second payslip:')
|
||||
payslip = self._createPayslip(employee, '2018-02-01', '2018-02-28')
|
||||
|
||||
payslip.compute_sheet()
|
||||
|
||||
cats = self._getCategories(payslip)
|
||||
|
||||
self.assertPayrollEqual(cats['WAGE_US_CA_UNEMP'], remaining_ca_uit_wages)
|
||||
self.assertPayrollEqual(cats['ER_US_CA_UNEMP'], remaining_ca_uit_wages * self.CA_UIT)
|
||||
|
||||
def test_example_b(self):
|
||||
salary = 1250
|
||||
schedule_pay = 'bi-weekly'
|
||||
allowances = 2
|
||||
additional_allowances = 1
|
||||
|
||||
wh = -2.89
|
||||
|
||||
employee = self._createEmployee()
|
||||
contract = self._createContract(employee,
|
||||
salary,
|
||||
struct_id=self.ref(
|
||||
'l10n_us_ca_hr_payroll.hr_payroll_salary_structure_us_ca_employee'),
|
||||
schedule_pay=schedule_pay)
|
||||
contract.ca_de4_allowances = allowances
|
||||
contract.ca_additional_allowances = additional_allowances
|
||||
contract.ca_de4_filing_status = 'married'
|
||||
|
||||
self.assertEqual(contract.schedule_pay, 'bi-weekly')
|
||||
self.assertEqual(contract.ca_de4_filing_status, 'married')
|
||||
self.assertEqual(contract.ca_de4_allowances, 2)
|
||||
self.assertEqual(contract.ca_additional_allowances, 1)
|
||||
|
||||
self._log('2017 California tax last payslip:')
|
||||
payslip = self._createPayslip(employee, '2017-12-01', '2017-12-31')
|
||||
payslip.compute_sheet()
|
||||
process_payslip(payslip)
|
||||
|
||||
self._log('2018 California tax first payslip:')
|
||||
payslip = self._createPayslip(employee, '2018-01-01', '2018-01-31')
|
||||
|
||||
payslip.compute_sheet()
|
||||
|
||||
cats = self._getCategories(payslip)
|
||||
|
||||
self.assertPayrollEqual(cats['WAGE_US_CA_UNEMP'], salary)
|
||||
self.assertPayrollEqual(cats['ER_US_CA_UNEMP'], round((cats['WAGE_US_CA_UNEMP'] * self.CA_UIT), 2))
|
||||
self.assertPayrollEqual(cats['WAGE_US_CA_ETT'], salary)
|
||||
self.assertPayrollEqual(cats['ER_US_CA_ETT'], round((cats['WAGE_US_CA_ETT'] * self.CA_ETT), 2))
|
||||
self.assertPayrollEqual(cats['WAGE_US_CA_SDI'], salary)
|
||||
self.assertPayrollEqual(cats['EE_US_CA_SDI'], round((cats['WAGE_US_CA_SDI'] * self.CA_SDI), 2))
|
||||
self.assertPayrollEqual(cats['EE_US_CA_INC_WITHHOLD'], wh)
|
||||
|
||||
process_payslip(payslip)
|
||||
|
||||
# Make a new payslip, this one will have maximums
|
||||
|
||||
remaining_ca_uit_wages = self.CA_UIT_MAX_WAGE - salary if (self.CA_UIT_MAX_WAGE - 2 * salary < salary) \
|
||||
else salary
|
||||
|
||||
self._log('2018 California tax second payslip:')
|
||||
payslip = self._createPayslip(employee, '2018-02-01', '2018-02-28')
|
||||
|
||||
payslip.compute_sheet()
|
||||
|
||||
cats = self._getCategories(payslip)
|
||||
|
||||
self.assertPayrollEqual(cats['WAGE_US_CA_UNEMP'], remaining_ca_uit_wages)
|
||||
self.assertPayrollEqual(cats['ER_US_CA_UNEMP'], round((remaining_ca_uit_wages * self.CA_UIT), 2))
|
||||
|
||||
def test_example_c(self):
|
||||
salary = 3800
|
||||
schedule_pay = 'monthly'
|
||||
allowances = 5
|
||||
additional_allowances = 0.72
|
||||
|
||||
wh = -0.72
|
||||
|
||||
employee = self._createEmployee()
|
||||
contract = self._createContract(employee,
|
||||
salary,
|
||||
struct_id=self.ref(
|
||||
'l10n_us_ca_hr_payroll.hr_payroll_salary_structure_us_ca_employee'),
|
||||
schedule_pay=schedule_pay)
|
||||
contract.ca_de4_allowances = allowances
|
||||
contract.ca_additional_allowances = additional_allowances
|
||||
contract.ca_de4_filing_status = 'married'
|
||||
|
||||
self.assertEqual(contract.schedule_pay, 'monthly')
|
||||
self.assertEqual(contract.ca_de4_filing_status, 'married')
|
||||
self.assertEqual(contract.ca_de4_allowances, 5)
|
||||
self.assertEqual(contract.ca_additional_allowances, 0)
|
||||
|
||||
self._log('2017 California tax last payslip:')
|
||||
payslip = self._createPayslip(employee, '2017-12-01', '2017-12-31')
|
||||
payslip.compute_sheet()
|
||||
process_payslip(payslip)
|
||||
|
||||
self._log('2018 California tax first payslip:')
|
||||
payslip = self._createPayslip(employee, '2018-01-01', '2018-01-31')
|
||||
|
||||
payslip.compute_sheet()
|
||||
|
||||
cats = self._getCategories(payslip)
|
||||
|
||||
self.assertPayrollEqual(cats['WAGE_US_CA_UNEMP'], salary)
|
||||
self.assertPayrollEqual(cats['ER_US_CA_UNEMP'], round((cats['WAGE_US_CA_UNEMP'] * self.CA_UIT), 2))
|
||||
self.assertPayrollEqual(cats['WAGE_US_CA_ETT'], salary)
|
||||
self.assertPayrollEqual(cats['ER_US_CA_ETT'], round((cats['WAGE_US_CA_ETT'] * self.CA_ETT), 2))
|
||||
self.assertPayrollEqual(cats['WAGE_US_CA_SDI'], salary)
|
||||
self.assertPayrollEqual(cats['EE_US_CA_SDI'], round((cats['WAGE_US_CA_SDI'] * self.CA_SDI), 2))
|
||||
self.assertPayrollEqual(cats['EE_US_CA_INC_WITHHOLD'], wh)
|
||||
|
||||
process_payslip(payslip)
|
||||
|
||||
# Make a new payslip, this one will have maximums
|
||||
|
||||
remaining_ca_uit_wages = self.CA_UIT_MAX_WAGE - salary if (self.CA_UIT_MAX_WAGE - 2 * salary < salary) \
|
||||
else salary
|
||||
|
||||
self._log('2018 California tax second payslip:')
|
||||
payslip = self._createPayslip(employee, '2018-02-01', '2018-02-28')
|
||||
|
||||
payslip.compute_sheet()
|
||||
|
||||
cats = self._getCategories(payslip)
|
||||
|
||||
self.assertPayrollEqual(cats['WAGE_US_CA_UNEMP'], remaining_ca_uit_wages)
|
||||
self.assertPayrollEqual(cats['ER_US_CA_UNEMP'], round((remaining_ca_uit_wages * self.CA_UIT), 2))
|
||||
|
||||
def test_example_d(self):
|
||||
salary = 800
|
||||
schedule_pay = 'weekly'
|
||||
allowances = 3
|
||||
additional_allowances = 0
|
||||
|
||||
wh = -3.31
|
||||
|
||||
employee = self._createEmployee()
|
||||
contract = self._createContract(employee,
|
||||
salary,
|
||||
struct_id=self.ref(
|
||||
'l10n_us_ca_hr_payroll.hr_payroll_salary_structure_us_ca_employee'),
|
||||
schedule_pay=schedule_pay)
|
||||
contract.ca_de4_allowances = allowances
|
||||
contract.ca_additional_allowances = additional_allowances
|
||||
contract.ca_de4_filing_status = 'head_household'
|
||||
|
||||
self.assertEqual(contract.schedule_pay, 'weekly')
|
||||
self.assertEqual(contract.ca_de4_filing_status, 'head_household')
|
||||
self.assertEqual(contract.ca_de4_allowances, 3)
|
||||
self.assertEqual(contract.ca_additional_allowances, 0)
|
||||
|
||||
self._log('2017 California tax last payslip:')
|
||||
payslip = self._createPayslip(employee, '2017-12-01', '2017-12-31')
|
||||
payslip.compute_sheet()
|
||||
process_payslip(payslip)
|
||||
|
||||
self._log('2018 California tax first payslip:')
|
||||
payslip = self._createPayslip(employee, '2018-01-01', '2018-01-31')
|
||||
|
||||
payslip.compute_sheet()
|
||||
|
||||
cats = self._getCategories(payslip)
|
||||
|
||||
self.assertPayrollEqual(cats['WAGE_US_CA_UNEMP'], salary)
|
||||
self.assertPayrollEqual(cats['ER_US_CA_UNEMP'], round((cats['WAGE_US_CA_UNEMP'] * self.CA_UIT), 2))
|
||||
self.assertPayrollEqual(cats['WAGE_US_CA_ETT'], salary)
|
||||
self.assertPayrollEqual(cats['ER_US_CA_ETT'], round((cats['WAGE_US_CA_ETT'] * self.CA_ETT), 2))
|
||||
self.assertPayrollEqual(cats['WAGE_US_CA_SDI'], salary)
|
||||
self.assertPayrollEqual(cats['EE_US_CA_SDI'], round((cats['WAGE_US_CA_SDI'] * self.CA_SDI), 2))
|
||||
self.assertPayrollEqual(cats['EE_US_CA_INC_WITHHOLD'], wh)
|
||||
|
||||
process_payslip(payslip)
|
||||
|
||||
# Make a new payslip, this one will have maximums
|
||||
|
||||
remaining_ca_uit_wages = self.CA_UIT_MAX_WAGE - salary if (self.CA_UIT_MAX_WAGE - 2 * salary < salary) \
|
||||
else salary
|
||||
|
||||
self._log('2018 California tax second payslip:')
|
||||
payslip = self._createPayslip(employee, '2018-02-01', '2018-02-28')
|
||||
|
||||
payslip.compute_sheet()
|
||||
|
||||
cats = self._getCategories(payslip)
|
||||
|
||||
self.assertPayrollEqual(cats['WAGE_US_CA_UNEMP'], remaining_ca_uit_wages)
|
||||
self.assertPayrollEqual(cats['ER_US_CA_UNEMP'], round((remaining_ca_uit_wages * self.CA_UIT), 2))
|
||||
|
||||
def test_example_e(self):
|
||||
salary = 1800
|
||||
schedule_pay = 'semi-monthly'
|
||||
allowances = 4
|
||||
additional_allowances = 0
|
||||
|
||||
wh = -3.39
|
||||
|
||||
employee = self._createEmployee()
|
||||
contract = self._createContract(employee,
|
||||
salary,
|
||||
struct_id=self.ref(
|
||||
'l10n_us_ca_hr_payroll.hr_payroll_salary_structure_us_ca_employee'),
|
||||
schedule_pay=schedule_pay)
|
||||
contract.ca_de4_allowances = allowances
|
||||
contract.ca_additional_allowances = additional_allowances
|
||||
contract.ca_de4_filing_status = 'married'
|
||||
|
||||
self.assertEqual(contract.schedule_pay, 'semi-monthly')
|
||||
self.assertEqual(contract.ca_de4_filing_status, 'married')
|
||||
self.assertEqual(contract.ca_de4_allowances, 4)
|
||||
self.assertEqual(contract.ca_additional_allowances, 0)
|
||||
|
||||
self._log('2017 California tax last payslip:')
|
||||
payslip = self._createPayslip(employee, '2017-12-01', '2017-12-31')
|
||||
payslip.compute_sheet()
|
||||
process_payslip(payslip)
|
||||
|
||||
self._log('2018 California tax first payslip:')
|
||||
payslip = self._createPayslip(employee, '2018-01-01', '2018-01-31')
|
||||
|
||||
payslip.compute_sheet()
|
||||
|
||||
cats = self._getCategories(payslip)
|
||||
|
||||
self.assertPayrollEqual(cats['WAGE_US_CA_UNEMP'], salary)
|
||||
self.assertPayrollEqual(cats['ER_US_CA_UNEMP'], round((cats['WAGE_US_CA_UNEMP'] * self.CA_UIT), 2))
|
||||
self.assertPayrollEqual(cats['WAGE_US_CA_ETT'], salary)
|
||||
self.assertPayrollEqual(cats['ER_US_CA_ETT'], round((cats['WAGE_US_CA_ETT'] * self.CA_ETT), 2))
|
||||
self.assertPayrollEqual(cats['WAGE_US_CA_SDI'], salary)
|
||||
self.assertPayrollEqual(cats['EE_US_CA_SDI'], round((cats['WAGE_US_CA_SDI'] * self.CA_SDI), 2))
|
||||
self.assertPayrollEqual(cats['EE_US_CA_INC_WITHHOLD'], wh)
|
||||
|
||||
process_payslip(payslip)
|
||||
|
||||
# Make a new payslip, this one will have maximums
|
||||
|
||||
remaining_ca_uit_wages = self.CA_UIT_MAX_WAGE - salary if (self.CA_UIT_MAX_WAGE - 2 * salary < salary) \
|
||||
else salary
|
||||
|
||||
self._log('2018 California tax second payslip:')
|
||||
payslip = self._createPayslip(employee, '2018-02-01', '2018-02-28')
|
||||
|
||||
payslip.compute_sheet()
|
||||
|
||||
cats = self._getCategories(payslip)
|
||||
|
||||
self.assertPayrollEqual(cats['WAGE_US_CA_UNEMP'], remaining_ca_uit_wages)
|
||||
self.assertPayrollEqual(cats['ER_US_CA_UNEMP'], round((remaining_ca_uit_wages * self.CA_UIT), 2))
|
||||
|
||||
def test_example_f(self):
|
||||
salary = 45000
|
||||
schedule_pay = 'annually'
|
||||
allowances = 4
|
||||
additional_allowances = 0
|
||||
|
||||
wh = -121.11
|
||||
|
||||
employee = self._createEmployee()
|
||||
contract = self._createContract(employee,
|
||||
salary,
|
||||
struct_id=self.ref(
|
||||
'l10n_us_ca_hr_payroll.hr_payroll_salary_structure_us_ca_employee'),
|
||||
schedule_pay=schedule_pay)
|
||||
contract.ca_de4_allowances = allowances
|
||||
contract.ca_additional_allowances = additional_allowances
|
||||
contract.ca_de4_filing_status = 'married'
|
||||
|
||||
self.assertEqual(contract.schedule_pay, 'annually')
|
||||
self.assertEqual(contract.ca_de4_filing_status, 'married')
|
||||
self.assertEqual(contract.ca_de4_allowances, 4)
|
||||
self.assertEqual(contract.ca_additional_allowances, 0)
|
||||
|
||||
self._log('2017 California tax last payslip:')
|
||||
payslip = self._createPayslip(employee, '2017-12-01', '2017-12-31')
|
||||
payslip.compute_sheet()
|
||||
process_payslip(payslip)
|
||||
|
||||
self._log('2018 California tax first payslip:')
|
||||
payslip = self._createPayslip(employee, '2018-01-01', '2018-01-31')
|
||||
|
||||
payslip.compute_sheet()
|
||||
|
||||
cats = self._getCategories(payslip)
|
||||
|
||||
self.assertPayrollEqual(cats['ER_US_CA_UNEMP'], round((cats['WAGE_US_CA_UNEMP'] * self.CA_UIT), 2))
|
||||
self.assertPayrollEqual(cats['ER_US_CA_ETT'], round((cats['WAGE_US_CA_ETT'] * self.CA_ETT), 2))
|
||||
self.assertPayrollEqual(cats['EE_US_CA_SDI'], round((cats['WAGE_US_CA_SDI'] * self.CA_SDI), 2))
|
||||
self.assertPayrollEqual(cats['EE_US_CA_INC_WITHHOLD'], wh)
|
||||
|
||||
process_payslip(payslip)
|
||||
|
||||
def test_estimated_deduction_table(self):
|
||||
salary = 600
|
||||
allowances = 5
|
||||
schedule_pay = 'bi-weekly'
|
||||
expected_deduction = 192
|
||||
deduction = 0
|
||||
taxable_pay = 0
|
||||
estimated_deduction_table = {
|
||||
'weekly': (19, 38, 58, 77, 96, 115, 135, 154, 173, 192),
|
||||
'bi-weekly': (38, 77, 115, 154, 192, 231, 269, 308, 346, 385),
|
||||
'semi-monthly': (42, 83, 125, 167, 208, 250, 292, 333, 375, 417),
|
||||
'monthly': (83, 167, 250, 333, 417, 500, 583, 667, 750, 833),
|
||||
'quarterly': (250, 500, 750, 1000, 1250, 1500, 1750, 2000, 2250, 2500),
|
||||
'semi-annual': (500, 1000, 1500, 2000, 2500, 3000, 3500, 4000, 4500, 5000),
|
||||
'annual': (1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000, 10000),
|
||||
}
|
||||
|
||||
allowance_index = allowances - 1
|
||||
if allowances > 10:
|
||||
deduction = (estimated_deduction_table[schedule_pay][0]) * allowances
|
||||
taxable_pay = salary - deduction
|
||||
elif allowances > 0:
|
||||
deduction = estimated_deduction_table[schedule_pay][allowance_index]
|
||||
taxable_pay = salary - deduction
|
||||
|
||||
self.assertEqual(expected_deduction, deduction)
|
||||
self.assertTrue(taxable_pay < salary)
|
||||
self.assertEqual(taxable_pay, salary - deduction)
|
||||
|
||||
def test_standard_deduction_table(self):
|
||||
salary = 3000
|
||||
schedule_pay = 'monthly'
|
||||
filing_status = 'head_household'
|
||||
expected_deduction = 706
|
||||
deduction = 0
|
||||
taxable_pay = 0
|
||||
standard_deduction_table = {
|
||||
'weekly': (81, 81, 163, 163),
|
||||
'bi-weekly': (163, 163, 326, 326),
|
||||
'semi-monthly': (177, 177, 353, 353),
|
||||
'monthly': (353, 352, 706, 706),
|
||||
'quarterly': (1059, 1059, 2188, 2188),
|
||||
'semi-annual': (2118, 2118, 4236, 4236),
|
||||
'annual': (4236, 4236, 8471, 8472),
|
||||
}
|
||||
|
||||
if filing_status == 'head_household':
|
||||
_, _, _, deduction = standard_deduction_table[schedule_pay]
|
||||
taxable_pay = salary - deduction
|
||||
elif filing_status == 'married':
|
||||
if allowances >= 2:
|
||||
_, _, deduction, _ = standard_deduction_table[schedule_pay]
|
||||
taxable_pay = salary - deduction
|
||||
else:
|
||||
_, deduction, _, _ = standard_deduction_table[schedule_pay]
|
||||
taxable_pay = salary - deduction
|
||||
else:
|
||||
deduction, _, _, _ = standard_deduction_table[schedule_pay]
|
||||
taxable_pay = salary - deduction
|
||||
|
||||
self.assertEqual(expected_deduction, deduction)
|
||||
self.assertTrue(taxable_pay < salary)
|
||||
self.assertEqual(taxable_pay, salary - deduction)
|
||||
425
l10n_us_ca_hr_payroll/tests/test_us_ca_payslip_2019.py
Executable file
425
l10n_us_ca_hr_payroll/tests/test_us_ca_payslip_2019.py
Executable file
@@ -0,0 +1,425 @@
|
||||
from odoo.addons.l10n_us_hr_payroll.tests.test_us_payslip import TestUsPayslip, process_payslip
|
||||
|
||||
|
||||
class TestUsCAPayslip(TestUsPayslip):
|
||||
###
|
||||
# Taxes and Rates
|
||||
###
|
||||
CA_UIT_MAX_WAGE = 7000
|
||||
CA_UIT_MAX_WAGE = 7000
|
||||
CA_SDI_MAX_WAGE = 18371
|
||||
|
||||
CA_UIT = -3.4 / 100.0
|
||||
CA_ETT = -0.1 / 100.0
|
||||
CA_SDI = -1.0 / 100.0
|
||||
|
||||
# Examples from http://www.edd.ca.gov/pdf_pub_ctr/18methb.pdf
|
||||
def test_example_a(self):
|
||||
salary = 210
|
||||
schedule_pay = 'weekly'
|
||||
allowances = 1
|
||||
additional_allowances = 0
|
||||
|
||||
wh = 0.00
|
||||
|
||||
employee = self._createEmployee()
|
||||
|
||||
contract = self._createContract(employee,
|
||||
salary,
|
||||
struct_id=self.ref(
|
||||
'l10n_us_ca_hr_payroll.hr_payroll_salary_structure_us_ca_employee'),
|
||||
schedule_pay=schedule_pay)
|
||||
contract.ca_c4_exemptions = allowances
|
||||
contract.ca_additional_allowances = additional_allowances
|
||||
contract.ca_de4_filing_status = 'single'
|
||||
|
||||
self.assertEqual(contract.schedule_pay, 'weekly')
|
||||
|
||||
self._log('2018 California tax last payslip:')
|
||||
payslip = self._createPayslip(employee, '2018-12-01', '2018-12-31')
|
||||
payslip.compute_sheet()
|
||||
process_payslip(payslip)
|
||||
|
||||
self._log('2019 California tax first payslip:')
|
||||
payslip = self._createPayslip(employee, '2019-01-01', '2019-01-31')
|
||||
|
||||
payslip.compute_sheet()
|
||||
|
||||
cats = self._getCategories(payslip)
|
||||
|
||||
self.assertPayrollEqual(cats['WAGE_US_CA_UNEMP'], salary)
|
||||
self.assertPayrollEqual(cats['ER_US_CA_UNEMP'], cats['WAGE_US_CA_UNEMP'] * self.CA_UIT)
|
||||
self.assertPayrollEqual(cats['WAGE_US_CA_ETT'], salary)
|
||||
self.assertPayrollEqual(cats['ER_US_CA_ETT'], cats['WAGE_US_CA_ETT'] * self.CA_ETT)
|
||||
self.assertPayrollEqual(cats['WAGE_US_CA_SDI'], salary)
|
||||
self.assertPayrollEqual(cats['EE_US_CA_SDI'], cats['WAGE_US_CA_SDI'] * self.CA_SDI)
|
||||
self.assertPayrollEqual(cats['EE_US_CA_INC_WITHHOLD'], wh)
|
||||
|
||||
process_payslip(payslip)
|
||||
|
||||
# Make a new payslip, this one will have maximums
|
||||
|
||||
remaining_ca_uit_wages = self.CA_UIT_MAX_WAGE - salary if (self.CA_UIT_MAX_WAGE - 2 * salary < salary) \
|
||||
else salary
|
||||
|
||||
self._log('2019 California tax second payslip:')
|
||||
payslip = self._createPayslip(employee, '2019-02-01', '2019-02-28')
|
||||
|
||||
payslip.compute_sheet()
|
||||
|
||||
cats = self._getCategories(payslip)
|
||||
|
||||
self.assertPayrollEqual(cats['WAGE_US_CA_UNEMP'], remaining_ca_uit_wages)
|
||||
self.assertPayrollEqual(cats['ER_US_CA_UNEMP'], remaining_ca_uit_wages * self.CA_UIT)
|
||||
|
||||
def test_example_b(self):
|
||||
salary = 1250
|
||||
schedule_pay = 'bi-weekly'
|
||||
allowances = 2
|
||||
additional_allowances = 1
|
||||
|
||||
# for additional allowances
|
||||
wh = salary - 38
|
||||
wh = wh - 339
|
||||
wh = (wh - 632) * 0.022 + 6.95
|
||||
wh = wh - 9.65
|
||||
# 2.651 - 9.65
|
||||
wh = -wh
|
||||
|
||||
employee = self._createEmployee()
|
||||
contract = self._createContract(employee,
|
||||
salary,
|
||||
struct_id=self.ref(
|
||||
'l10n_us_ca_hr_payroll.hr_payroll_salary_structure_us_ca_employee'),
|
||||
schedule_pay=schedule_pay)
|
||||
contract.ca_de4_allowances = allowances
|
||||
contract.ca_additional_allowances = additional_allowances
|
||||
contract.ca_de4_filing_status = 'married'
|
||||
|
||||
self.assertEqual(contract.schedule_pay, 'bi-weekly')
|
||||
self.assertEqual(contract.ca_de4_filing_status, 'married')
|
||||
self.assertEqual(contract.ca_de4_allowances, 2)
|
||||
self.assertEqual(contract.ca_additional_allowances, 1)
|
||||
|
||||
self._log('2018 California tax last payslip:')
|
||||
payslip = self._createPayslip(employee, '2018-12-01', '2018-12-31')
|
||||
payslip.compute_sheet()
|
||||
process_payslip(payslip)
|
||||
|
||||
self._log('2019 California tax first payslip:')
|
||||
payslip = self._createPayslip(employee, '2019-01-01', '2019-01-31')
|
||||
|
||||
payslip.compute_sheet()
|
||||
|
||||
cats = self._getCategories(payslip)
|
||||
|
||||
self.assertPayrollEqual(cats['WAGE_US_CA_UNEMP'], salary)
|
||||
self.assertPayrollEqual(cats['ER_US_CA_UNEMP'], round((cats['WAGE_US_CA_UNEMP'] * self.CA_UIT), 2))
|
||||
self.assertPayrollEqual(cats['WAGE_US_CA_ETT'], salary)
|
||||
self.assertPayrollEqual(cats['ER_US_CA_ETT'], round((cats['WAGE_US_CA_ETT'] * self.CA_ETT), 2))
|
||||
self.assertPayrollEqual(cats['WAGE_US_CA_SDI'], salary)
|
||||
self.assertPayrollEqual(cats['EE_US_CA_SDI'], round((cats['WAGE_US_CA_SDI'] * self.CA_SDI), 2))
|
||||
self.assertPayrollEqual(cats['EE_US_CA_INC_WITHHOLD'], wh)
|
||||
|
||||
process_payslip(payslip)
|
||||
|
||||
# Make a new payslip, this one will have maximums
|
||||
|
||||
remaining_ca_uit_wages = self.CA_UIT_MAX_WAGE - salary if (self.CA_UIT_MAX_WAGE - 2 * salary < salary) \
|
||||
else salary
|
||||
|
||||
self._log('2019 California tax second payslip:')
|
||||
payslip = self._createPayslip(employee, '2019-02-01', '2019-02-28')
|
||||
|
||||
payslip.compute_sheet()
|
||||
|
||||
cats = self._getCategories(payslip)
|
||||
|
||||
self.assertPayrollEqual(cats['WAGE_US_CA_UNEMP'], remaining_ca_uit_wages)
|
||||
self.assertPayrollEqual(cats['ER_US_CA_UNEMP'], round((remaining_ca_uit_wages * self.CA_UIT), 2))
|
||||
|
||||
def test_example_c(self):
|
||||
salary = 3800
|
||||
schedule_pay = 'monthly'
|
||||
allowances = 5
|
||||
additional_allowances = 0.72
|
||||
|
||||
wh = -0.11
|
||||
|
||||
employee = self._createEmployee()
|
||||
contract = self._createContract(employee,
|
||||
salary,
|
||||
struct_id=self.ref(
|
||||
'l10n_us_ca_hr_payroll.hr_payroll_salary_structure_us_ca_employee'),
|
||||
schedule_pay=schedule_pay)
|
||||
contract.ca_de4_allowances = allowances
|
||||
contract.ca_additional_allowances = additional_allowances
|
||||
contract.ca_de4_filing_status = 'married'
|
||||
|
||||
self.assertEqual(contract.schedule_pay, 'monthly')
|
||||
self.assertEqual(contract.ca_de4_filing_status, 'married')
|
||||
self.assertEqual(contract.ca_de4_allowances, 5)
|
||||
self.assertEqual(contract.ca_additional_allowances, 0)
|
||||
|
||||
self._log('2018 California tax last payslip:')
|
||||
payslip = self._createPayslip(employee, '2018-12-01', '2018-12-31')
|
||||
payslip.compute_sheet()
|
||||
process_payslip(payslip)
|
||||
|
||||
self._log('2019 California tax first payslip:')
|
||||
payslip = self._createPayslip(employee, '2019-01-01', '2019-01-31')
|
||||
|
||||
payslip.compute_sheet()
|
||||
|
||||
cats = self._getCategories(payslip)
|
||||
|
||||
self.assertPayrollEqual(cats['WAGE_US_CA_UNEMP'], salary)
|
||||
self.assertPayrollEqual(cats['ER_US_CA_UNEMP'], round((cats['WAGE_US_CA_UNEMP'] * self.CA_UIT), 2))
|
||||
self.assertPayrollEqual(cats['WAGE_US_CA_ETT'], salary)
|
||||
self.assertPayrollEqual(cats['ER_US_CA_ETT'], round((cats['WAGE_US_CA_ETT'] * self.CA_ETT), 2))
|
||||
self.assertPayrollEqual(cats['WAGE_US_CA_SDI'], salary)
|
||||
self.assertPayrollEqual(cats['EE_US_CA_SDI'], round((cats['WAGE_US_CA_SDI'] * self.CA_SDI), 2))
|
||||
self.assertPayrollEqual(cats['EE_US_CA_INC_WITHHOLD'], wh)
|
||||
|
||||
process_payslip(payslip)
|
||||
|
||||
# Make a new payslip, this one will have maximums
|
||||
|
||||
remaining_ca_uit_wages = self.CA_UIT_MAX_WAGE - salary if (self.CA_UIT_MAX_WAGE - 2 * salary < salary) \
|
||||
else salary
|
||||
|
||||
self._log('2019 California tax second payslip:')
|
||||
payslip = self._createPayslip(employee, '2019-02-01', '2019-02-28')
|
||||
|
||||
payslip.compute_sheet()
|
||||
|
||||
cats = self._getCategories(payslip)
|
||||
|
||||
self.assertPayrollEqual(cats['WAGE_US_CA_UNEMP'], remaining_ca_uit_wages)
|
||||
self.assertPayrollEqual(cats['ER_US_CA_UNEMP'], round((remaining_ca_uit_wages * self.CA_UIT), 2))
|
||||
|
||||
def test_example_d(self):
|
||||
salary = 800
|
||||
schedule_pay = 'weekly'
|
||||
allowances = 3
|
||||
additional_allowances = 0
|
||||
|
||||
wh = -3.18
|
||||
|
||||
employee = self._createEmployee()
|
||||
contract = self._createContract(employee,
|
||||
salary,
|
||||
struct_id=self.ref(
|
||||
'l10n_us_ca_hr_payroll.hr_payroll_salary_structure_us_ca_employee'),
|
||||
schedule_pay=schedule_pay)
|
||||
contract.ca_de4_allowances = allowances
|
||||
contract.ca_additional_allowances = additional_allowances
|
||||
contract.ca_de4_filing_status = 'head_household'
|
||||
|
||||
self.assertEqual(contract.schedule_pay, 'weekly')
|
||||
self.assertEqual(contract.ca_de4_filing_status, 'head_household')
|
||||
self.assertEqual(contract.ca_de4_allowances, 3)
|
||||
self.assertEqual(contract.ca_additional_allowances, 0)
|
||||
|
||||
self._log('2018 California tax last payslip:')
|
||||
payslip = self._createPayslip(employee, '2018-12-01', '2018-12-31')
|
||||
payslip.compute_sheet()
|
||||
process_payslip(payslip)
|
||||
|
||||
self._log('2019 California tax first payslip:')
|
||||
payslip = self._createPayslip(employee, '2019-01-01', '2019-01-31')
|
||||
|
||||
payslip.compute_sheet()
|
||||
|
||||
cats = self._getCategories(payslip)
|
||||
|
||||
self.assertPayrollEqual(cats['WAGE_US_CA_UNEMP'], salary)
|
||||
self.assertPayrollEqual(cats['ER_US_CA_UNEMP'], round((cats['WAGE_US_CA_UNEMP'] * self.CA_UIT), 2))
|
||||
self.assertPayrollEqual(cats['WAGE_US_CA_ETT'], salary)
|
||||
self.assertPayrollEqual(cats['ER_US_CA_ETT'], round((cats['WAGE_US_CA_ETT'] * self.CA_ETT), 2))
|
||||
self.assertPayrollEqual(cats['WAGE_US_CA_SDI'], salary)
|
||||
self.assertPayrollEqual(cats['EE_US_CA_SDI'], round((cats['WAGE_US_CA_SDI'] * self.CA_SDI), 2))
|
||||
self.assertPayrollEqual(cats['EE_US_CA_INC_WITHHOLD'], wh)
|
||||
|
||||
process_payslip(payslip)
|
||||
|
||||
# Make a new payslip, this one will have maximums
|
||||
|
||||
remaining_ca_uit_wages = self.CA_UIT_MAX_WAGE - salary if (self.CA_UIT_MAX_WAGE - 2 * salary < salary) \
|
||||
else salary
|
||||
|
||||
self._log('2019 California tax second payslip:')
|
||||
payslip = self._createPayslip(employee, '2019-02-01', '2019-02-28')
|
||||
|
||||
payslip.compute_sheet()
|
||||
|
||||
cats = self._getCategories(payslip)
|
||||
|
||||
self.assertPayrollEqual(cats['WAGE_US_CA_UNEMP'], remaining_ca_uit_wages)
|
||||
self.assertPayrollEqual(cats['ER_US_CA_UNEMP'], round((remaining_ca_uit_wages * self.CA_UIT), 2))
|
||||
|
||||
def test_example_e(self):
|
||||
salary = 1800
|
||||
schedule_pay = 'semi-monthly'
|
||||
allowances = 4
|
||||
additional_allowances = 0
|
||||
|
||||
wh = -3.08
|
||||
|
||||
employee = self._createEmployee()
|
||||
contract = self._createContract(employee,
|
||||
salary,
|
||||
struct_id=self.ref(
|
||||
'l10n_us_ca_hr_payroll.hr_payroll_salary_structure_us_ca_employee'),
|
||||
schedule_pay=schedule_pay)
|
||||
contract.ca_de4_allowances = allowances
|
||||
contract.ca_additional_allowances = additional_allowances
|
||||
contract.ca_de4_filing_status = 'married'
|
||||
|
||||
self.assertEqual(contract.schedule_pay, 'semi-monthly')
|
||||
self.assertEqual(contract.ca_de4_filing_status, 'married')
|
||||
self.assertEqual(contract.ca_de4_allowances, 4)
|
||||
self.assertEqual(contract.ca_additional_allowances, 0)
|
||||
|
||||
self._log('2018 California tax last payslip:')
|
||||
payslip = self._createPayslip(employee, '2018-12-01', '2018-12-31')
|
||||
payslip.compute_sheet()
|
||||
process_payslip(payslip)
|
||||
|
||||
self._log('2019 California tax first payslip:')
|
||||
payslip = self._createPayslip(employee, '2019-01-01', '2019-01-31')
|
||||
|
||||
payslip.compute_sheet()
|
||||
|
||||
cats = self._getCategories(payslip)
|
||||
|
||||
self.assertPayrollEqual(cats['WAGE_US_CA_UNEMP'], salary)
|
||||
self.assertPayrollEqual(cats['ER_US_CA_UNEMP'], round((cats['WAGE_US_CA_UNEMP'] * self.CA_UIT), 2))
|
||||
self.assertPayrollEqual(cats['WAGE_US_CA_ETT'], salary)
|
||||
self.assertPayrollEqual(cats['ER_US_CA_ETT'], round((cats['WAGE_US_CA_ETT'] * self.CA_ETT), 2))
|
||||
self.assertPayrollEqual(cats['WAGE_US_CA_SDI'], salary)
|
||||
self.assertPayrollEqual(cats['EE_US_CA_SDI'], round((cats['WAGE_US_CA_SDI'] * self.CA_SDI), 2))
|
||||
self.assertPayrollEqual(cats['EE_US_CA_INC_WITHHOLD'], wh)
|
||||
|
||||
process_payslip(payslip)
|
||||
|
||||
# Make a new payslip, this one will have maximums
|
||||
|
||||
remaining_ca_uit_wages = self.CA_UIT_MAX_WAGE - salary if (self.CA_UIT_MAX_WAGE - 2 * salary < salary) \
|
||||
else salary
|
||||
|
||||
self._log('2019 California tax second payslip:')
|
||||
payslip = self._createPayslip(employee, '2019-02-01', '2019-02-28')
|
||||
|
||||
payslip.compute_sheet()
|
||||
|
||||
cats = self._getCategories(payslip)
|
||||
|
||||
self.assertPayrollEqual(cats['WAGE_US_CA_UNEMP'], remaining_ca_uit_wages)
|
||||
self.assertPayrollEqual(cats['ER_US_CA_UNEMP'], round((remaining_ca_uit_wages * self.CA_UIT), 2))
|
||||
|
||||
def test_example_f(self):
|
||||
salary = 45000
|
||||
schedule_pay = 'annually'
|
||||
allowances = 4
|
||||
additional_allowances = 0
|
||||
|
||||
wh = -113.85
|
||||
|
||||
employee = self._createEmployee()
|
||||
contract = self._createContract(employee,
|
||||
salary,
|
||||
struct_id=self.ref(
|
||||
'l10n_us_ca_hr_payroll.hr_payroll_salary_structure_us_ca_employee'),
|
||||
schedule_pay=schedule_pay)
|
||||
contract.ca_de4_allowances = allowances
|
||||
contract.ca_additional_allowances = additional_allowances
|
||||
contract.ca_de4_filing_status = 'married'
|
||||
|
||||
self.assertEqual(contract.schedule_pay, 'annually')
|
||||
self.assertEqual(contract.ca_de4_filing_status, 'married')
|
||||
self.assertEqual(contract.ca_de4_allowances, 4)
|
||||
self.assertEqual(contract.ca_additional_allowances, 0)
|
||||
|
||||
self._log('2018 California tax last payslip:')
|
||||
payslip = self._createPayslip(employee, '2018-12-01', '2018-12-31')
|
||||
payslip.compute_sheet()
|
||||
process_payslip(payslip)
|
||||
|
||||
self._log('2019 California tax first payslip:')
|
||||
payslip = self._createPayslip(employee, '2019-01-01', '2019-01-31')
|
||||
|
||||
payslip.compute_sheet()
|
||||
|
||||
cats = self._getCategories(payslip)
|
||||
|
||||
self.assertPayrollEqual(cats['ER_US_CA_UNEMP'], round((cats['WAGE_US_CA_UNEMP'] * self.CA_UIT), 2))
|
||||
self.assertPayrollEqual(cats['ER_US_CA_ETT'], round((cats['WAGE_US_CA_ETT'] * self.CA_ETT), 2))
|
||||
self.assertPayrollEqual(cats['EE_US_CA_SDI'], round((cats['WAGE_US_CA_SDI'] * self.CA_SDI), 2))
|
||||
self.assertPayrollEqual(cats['EE_US_CA_INC_WITHHOLD'], wh)
|
||||
|
||||
process_payslip(payslip)
|
||||
|
||||
def test_estimated_deduction_table(self):
|
||||
salary = 600
|
||||
allowances = 5
|
||||
schedule_pay = 'bi-weekly'
|
||||
expected_deduction = 192
|
||||
deduction = 0
|
||||
taxable_pay = 0
|
||||
estimated_deduction_table = {
|
||||
'weekly': (19, 38, 58, 77, 96, 115, 135, 154, 173, 192),
|
||||
'bi-weekly': (38, 77, 115, 154, 192, 231, 269, 308, 346, 385),
|
||||
'semi-monthly': (42, 83, 125, 167, 208, 250, 292, 333, 375, 417),
|
||||
'monthly': (83, 167, 250, 333, 417, 500, 583, 667, 750, 833),
|
||||
'quarterly': (250, 500, 750, 1000, 1250, 1500, 1750, 2000, 2250, 2500),
|
||||
'semi-annual': (500, 1000, 1500, 2000, 2500, 3000, 3500, 4000, 4500, 5000),
|
||||
'annual': (1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000, 10000),
|
||||
}
|
||||
|
||||
allowance_index = allowances - 1
|
||||
if allowances > 10:
|
||||
deduction = (estimated_deduction_table[schedule_pay][0]) * allowances
|
||||
taxable_pay = salary - deduction
|
||||
elif allowances > 0:
|
||||
deduction = estimated_deduction_table[schedule_pay][allowance_index]
|
||||
taxable_pay = salary - deduction
|
||||
|
||||
self.assertEqual(expected_deduction, deduction)
|
||||
self.assertTrue(taxable_pay < salary)
|
||||
self.assertEqual(taxable_pay, salary - deduction)
|
||||
|
||||
def test_standard_deduction_table(self):
|
||||
salary = 3000
|
||||
schedule_pay = 'monthly'
|
||||
filing_status = 'head_household'
|
||||
expected_deduction = 706
|
||||
deduction = 0
|
||||
taxable_pay = 0
|
||||
standard_deduction_table = {
|
||||
'weekly': (81, 81, 163, 163),
|
||||
'bi-weekly': (163, 163, 326, 326),
|
||||
'semi-monthly': (177, 177, 353, 353),
|
||||
'monthly': (353, 352, 706, 706),
|
||||
'quarterly': (1059, 1059, 2188, 2188),
|
||||
'semi-annual': (2118, 2118, 4236, 4236),
|
||||
'annual': (4236, 4236, 8471, 8472),
|
||||
}
|
||||
|
||||
if filing_status == 'head_household':
|
||||
_, _, _, deduction = standard_deduction_table[schedule_pay]
|
||||
taxable_pay = salary - deduction
|
||||
elif filing_status == 'married':
|
||||
if allowances >= 2:
|
||||
_, _, deduction, _ = standard_deduction_table[schedule_pay]
|
||||
taxable_pay = salary - deduction
|
||||
else:
|
||||
_, deduction, _, _ = standard_deduction_table[schedule_pay]
|
||||
taxable_pay = salary - deduction
|
||||
else:
|
||||
deduction, _, _, _ = standard_deduction_table[schedule_pay]
|
||||
taxable_pay = salary - deduction
|
||||
|
||||
self.assertEqual(expected_deduction, deduction)
|
||||
self.assertTrue(taxable_pay < salary)
|
||||
self.assertEqual(taxable_pay, salary - deduction)
|
||||
22
l10n_us_ca_hr_payroll/views/hr_payroll_views.xml
Executable file
22
l10n_us_ca_hr_payroll/views/hr_payroll_views.xml
Executable file
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<data>
|
||||
<record id="hr_contract_form_l10n_us_ca_inherit" model="ir.ui.view">
|
||||
<field name="name">hr.contract.form.inherit</field>
|
||||
<field name="model">hr.contract</field>
|
||||
<field name="priority">147</field>
|
||||
<field name="inherit_id" ref="hr_contract.hr_contract_view_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<data>
|
||||
<xpath expr="//group[@name='state_filing']" position="inside">
|
||||
<group string="California" name="ca">
|
||||
<field name="ca_de4_filing_status"/>
|
||||
<field name="ca_de4_allowances" string="DE-4 Allowances"/>
|
||||
<field name="ca_additional_allowances" string="Additional Allowances"/>
|
||||
</group>
|
||||
</xpath>
|
||||
</data>
|
||||
</field>
|
||||
</record>
|
||||
</data>
|
||||
</odoo>
|
||||
Reference in New Issue
Block a user