mirror of
https://gitlab.com/hibou-io/hibou-odoo/suite.git
synced 2025-01-20 12:37:31 +02:00
Merge branch 'new/11.0/l10n_us_ia_hr_payroll' into 11.0
This commit is contained in:
1
l10n_us_ia_hr_payroll/__init__.py
Executable file
1
l10n_us_ia_hr_payroll/__init__.py
Executable file
@@ -0,0 +1 @@
|
|||||||
|
from . import models
|
||||||
29
l10n_us_ia_hr_payroll/__manifest__.py
Executable file
29
l10n_us_ia_hr_payroll/__manifest__.py
Executable file
@@ -0,0 +1,29 @@
|
|||||||
|
{
|
||||||
|
'name': 'USA - Iowa - Payroll',
|
||||||
|
'author': 'Hibou Corp. <hello@hibou.io>',
|
||||||
|
'license': 'AGPL-3',
|
||||||
|
'category': 'Localization',
|
||||||
|
'depends': ['l10n_us_hr_payroll'],
|
||||||
|
'version': '11.0.2019.0.0',
|
||||||
|
'description': """
|
||||||
|
USA::Iowa Payroll Rules.
|
||||||
|
==================================
|
||||||
|
|
||||||
|
* Contribution register and partner for Additional WithholdingTaxaction - Income Tax Withholding
|
||||||
|
* Contribution register and partner for Iowa Workforce Development- Unemployment
|
||||||
|
* Contract level Iowa Exemptions
|
||||||
|
* Company level Iowa Unemployment Rate
|
||||||
|
* Salary Structure for Iowa
|
||||||
|
""",
|
||||||
|
|
||||||
|
'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
|
||||||
|
}
|
||||||
47
l10n_us_ia_hr_payroll/data/base.xml
Executable file
47
l10n_us_ia_hr_payroll/data/base.xml
Executable file
@@ -0,0 +1,47 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<odoo>
|
||||||
|
|
||||||
|
<!-- PARTNERS -->
|
||||||
|
<record id="res_partner_ia_wd_unemp" model="res.partner">
|
||||||
|
<field name="name">Iowa Workforce Development- Unemployment Tax</field>
|
||||||
|
<field name="supplier">1</field>
|
||||||
|
<field eval="0" name="customer"/>
|
||||||
|
</record>
|
||||||
|
<record id="res_partner_ia_dor_withhold" model="res.partner">
|
||||||
|
<field name="name">Iowa Department of Revenue - Income Tax Withholding</field>
|
||||||
|
<field name="supplier">1</field>
|
||||||
|
<field eval="0" name="customer"/>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<!-- CONTRIBUTION REGISTERS -->
|
||||||
|
<record id="contrib_register_ia_wd_unemp" model="hr.contribution.register">
|
||||||
|
<field name="name">Iowa Unemployment</field>
|
||||||
|
<field name="note">Iowa Workforce Development - Unemployment</field>
|
||||||
|
<field name="partner_id" ref="res_partner_ia_wd_unemp"/>
|
||||||
|
</record>
|
||||||
|
<record id="contrib_register_ia_dor_withhold" model="hr.contribution.register">
|
||||||
|
<field name="name">Iowa Income Tax Withholding</field>
|
||||||
|
<field name="note">Iowa Department of Revenue - Income Tax Withholding</field>
|
||||||
|
<field name="partner_id" ref="res_partner_ia_dor_withhold"/>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- HR SALARY RULE CATEGORIES-->
|
||||||
|
<record id="hr_payroll_ia_unemp_wages" model="hr.salary.rule.category">
|
||||||
|
<field name="name">Wage: US-IA Unemployment</field>
|
||||||
|
<field name="code">WAGE_US_IA_UNEMP</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="hr_payroll_ia_unemp" model="hr.salary.rule.category">
|
||||||
|
<field name="name">ER: US-IA Unemployment</field>
|
||||||
|
<field name="code">ER_US_IA_UNEMP</field>
|
||||||
|
<field name="parent_id" ref="hr_payroll.COMP"/>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="hr_payroll_ia_income_withhold" model="hr.salary.rule.category">
|
||||||
|
<field name="name">EE: US-IA Income Tax Withholding</field>
|
||||||
|
<field name="code">EE_US_IA_INC_WITHHOLD</field>
|
||||||
|
<field name="parent_id" ref="hr_payroll.DED"/>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
</odoo>
|
||||||
17
l10n_us_ia_hr_payroll/data/final.xml
Executable file
17
l10n_us_ia_hr_payroll/data/final.xml
Executable file
@@ -0,0 +1,17 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<odoo>
|
||||||
|
|
||||||
|
<!-- HR PAYROLL STRUCTURE -->
|
||||||
|
<record id="hr_payroll_salary_structure_us_ia_employee" model="hr.payroll.structure">
|
||||||
|
<field name="code">US_IA_EMP</field>
|
||||||
|
<field name="name">USA Iowa Employee</field>
|
||||||
|
<field eval="[(6, 0, [
|
||||||
|
ref('hr_payroll_rules_ia_unemp_wages'),
|
||||||
|
ref('hr_payroll_rules_ia_unemp'),
|
||||||
|
ref('hr_payroll_rules_ia_inc_withhold'),
|
||||||
|
])]" 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>
|
||||||
|
|
||||||
|
</odoo>
|
||||||
14
l10n_us_ia_hr_payroll/data/rates.xml
Executable file
14
l10n_us_ia_hr_payroll/data/rates.xml
Executable file
@@ -0,0 +1,14 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<odoo>
|
||||||
|
<data noupdate="1">
|
||||||
|
|
||||||
|
<record id="hr_payroll_rates_ia_unemp" model="hr.payroll.rate">
|
||||||
|
<field name="name">US IA Unemployment</field>
|
||||||
|
<field name="code">US_IA_UNEMP</field>
|
||||||
|
<field name="rate">1.0</field>
|
||||||
|
<field name="date_from">2019-01-01</field>
|
||||||
|
<field name="wage_limit_year" eval="30600.00"/>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
</data>
|
||||||
|
</odoo>
|
||||||
160
l10n_us_ia_hr_payroll/data/rules.xml
Executable file
160
l10n_us_ia_hr_payroll/data/rules.xml
Executable file
@@ -0,0 +1,160 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<odoo>
|
||||||
|
|
||||||
|
<!-- HR SALARY RULES-->
|
||||||
|
<record id="hr_payroll_rules_ia_unemp_wages" model="hr.salary.rule">
|
||||||
|
<field name="sequence" eval="423"/>
|
||||||
|
<field name="category_id" ref="hr_payroll_ia_unemp_wages"/>
|
||||||
|
<field name="name">Wage: US-IA Unemployment</field>
|
||||||
|
<field name="code">WAGE_US_IA_UNEMP</field>
|
||||||
|
<field name="condition_select">python</field>
|
||||||
|
<field name="condition_python">result = (contract.futa_type != contract.FUTA_TYPE_BASIC)</field>
|
||||||
|
<field name="amount_select">code</field>
|
||||||
|
<field name="amount_python_compute">
|
||||||
|
rate = payslip.dict.get_rate('US_IA_UNEMP')
|
||||||
|
year = int(payslip.dict.date_to[:4])
|
||||||
|
ytd = payslip.sum('WAGE_US_IA_UNEMP', str(year) + '-01-01', str(year+1) + '-01-01')
|
||||||
|
ytd += contract.external_wages
|
||||||
|
remaining = rate.wage_limit_year - ytd
|
||||||
|
if remaining <= 0.0:
|
||||||
|
result = 0
|
||||||
|
elif remaining < categories.BASIC:
|
||||||
|
result = remaining
|
||||||
|
else:
|
||||||
|
result = categories.BASIC
|
||||||
|
</field>
|
||||||
|
<field name="appears_on_payslip" eval="False"/>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="hr_payroll_rules_ia_unemp" model="hr.salary.rule">
|
||||||
|
<field name="sequence" eval="443"/>
|
||||||
|
<field name="category_id" ref="hr_payroll_ia_unemp"/>
|
||||||
|
<field name="name">ER: US-IA Unemployment</field>
|
||||||
|
<field name="code">ER_US_IA_UNEMP</field>
|
||||||
|
<field name="condition_select">python</field>
|
||||||
|
<field name="condition_python">result = (contract.futa_type != contract.FUTA_TYPE_BASIC)</field>
|
||||||
|
<field name="amount_select">code</field>
|
||||||
|
<field name="amount_python_compute">
|
||||||
|
rate = payslip.dict.get_rate('US_IA_UNEMP')
|
||||||
|
result_rate = -rate.rate
|
||||||
|
result = categories.WAGE_US_IA_UNEMP
|
||||||
|
|
||||||
|
# result_rate of 0 implies 100% due to bug
|
||||||
|
if result_rate == 0.0:
|
||||||
|
result = 0.0
|
||||||
|
</field>
|
||||||
|
<field name="register_id" ref="contrib_register_ia_wd_unemp"/>
|
||||||
|
<field name="appears_on_payslip" eval="False"/>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="hr_payroll_rules_ia_inc_withhold" model="hr.salary.rule">
|
||||||
|
<field name="sequence" eval="155"/>
|
||||||
|
<field name="category_id" ref="hr_payroll_ia_income_withhold"/>
|
||||||
|
<field name="name">EE: US-IA Income Tax Withholding</field>
|
||||||
|
<field name="code">EE_US_IA_INC_WITHHOLD</field>
|
||||||
|
<field name="condition_select">python</field>
|
||||||
|
<field name="condition_python">result = not contract.ia_w4_tax_exempt</field>
|
||||||
|
<field name="amount_select">code</field>
|
||||||
|
<field name="amount_python_compute">
|
||||||
|
wages = categories.GROSS
|
||||||
|
federal_withholding = categories.EE_US_FED_INC_WITHHOLD
|
||||||
|
schedule_pay = contract.schedule_pay
|
||||||
|
allowances = contract.ia_w4_allowances
|
||||||
|
# It is + federal_withholding because federal_withholding is negative.
|
||||||
|
t1 = wages + federal_withholding
|
||||||
|
standard_deduction_table = {
|
||||||
|
'daily': (6.50, 16.00),
|
||||||
|
'weekly': (32.50, 80.00),
|
||||||
|
'bi-weekly': (65.00, 160.00),
|
||||||
|
'semi-monthly': (70.42, 173.33),
|
||||||
|
'monthly': (140.83, 346.67),
|
||||||
|
'annually': (1690.00, 4160.00)}
|
||||||
|
t2 = t1 - standard_deduction_table[schedule_pay][0] if (allowances < 2) else standard_deduction_table[schedule_pay][1]
|
||||||
|
# IMPORTANT -- ALL RATES ARE ALREADY DIVIDED BY 100 -> 8.53% is in the table as 0.0853
|
||||||
|
if schedule_pay == 'weekly':
|
||||||
|
tax_rate_table = [
|
||||||
|
(25.63, 0.0033, 0.0),
|
||||||
|
(51.27, 0.0067, 0.08),
|
||||||
|
(102.52, 0.0225, 0.025),
|
||||||
|
(230.67, 0.0414, 1.40),
|
||||||
|
(384.46, 0.0563, 6.71),
|
||||||
|
(512.62, 0.0596, 15.37),
|
||||||
|
(768.92, 0.0625, 23.01),
|
||||||
|
(1153.38, 0.0744, 39.03),
|
||||||
|
(float('inf'), 0.0853, 67.63),
|
||||||
|
]
|
||||||
|
elif schedule_pay == 'bi-weekly':
|
||||||
|
tax_rate_table = [
|
||||||
|
(51.27, 0.0033, 0.00),
|
||||||
|
(102.54, 0.0067, 0.17),
|
||||||
|
(205.04, 0.00225, 0.51),
|
||||||
|
(461.35, 0.0414, 2.82),
|
||||||
|
(768.92, 0.0563, 13.43),
|
||||||
|
(1025.23, 0.0596, 30.75),
|
||||||
|
(1537.85, 0.0625, 46.03),
|
||||||
|
(2306.77, 0.0744, 78.07),
|
||||||
|
(float('inf'), 0.0853, 135.28)
|
||||||
|
]
|
||||||
|
elif schedule_pay == 'semi-monthly':
|
||||||
|
tax_rate_table = [
|
||||||
|
(55.54, 0.0033, 0.00),
|
||||||
|
(111.08, 0.0067, 0.18),
|
||||||
|
(222.13, 0.0225, 0.55),
|
||||||
|
(499.79, 0.0414, 3.05),
|
||||||
|
(833.00, 0.0563, 14.59),
|
||||||
|
(1110.67, 0.0596, 33.31),
|
||||||
|
(1666.00, 0.0625, 49.86),
|
||||||
|
(2499.00, 0.0744, 84.57),
|
||||||
|
(float('inf'), 0.0853, 146.55)
|
||||||
|
]
|
||||||
|
elif schedule_pay == 'monthly':
|
||||||
|
tax_rate_table = [
|
||||||
|
(111.08, 0.0033, 0.00),
|
||||||
|
(222.17, 0.0067, 0.37),
|
||||||
|
(444.25, 0.0225, 1.11),
|
||||||
|
(999.58, 0.0414, 6.11),
|
||||||
|
(1666.00, 0.0563, 29.10),
|
||||||
|
(2221.33, 0.0596, 62.66),
|
||||||
|
(3332.00, 0.0625, 99.72),
|
||||||
|
(4998.00, 0.0744, 169.14),
|
||||||
|
(float('inf'), 0.0853, 293.09)
|
||||||
|
]
|
||||||
|
elif schedule_pay == 'annual':
|
||||||
|
tax_rate_table = [
|
||||||
|
(1333.00, 0.0033, 0.00),
|
||||||
|
(2666.00, 0.0067, 4.40),
|
||||||
|
(5331.00, 0.0225, 13.33),
|
||||||
|
(11995.00, 0.0414, 73.29),
|
||||||
|
(19992.00, 0.0563, 349.19),
|
||||||
|
(26656.00, 0.0596, 799.41),
|
||||||
|
(39984.00, 0.0625, 1196.58),
|
||||||
|
(59976.00, 0.0744, 2029.58),
|
||||||
|
(float('inf'), 0.0853, 3516.98)
|
||||||
|
]
|
||||||
|
|
||||||
|
t3 = 0.0
|
||||||
|
last = 0.0
|
||||||
|
for row in tax_rate_table:
|
||||||
|
cap, rate, flat_fee = row
|
||||||
|
if cap > t2:
|
||||||
|
taxed_amount = t2 - last
|
||||||
|
t3 = flat_fee + (rate * taxed_amount)
|
||||||
|
break
|
||||||
|
last = cap
|
||||||
|
|
||||||
|
deduction_per_allowance = {
|
||||||
|
'daily': 0.15,
|
||||||
|
'weekly': 0.77,
|
||||||
|
'bi-weekly': 1.54,
|
||||||
|
'semi-monthly': 1.67,
|
||||||
|
'monthly': 3.33,
|
||||||
|
'annually': 40.00,
|
||||||
|
}
|
||||||
|
t4 = t3 - (deduction_per_allowance[schedule_pay] * allowances)
|
||||||
|
t5 = t4 + contract.ia_w4_additional_wh
|
||||||
|
result = -t5
|
||||||
|
</field>
|
||||||
|
<field name="register_id" ref="contrib_register_ia_dor_withhold"/>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
</odoo>
|
||||||
1
l10n_us_ia_hr_payroll/models/__init__.py
Normal file
1
l10n_us_ia_hr_payroll/models/__init__.py
Normal file
@@ -0,0 +1 @@
|
|||||||
|
from . import hr_payroll
|
||||||
9
l10n_us_ia_hr_payroll/models/hr_payroll.py
Executable file
9
l10n_us_ia_hr_payroll/models/hr_payroll.py
Executable file
@@ -0,0 +1,9 @@
|
|||||||
|
from odoo import models, fields, api
|
||||||
|
|
||||||
|
|
||||||
|
class USIAHrContract(models.Model):
|
||||||
|
_inherit = 'hr.contract'
|
||||||
|
|
||||||
|
ia_w4_allowances = fields.Integer(string='Iowa W-4 allowances', default=0)
|
||||||
|
ia_w4_additional_wh = fields.Float(string="Iowa Additional Withholding", default=0.0)
|
||||||
|
ia_w4_tax_exempt = fields.Boolean(string="Tax Exempt")
|
||||||
1
l10n_us_ia_hr_payroll/tests/__init__.py
Executable file
1
l10n_us_ia_hr_payroll/tests/__init__.py
Executable file
@@ -0,0 +1 @@
|
|||||||
|
from . import test_us_ia_payslip
|
||||||
192
l10n_us_ia_hr_payroll/tests/test_us_ia_payslip.py
Executable file
192
l10n_us_ia_hr_payroll/tests/test_us_ia_payslip.py
Executable file
@@ -0,0 +1,192 @@
|
|||||||
|
from odoo.addons.l10n_us_hr_payroll.tests.test_us_payslip import TestUsPayslip, process_payslip
|
||||||
|
from odoo.addons.l10n_us_hr_payroll.models.l10n_us_hr_payroll import USHrContract
|
||||||
|
|
||||||
|
|
||||||
|
class TestUsIAPayslip(TestUsPayslip):
|
||||||
|
IA_UNEMP_MAX_WAGE = 30600
|
||||||
|
IA_UNEMP = -1.0 / 100.0
|
||||||
|
IA_INC_TAX = -0.0535
|
||||||
|
|
||||||
|
def test_taxes_weekly(self):
|
||||||
|
wages = 30000.00
|
||||||
|
schedule_pay = 'weekly'
|
||||||
|
allowances = 1
|
||||||
|
additional_wh = 0.00
|
||||||
|
employee = self._createEmployee()
|
||||||
|
contract = self._createContract(employee, wages,
|
||||||
|
struct_id=self.ref('l10n_us_ia_hr_payroll.hr_payroll_salary_structure_us_ia_employee'),
|
||||||
|
schedule_pay=schedule_pay)
|
||||||
|
contract.ia_w4_allowances = allowances
|
||||||
|
contract.ia_w4_additional_wh = additional_wh
|
||||||
|
|
||||||
|
self.assertEqual(contract.schedule_pay, 'weekly')
|
||||||
|
|
||||||
|
self._log('2019 Iowa tax first payslip weekly:')
|
||||||
|
payslip = self._createPayslip(employee, '2019-01-01', '2019-01-31')
|
||||||
|
payslip.compute_sheet()
|
||||||
|
cats = self._getCategories(payslip)
|
||||||
|
|
||||||
|
# T1 is the gross taxable wages for the pay period minus the Federal withholding amount. We add the federal
|
||||||
|
# withholding amount because it is calculated in the base US payroll module as a negative
|
||||||
|
# t1 = 30000 - (10399.66) = 19600.34
|
||||||
|
t1_to_test = wages + cats['EE_US_FED_INC_WITHHOLD']
|
||||||
|
self.assertPayrollEqual(t1_to_test, 19600.34)
|
||||||
|
|
||||||
|
# T2 is T1 minus our standard deduction which is a table of flat rates dependent on the number of allowances.
|
||||||
|
# In our case, we have a weekly period which on the table has a std deduct. of $32.50 for 0 or 1 allowances,
|
||||||
|
# and 80.00 of 2 or more allowances.
|
||||||
|
standard_deduction = 32.50 # The allowance tells us what standard_deduction amount to use.
|
||||||
|
# t2 = 19600.34 - 32.50 = 19567.84
|
||||||
|
t2_to_test = t1_to_test - standard_deduction
|
||||||
|
self.assertPayrollEqual(t2_to_test, 19567.84)
|
||||||
|
# T3 is T2 multiplied by the income rates in the large table plus a flat fee for that bracket.
|
||||||
|
# 1153.38 is the bracket floor. 8.53 is the rate, and 67.63 is the flat fee.
|
||||||
|
# t3 = 1638.38
|
||||||
|
t3_to_test = ((t2_to_test - 1153.38) * (8.53 / 100)) + 67.63
|
||||||
|
self.assertPayrollEqual(t3_to_test, 1638.38)
|
||||||
|
# T4 is T3 minus a flat amount determined by pay period * the number of deductions. For 2019, our weekly
|
||||||
|
# deduction amount per allowance is 0.77
|
||||||
|
# t4 = 1638.38 - 0.77 = 155.03
|
||||||
|
t4_to_test = t3_to_test - (0.77 * allowances)
|
||||||
|
self.assertPayrollEqual(t4_to_test, 1637.61)
|
||||||
|
# t5 is our T4 plus the additional withholding per period
|
||||||
|
# t5 = 1637.61 + 0.0
|
||||||
|
# Convert to negative as well.
|
||||||
|
t5_to_test = -t4_to_test - additional_wh
|
||||||
|
self.assertPayrollEqual(t5_to_test, -1637.61)
|
||||||
|
|
||||||
|
self.assertPayrollEqual(cats['WAGE_US_IA_UNEMP'], wages)
|
||||||
|
self.assertPayrollEqual(cats['ER_US_IA_UNEMP'], cats['WAGE_US_IA_UNEMP'] * self.IA_UNEMP)
|
||||||
|
self.assertPayrollEqual(cats['EE_US_IA_INC_WITHHOLD'], t5_to_test)
|
||||||
|
|
||||||
|
# Test additional
|
||||||
|
additional_wh = 15.00
|
||||||
|
contract.ia_w4_additional_wh = additional_wh
|
||||||
|
payslip.compute_sheet()
|
||||||
|
cats = self._getCategories(payslip)
|
||||||
|
self.assertPayrollEqual(cats['EE_US_IA_INC_WITHHOLD'], t5_to_test - additional_wh)
|
||||||
|
|
||||||
|
process_payslip(payslip)
|
||||||
|
|
||||||
|
# Make a new payslip, this one will have maximums
|
||||||
|
|
||||||
|
remaining_IA_UNEMP_wages = self.IA_UNEMP_MAX_WAGE - wages if (self.IA_UNEMP_MAX_WAGE - 2*wages < wages) \
|
||||||
|
else wages
|
||||||
|
|
||||||
|
self._log('2019 Iowa tax second payslip weekly:')
|
||||||
|
payslip = self._createPayslip(employee, '2019-02-01', '2019-02-28')
|
||||||
|
payslip.compute_sheet()
|
||||||
|
cats = self._getCategories(payslip)
|
||||||
|
|
||||||
|
self.assertPayrollEqual(cats['WAGE_US_IA_UNEMP'], remaining_IA_UNEMP_wages)
|
||||||
|
self.assertPayrollEqual(cats['ER_US_IA_UNEMP'], remaining_IA_UNEMP_wages * self.IA_UNEMP)
|
||||||
|
|
||||||
|
def test_taxes_biweekly(self):
|
||||||
|
wages = 3000.00
|
||||||
|
schedule_pay = 'bi-weekly'
|
||||||
|
allowances = 1
|
||||||
|
additional_wh = 0.00
|
||||||
|
employee = self._createEmployee()
|
||||||
|
contract = self._createContract(employee, wages,
|
||||||
|
struct_id=self.ref(
|
||||||
|
'l10n_us_ia_hr_payroll.hr_payroll_salary_structure_us_ia_employee'),
|
||||||
|
schedule_pay=schedule_pay)
|
||||||
|
contract.ia_w4_allowances = allowances
|
||||||
|
contract.ia_w4_additional_wh = additional_wh
|
||||||
|
|
||||||
|
self.assertEqual(contract.schedule_pay, 'bi-weekly')
|
||||||
|
|
||||||
|
self._log('2019 Iowa tax first payslip bi-weekly:')
|
||||||
|
payslip = self._createPayslip(employee, '2019-01-01', '2019-01-31')
|
||||||
|
payslip.compute_sheet()
|
||||||
|
cats = self._getCategories(payslip)
|
||||||
|
|
||||||
|
# T1 is the gross taxable wages for the pay period minus the Federal withholding amount. We add the federal
|
||||||
|
# withholding amount because it is calculated in the base US payroll module as a negative
|
||||||
|
t1_to_test = wages + cats['EE_US_FED_INC_WITHHOLD']
|
||||||
|
# T2 is T1 minus our standard deduction which is a table of flat rates dependent on the number of allowances.
|
||||||
|
# In our case, we have a biweekly period which on the table has a std deduct. of $65.00 for 0 or 1 allowances,
|
||||||
|
# and $160.00 of 2 or more allowances.
|
||||||
|
standard_deduction = 65.00 # The allowance tells us what standard_deduction amount to use.
|
||||||
|
t2_to_test = t1_to_test - standard_deduction
|
||||||
|
# T3 is T2 multiplied by the income rates in the large table plus a flat fee for that bracket.
|
||||||
|
t3_to_test = ((t2_to_test - 2306.77) * (8.53 / 100)) + 135.28
|
||||||
|
# T4 is T3 minus a flat amount determined by pay period * the number of deductions. For 2019, our weekly
|
||||||
|
# deduction amount per allowance is 0.77
|
||||||
|
t4_to_test = t3_to_test - (1.54 * allowances)
|
||||||
|
# t5 is our T4 plus the additional withholding per period
|
||||||
|
t5_to_test = -t4_to_test - additional_wh
|
||||||
|
|
||||||
|
self.assertPayrollEqual(cats['WAGE_US_IA_UNEMP'], wages)
|
||||||
|
self.assertPayrollEqual(cats['ER_US_IA_UNEMP'], cats['WAGE_US_IA_UNEMP'] * self.IA_UNEMP)
|
||||||
|
self.assertPayrollEqual(cats['EE_US_IA_INC_WITHHOLD'], t5_to_test - additional_wh)
|
||||||
|
|
||||||
|
process_payslip(payslip)
|
||||||
|
|
||||||
|
def test_taxes_with_external_weekly(self):
|
||||||
|
wages = 2500.00
|
||||||
|
schedule_pay = 'weekly'
|
||||||
|
allowances = 1
|
||||||
|
additional_wh = 0.00
|
||||||
|
external_wages = 500.0
|
||||||
|
|
||||||
|
employee = self._createEmployee()
|
||||||
|
contract = self._createContract(employee, wages, external_wages=external_wages,
|
||||||
|
struct_id=self.ref('l10n_us_ia_hr_payroll.hr_payroll_salary_structure_us_ia_employee'),
|
||||||
|
schedule_pay=schedule_pay)
|
||||||
|
contract.ia_w4_additional_wh = additional_wh
|
||||||
|
contract.ia_w4_allowances = allowances
|
||||||
|
|
||||||
|
self._log('2019 Iowa external tax first payslip external weekly:')
|
||||||
|
payslip = self._createPayslip(employee, '2019-01-01', '2019-01-31')
|
||||||
|
payslip.compute_sheet()
|
||||||
|
cats = self._getCategories(payslip)
|
||||||
|
|
||||||
|
|
||||||
|
# T1 is the gross taxable wages for the pay period minus the Federal withholding amount. We add the federal
|
||||||
|
# withholding amount because it is calculated in the base US payroll module as a negative
|
||||||
|
t1_to_test = wages + cats['EE_US_FED_INC_WITHHOLD']
|
||||||
|
# T2 is T1 minus our standard deduction which is a table of flat rates dependent on the number of allowances.
|
||||||
|
# In our case, we have a weekly period which on the table has a std deduct. of $32.50 for 0 or 1 allowances,
|
||||||
|
# and 80.00 of 2 or more allowances.
|
||||||
|
standard_deduction = 32.50 # The allowance tells us what standard_deduction amount to use.
|
||||||
|
t2_to_test = t1_to_test - standard_deduction
|
||||||
|
# T3 is T2 multiplied by the income rates in the large table plus a flat fee for that bracket.
|
||||||
|
t3_to_test = ((t2_to_test - 1153.38) * (8.53 / 100)) + 67.63
|
||||||
|
# T4 is T3 minus a flat amount determined by pay period * the number of deductions. For 2019, our weekly
|
||||||
|
# deduction amount per allowance is 0.77
|
||||||
|
t4_to_test = t3_to_test - (0.77 * allowances)
|
||||||
|
# t5 is our T4 plus the additional withholding per period
|
||||||
|
t5_to_test = -t4_to_test - additional_wh
|
||||||
|
|
||||||
|
self.assertPayrollEqual(cats['WAGE_US_IA_UNEMP'], wages)
|
||||||
|
self.assertPayrollEqual(cats['ER_US_IA_UNEMP'], cats['WAGE_US_IA_UNEMP'] * self.IA_UNEMP)
|
||||||
|
self.assertPayrollEqual(cats['EE_US_IA_INC_WITHHOLD'], t5_to_test)
|
||||||
|
|
||||||
|
process_payslip(payslip)
|
||||||
|
|
||||||
|
def test_taxes_with_state_exempt_weekly(self):
|
||||||
|
salary = 5000.0
|
||||||
|
external_wages = 10000.0
|
||||||
|
schedule_pay = 'weekly'
|
||||||
|
|
||||||
|
employee = self._createEmployee()
|
||||||
|
contract = self._createContract(employee,
|
||||||
|
salary,
|
||||||
|
external_wages=external_wages,
|
||||||
|
struct_id=self.ref('l10n_us_ia_hr_payroll.hr_payroll_salary_structure_us_ia_employee'),
|
||||||
|
futa_type=USHrContract.FUTA_TYPE_BASIC,
|
||||||
|
schedule_pay=schedule_pay)
|
||||||
|
contract.ia_w4_tax_exempt = True
|
||||||
|
|
||||||
|
self._log('2019 Iowa exempt tax first payslip exempt weekly:')
|
||||||
|
payslip = self._createPayslip(employee, '2019-01-01', '2019-01-31')
|
||||||
|
payslip.compute_sheet()
|
||||||
|
cats = self._getCategories(payslip)
|
||||||
|
|
||||||
|
self.assertPayrollEqual(cats.get('WAGE_US_IA_UNEMP', 0.0), 0.0)
|
||||||
|
self.assertPayrollEqual(cats.get('ER_US_IA_UNEMP', 0.0), cats.get('WAGE_US_IA_UNEMP', 0.0) * self.IA_UNEMP)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
24
l10n_us_ia_hr_payroll/views/hr_payroll_views.xml
Executable file
24
l10n_us_ia_hr_payroll/views/hr_payroll_views.xml
Executable file
@@ -0,0 +1,24 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<odoo>
|
||||||
|
|
||||||
|
<data>
|
||||||
|
<record id="hr_contract_form_l10n_us_ia_inherit" model="ir.ui.view">
|
||||||
|
<field name="name">hr.contract.form.inherit</field>
|
||||||
|
<field name="model">hr.contract</field>
|
||||||
|
<field name="priority">119</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="Iowa" name="ia">
|
||||||
|
<field name="ia_w4_allowances" string="Allowances"/>
|
||||||
|
<field name="ia_w4_additional_wh" string="Additional Withholding"/>
|
||||||
|
<field name="ia_w4_tax_exempt" string="Tax Exempt"/>
|
||||||
|
</group>
|
||||||
|
</xpath>
|
||||||
|
</data>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
</data>
|
||||||
|
|
||||||
|
</odoo>
|
||||||
Reference in New Issue
Block a user