From 9edbd40bc9cd1ea4e7554c2f0ecb64bb39589398 Mon Sep 17 00:00:00 2001 From: Bhoomi Vaishnani Date: Fri, 27 Mar 2020 13:56:06 -0400 Subject: [PATCH] IMP `l10n_us_hr_payroll` for New Mexico 13.0 --- l10n_us_hr_payroll/__manifest__.py | 1 + .../data/state/nm_new_mexico.xml | 113 ++++++++++++++++++ l10n_us_hr_payroll/models/hr_payslip.py | 2 + .../models/state/nm_new_mexico.py | 40 +++++++ l10n_us_hr_payroll/tests/__init__.py | 2 + .../test_us_nm_new_mexico_payslip_2020.py | 35 ++++++ .../views/us_payroll_config_views.xml | 4 + 7 files changed, 197 insertions(+) create mode 100644 l10n_us_hr_payroll/data/state/nm_new_mexico.xml create mode 100644 l10n_us_hr_payroll/models/state/nm_new_mexico.py create mode 100755 l10n_us_hr_payroll/tests/test_us_nm_new_mexico_payslip_2020.py diff --git a/l10n_us_hr_payroll/__manifest__.py b/l10n_us_hr_payroll/__manifest__.py index d04c4772..672a620e 100644 --- a/l10n_us_hr_payroll/__manifest__.py +++ b/l10n_us_hr_payroll/__manifest__.py @@ -46,6 +46,7 @@ United States of America - Payroll Rules. 'data/state/mt_montana.xml', 'data/state/nc_northcarolina.xml', 'data/state/nj_newjersey.xml', + 'data/state/nm_new_mexico.xml', 'data/state/oh_ohio.xml', 'data/state/pa_pennsylvania.xml', 'data/state/tx_texas.xml', diff --git a/l10n_us_hr_payroll/data/state/nm_new_mexico.xml b/l10n_us_hr_payroll/data/state/nm_new_mexico.xml new file mode 100644 index 00000000..a823c608 --- /dev/null +++ b/l10n_us_hr_payroll/data/state/nm_new_mexico.xml @@ -0,0 +1,113 @@ + + + + + US NM New Mexico SUTA Wage Base + us_nm_suta_wage_base + + + + + 25800.0 + + + + + + + + US NM New Mexico SUTA Rate + us_nm_suta_rate + + + + + 1.0 + + + + + + + US NM New Mexico SIT Tax Rate + us_nm_sit_tax_rate + + + + + { + 'single': { + 'weekly': ((119, 0.00, 0.0), (225, 0.00, 1.7), (331, 1.80, 3.2), (427, 5.18, 4.7), (619, 9.70, 4.9), (927, 19.13, 4.9), (1369, 34.20, 4.9), ('inf', 55.88, 4.9)), + 'bi-weekly': ((238, 0.00, 0.0), (450, 0.00, 1.7), (662, 3.60, 3.2), (854, 10.37, 4.7), (1238, 19.40, 4.9), (1854, 38.25, 4.9), (2738, 68.40, 4.9), ('inf', 111.75, 4.9)), + 'semi-monthly': ((258, 0.00, 0.0), (488, 0.00, 1.7), (717, 3.90, 3.2), (925, 11.23, 4.7), (1342, 21.02, 4.9), (2008, 41.44, 4.9), (2967, 74.10, 4.9), ('inf', 121.06, 4.9)), + 'monthly': ((517, 0.00, 0.0), (975, 0.00, 1.7), (1433, 7.79, 3.2), (1850, 22.46, 4.7), (2683, 42.04, 4.9), (4017, 82.88, 4.9), (5933, 148.21, 4.9), ('inf', 242.13, 4.9)), + 'quarterly': ((1550, 0.00, 0.0), (2925, 0.00, 1.7), (4300, 23.38, 3.2), (5550, 67.38, 4.7), (8050, 126.13, 4.9), (12050, 248.63, 4.9), (17800, 444.63, 4.9), ('inf', 726.38, 4.9)), + 'semi-annual': ((3100, 0.00, 0.0), (5850, 0.00, 1.7), (8600, 46.75, 3.2), (11100, 134.75, 4.7), (16100, 252.25, 4.9), (24100, 497.25, 4.9), (35600, 889.25, 4.9), ('inf', 1452.75, 4.9)), + 'annually': ((6200, 0.00, 0.0), (11700, 0.00, 1.7), (17200, 93.50, 3.2), (22200, 269.50, 4.7), (32200, 504.50, 4.9), (48200, 994.50, 4.9), (71200, 1778.50, 4.9), ('inf', 2905.50, 4.9)), + }, + 'married': { + 'weekly': ((238, 0.00, 0.0), (392, 0.00, 1.7), (546, 2.62, 3.2), (700, 7.54, 4.7), (1008, 14.77, 4.9), (1469, 29.85, 4.9), (2162, 52.46, 4.9), ('inf', 86.38, 4.9)), + 'bi-weekly': ((477, 0.00, 0.0), (785, 0.00, 1.7), (1092, 5.23, 3.2), (1400, 15.08, 4.7), (2015, 29.54, 4.9), (2938, 59.69, 4.9), (4323, 104.92, 4.9), ('inf', 172.77, 4.9)), + 'semi-monthly': ((517, 0.00, 0.0), (850, 0.00, 1.7), (1183, 5.67, 3.2), (1517, 16.33, 4.7), (2183, 32.00, 4.9), (3183, 64.67, 4.9), (4683, 113.67, 4.9), ('inf', 187.17, 4.9)), + 'monthly': ((1033, 0.00, 0.0), (1700, 0.00, 1.7), (2367, 11.33, 3.2), (3033, 32.67, 4.7), (4367, 64.00, 4.9), (6367, 129.33, 4.9), (9367, 227.33, 4.9), ('inf', 374.33, 4.9)), + 'quarterly': ((3100, 0.00, 0.0), (5100, 0.00, 1.7), (7100, 34.00, 3.2), (9100, 98.00, 4.7), (13100, 192.00, 4.9), (19100, 388.00, 4.9), (28100, 682.00, 4.9), ('inf', 1123.00, 4.9)), + 'semi-annual': ((6200, 0.00, 0.0), (10200, 0.00, 1.7), (14200, 68.00, 3.2), (18200, 196.00, 4.7), (26200, 384.00, 4.9), (38200, 776.00, 4.9), (56200, 1364.00, 4.9), ('inf', 2246.00, 4.9)), + 'annually': ((12400, 0.00, 0.0), (20400, 0.00, 1.7), (28400, 136.00, 3.2), (36400, 392.00, 4.7), (52400, 768.00, 4.9), (76400, 1552.00, 4.9), (112400, 2728.00, 4.9), ('inf', 4492.00, 4.9)), + }, + 'married_as_single': { + 'weekly': ((179, 0.00, 0.0), (333, 0.00, 1.7), (487, 2.62, 3.2), (641, 7.54, 4.7), (949, 14.77, 4.9), (1410, 29.85, 4.9), (2102, 52.46, 4.9), ('inf', 86.38, 4.9)), + 'bi-weekly': ((359, 0.00, 0.0), (666, 0.00, 1.7), (974, 5.23, 3.2), (1282, 15.08, 4.7), (1897, 29.54, 4.9), (2820, 59.69, 4.9), (4205, 104.92, 4.9), ('inf', 172.77, 4.9)), + 'semi-monthly': ((389, 0.00, 0.0), (722, 0.00, 1.7), (1055, 5.67, 3.2), (1389, 16.33, 4.7), (2055, 32.00, 4.9), (3055, 64.67, 4.9), (4555, 113.67, 4.9), ('inf', 187.17, 4.9)), + 'monthly': ((777, 0.00, 0.0), (1444, 0.00, 1.7), (2110, 11.33, 3.2), (2777, 32.67, 4.7), (4110, 64.00, 4.9), (6110, 129.33, 4.9), (9110, 227.33, 4.9), ('inf', 374.33, 4.9)), + 'quarterly': ((2331, 0.00, 0.0), (4331, 0.00, 1.7), (6331, 34.00, 3.2), (8331, 98.00, 4.7), (12331, 192.00, 4.9), (18331, 388.00, 4.9), (27331, 682.00, 4.9), ('inf', 1123.00, 4.9)), + 'semi-annual': ((4663, 0.00, 0.0), (8663, 0.00, 1.7), (12663, 68.00, 3.2), (16663, 196.00, 4.7), (24663, 384.00, 4.9), (36663, 776.00, 4.9), (54663, 1364.00, 4.9), ('inf', 2246.00, 4.9)), + 'annually': ((9325, 0.00, 0.0), (17325, 0.00, 1.7), (25325, 136.00, 3.2), (33325, 392.00, 4.7), (49325, 768.00, 4.9), (73325, 1552.00, 4.9), (109325, 2728.00, 4.9), ('inf', 4492.00, 4.9)), + } + } + + + + + + + + + US New Mexico - Department of Workforce Solutions - Unemployment Tax + + + + US New Mexico - Department of Taxation and Revenue - Income Tax + + + + + + + + + + ER: US NM New Mexico State Unemployment + ER_US_NM_SUTA + python + result, _ = general_state_unemployment(payslip, categories, worked_days, inputs, wage_base='us_nm_suta_wage_base', rate='us_nm_suta_rate', state_code='NM') + code + result, result_rate = general_state_unemployment(payslip, categories, worked_days, inputs, wage_base='us_nm_suta_wage_base', rate='us_nm_suta_rate', state_code='NM') + + + + + + + + + EE: US NM New Mexico State Income Tax Withholding + EE_US_NM_SIT + python + result, _ = nm_new_mexico_state_income_withholding(payslip, categories, worked_days, inputs) + code + result, result_rate = nm_new_mexico_state_income_withholding(payslip, categories, worked_days, inputs) + + + + + \ No newline at end of file diff --git a/l10n_us_hr_payroll/models/hr_payslip.py b/l10n_us_hr_payroll/models/hr_payslip.py index 24bf0548..888a9ebc 100644 --- a/l10n_us_hr_payroll/models/hr_payslip.py +++ b/l10n_us_hr_payroll/models/hr_payslip.py @@ -31,6 +31,7 @@ from .state.ms_mississippi import ms_mississippi_state_income_withholding from .state.mt_montana import mt_montana_state_income_withholding from .state.nc_northcarolina import nc_northcarolina_state_income_withholding from .state.nj_newjersey import nj_newjersey_state_income_withholding +from .state.nm_new_mexico import nm_new_mexico_state_income_withholding from .state.oh_ohio import oh_ohio_state_income_withholding from .state.va_virginia import va_virginia_state_income_withholding from .state.wa_washington import wa_washington_fml_er, \ @@ -85,6 +86,7 @@ class HRPayslip(models.Model): 'mt_montana_state_income_withholding': mt_montana_state_income_withholding, 'nc_northcarolina_state_income_withholding': nc_northcarolina_state_income_withholding, 'nj_newjersey_state_income_withholding': nj_newjersey_state_income_withholding, + 'nm_new_mexico_state_income_withholding': nm_new_mexico_state_income_withholding, 'oh_ohio_state_income_withholding': oh_ohio_state_income_withholding, 'va_virginia_state_income_withholding': va_virginia_state_income_withholding, 'wa_washington_fml_er': wa_washington_fml_er, diff --git a/l10n_us_hr_payroll/models/state/nm_new_mexico.py b/l10n_us_hr_payroll/models/state/nm_new_mexico.py new file mode 100644 index 00000000..48bf1ae1 --- /dev/null +++ b/l10n_us_hr_payroll/models/state/nm_new_mexico.py @@ -0,0 +1,40 @@ +# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details. + +from .general import _state_applies, sit_wage + + +def nm_new_mexico_state_income_withholding(payslip, categories, worked_days, inputs): + """ + Returns SIT eligible wage and rate. + + :return: result, result_rate (wage, percent) + """ + state_code = 'NM' + if not _state_applies(payslip, state_code): + return 0.0, 0.0 + + # Determine Wage + wage = sit_wage(payslip, categories) + if not wage: + return 0.0, 0.0 + + filing_status = payslip.contract_id.us_payroll_config_value('fed_941_fit_w4_filing_status') + if not filing_status: + return 0.0, 0.0 + + schedule_pay = payslip.contract_id.schedule_pay + additional = payslip.contract_id.us_payroll_config_value('state_income_tax_additional_withholding') + tax_table = payslip.rule_parameter('us_nm_sit_tax_rate')[filing_status].get(schedule_pay) + + taxable_income = wage + withholding = 0.0 + last = 0.0 + for row in tax_table: + if taxable_income <= float(row[0]): + withholding = row[1] + ((row[2] / 100.0) * (taxable_income - last)) + break + last = row[0] + + withholding = max(withholding, 0.0) + withholding += additional + return wage, -((withholding / wage) * 100.0) diff --git a/l10n_us_hr_payroll/tests/__init__.py b/l10n_us_hr_payroll/tests/__init__.py index ffbcfba4..d8499ab3 100755 --- a/l10n_us_hr_payroll/tests/__init__.py +++ b/l10n_us_hr_payroll/tests/__init__.py @@ -65,6 +65,8 @@ from . import test_us_nc_northcarolina_payslip_2020 from . import test_us_nj_newjersey_payslip_2019 from . import test_us_nj_newjersey_payslip_2020 +from . import test_us_nm_new_mexico_payslip_2020 + from . import test_us_oh_ohio_payslip_2019 from . import test_us_oh_ohio_payslip_2020 diff --git a/l10n_us_hr_payroll/tests/test_us_nm_new_mexico_payslip_2020.py b/l10n_us_hr_payroll/tests/test_us_nm_new_mexico_payslip_2020.py new file mode 100755 index 00000000..0ab6c321 --- /dev/null +++ b/l10n_us_hr_payroll/tests/test_us_nm_new_mexico_payslip_2020.py @@ -0,0 +1,35 @@ +# 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 TestUsNMPayslip(TestUsPayslip): + ### + # 2020 Taxes and Rates + ### + NM_UNEMP_MAX_WAGE = 25800.0 + NM_UNEMP = 1.0 + # Calculation based on section 17. https://s3.amazonaws.com/realFile34821a95-73ca-43e7-b06d-fad20f5183fd/a9bf1098-533b-4a3d-806a-4bf6336af6e4?response-content-disposition=filename%3D%22FYI-104+-+New+Mexico+Withholding+Tax+-+Effective+January+1%2C+2020.pdf%22&response-content-type=application%2Fpdf&AWSAccessKeyId=AKIAJBI25DHBYGD7I7TA&Signature=feu%2F1oJvU6BciRfKcoR0iNxoVZE%3D&Expires=1585159702 + + def _test_sit(self, wage, filing_status, additional_withholding, schedule_pay, date_start, expected_withholding): + employee = self._createEmployee() + contract = self._createContract(employee, + wage=wage, + state_id=self.get_us_state('NM'), + fed_941_fit_w4_filing_status=filing_status, + state_income_tax_additional_withholding=additional_withholding, + 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('NM', self.NM_UNEMP, date(2020, 1, 1), wage_base=self.NM_UNEMP_MAX_WAGE) + self._test_sit(1000.0, 'married', 0.0, 'weekly', date(2020, 1, 1), 29.47) + self._test_sit(1000.0, 'married', 10.0, 'weekly', date(2020, 1, 1), 39.47) + self._test_sit(25000.0, 'single', 0.0, 'bi-weekly', date(2020, 1, 1), 1202.60) + self._test_sit(25000.0, 'married_as_single', 0.0, 'monthly', date(2020, 1, 1), 1152.95) diff --git a/l10n_us_hr_payroll/views/us_payroll_config_views.xml b/l10n_us_hr_payroll/views/us_payroll_config_views.xml index a1afad81..c16391ae 100644 --- a/l10n_us_hr_payroll/views/us_payroll_config_views.xml +++ b/l10n_us_hr_payroll/views/us_payroll_config_views.xml @@ -162,6 +162,10 @@ + +

Form NM W-4 - State Income Tax

+ +

Form IT-4 - State Income Tax