mirror of
https://gitlab.com/hibou-io/hibou-odoo/suite.git
synced 2025-01-20 12:37:31 +02:00
Merge branch 'mig/12.0/l10n_us_hr_payroll__2020' into '12.0-test'
mig/12.0/l10n_us_hr_payroll__2020 into 12.0-test See merge request hibou-io/hibou-odoo/suite!273
This commit is contained in:
@@ -31,6 +31,7 @@ USA Payroll Rules.
|
||||
'data/state/fl_florida.xml',
|
||||
'data/state/ga_georgia.xml',
|
||||
'data/state/mi_michigan.xml',
|
||||
'data/state/mn_minnesota.xml',
|
||||
'data/state/mo_missouri.xml',
|
||||
'data/state/ms_mississippi.xml',
|
||||
'data/state/mt_montana.xml',
|
||||
|
||||
@@ -21,6 +21,9 @@
|
||||
ref('hr_payroll_rule_er_us_ga_suta'),
|
||||
ref('hr_payroll_rule_ee_us_ga_sit'),
|
||||
|
||||
ref('hr_payroll_rule_er_us_mn_suta'),
|
||||
ref('hr_payroll_rule_ee_us_mn_sit'),
|
||||
|
||||
ref('hr_payroll_rule_er_us_mi_suta'),
|
||||
ref('hr_payroll_rule_ee_us_mi_sit'),
|
||||
|
||||
|
||||
137
l10n_us_hr_payroll/data/state/mn_minnesota.xml
Normal file
137
l10n_us_hr_payroll/data/state/mn_minnesota.xml
Normal file
@@ -0,0 +1,137 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<odoo>
|
||||
<!-- Wage Base -->
|
||||
<data noupdate="1">
|
||||
<record id="rule_parameter_us_mn_suta_wage_base_2019" model="hr.payroll.rate">
|
||||
<field name="name">US MN Minnesota SUTA Wage Base</field>
|
||||
<field name="code">us_mn_suta_wage_base</field>
|
||||
<field name="parameter_value">34000.0</field>
|
||||
<field name="date_from" eval="datetime(2019, 1, 1).date()"/>
|
||||
</record>
|
||||
<record id="rule_parameter_us_mn_suta_wage_base_2020" model="hr.payroll.rate">
|
||||
<field name="name">US MN Minnesota SUTA Wage Base</field>
|
||||
<field name="code">us_mn_suta_wage_base</field>
|
||||
<field name="parameter_value">35000.0</field>
|
||||
<field name="date_from" eval="datetime(2020, 1, 1).date()"/>
|
||||
</record>
|
||||
</data>
|
||||
|
||||
<!-- Rate -->
|
||||
<data noupdate="1">
|
||||
<record id="rule_parameter_us_mn_suta_rate_2019" model="hr.payroll.rate">
|
||||
<field name="name">US MN Minnesota SUTA Rate</field>
|
||||
<field name="code">us_mn_suta_rate</field>
|
||||
<field name="parameter_value">1.11</field>
|
||||
<field name="date_from" eval="datetime(2019, 1, 1).date()"/>
|
||||
</record>
|
||||
<record id="rule_parameter_us_mn_suta_rate_2020" model="hr.payroll.rate">
|
||||
<field name="name">US MN Minnesota SUTA Rate</field>
|
||||
<field name="code">us_mn_suta_rate</field>
|
||||
<field name="parameter_value">1.11</field>
|
||||
<field name="date_from" eval="datetime(2020, 1, 1).date()"/>
|
||||
</record>
|
||||
</data>
|
||||
|
||||
<data noupdate="1">
|
||||
<record id="rule_parameter_us_mn_sit_tax_rate_2019" model="hr.payroll.rate">
|
||||
<field name="name">US MN Minnesota SIT Tax Rate</field>
|
||||
<field name="code">us_mn_sit_tax_rate</field>
|
||||
<field name="parameter_value">{
|
||||
'single': [
|
||||
( 28920, 2400, 5.35, 0.00),
|
||||
( 89510, 28920, 7.05, 1418.82),
|
||||
(166290, 89510, 7.85, 5690.42),
|
||||
( 'inf', 166290, 9.85, 11717.65),
|
||||
],
|
||||
'married': [
|
||||
( 47820, 9050, 5.35, 0.00),
|
||||
( 163070, 47820, 7.05, 2074.20),
|
||||
( 282200, 163070, 7.85, 10199.33),
|
||||
( 'inf', 282200, 9.85, 19551.04),
|
||||
],
|
||||
}</field>
|
||||
<field name="date_from" eval="datetime(2019, 1, 1).date()"/>
|
||||
</record>
|
||||
<record id="rule_parameter_us_mn_sit_tax_rate_2020" model="hr.payroll.rate">
|
||||
<field name="name">US MN Minnesota SIT Tax Rate</field>
|
||||
<field name="code">us_mn_sit_tax_rate</field>
|
||||
<field name="parameter_value">{
|
||||
'single': [
|
||||
( 30760, 3800, 5.35, 0.00),
|
||||
( 92350, 30760, 6.80, 1442.36),
|
||||
(168200, 92350, 7.85, 5630.48),
|
||||
( 'inf', 168200, 9.85, 11584.71),
|
||||
],
|
||||
'married': [
|
||||
( 51310, 11900, 5.35, 0.00),
|
||||
( 168470, 51310, 6.80, 2108.44),
|
||||
( 285370, 168470, 7.85, 10075.32),
|
||||
( 'inf', 285370, 9.85, 19251.97),
|
||||
],
|
||||
}</field>
|
||||
<field name="date_from" eval="datetime(2020, 1, 1).date()"/>
|
||||
</record>
|
||||
</data>
|
||||
|
||||
<data noupdate="1">
|
||||
<record id="rule_parameter_us_mn_sit_allowances_rate_2019" model="hr.payroll.rate">
|
||||
<field name="name">US MN Minnesota Allowances Rate</field>
|
||||
<field name="code">us_mn_sit_allowances_rate</field>
|
||||
<field name="parameter_value">4250.0</field>
|
||||
<field name="date_from" eval="datetime(2019, 1, 1).date()"/>
|
||||
</record>
|
||||
<record id="rule_parameter_us_mn_sit_allowances_rate_2020" model="hr.payroll.rate">
|
||||
<field name="name">US MN Minnesota Allowances Rate</field>
|
||||
<field name="code">us_mn_sit_allowances_rate</field>
|
||||
<field name="parameter_value">4300.0</field>
|
||||
<field name="date_from" eval="datetime(2020, 1, 1).date()"/>
|
||||
</record>
|
||||
</data>
|
||||
|
||||
<!-- Partners and Contribution Registers -->
|
||||
<record id="res_partner_us_mn_dor" model="res.partner">
|
||||
<field name="name">US Minnesota - Unemployment Insurance Agency - Unemployment Tax</field>
|
||||
</record>
|
||||
<record id="contrib_register_us_mn_dor" model="hr.contribution.register">
|
||||
<field name="name">US Minnesota - Unemployment Insurance Agency - Unemployment Tax</field>
|
||||
<field name="partner_id" ref="res_partner_us_mn_dor"/>
|
||||
</record>
|
||||
|
||||
<record id="res_partner_us_mn_dor_sit" model="res.partner">
|
||||
<field name="name">US Minnesota - Department of Treasury - Income Tax</field>
|
||||
</record>
|
||||
<record id="contrib_register_us_mn_dor_sit" model="hr.contribution.register">
|
||||
<field name="name">US Minnesota - Department of Treasury - Income Tax</field>
|
||||
<field name="partner_id" ref="res_partner_us_mn_dor_sit"/>
|
||||
</record>
|
||||
|
||||
<!-- Categories -->
|
||||
|
||||
<!-- Rules -->
|
||||
<record id="hr_payroll_rule_er_us_mn_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 MN Minnesota State Unemployment</field>
|
||||
<field name="code">ER_US_MN_SUTA</field>
|
||||
<field name="condition_select">python</field>
|
||||
<field name="condition_python">result, _ = general_state_unemployment(payslip, categories, worked_days, inputs, wage_base='us_mn_suta_wage_base', rate='us_mn_suta_rate', state_code='MN')</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_mn_suta_wage_base', rate='us_mn_suta_rate', state_code='MN')</field>
|
||||
<field name="register_id" ref="contrib_register_us_mn_dor"/>
|
||||
<field name="appears_on_payslip" eval="False"/>
|
||||
</record>
|
||||
|
||||
<record id="hr_payroll_rule_ee_us_mn_sit" model="hr.salary.rule">
|
||||
<field name="sequence" eval="195"/>
|
||||
<field name="category_id" ref="hr_payroll_category_ee_us_sit"/>
|
||||
<field name="name">EE: US MN Minnesota State Income Tax Withholding</field>
|
||||
<field name="code">EE_US_MN_SIT</field>
|
||||
<field name="condition_select">python</field>
|
||||
<field name="condition_python">result, _ = mn_minnesota_state_income_withholding(payslip, categories, worked_days, inputs)</field>
|
||||
<field name="amount_select">code</field>
|
||||
<field name="amount_python_compute">result, result_rate = mn_minnesota_state_income_withholding(payslip, categories, worked_days, inputs)</field>
|
||||
<field name="register_id" ref="contrib_register_us_mn_dor_sit"/>
|
||||
<field name="appears_on_payslip" eval="True"/>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
@@ -18,6 +18,10 @@ FIELDS_CONTRACT_TO_US_PAYROLL_FORMS_2020 = {
|
||||
'mi_w4_tax_exempt': 'state_income_tax_exempt',
|
||||
'mi_w4_additional_wh': 'state_income_tax_additional_withholding',
|
||||
|
||||
'mn_w4mn_filing_status': 'mn_w4mn_sit_filing_status',
|
||||
'mn_w4mn_allowances': 'mn_w4mn_sit_allowances',
|
||||
'mn_w4mn_additional_wh': 'state_income_tax_additional_withholding',
|
||||
|
||||
'mo_mow4_filing_status': 'mo_mow4_sit_filing_status',
|
||||
'mo_mow4_additional_withholding': 'state_income_tax_additional_withholding',
|
||||
|
||||
@@ -78,6 +82,11 @@ XMLIDS_TO_REMOVE_2020 = [
|
||||
'l10n_us_mi_hr_payroll.hr_payroll_mi_income_withhold',
|
||||
'l10n_us_mi_hr_payroll.hr_payroll_rules_mi_unemp_wages',
|
||||
|
||||
'l10n_us_mn_hr_payroll.hr_payroll_mn_unemp_wages',
|
||||
'l10n_us_mn_hr_payroll.hr_payroll_mn_unemp',
|
||||
'l10n_us_mn_hr_payroll.hr_payroll_mn_income_withhold',
|
||||
'l10n_us_mn_hr_payroll.hr_payroll_rules_mn_unemp_wages',
|
||||
|
||||
'l10n_us_mo_hr_payroll.hr_payroll_mo_unemp_wages',
|
||||
'l10n_us_mo_hr_payroll.hr_payroll_mo_unemp',
|
||||
'l10n_us_mo_hr_payroll.hr_payroll_mo_income_withhold',
|
||||
@@ -191,6 +200,13 @@ XMLIDS_TO_RENAME_2020 = {
|
||||
'l10n_us_mi_hr_payroll.hr_payroll_rules_mi_unemp': 'l10n_us_hr_payroll.hr_payroll_rule_er_us_mi_suta',
|
||||
'l10n_us_mi_hr_payroll.hr_payroll_rules_mi_inc_withhold': 'l10n_us_hr_payroll.hr_payroll_rule_ee_us_mi_sit',
|
||||
|
||||
'l10n_us_mn_hr_payrol.res_partner_mn_ui_unemp': 'l10n_us_hr_payroll.res_partner_us_mn_dor',
|
||||
'l10n_us_mn_hr_payrol.res_partner_mn_dor_withhold': 'l10n_us_hr_payroll.res_partner_us_mn_dor_sit',
|
||||
'l10n_us_mn_hr_payrol.contrib_register_mn_ui_unemp': 'l10n_us_hr_payroll.contrib_register_us_mn_dor',
|
||||
'l10n_us_mn_hr_payrol.contrib_register_mn_dor_withhold': 'l10n_us_hr_payroll.contrib_register_us_mn_dor_sit',
|
||||
'l10n_us_mn_hr_payrol.hr_payroll_rules_mn_unemp': 'l10n_us_hr_payroll.hr_payroll_rule_er_us_mn_suta',
|
||||
'l10n_us_mn_hr_payrol.hr_payroll_rules_mn_inc_withhold': 'l10n_us_hr_payroll.hr_payroll_rule_ee_us_mn_sit',
|
||||
|
||||
'l10n_us_mo_hr_payroll.res_partner_modor_unemp': 'l10n_us_hr_payroll.res_partner_us_mo_dor',
|
||||
'l10n_us_mo_hr_payroll.res_partner_modor_withhold': 'l10n_us_hr_payroll.res_partner_us_mo_dor_sit',
|
||||
'l10n_us_mo_hr_payroll.contrib_register_modor_unemp': 'l10n_us_hr_payroll.contrib_register_us_mo_dor',
|
||||
|
||||
@@ -16,6 +16,7 @@ from .state.general import general_state_unemployment, \
|
||||
is_us_state
|
||||
from .state.ga_georgia import ga_georgia_state_income_withholding
|
||||
from .state.mi_michigan import mi_michigan_state_income_withholding
|
||||
from .state.mn_minnesota import mn_minnesota_state_income_withholding
|
||||
from .state.mo_missouri import mo_missouri_state_income_withholding
|
||||
from .state.ms_mississippi import ms_mississippi_state_income_withholding
|
||||
from .state.mt_montana import mt_montana_state_income_withholding
|
||||
@@ -59,6 +60,7 @@ class HRPayslip(models.Model):
|
||||
'is_us_state': is_us_state,
|
||||
'ga_georgia_state_income_withholding': ga_georgia_state_income_withholding,
|
||||
'mi_michigan_state_income_withholding': mi_michigan_state_income_withholding,
|
||||
'mn_minnesota_state_income_withholding': mn_minnesota_state_income_withholding,
|
||||
'mo_missouri_state_income_withholding': mo_missouri_state_income_withholding,
|
||||
'ms_mississippi_state_income_withholding': ms_mississippi_state_income_withholding,
|
||||
'mt_montana_state_income_withholding': mt_montana_state_income_withholding,
|
||||
|
||||
43
l10n_us_hr_payroll/models/state/mn_minnesota.py
Normal file
43
l10n_us_hr_payroll/models/state/mn_minnesota.py
Normal file
@@ -0,0 +1,43 @@
|
||||
# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details.
|
||||
|
||||
from .general import _state_applies
|
||||
|
||||
|
||||
def mn_minnesota_state_income_withholding(payslip, categories, worked_days, inputs):
|
||||
"""
|
||||
Returns SIT eligible wage and rate.
|
||||
WAGE = GROSS + DED_FIT_EXEMPT
|
||||
|
||||
:return: result, result_rate (wage, percent)
|
||||
"""
|
||||
state_code = 'MN'
|
||||
if not _state_applies(payslip, state_code):
|
||||
return 0.0, 0.0
|
||||
|
||||
filing_status = payslip.dict.contract_id.us_payroll_config_value('mn_w4mn_sit_filing_status')
|
||||
if not filing_status:
|
||||
return 0.0, 0.0
|
||||
|
||||
# Determine Wage
|
||||
wage = categories.GROSS + categories.DED_FIT_EXEMPT
|
||||
pay_periods = payslip.dict.get_pay_periods_in_year()
|
||||
additional = payslip.dict.contract_id.us_payroll_config_value('state_income_tax_additional_withholding')
|
||||
sit_tax_rate = payslip.dict.rule_parameter('us_mn_sit_tax_rate')[filing_status]
|
||||
allowances_rate = payslip.dict.rule_parameter('us_mn_sit_allowances_rate')
|
||||
allowances = payslip.dict.contract_id.us_payroll_config_value('mn_w4mn_sit_allowances')
|
||||
if wage == 0.0:
|
||||
return 0.0, 0.0
|
||||
|
||||
taxable_income = (wage * pay_periods) - (allowances * allowances_rate)
|
||||
withholding = 0.0
|
||||
for row in sit_tax_rate:
|
||||
cap, subtract_amt, rate, flat_fee = row
|
||||
cap = float(cap)
|
||||
if cap > taxable_income:
|
||||
withholding = ((rate / 100.00) * (taxable_income - subtract_amt)) + flat_fee
|
||||
break
|
||||
withholding = round(withholding / pay_periods)
|
||||
if withholding < 0.0:
|
||||
withholding = 0.0
|
||||
withholding += additional
|
||||
return wage, -((withholding / wage) * 100.0)
|
||||
@@ -66,6 +66,13 @@ class HRContractUSPayrollConfig(models.Model):
|
||||
|
||||
mi_w4_sit_exemptions = fields.Integer(string='Michigan MI W-4 Exemptions', help='MI-W4 6.')
|
||||
|
||||
mn_w4mn_sit_filing_status = fields.Selection([
|
||||
('', 'Exempt'),
|
||||
('single', 'Single'),
|
||||
('married', 'Married'),
|
||||
], string='Minnesota W-4MN Marital Status', help='W-4MN')
|
||||
mn_w4mn_sit_allowances = fields.Integer(string='Minnesota Allowances', help='W-4MN 1.')
|
||||
|
||||
mo_mow4_sit_filing_status = fields.Selection([
|
||||
('', 'Exempt'),
|
||||
('single', 'Single or Married Spouse Works or Married Filing Separate'),
|
||||
|
||||
@@ -13,6 +13,9 @@ from . import test_us_ga_georgia_payslip_2020
|
||||
from . import test_us_mi_michigan_payslip_2019
|
||||
from . import test_us_mi_michigan_payslip_2020
|
||||
|
||||
from . import test_us_mn_minnesota_payslip_2019
|
||||
from . import test_us_mn_minnesota_payslip_2020
|
||||
|
||||
from . import test_us_mo_missouri_payslip_2019
|
||||
from . import test_us_mo_missouri_payslip_2020
|
||||
|
||||
|
||||
159
l10n_us_hr_payroll/tests/test_us_mn_minnesota_payslip_2019.py
Executable file
159
l10n_us_hr_payroll/tests/test_us_mn_minnesota_payslip_2019.py
Executable file
@@ -0,0 +1,159 @@
|
||||
# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details.
|
||||
|
||||
from .common import TestUsPayslip, process_payslip
|
||||
|
||||
|
||||
class TestUsMNPayslip(TestUsPayslip):
|
||||
# TAXES AND RATES
|
||||
MN_UNEMP_MAX_WAGE = 34000.0
|
||||
MN_UNEMP = -1.11 / 100.0
|
||||
|
||||
def test_taxes_weekly(self):
|
||||
salary = 30000.0
|
||||
# Hand Calculated Amount to Test
|
||||
# Step 1 -> 30000.00 for wages per period Step 2 -> 52.0 for weekly -> 30000 * 52 -> 1560000
|
||||
# Step 3 -> allowances * 4250.0 -> 4250.00 in this case.
|
||||
# Step 4 -> Step 2 - Step 3 -> 1560000 - 4250.00 -> 1555750
|
||||
# Step 5 -> using chart -> we have last row -> ((1555750 - 166290) * (9.85 / 100)) + 11717.65 -> 148579.46
|
||||
# Step 6 -> Convert back to pay period amount and round - > 2857.297 - > 2857.0
|
||||
# wh = 2857.0
|
||||
wh = -2857.0
|
||||
|
||||
employee = self._createEmployee()
|
||||
contract = self._createContract(employee,
|
||||
wage=salary,
|
||||
state_id=self.get_us_state('MN'),
|
||||
mn_w4mn_sit_filing_status='single',
|
||||
state_income_tax_additional_withholding=0.0,
|
||||
mn_w4mn_sit_allowances=1.0,
|
||||
schedule_pay='weekly')
|
||||
|
||||
self._log('2019 Minnesota tax first payslip weekly:')
|
||||
payslip = self._createPayslip(employee, '2019-01-01', '2019-01-31')
|
||||
payslip.compute_sheet()
|
||||
cats = self._getCategories(payslip)
|
||||
|
||||
self.assertPayrollEqual(cats['ER_US_SUTA'], salary * self.MN_UNEMP)
|
||||
self.assertPayrollAlmostEqual(cats['EE_US_SIT'], wh) # Test numbers are off by 1 penny
|
||||
|
||||
process_payslip(payslip)
|
||||
|
||||
# Make a new payslip, this one will have maximums
|
||||
remaining_MN_UNEMP_wages = self.MN_UNEMP_MAX_WAGE - salary if (self.MN_UNEMP_MAX_WAGE - 2*salary < salary) \
|
||||
else salary
|
||||
|
||||
self._log('2019 Minnesota tax second payslip weekly:')
|
||||
payslip = self._createPayslip(employee, '2019-02-01', '2019-02-28')
|
||||
payslip.compute_sheet()
|
||||
cats = self._getCategories(payslip)
|
||||
|
||||
self.assertPayrollEqual(cats['ER_US_SUTA'], remaining_MN_UNEMP_wages * self.MN_UNEMP)
|
||||
|
||||
def test_taxes_married(self):
|
||||
salary = 5000.00
|
||||
|
||||
# Hand Calculated Amount to Test
|
||||
# Step 1 -> 5000.0 for wages per period Step 2 -> 52.0 for weekly -> 5000 * 52 -> 260,000
|
||||
# Step 3 -> allowances * 4250.0 -> 4250.00 in this case.
|
||||
# Step 4 -> Step 2 - Step 3 -> 260,000 - 4250.00 -> 255750.0
|
||||
# For step five we used the married section
|
||||
# Step 5 -> using chart -> we have 2nd last row -> ((255750 - 163070) * (7.85 / 100)) + 10199.33 ->
|
||||
# Step 6 -> Convert back to pay period amount and round
|
||||
# wh = 336.0
|
||||
wh = -336.0
|
||||
|
||||
employee = self._createEmployee()
|
||||
contract = self._createContract(employee,
|
||||
wage=salary,
|
||||
state_id=self.get_us_state('MN'),
|
||||
mn_w4mn_sit_filing_status='married',
|
||||
state_income_tax_additional_withholding=0.0,
|
||||
mn_w4mn_sit_allowances=1.0,
|
||||
schedule_pay='weekly')
|
||||
|
||||
self._log('2019 Minnesota tax first payslip married:')
|
||||
payslip = self._createPayslip(employee, '2019-01-01', '2019-01-31')
|
||||
payslip.compute_sheet()
|
||||
cats = self._getCategories(payslip)
|
||||
|
||||
self.assertPayrollEqual(cats['ER_US_SUTA'], salary * self.MN_UNEMP)
|
||||
self.assertPayrollAlmostEqual(cats['EE_US_SIT'], wh)
|
||||
|
||||
def test_taxes_semimonthly(self):
|
||||
salary = 6500.00
|
||||
# Hand Calculated Amount to Test
|
||||
# Step 1 -> 6500.00 for wages per period Step 2 -> 24 for semi-monthly -> 6500.00 * 24 -> 156000.00
|
||||
# Step 3 -> allowances * 4250.0 -> 4250.00 in this case.
|
||||
# Step 4 -> Step 2 - Step 3 -> 156000.00 - 4250.00 -> 151750.0
|
||||
# Step 5 -> using chart -> we have 2nd last row -> ((151750.0- 89510) * (7.85 / 100)) + 5690.42 -> 10576.26
|
||||
# Step 6 -> Convert back to pay period amount and round
|
||||
# wh = -441
|
||||
wh = -441.00
|
||||
|
||||
employee = self._createEmployee()
|
||||
contract = self._createContract(employee,
|
||||
wage=salary,
|
||||
state_id=self.get_us_state('MN'),
|
||||
mn_w4mn_sit_filing_status='single',
|
||||
state_income_tax_additional_withholding=0.0,
|
||||
mn_w4mn_sit_allowances=1.0,
|
||||
schedule_pay='semi-monthly')
|
||||
|
||||
|
||||
self._log('2019 Minnesota tax first payslip semimonthly:')
|
||||
payslip = self._createPayslip(employee, '2019-01-01', '2019-01-31')
|
||||
payslip.compute_sheet()
|
||||
cats = self._getCategories(payslip)
|
||||
|
||||
self.assertPayrollEqual(cats['ER_US_SUTA'], salary * self.MN_UNEMP)
|
||||
self.assertPayrollAlmostEqual(cats['EE_US_SIT'], wh)
|
||||
|
||||
def test_tax_exempt(self):
|
||||
salary = 5500.00
|
||||
wh = 0
|
||||
employee = self._createEmployee()
|
||||
contract = self._createContract(employee,
|
||||
wage=salary,
|
||||
state_id=self.get_us_state('MN'),
|
||||
mn_w4mn_sit_filing_status='',
|
||||
state_income_tax_additional_withholding=0.0,
|
||||
mn_w4mn_sit_allowances=2.0,
|
||||
schedule_pay='weekly')
|
||||
|
||||
self._log('2019 Minnesota tax first payslip exempt:')
|
||||
payslip = self._createPayslip(employee, '2019-01-01', '2019-01-31')
|
||||
payslip.compute_sheet()
|
||||
cats = self._getCategories(payslip)
|
||||
|
||||
self.assertPayrollEqual(cats['ER_US_SUTA'], salary * self.MN_UNEMP)
|
||||
self.assertPayrollAlmostEqual(cats['EE_US_SIT'], wh)
|
||||
|
||||
def test_additional_withholding(self):
|
||||
salary = 5500.0
|
||||
# Hand Calculated Amount to Test
|
||||
# Step 1 -> 5500 for wages per period Step 2 -> 52 for weekly -> 5500 * 52 -> 286000.00
|
||||
# Step 3 -> allowances * 4250.0 -> 8500 in this case.
|
||||
# Step 4 -> Step 2 - Step 3 -> 286000.00 - 8500 -> 277500
|
||||
# Step 5 -> using chart -> we have last row -> ((277500- 166290) * (9.85 / 100)) + 11717.65 -> 22671.835
|
||||
# Step 6 -> Convert back to pay period amount and round
|
||||
# wh = -436.0
|
||||
# Add additional_withholding
|
||||
# wh = -436.0 + 40.0
|
||||
wh = -476.0
|
||||
|
||||
employee = self._createEmployee()
|
||||
contract = self._createContract(employee,
|
||||
wage=salary,
|
||||
state_id=self.get_us_state('MN'),
|
||||
mn_w4mn_sit_filing_status='single',
|
||||
state_income_tax_additional_withholding=40.0,
|
||||
mn_w4mn_sit_allowances=2.0,
|
||||
schedule_pay='weekly')
|
||||
|
||||
self._log('2019 Minnesota tax first payslip additional withholding:')
|
||||
payslip = self._createPayslip(employee, '2019-01-01', '2019-01-31')
|
||||
payslip.compute_sheet()
|
||||
cats = self._getCategories(payslip)
|
||||
|
||||
self.assertPayrollEqual(cats['ER_US_SUTA'], salary * self.MN_UNEMP)
|
||||
self.assertPayrollAlmostEqual(cats['EE_US_SIT'], wh)
|
||||
36
l10n_us_hr_payroll/tests/test_us_mn_minnesota_payslip_2020.py
Executable file
36
l10n_us_hr_payroll/tests/test_us_mn_minnesota_payslip_2020.py
Executable file
@@ -0,0 +1,36 @@
|
||||
# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details.
|
||||
|
||||
from datetime import date, timedelta
|
||||
from .common import TestUsPayslip
|
||||
|
||||
|
||||
class TestUsMNPayslip(TestUsPayslip):
|
||||
# TAXES AND RATES
|
||||
MN_UNEMP_MAX_WAGE = 35000.0
|
||||
MN_UNEMP = 1.11
|
||||
|
||||
def _test_sit(self, wage, filing_status, allowances, additional_withholding, schedule_pay, date_start, expected_withholding):
|
||||
employee = self._createEmployee()
|
||||
contract = self._createContract(employee,
|
||||
wage=wage,
|
||||
state_id=self.get_us_state('MN'),
|
||||
mn_w4mn_sit_filing_status=filing_status,
|
||||
state_income_tax_additional_withholding=additional_withholding,
|
||||
mn_w4mn_sit_allowances=allowances,
|
||||
schedule_pay=schedule_pay)
|
||||
|
||||
payslip = self._createPayslip(employee, date_start, date_start + timedelta(days=7))
|
||||
payslip.compute_sheet()
|
||||
cats = self._getCategories(payslip)
|
||||
|
||||
self._log('Computed period tax: ' + str(expected_withholding))
|
||||
self.assertPayrollEqual(cats.get('EE_US_SIT', 0.0), -expected_withholding)
|
||||
|
||||
def test_2020_taxes_example(self):
|
||||
self._test_er_suta('MN', self.MN_UNEMP, date(2020, 1, 1), wage_base=self.MN_UNEMP_MAX_WAGE)
|
||||
self._test_sit(5000.0, 'single', 1.0, 0.0, 'weekly', date(2020, 1, 1), 389.0)
|
||||
self._test_sit(30000.0, 'single', 1.0, 0.0, 'weekly', date(2020, 1, 1), 2850.99)
|
||||
self._test_sit(5000.0, 'married', 1.0, 0.0, 'weekly', date(2020, 1, 1), 325.0)
|
||||
self._test_sit(6500.0, 'single', 1.0, 0.0, 'semi-monthly', date(2020, 1, 1), 429.0)
|
||||
self._test_sit(5500.0, '', 2.0, 0.0, 'weekly', date(2020, 1, 1), 0.0)
|
||||
self._test_sit(5500.0, 'single', 2.0, 40.0, 'weekly', date(2020, 1, 1), 470.0)
|
||||
@@ -61,6 +61,12 @@
|
||||
<field name="state_income_tax_additional_withholding" string="Additional Withholding 7."/>
|
||||
<field name="state_income_tax_exempt" string="Exempt 8."/>
|
||||
</group>
|
||||
<group name="state_mn_minnesota" string="MN Minnesota" attrs="{'invisible':[('state_id', '!=', %(base.state_us_36)s)]}">
|
||||
<p colspan="2"><h3>Form W-4MN - State Income Tax</h3></p>
|
||||
<field name="mn_w4mn_sit_filing_status" string="Marital Status"/>
|
||||
<field name="mn_w4mn_sit_allowances" string="Allowances 1."/>
|
||||
<field name="state_income_tax_additional_withholding" string="Additional Withholding 2."/>
|
||||
</group>
|
||||
<group name="state_mo_missouri" string="MO Missouri" attrs="{'invisible':[('state_id', '!=', %(base.state_us_38)s)]}">
|
||||
<p colspan="2"><h3>Form MO W-4 - State Income Tax</h3></p>
|
||||
<field name="mo_mow4_sit_filing_status" string="Filing Status 1."/>
|
||||
|
||||
Reference in New Issue
Block a user