IMP l10n_us_hr_payroll Port l10n_us_wa_hr_payroll WA Washington including migration + FML rules

This commit is contained in:
Jared Kipe
2020-01-08 18:56:49 -08:00
parent 3896bec5f6
commit e2c73da402
17 changed files with 467 additions and 4 deletions

View File

@@ -32,6 +32,7 @@ USA Payroll Rules.
'data/state/mt_montana.xml', 'data/state/mt_montana.xml',
'data/state/oh_ohio.xml', 'data/state/oh_ohio.xml',
'data/state/pa_pennsylvania.xml', 'data/state/pa_pennsylvania.xml',
'data/state/wa_washington.xml',
'data/final.xml', 'data/final.xml',
'views/hr_contract_views.xml', 'views/hr_contract_views.xml',
'views/us_payroll_config_views.xml', 'views/us_payroll_config_views.xml',

View File

@@ -29,6 +29,12 @@
ref('hr_payroll_rule_ee_us_pa_suta'), ref('hr_payroll_rule_ee_us_pa_suta'),
ref('hr_payroll_rule_ee_us_pa_sit'), ref('hr_payroll_rule_ee_us_pa_sit'),
ref('hr_payroll_rule_er_us_wa_suta'),
ref('hr_payroll_rule_er_us_wa_fml'),
ref('hr_payroll_rule_ee_us_wa_fml'),
ref('hr_payroll_rule_er_us_wa_lni'),
ref('hr_payroll_rule_ee_us_wa_lni'),
ref('hr_salary_rule_commission'), ref('hr_salary_rule_commission'),
ref('hr_salary_rule_gamification'), ref('hr_salary_rule_gamification'),
])]" name="rule_ids"/> ])]" name="rule_ids"/>

View File

@@ -0,0 +1,203 @@
<?xml version="1.0" encoding="UTF-8" ?>
<odoo>
<!-- Wage Base -->
<data noupdate="1">
<record id="rule_parameter_us_wa_suta_wage_base_2019" model="hr.payroll.rate">
<field name="name">US WA Washington SUTA Wage Base</field>
<field name="code">us_wa_suta_wage_base</field>
<field name="parameter_value">49800.0</field>
<field name="date_from" eval="datetime(2019, 1, 1).date()"/>
</record>
<record id="rule_parameter_us_wa_suta_wage_base_2020" model="hr.payroll.rate">
<field name="name">US WA Washington SUTA Wage Base</field>
<field name="code">us_wa_suta_wage_base</field>
<field name="parameter_value">52700.00</field>
<field name="date_from" eval="datetime(2020, 1, 1).date()"/>
</record>
</data>
<data noupdate="1">
<record id="rule_parameter_us_wa_fml_wage_base_2019" model="hr.payroll.rate">
<field name="name">US WA Washington FML Wage Base</field>
<field name="code">us_wa_fml_wage_base</field>
<field name="parameter_value">132900.00</field>
<field name="date_from" eval="datetime(2019, 1, 1).date()"/>
</record>
<record id="rule_parameter_us_wa_fml_wage_base_2020" model="hr.payroll.rate">
<field name="name">US WA Washington FML Wage Base</field>
<field name="code">us_wa_fml_wage_base</field>
<field name="parameter_value">137700.00</field>
<field name="date_from" eval="datetime(2020, 1, 1).date()"/>
</record>
</data>
<!-- Rate -->
<data noupdate="1">
<record id="rule_parameter_us_wa_suta_rate_2019" model="hr.payroll.rate">
<field name="name">US WA Washington SUTA Rate</field>
<field name="code">us_wa_suta_rate</field>
<field name="parameter_value">1.18</field>
<field name="date_from" eval="datetime(2019, 1, 1).date()"/>
</record>
<record id="rule_parameter_us_wa_suta_rate_2020" model="hr.payroll.rate">
<field name="name">US WA Washington SUTA Rate</field>
<field name="code">us_wa_suta_rate</field>
<field name="parameter_value">1.0</field>
<field name="date_from" eval="datetime(2020, 1, 1).date()"/>
</record>
</data>
<data noupdate="1">
<record id="rule_parameter_us_wa_fml_rate_2019" model="hr.payroll.rate">
<field name="name">US WA Washington FML Rate (Total)</field>
<field name="code">us_wa_fml_rate</field>
<field name="parameter_value">0.4</field>
<field name="date_from" eval="datetime(2019, 1, 1).date()"/>
</record>
<record id="rule_parameter_us_wa_fml_rate_2020" model="hr.payroll.rate">
<field name="name">US WA Washington FML Rate (Total)</field>
<field name="code">us_wa_fml_rate</field>
<field name="parameter_value">0.4</field>
<field name="date_from" eval="datetime(2020, 1, 1).date()"/>
</record>
</data>
<data noupdate="1">
<record id="rule_parameter_us_wa_fml_rate_ee_2019" model="hr.payroll.rate">
<field name="name">US WA Washington FML Rate (Employee)</field>
<field name="code">us_wa_fml_rate_ee</field>
<field name="parameter_value">66.33</field>
<field name="date_from" eval="datetime(2019, 1, 1).date()"/>
</record>
<record id="rule_parameter_us_wa_fml_rate_ee_2020" model="hr.payroll.rate">
<field name="name">US WA Washington FML Rate (Employee)</field>
<field name="code">us_wa_fml_rate_ee</field>
<field name="parameter_value">66.33</field>
<field name="date_from" eval="datetime(2020, 1, 1).date()"/>
</record>
</data>
<data noupdate="1">
<record id="rule_parameter_us_wa_fml_rate_er_2019" model="hr.payroll.rate">
<field name="name">US WA Washington FML Rate (Employer)</field>
<field name="code">us_wa_fml_rate_er</field>
<field name="parameter_value">33.67</field>
<field name="date_from" eval="datetime(2019, 1, 1).date()"/>
</record>
<record id="rule_parameter_us_wa_fml_rate_er_2020" model="hr.payroll.rate">
<field name="name">US WA Washington FML Rate (Employer)</field>
<field name="code">us_wa_fml_rate_er</field>
<field name="parameter_value">33.67</field>
<field name="date_from" eval="datetime(2020, 1, 1).date()"/>
</record>
</data>
<!-- Partners and Contribution Registers -->
<record id="res_partner_us_wa_dor" model="res.partner">
<field name="name">US Washington - Employment Security Department (Unemployment)</field>
</record>
<record id="contrib_register_us_wa_dor" model="hr.contribution.register">
<field name="name">US Washington - Employment Security Department (Unemployment)</field>
<field name="partner_id" ref="res_partner_us_wa_dor"/>
</record>
<record id="res_partner_us_wa_dor_lni" model="res.partner">
<field name="name">US Washington - Department of Labor &amp; Industries</field>
</record>
<record id="contrib_register_us_wa_dor_lni" model="hr.contribution.register">
<field name="name">US Washington - Department of Labor &amp; Industries</field>
<field name="partner_id" ref="res_partner_us_wa_dor_lni"/>
</record>
<record id="res_partner_us_wa_dor_fml" model="res.partner">
<field name="name">US Washington - Employment Security Department (PFML)</field>
</record>
<record id="contrib_register_us_wa_dor_fml" model="hr.contribution.register">
<field name="name">US Washington - Employment Security Department (PFML)</field>
<field name="partner_id" ref="res_partner_us_wa_dor_fml"/>
</record>
<!-- Categories -->
<!-- Rules -->
<record id="hr_payroll_rule_er_us_wa_suta" model="hr.salary.rule">
<field name="sequence" eval="450"/>
<field name="category_id" ref="hr_payroll_category_er_us_suta"/>
<field name="name">ER: US WA Washington State Unemployment (5208A/B)</field>
<field name="code">ER_US_WA_SUTA</field>
<field name="condition_select">python</field>
<field name="condition_python">result, _ = general_state_unemployment(payslip, categories, worked_days, inputs, wage_base='us_wa_suta_wage_base', rate='us_wa_suta_rate', state_code='WA')</field>
<field name="amount_select">code</field>
<field name="amount_python_compute">result, result_rate = general_state_unemployment(payslip, categories, worked_days, inputs, wage_base='us_wa_suta_wage_base', rate='us_wa_suta_rate', state_code='WA')</field>
<field name="register_id" ref="contrib_register_us_wa_dor"/>
<field name="appears_on_payslip" eval="False"/>
</record>
<record id="hr_payroll_rule_er_us_wa_fml" model="hr.salary.rule">
<field name="sequence" eval="451"/>
<field name="category_id" ref="hr_payroll.COMP"/>
<field name="name">ER: US WA Washington State Family Medical Leave</field>
<field name="code">ER_US_WA_FML</field>
<field name="condition_select">python</field>
<field name="condition_python">result, _ = wa_washington_fml_er(payslip, categories, worked_days, inputs)</field>
<field name="amount_select">code</field>
<field name="amount_python_compute">result, result_rate = wa_washington_fml_er(payslip, categories, worked_days, inputs)</field>
<field name="register_id" ref="contrib_register_us_wa_dor_fml"/>
<field name="appears_on_payslip" eval="False"/>
</record>
<record id="hr_payroll_rule_ee_us_wa_fml" model="hr.salary.rule">
<field name="sequence" eval="196"/>
<field name="category_id" ref="hr_payroll.DED"/>
<field name="name">EE: US WA Washington State Family Medical Leave</field>
<field name="code">EE_US_WA_FML</field>
<field name="condition_select">python</field>
<field name="condition_python">result, _ = wa_washington_fml_ee(payslip, categories, worked_days, inputs)</field>
<field name="amount_select">code</field>
<field name="amount_python_compute">result, result_rate = wa_washington_fml_ee(payslip, categories, worked_days, inputs)</field>
<field name="register_id" ref="contrib_register_us_wa_dor_fml"/>
<field name="appears_on_payslip" eval="True"/>
</record>
<!-- LNI May need to be updated depending on hours worked (or drywall laid) -->
<record id="hr_payroll_rule_er_us_wa_lni" model="hr.salary.rule">
<field name="sequence" eval="451"/>
<field name="category_id" ref="hr_payroll.COMP"/>
<field name="name">ER: US WA Washington State LNI</field>
<field name="code">ER_US_WA_LNI</field>
<field name="condition_select">python</field>
<field name="condition_python">result = is_us_state(payslip, 'WA') and payslip.contract_id.us_payroll_config_value('workers_comp_er_code') and worked_days.WORK100 and worked_days.WORK100.number_of_hours and payslip.dict.rule_parameter(payslip.contract_id.us_payroll_config_value('workers_comp_er_code'))</field>
<field name="amount_select">code</field>
<field name="amount_python_compute">
hours = worked_days.WORK100.number_of_hours
rate = payslip.dict.rule_parameter(payslip.contract_id.us_payroll_config_value('workers_comp_er_code'))
try:
# Redo employee withholding calculation
ee_withholding = worked_days.WORK100.number_of_hours * -payslip.dict.rule_parameter(payslip.contract_id.us_payroll_config_value('workers_comp_ee_code')) / 100.0
except:
ee_withholding = 0.0
er_withholding = -(hours * (rate / 100.0)) - ee_withholding
result = hours
result_rate = (er_withholding / hours) * 100.0
</field>
<field name="register_id" ref="contrib_register_us_wa_dor_lni"/>
<field name="appears_on_payslip" eval="False"/>
</record>
<record id="hr_payroll_rule_ee_us_wa_lni" model="hr.salary.rule">
<field name="sequence" eval="196"/>
<field name="category_id" ref="hr_payroll.DED"/>
<field name="name">EE: US WA Washington State LNI</field>
<field name="code">EE_US_WA_LNI</field>
<field name="condition_select">python</field>
<field name="condition_python">result = is_us_state(payslip, 'WA') and payslip.contract_id.us_payroll_config_value('workers_comp_ee_code') and worked_days.WORK100 and worked_days.WORK100.number_of_hours and payslip.dict.rule_parameter(payslip.contract_id.us_payroll_config_value('workers_comp_ee_code'))</field>
<field name="amount_select">code</field>
<field name="amount_python_compute">result, result_rate = worked_days.WORK100.number_of_hours, -payslip.dict.rule_parameter(payslip.contract_id.us_payroll_config_value('workers_comp_ee_code'))</field>
<field name="register_id" ref="contrib_register_us_wa_dor_lni"/>
<field name="appears_on_payslip" eval="True"/>
</record>
</odoo>

View File

@@ -58,6 +58,13 @@ XMLIDS_TO_REMOVE_2020 = [
'l10n_us_pa_hr_payroll.hr_payroll_pa_withhold', 'l10n_us_pa_hr_payroll.hr_payroll_pa_withhold',
'l10n_us_pa_hr_payroll.hr_payroll_rules_pa_unemp_wages_2018', 'l10n_us_pa_hr_payroll.hr_payroll_rules_pa_unemp_wages_2018',
'l10n_us_pa_hr_payroll.hr_payroll_rules_pa_inc_withhold_add', 'l10n_us_pa_hr_payroll.hr_payroll_rules_pa_inc_withhold_add',
'l10n_us_wa_hr_payroll.hr_payroll_wa_unemp_wages',
'l10n_us_wa_hr_payroll.hr_payroll_wa_unemp',
'l10n_us_wa_hr_payroll.hr_payroll_wa_lni',
'l10n_us_wa_hr_payroll.hr_payroll_wa_lni_withhold',
'l10n_us_wa_hr_payroll.hr_payroll_rules_wa_unemp_wages_2018',
] ]
XMLIDS_TO_RENAME_2020 = { XMLIDS_TO_RENAME_2020 = {
@@ -100,10 +107,24 @@ XMLIDS_TO_RENAME_2020 = {
'l10n_us_pa_hr_payroll.hr_payroll_rules_pa_unemp_company_2018': 'l10n_us_hr_payroll.hr_payroll_rule_er_us_pa_suta', 'l10n_us_pa_hr_payroll.hr_payroll_rules_pa_unemp_company_2018': 'l10n_us_hr_payroll.hr_payroll_rule_er_us_pa_suta',
'l10n_us_pa_hr_payroll.hr_payroll_rules_pa_inc_withhold_2018': 'l10n_us_hr_payroll.hr_payroll_rule_ee_us_pa_sit', 'l10n_us_pa_hr_payroll.hr_payroll_rules_pa_inc_withhold_2018': 'l10n_us_hr_payroll.hr_payroll_rule_ee_us_pa_sit',
'l10n_us_wa_hr_payroll.res_partner_wador_unemp': 'l10n_us_hr_payroll.res_partner_us_wa_dor',
'l10n_us_wa_hr_payroll.res_partner_wador_lni': 'l10n_us_hr_payroll.res_partner_us_wa_dor_lni',
'l10n_us_wa_hr_payroll.contrib_register_wador_unemp': 'l10n_us_hr_payroll.contrib_register_us_wa_dor',
'l10n_us_wa_hr_payroll.contrib_register_wador_lni': 'l10n_us_hr_payroll.contrib_register_us_wa_dor_lni',
'l10n_us_wa_hr_payroll.hr_payroll_rules_wa_unemp_2018': 'l10n_us_hr_payroll.hr_payroll_rule_er_us_wa_suta',
'l10n_us_wa_hr_payroll.hr_payroll_rules_wa_lni_withhold': 'l10n_us_hr_payroll.hr_payroll_rule_ee_us_wa_lni',
'l10n_us_wa_hr_payroll.hr_payroll_rules_wa_lni': 'l10n_us_hr_payroll.hr_payroll_rule_er_us_wa_lni',
} }
XMLIDS_COPY_ACCOUNTING_2020 = { XMLIDS_COPY_ACCOUNTING_2020 = {
'l10n_us_hr_payroll.hr_payroll_rule_er_us_mt_suta': [ 'l10n_us_hr_payroll.hr_payroll_rule_er_us_mt_suta': [
'l10n_us_hr_payroll.hr_payroll_rule_er_us_mt_suta_aft', 'l10n_us_hr_payroll.hr_payroll_rule_er_us_mt_suta_aft',
], ],
'l10n_us_hr_payroll.hr_payroll_rule_er_us_wa_lni': [
'l10n_us_hr_payroll.hr_payroll_rule_er_us_wa_fml',
],
'l10n_us_hr_payroll.hr_payroll_rule_ee_us_wa_lni': [
'l10n_us_hr_payroll.hr_payroll_rule_ee_us_wa_fml',
],
} }

View File

@@ -10,9 +10,12 @@ from .federal.fed_941 import ee_us_941_fica_ss, \
er_us_941_fica_m, \ er_us_941_fica_m, \
ee_us_941_fit ee_us_941_fit
from .state.general import general_state_unemployment, \ from .state.general import general_state_unemployment, \
general_state_income_withholding general_state_income_withholding, \
is_us_state
from .state.mt_montana import mt_montana_state_income_withholding from .state.mt_montana import mt_montana_state_income_withholding
from .state.oh_ohio import oh_ohio_state_income_withholding from .state.oh_ohio import oh_ohio_state_income_withholding
from .state.wa_washington import wa_washington_fml_er, \
wa_washington_fml_ee
class HRPayslip(models.Model): class HRPayslip(models.Model):
@@ -44,8 +47,11 @@ class HRPayslip(models.Model):
'ee_us_941_fit': ee_us_941_fit, 'ee_us_941_fit': ee_us_941_fit,
'general_state_unemployment': general_state_unemployment, 'general_state_unemployment': general_state_unemployment,
'general_state_income_withholding': general_state_income_withholding, 'general_state_income_withholding': general_state_income_withholding,
'is_us_state': is_us_state,
'mt_montana_state_income_withholding': mt_montana_state_income_withholding, 'mt_montana_state_income_withholding': mt_montana_state_income_withholding,
'oh_ohio_state_income_withholding': oh_ohio_state_income_withholding, 'oh_ohio_state_income_withholding': oh_ohio_state_income_withholding,
'wa_washington_fml_er': wa_washington_fml_er,
'wa_washington_fml_ee': wa_washington_fml_ee,
} }
def get_year(self): def get_year(self):

View File

@@ -9,6 +9,10 @@ def _state_applies(payslip, state_code):
return state_code == payslip.dict.contract_id.us_payroll_config_value('state_code') return state_code == payslip.dict.contract_id.us_payroll_config_value('state_code')
# Export for eval context
is_us_state = _state_applies
def _general_rate(payslip, wage, ytd_wage, wage_base=None, wage_start=None, rate=None): def _general_rate(payslip, wage, ytd_wage, wage_base=None, wage_start=None, rate=None):
""" """
Function parameters: Function parameters:

View File

@@ -1,3 +1,5 @@
# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details.
from .general import _state_applies from .general import _state_applies

View File

@@ -1,3 +1,5 @@
# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details.
from .general import _state_applies from .general import _state_applies

View File

@@ -0,0 +1,27 @@
# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details.
from .general import _state_applies, _general_rate
def _wa_washington_fml(payslip, categories, worked_days, inputs, inner_rate=None):
if not inner_rate:
return 0.0, 0.0
if not _state_applies(payslip, 'WA'):
return 0.0, 0.0
wage = categories.GROSS
year = payslip.dict.get_year()
ytd_wage = payslip.sum_category('GROSS', str(year) + '-01-01', str(year + 1) + '-01-01')
ytd_wage += payslip.contract_id.external_wages
rate = payslip.dict.rule_parameter('us_wa_fml_rate')
rate *= payslip.dict.rule_parameter(inner_rate) / 100.0
return _general_rate(payslip, wage, ytd_wage, wage_base='us_wa_fml_wage_base', rate=rate)
def wa_washington_fml_er(payslip, categories, worked_days, inputs):
return _wa_washington_fml(payslip, categories, worked_days, inputs, inner_rate='us_wa_fml_rate_er')
def wa_washington_fml_ee(payslip, categories, worked_days, inputs):
return _wa_washington_fml(payslip, categories, worked_days, inputs, inner_rate='us_wa_fml_rate_ee')

View File

@@ -17,6 +17,10 @@ class HRContractUSPayrollConfig(models.Model):
state_code = fields.Char(related='state_id.code') state_code = fields.Char(related='state_id.code')
state_income_tax_exempt = fields.Boolean(string='State Income Tax Exempt') state_income_tax_exempt = fields.Boolean(string='State Income Tax Exempt')
state_income_tax_additional_withholding = fields.Float(string='State Income Tax Additional Withholding') state_income_tax_additional_withholding = fields.Float(string='State Income Tax Additional Withholding')
workers_comp_ee_code = fields.Char(string='Workers\' Comp Code (Employee Withholding)',
help='Code for a Payroll Rate, used by some states or your own rules.')
workers_comp_er_code = fields.Char(string='Workers\' Comp Code (Employer Withholding)',
help='Code for a Payroll Rate, used by some states or your own rules.')
fed_940_type = fields.Selection([ fed_940_type = fields.Selection([
(FUTA_TYPE_EXEMPT, 'Exempt (0%)'), (FUTA_TYPE_EXEMPT, 'Exempt (0%)'),

View File

@@ -15,3 +15,6 @@ from . import test_us_oh_ohio_payslip_2020
from . import test_us_pa_pennsylvania_payslip_2019 from . import test_us_pa_pennsylvania_payslip_2019
from . import test_us_pa_pennsylvania_payslip_2020 from . import test_us_pa_pennsylvania_payslip_2020
from . import test_us_wa_washington_payslip_2019
from . import test_us_wa_washington_payslip_2020

View File

@@ -151,6 +151,9 @@ class TestUsPayslip(common.TransactionCase):
def assertPayrollEqual(self, first, second): def assertPayrollEqual(self, first, second):
self.assertAlmostEqual(first, second, self.payroll_digits) self.assertAlmostEqual(first, second, self.payroll_digits)
def assertPayrollAlmostEqual(self, first, second):
self.assertAlmostEqual(first, second, self.payroll_digits-1)
def test_semi_monthly(self): def test_semi_monthly(self):
salary = 80000.0 salary = 80000.0
employee = self._createEmployee() employee = self._createEmployee()

View File

@@ -34,7 +34,7 @@ class TestUsOhPayslip(TestUsPayslip):
cats = self._getCategories(payslip) cats = self._getCategories(payslip)
self.assertPayrollEqual(cats['ER_US_SUTA'], salary * self.OH_UNEMP) self.assertPayrollEqual(cats['ER_US_SUTA'], salary * self.OH_UNEMP)
self.assertAlmostEqual(cats['EE_US_SIT'], -wd, 1) # Off by 0.6 cents so it rounds off by a penny self.assertPayrollAlmostEqual(cats['EE_US_SIT'], -wd) # Off by 0.6 cents so it rounds off by a penny
#self.assertPayrollEqual(cats['EE_US_SIT'], -wd) #self.assertPayrollEqual(cats['EE_US_SIT'], -wd)
process_payslip(payslip) process_payslip(payslip)

View File

@@ -48,7 +48,7 @@ class TestUsOhPayslip(TestUsPayslip):
payslip.compute_sheet() payslip.compute_sheet()
cats = self._getCategories(payslip) cats = self._getCategories(payslip)
# Instead of PayrollEqual after initial first round of testing. # Instead of PayrollEqual after initial first round of testing.
self.assertAlmostEqual(cats.get('EE_US_SIT', 0.0), -expected, 1) self.assertPayrollAlmostEqual(cats.get('EE_US_SIT', 0.0), -expected)
return payslip return payslip
def test_2020_sit_1(self): def test_2020_sit_1(self):

View File

@@ -0,0 +1,88 @@
# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details.
from datetime import date
from .common import TestUsPayslip, process_payslip
class TestUsWAPayslip(TestUsPayslip):
###
# Taxes and Rates
###
WA_UNEMP_MAX_WAGE = 49800.0
WA_UNEMP_RATE = 1.18
WA_FML_RATE = 0.4
WA_FML_RATE_EE = 66.33
WA_FML_RATE_ER = 33.67
def setUp(self):
super(TestUsWAPayslip, self).setUp()
# self.lni = self.env['hr.contract.lni.wa'].create({
# 'name': '5302 Computer Consulting',
# 'rate': 0.1261,
# 'rate_emp_withhold': 0.05575,
# })
self.test_ee_lni = 0.05575 # per 100 hours
self.test_er_lni = 0.1261 # per 100 hours
self.parameter_lni_ee = self.env['hr.payroll.rate'].create({
'name': 'Test LNI EE',
'code': 'test_lni_ee',
'date_from': date(2019, 1, 1),
'parameter_value': str(self.test_ee_lni * 100),
})
self.parameter_lni_er = self.env['hr.payroll.rate'].create({
'name': 'Test LNI ER',
'code': 'test_lni_er',
'date_from': date(2019, 1, 1),
'parameter_value': str(self.test_er_lni * 100),
})
def test_2019_taxes(self):
salary = 25000.0
employee = self._createEmployee()
contract = self._createContract(employee,
wage=salary,
state_id=self.get_us_state('WA'),
workers_comp_ee_code=self.parameter_lni_ee.code,
workers_comp_er_code=self.parameter_lni_er.code,
)
self._log(str(contract.resource_calendar_id) + ' ' + contract.resource_calendar_id.name)
# tax rates
wa_unemp = self.WA_UNEMP_RATE / -100.0
self._log('2019 Washington tax first payslip:')
payslip = self._createPayslip(employee, '2019-01-01', '2019-01-31')
hours_in_period = payslip.worked_days_line_ids.filtered(lambda l: l.code == 'WORK100').number_of_hours
self.assertEqual(hours_in_period, 184) # only asserted to test algorithm
payslip.compute_sheet()
cats = self._getCategories(payslip)
rules = self._getRules(payslip)
self.assertPayrollEqual(cats['ER_US_SUTA'], salary * wa_unemp)
self.assertPayrollEqual(rules['EE_US_WA_LNI'], -(self.test_ee_lni * hours_in_period))
self.assertPayrollEqual(rules['ER_US_WA_LNI'], -(self.test_er_lni * hours_in_period) - rules['EE_US_WA_LNI'])
# Both of these are known to be within 1 penny
self.assertPayrollAlmostEqual(rules['EE_US_WA_FML'], -(salary * (self.WA_FML_RATE / 100.0) * (self.WA_FML_RATE_EE / 100.0)))
self.assertPayrollAlmostEqual(rules['ER_US_WA_FML'], -(salary * (self.WA_FML_RATE / 100.0) * (self.WA_FML_RATE_ER / 100.0)))
# FML
process_payslip(payslip)
# Make a new payslip, this one will have maximums
remaining_wa_unemp_wages = self.WA_UNEMP_MAX_WAGE - salary if (self.WA_UNEMP_MAX_WAGE - 2*salary < salary) \
else salary
self._log('2019 Washington tax second payslip:')
payslip = self._createPayslip(employee, '2019-02-01', '2019-02-28')
payslip.compute_sheet()
cats = self._getCategories(payslip)
self.assertPayrollEqual(cats['ER_US_SUTA'], remaining_wa_unemp_wages * wa_unemp)

View File

@@ -0,0 +1,86 @@
# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details.
from datetime import date
from .common import TestUsPayslip, process_payslip
class TestUsWAPayslip(TestUsPayslip):
###
# Taxes and Rates
###
WA_UNEMP_MAX_WAGE = 52700.00
WA_UNEMP_RATE = 1.0
WA_FML_MAX_WAGE = 137700.00
WA_FML_RATE = 0.4
WA_FML_RATE_EE = 66.33
WA_FML_RATE_ER = 33.67
def setUp(self):
super(TestUsWAPayslip, self).setUp()
# self.lni = self.env['hr.contract.lni.wa'].create({
# 'name': '5302 Computer Consulting',
# 'rate': 0.1261,
# 'rate_emp_withhold': 0.05575,
# })
self.test_ee_lni = 0.05575 # per 100 hours
self.test_er_lni = 0.1261 # per 100 hours
self.parameter_lni_ee = self.env['hr.payroll.rate'].create({
'name': 'Test LNI EE',
'code': 'test_lni_ee',
'date_from': date(2019, 1, 1),
'parameter_value': str(self.test_ee_lni * 100),
})
self.parameter_lni_er = self.env['hr.payroll.rate'].create({
'name': 'Test LNI ER',
'code': 'test_lni_er',
'date_from': date(2019, 1, 1),
'parameter_value': str(self.test_er_lni * 100),
})
def test_2020_taxes(self):
self._test_er_suta('WA', self.WA_UNEMP_RATE, date(2020, 1, 1), wage_base=self.WA_UNEMP_MAX_WAGE)
salary = (self.WA_FML_MAX_WAGE / 2.0) + 1000.0
employee = self._createEmployee()
contract = self._createContract(employee,
wage=salary,
state_id=self.get_us_state('WA'),
workers_comp_ee_code=self.parameter_lni_ee.code,
workers_comp_er_code=self.parameter_lni_er.code,
)
self._log(str(contract.resource_calendar_id) + ' ' + contract.resource_calendar_id.name)
# Non SUTA
self._log('2020 Washington tax first payslip:')
payslip = self._createPayslip(employee, '2020-01-01', '2020-01-31')
hours_in_period = payslip.worked_days_line_ids.filtered(lambda l: l.code == 'WORK100').number_of_hours
self.assertEqual(hours_in_period, 184) # only asserted to test algorithm
payslip.compute_sheet()
rules = self._getRules(payslip)
self.assertPayrollEqual(rules['EE_US_WA_LNI'], -(self.test_ee_lni * hours_in_period))
self.assertPayrollEqual(rules['ER_US_WA_LNI'], -(self.test_er_lni * hours_in_period) - rules['EE_US_WA_LNI'])
# Both of these are known to be within 1 penny
self.assertPayrollAlmostEqual(rules['EE_US_WA_FML'], -(salary * (self.WA_FML_RATE / 100.0) * (self.WA_FML_RATE_EE / 100.0)))
self.assertPayrollAlmostEqual(rules['ER_US_WA_FML'], -(salary * (self.WA_FML_RATE / 100.0) * (self.WA_FML_RATE_ER / 100.0)))
process_payslip(payslip)
# Second payslip
remaining_wage = self.WA_FML_MAX_WAGE - salary
payslip = self._createPayslip(employee, '2020-03-01', '2020-03-31')
payslip.compute_sheet()
rules = self._getRules(payslip)
self.assertPayrollAlmostEqual(rules['EE_US_WA_FML'], -(remaining_wage * (self.WA_FML_RATE / 100.0) * (self.WA_FML_RATE_EE / 100.0)))
self.assertPayrollAlmostEqual(rules['ER_US_WA_FML'], -(remaining_wage * (self.WA_FML_RATE / 100.0) * (self.WA_FML_RATE_ER / 100.0)))
process_payslip(payslip)
# Third payslip
payslip = self._createPayslip(employee, '2020-04-01', '2020-04-30')
payslip.compute_sheet()
rules = self._getRules(payslip)
self.assertPayrollAlmostEqual(rules['EE_US_WA_FML'], 0.0)
self.assertPayrollAlmostEqual(rules['ER_US_WA_FML'], 0.0)

View File

@@ -26,7 +26,6 @@
</group> </group>
<group> <group>
<group name="federal" string="Federal"> <group name="federal" string="Federal">
<field name="state_id" domain="[('country_id', '=', %(base.us)s)]" options="{'no_create': True}"/>
<p colspan="2"><h3>Form 940 - Federal Unemployment</h3></p> <p colspan="2"><h3>Form 940 - Federal Unemployment</h3></p>
<field name="fed_940_type" string="Federal Unemployment Rate"/> <field name="fed_940_type" string="Federal Unemployment Rate"/>
<p colspan="2"><h3>Form 941 / W4 - Federal Income Tax</h3></p> <p colspan="2"><h3>Form 941 / W4 - Federal Income Tax</h3></p>
@@ -39,6 +38,10 @@
<field name="fed_941_fit_w4_other_income" string="Other Income"/> <field name="fed_941_fit_w4_other_income" string="Other Income"/>
<field name="fed_941_fit_w4_deductions" string="Deductions"/> <field name="fed_941_fit_w4_deductions" string="Deductions"/>
<field name="fed_941_fit_w4_additional_withholding" string="Additional Withholding"/> <field name="fed_941_fit_w4_additional_withholding" string="Additional Withholding"/>
<p colspan="2"><h3>State Information and Extra</h3></p>
<field name="state_id" domain="[('country_id', '=', %(base.us)s)]" options="{'no_create': True}"/>
<field name="workers_comp_ee_code"/>
<field name="workers_comp_er_code"/>
</group> </group>
<group name="state_fl_florida" string="FL Florida" attrs="{'invisible':[('state_id', '!=', %(base.state_us_10)s)]}"> <group name="state_fl_florida" string="FL Florida" attrs="{'invisible':[('state_id', '!=', %(base.state_us_10)s)]}">
@@ -60,6 +63,10 @@
<field name="state_income_tax_exempt"/> <field name="state_income_tax_exempt"/>
<field name="state_income_tax_additional_withholding"/> <field name="state_income_tax_additional_withholding"/>
</group> </group>
<group name="state_wa_washington" string="WA Washington" attrs="{'invisible':[('state_id', '!=', %(base.state_us_48)s)]}">
<p colspan="2"><h3>No additional fields.</h3></p>
<p colspan="2">Ensure that your Employee and Employer workers' comp code fields are filled in for WA LNI withholding.</p>
</group>
</group> </group>
</sheet> </sheet>
</form> </form>