#31 Merge branch 'mig/12.0/l10n_us_ca_hr_payroll' into mig/12.0/us_payroll

This commit is contained in:
Jared Kipe
2019-02-10 15:16:44 -08:00
13 changed files with 2132 additions and 0 deletions

View 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

View File

@@ -0,0 +1 @@
from . import models

View 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
}

View 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>

View 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>

View 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>

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1 @@
from . import hr_payroll

View 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')

View File

@@ -0,0 +1,2 @@
from . import test_us_ca_payslip_2018
from . import test_us_ca_payslip_2019

View 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)

View 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)

View 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>