From 3bed3f161ad1eb98c7541e756a1fe48c79e5bc7b Mon Sep 17 00:00:00 2001 From: Kristen Marie Kulha Date: Tue, 22 May 2018 13:31:06 -0700 Subject: [PATCH 01/11] Initial commit of `l10n_us_nj_hr_payroll` for 11.0. --- l10n_us_nj_hr_payroll/__init__.py | 1 + l10n_us_nj_hr_payroll/__manifest__.py | 31 + l10n_us_nj_hr_payroll/data/base.xml | 155 ++++ l10n_us_nj_hr_payroll/data/final.xml | 27 + l10n_us_nj_hr_payroll/data/rules_2018.xml | 697 ++++++++++++++++++ l10n_us_nj_hr_payroll/tests/__init__.py | 1 + .../tests/test_us_nj_payslip_2018.py | 135 ++++ l10n_us_nj_hr_payroll/us_nj_hr_payroll.py | 92 +++ .../us_nj_hr_payroll_view.xml | 40 + 9 files changed, 1179 insertions(+) create mode 100755 l10n_us_nj_hr_payroll/__init__.py create mode 100755 l10n_us_nj_hr_payroll/__manifest__.py create mode 100755 l10n_us_nj_hr_payroll/data/base.xml create mode 100755 l10n_us_nj_hr_payroll/data/final.xml create mode 100755 l10n_us_nj_hr_payroll/data/rules_2018.xml create mode 100755 l10n_us_nj_hr_payroll/tests/__init__.py create mode 100755 l10n_us_nj_hr_payroll/tests/test_us_nj_payslip_2018.py create mode 100755 l10n_us_nj_hr_payroll/us_nj_hr_payroll.py create mode 100755 l10n_us_nj_hr_payroll/us_nj_hr_payroll_view.xml diff --git a/l10n_us_nj_hr_payroll/__init__.py b/l10n_us_nj_hr_payroll/__init__.py new file mode 100755 index 00000000..48629d95 --- /dev/null +++ b/l10n_us_nj_hr_payroll/__init__.py @@ -0,0 +1 @@ +from . import us_nj_hr_payroll diff --git a/l10n_us_nj_hr_payroll/__manifest__.py b/l10n_us_nj_hr_payroll/__manifest__.py new file mode 100755 index 00000000..6b34c3aa --- /dev/null +++ b/l10n_us_nj_hr_payroll/__manifest__.py @@ -0,0 +1,31 @@ +{ + 'name': 'USA - New Jersey - Payroll', + 'author': 'Hibou Corp. ', + 'license': 'AGPL-3', + 'category': 'Localization', + 'depends': ['l10n_us_hr_payroll'], + 'version': '11.0.2018.0.0', + 'description': """ +USA::New Jersey Payroll Rules. +============================== + + * New Jersey Division of Taxation partner + * Contribution register for New Jersey DoT + * Company level New Jersey Unemployment Rate + * Company level New Jersey State Disability Insurance Rate + * Contract level New Jersey Unemployment Rate + * Contract level New Jersey State Disability Insurance Rate + * Contract level New Jersey Family Leave Insurance Rate + * Contract level New Jersey Workforce Development/Supplemental Workforce Funds + """, + + 'auto_install': False, + 'website': 'https://hibou.io/', + 'data':[ + 'us_nj_hr_payroll_view.xml', + 'data/base.xml', + 'data/rules_2018.xml', + 'data/final.xml', + ], + 'installable': True +} diff --git a/l10n_us_nj_hr_payroll/data/base.xml b/l10n_us_nj_hr_payroll/data/base.xml new file mode 100755 index 00000000..5db83ed6 --- /dev/null +++ b/l10n_us_nj_hr_payroll/data/base.xml @@ -0,0 +1,155 @@ + + + + + + + New Jersey Division of Taxation - Unemployment Insurance Tax(Employee) + 1 + + + + + New Jersey Division of Taxation - Unemployment Insurance Tax(Employer) + 1 + + + + + New Jersey Division of Taxation - State Disability Insurance Tax(Employee) + 1 + + + + + New Jersey Division of Taxation - State Disability Insurance Tax(Employer) + 1 + + + + + New Jersey Division of Taxation - Family Leave Insurance Tax + 1 + + + + + New Jersey Division of Taxation - Workforce Development/Supplemental Workforce Funds Tax + 1 + + + + + New Jersey Division of Taxation - Income Tax Withholding + 1 + + + + + New Jersey Unemployment Insurance Tax + New Jersey Division of Taxation - Unemployment Insurance Tax(Employee) + + + + + New Jersey Unemployment Insurance Tax + New Jersey Division of Taxation - Unemployment Insurance Tax(Employer) + + + + + New Jersey State Disability Insurance + New Jersey Division of Taxation - State Disability Insurance Tax(Employee) + + + + + New Jersey State Disability Insurance + New Jersey Division of Taxation - State Disability Insurance Tax(Employer) + + + + + New Jersey State Family Leave Insurance + New Jersey Division of Taxation - Family Leave Insurance Tax + + + + + New Jersey State Workforce Development/Supplemental Workforce Funds + New Jersey Division of Taxation - Workforce Development/Supplemental Workforce Funds Tax + + + + + New Jersey Income Tax Withholding + New Jersey Division of Taxation - Income Tax Withholding + + + + + + + New Jersey Unemployment Insurance Tax - Wages + NJ_UNEMP_WAGES + + + + New Jersey State Disability Insurance Tax - Wages + NJ_SDI_WAGES + + + + New Jersey Family Leave Insurance Tax - Wages + NJ_FLI_WAGES + + + + New Jersey Work Force Development - Wages + NJ_WF_WAGES + + + + New Jersey Unemployment Insurance Tax - Employee + NJ_UNEMP_EMPLOYEE + + + + + New Jersey Unemployment Insurance Tax - Employer + NJ_UNEMP_COMPANY + + + + + New Jersey State Disability Insurance - Employer + NJ_SDI_COMPANY + + + + + New Jersey State Disability Insurance - Employee + NJ_SDI_EMPLOYEE + + + + + New Jersey State Family Leave Insurance Tax + NJ_FLI + + + + + New Jersey State Workforce Development/Suppllemental Tax + NJ_WF + + + + + New Jersey Income Withholding + NJ_WITHHOLD + + + + + diff --git a/l10n_us_nj_hr_payroll/data/final.xml b/l10n_us_nj_hr_payroll/data/final.xml new file mode 100755 index 00000000..568bd523 --- /dev/null +++ b/l10n_us_nj_hr_payroll/data/final.xml @@ -0,0 +1,27 @@ + + + + + + + US_NJ_EMP + USA New Jersey Employee + + + + + + + diff --git a/l10n_us_nj_hr_payroll/data/rules_2018.xml b/l10n_us_nj_hr_payroll/data/rules_2018.xml new file mode 100755 index 00000000..0641e08f --- /dev/null +++ b/l10n_us_nj_hr_payroll/data/rules_2018.xml @@ -0,0 +1,697 @@ + + + + + + + + + + New Jersey Unemployment Insurance Tax - Wages (2018) + NJ_UNEMP_WAGES_2018 + python + result = (payslip.date_to[:4] == '2018') + code + +### +ytd = payslip.sum('NJ_UNEMP_WAGES_2018', '2018-01-01', '2019-01-01') +ytd += contract.external_wages +remaining = 33700.0 - ytd +if remaining <= 0.0: + result = 0 +elif remaining < categories.GROSS: + result = remaining +else: + result = categories.GROSS + + + + + + + New Jersey Unemployment - Employee(2018) + NJ_UNEMP_EMPLOYEE_2018 + python + result = (payslip.date_to[:4] == '2018') + code + +result_rate = -contract.nj_unemp_employee_rate(2018) +result = categories.NJ_UNEMP_WAGES + +# result_rate of 0 implies 100% due to bug +if result_rate == 0.0: + result = 0.0 + + + + + + + + New Jersey Unemployment - Employer(2018) + NJ_UNEMP_COMPANY_2018 + python + result = (payslip.date_to[:4] == '2018') + code + +result_rate = -contract.nj_unemp_company_rate(2018) +result = categories.NJ_UNEMP_WAGES + +# result_rate of 0 implies 100% due to bug +if result_rate == 0.0: + result = 0.0 + + + + + + + + + + + New Jersey State Disability Tax - Wages (2018) + NJ_SDI_WAGES_2018 + python + result = (payslip.date_to[:4] == '2018') + code + +### +ytd = payslip.sum('NJ_SDI_WAGES_2018', '2018-01-01', '2019-01-01') +ytd += contract.external_wages +remaining = 33700.0 - ytd +if remaining <= 0.0: + result = 0 +elif remaining < categories.GROSS: + result = remaining +else: + result = categories.GROSS + + + + + + + New Jersey State Disability Insurance - Employee(2018) + NJ_SDI_EMPLOYEE_2018 + python + result = (payslip.date_to[:4] == '2018') + code + +result_rate = -contract.nj_sdi_employee_rate(2018) +result = categories.NJ_SDI_WAGES + +# result_rate of 0 implies 100% due to bug +if result_rate == 0.0: + result = 0.0 + + + + + + + + New Jersey State Disability Insurance - Employer(2018) + NJ_SDI_COMPANY_2018 + python + result = (payslip.date_to[:4] == '2018') + code + +result_rate = -contract.nj_sdi_company_rate(2018) +result = categories.NJ_SDI_WAGES + +# result_rate of 0 implies 100% due to bug +if result_rate == 0.0: + result = 0.0 + + + + + + + + + + New Jersey Family Leave Insurance Tax - Wages (2018) + NJ_FLI_WAGES_2018 + python + result = (payslip.date_to[:4] == '2018') + code + +### +ytd = payslip.sum('NJ_FLI_WAGES_2018', '2018-01-01', '2019-01-01') +ytd += contract.external_wages +remaining = 33700.0 - ytd +if remaining <= 0.0: + result = 0 +elif remaining < categories.GROSS: + result = remaining +else: + result = categories.GROSS + + + + + + + New Jersey Family Leave Insurance(2018) + NJ_FLI_2018 + python + result = (payslip.date_to[:4] == '2018') + code + +result_rate = -contract.nj_fli_rate(2018) +result = categories.NJ_FLI_WAGES + + + + + + + + + + New Jersey Workforce Development/Supplemental Workforce Funds Tax - Wages (2018) + NJ_WF_WAGES_2018 + python + result = (payslip.date_to[:4] == '2018') + code + +### +ytd = payslip.sum('NJ_WF_WAGES_2018', '2018-01-01', '2019-01-01') +ytd += contract.external_wages +remaining = 33700.0 - ytd +if remaining <= 0.0: + result = 0 +elif remaining < categories.GROSS: + result = remaining +else: + result = categories.GROSS + + + + + + + New Jersey Workforce Development/Supplemental Workforce Funds(2018) + NJ_WF_2018 + python + result = (payslip.date_to[:4] == '2018') + code + +result_rate = -contract.nj_wf_rate(2018) +result = categories.NJ_WF_WAGES + + + + + + + + + + New Jersey Income Withholding + NJ_INC_WITHHOLD_2018 + python + result = (payslip.date_to[:4] == '2018') + code + +wages = categories.GROSS +allowances = contract.nj_njw4_allowances +additional_withholding = contract.nj_additional_withholding +schedule_pay = contract.schedule_pay +filing_status = contract.nj_njw4_filing_status +rate_table = contract.nj_njw4_rate_table + +# Determine which rate table to use +if not rate_table: + if filing_status == 'single' or filing_status == 'married_separate': + rate_table = 'A' + elif filing_status == 'married_joint' or filing_status == 'widower' or filing_status == 'head_household': + rate_table = 'B' + +# Tables are found in http://www.state.nj.us/treasury/taxation/pdf/current/njwt.pdf +# Tax Rate Tables to calculate income withholding + +#### RATE 'A' #### +if rate_table == 'A': + ### WEEKLY ### + if schedule_pay == 'weekly': + wages -= 19.20 * allowances + tax_rate_table = [ + (384, 0.015, 0.0), + (673, 0.02, 5.76), + (769, 0.039, 11.54), + (1442, 0.061, 15.28), + (9615, 0.07, 56.34), + (float('inf'), 0.099, 628.45), + ] + + ### BI-WEEKLY ### + elif schedule_pay == 'bi-weekly': + wages -= 38.40 * allowances + tax_rate_table = [ + (769, 0.015, 0.0), + (1346, 0.02, 11.54), + (1538, 0.039, 23.08), + (2884, 0.061, 30.56), + (19231, 0.07, 112.67), + (float('inf'), 0.099, 1256.96), + ] + + ### SEMI-MONTHLY ### + elif schedule_pay == 'semi-monthly': + wages -= 41.60 * allowances + tax_rate_table = [ + (833, 0.015, 0.0), + (1458, 0.02, 12.50), + (1666, 0.039, 25.00), + (3125, 0.061, 33.11), + (20833, 0.07, 112.11), + (float('inf'), 0.099, 1361.67), + ] + + ### MONTHLY ### + elif schedule_pay == 'monthly': + wages -= 83.30 * allowances + tax_rate_table = [ + (1666, 0.015, 0.0), + (2916, 0.02, 24.99), + (3333, 0.039, 49.99), + (6250, 0.061, 66.25), + (41667, 0.07, 244.19), + (float('inf'), 0.099, 2723.38), + ] + + ### QUARTERLY ### + elif schedule_pay == 'quarterly': + wages -= 250.00 * allowances + tax_rate_table = [ + (5000, 0.015, 0.0), + (8750, 0.02, 75.00), + (10000, 0.039, 150.00), + (18750, 0.061, 198.75), + (125000, 0.07, 732.50), + (float('inf'), 0.099, 8170.00), + ] + + ### SEMI-ANNUAL ### + elif schedule_pay == 'semi-annual': + wages -= 500 * allowances + tax_rate_table = [ + (10000, 0.015, 0.0), + (17500, 0.02, 150.00), + (20000, 0.039, 300.00), + (37500, 0.061, 397.50), + (250000, 0.07, 1465.00), + (float('inf'), 0.099, 16340.00), + ] + + ### ANNUAL ### + elif schedule_pay == 'annually': + wages -= 1000.00 * allowances + tax_rate_table = [ + (20000, 0.015, 0.0), + (35000, 0.02, 300.00), + (40000, 0.039, 600.00), + (75000, 0.061, 795.00), + (500000, 0.07, 2930.00), + (float('inf'), 0.099, 32680.00), + ] + +#### RATE 'B' #### +elif rate_table == 'B': + ### WEEKLY ### + if schedule_pay == 'weekly': + wages -= 19.20 * allowances + tax_rate_table = [ + (384, 0.015, 0.0), + (961, 0.02, 5.76), + (1346, 0.027, 17.30), + (1538, 0.039, 27.70), + (2884, 0.061, 35.18), + (9615, 0.07, 117.29), + (float('inf'), 0.099, 588.46), + ] + + ### BI-WEEKLY ### + elif schedule_pay == 'bi-weekly': + wages -= 38.40 * allowances + tax_rate_table = [ + (769, 0.015, 0.0), + (1923, 0.02, 11.54), + (2692, 0.027, 34.62), + (3076, 0.039, 55.38), + (5769, 0.061, 70.35), + (19231, 0.07, 234.63), + (float('inf'), 0.099, 1176.97), + ] + + ### SEMI-MONTHLY ### + elif schedule_pay == 'semi-monthly': + wages -= 41.60 * allowances + tax_rate_table = [ + (833, 0.015, 0.0), + (2083, 0.02, 12.50), + (2916, 0.027, 37.50), + (3333, 0.039, 59.99), + (6250, 0.061, 76.25), + (20833, 0.07, 254.19), + (float('inf'), 0.099, 1275), + ] + + ### MONTHLY ### + elif schedule_pay == 'monthly': + wages -= 83.30 * allowances + tax_rate_table = [ + (1666, 0.015, 0.0), + (4166, 0.02, 24.99), + (5833, 0.027, 74.99), + (6666, 0.039, 120.00), + (12500, 0.061, 152.49), + (41667, 0.07, 508.36), + (float('inf'), 0.099, 2550.05), + ] + + ### QUARTERLY ### + elif schedule_pay == 'quarterly': + wages -= 250.00 * allowances + tax_rate_table = [ + (5000, 0.015, 0.0), + (12500, 0.02, 75.00), + (17500, 0.027, 225.00), + (20000, 0.039, 360.00), + (37500, 0.061, 457.50), + (125000, 0.07, 1525.00), + (float('inf'), 0.099, 7650.00), + ] + + ### SEMI-ANNUAL ### + elif schedule_pay == 'semi-annual': + wages -= 500.00 * allowances + tax_rate_table = [ + (10000, 0.015, 0.0), + (25000, 0.02, 150.00), + (35000, 0.027, 450.00), + (40000, 0.039, 720.00), + (75000, 0.061, 915.00), + (250000, 0.07, 3050.00), + (float('inf'), 0.099, 15300.00), + ] + + ### ANNUAL ### + elif schedule_pay == 'annually': + wages -= 1000.00 * allowances + tax_rate_table = [ + (20000, 0.015, 0.0), + (50000, 0.02, 300.00), + (70000, 0.027, 900.00), + (80000, 0.039, 1440.00), + (150000, 0.061, 1830.00), + (500000, 0.07, 6100.00), + (float('inf'), 0.099, 30600.00), + ] + +#### RATE 'C' #### +elif rate_table == 'C': + ### WEEKLY ### + if schedule_pay == 'weekly': + wages -= 19.20 * allowances + tax_rate_table = [ + (384, 0.015, 0.0), + (769, 0.023, 5.76), + (961, 0.028, 14.62), + (1153, 0.035, 19.99), + (2884, 0.056, 26.71), + (9615, 0.066, 123.65), + (float('inf'), 0.099, 567.90), + ] + + ### BI-WEEKLY ### + elif schedule_pay == 'bi-weekly': + wages -= 38.40 * allowances + tax_rate_table = [ + (769, 0.015, 0.0), + (1538, 0.023, 11.54), + (1923, 0.028, 29.22), + (2307, 0.035, 40.00), + (5769, 0.056, 53.44), + (19231, 0.066, 247.31), + (float('inf'), 0.099, 1135.80), + ] + + ### SEMI-MONTHLY ### + elif schedule_pay == 'semi-monthly': + wages -= 41.60 * allowances + tax_rate_table = [ + (833, 0.015, 0.0), + (1666, 0.023, 12.50), + (2083, 0.028, 31.65), + (2500, 0.035, 43.33), + (6250, 0.056, 57.93), + (20833, 0.066, 26793), + (float('inf'), 0.099, 1230.41), + ] + + ### MONTHLY ### + elif schedule_pay == 'monthly': + wages -= 83.30 * allowances + tax_rate_table = [ + (1666, 0.015, 0.0), + (3333, 0.023, 24.99), + (4166, 0.028, 63.33), + (5000, 0.035, 86.66), + (12500, 0.056, 115.85), + (41667, 0.066, 535.85), + (float('inf'), 0.099, 2460.87), + ] + + ### QUARTERLY ### + elif schedule_pay == 'quarterly': + wages -= 250.00 * allowances + tax_rate_table = [ + (5000, 0.015, 0.0), + (10000, 0.023, 75.00), + (12500, 0.028, 190.00), + (15000, 0.035, 260.00), + (37500, 0.056, 347.50), + (125000, 0.066, 1607.50), + (float('inf'), 0.099, 7382.50), + ] + + ### SEMI-ANNUAL ### + elif schedule_pay == 'semi-annual': + wages -= 500.00 * allowances + tax_rate_table = [ + (10000, 0.015, 0.0), + (20000, 0.023, 150.00), + (25000, 0.028, 380.00), + (30000, 0.035, 520.00), + (75000, 0.056, 695.00), + (250000, 0.066, 3215.00), + (float('inf'), 0.099, 14765.00), + ] + + ### ANNUAL ### + elif schedule_pay == 'annually': + wages -= 1000.00 * allowances + tax_rate_table = [ + (20000, 0.015, 0.0), + (40000, 0.023, 300.00), + (50000, 0.028, 760.00), + (60000, 0.035, 1040.00), + (150000, 0.056, 1390.00), + (500000, 0.066, 6430.00), + (float('inf'), 0.099, 29530.00), + ] + +#### RATE 'D' #### +elif rate_table == 'D': + ### WEEKLY ### + if schedule_pay == 'weekly': + wages -= 19.20 * allowances + tax_rate_table = [ + (384, 0.015, 0.0), + (769, 0.027, 5.76), + (961, 0.034, 16.16), + (1153, 0.043, 22.68), + (2884, 0.056, 30.94), + (9615, 0.065, 127.88), + (float('inf'), 0.099, 565.40), + ] + + ### BI-WEEKLY ### + elif schedule_pay == 'bi-weekly': + wages -= 38.40 * allowances + tax_rate_table = [ + (769, 0.015, 0.0), + (1538, 0.027, 11.54), + (1923, 0.034, 32.30), + (2307, 0.043, 45.39), + (5769, 0.056, 61.90), + (19231, 0.065, 255.77), + (float('inf'), 0.099, 1130.80), + ] + + ### SEMI-MONTHLY ### + elif schedule_pay == 'semi-monthly': + wages -= 41.60 * allowances + tax_rate_table = [ + (833, 0.015, 0.0), + (1666, 0.027, 12.50), + (2083, 0.034, 34.99), + (2500, 0.043, 49.16), + (6250, 0.056, 67.10), + (20833, 0.065, 277.10), + (float('inf'), 0.099, 1225.00), + ] + + ### MONTHLY ### + elif schedule_pay == 'monthly': + wages -= 83.30 * allowances + tax_rate_table = [ + (1666, 0.015, 0.0), + (3333, 0.027, 24.99), + (4166, 0.034, 70.00), + (5000, 0.043, 98.32), + (12500, 0.056, 134.18), + (41667, 0.065, 554.18), + (float('inf'), 0.099, 2450.04), + ] + + ### QUARTERLY ### + elif schedule_pay == 'quarterly': + wages -= 250.00 * allowances + tax_rate_table = [ + (5000, 0.015, 0.0), + (10000, 0.027, 75.00), + (12500, 0.034, 210.00), + (15000, 0.043, 295.00), + (37500, 0.056, 402.50), + (125000, 0.065, 1662.50), + (float('inf'), 0.099, 7350.00), + ] + + ### SEMI-ANNUAL ### + elif schedule_pay == 'semi-annual': + wages -= 500.00 * allowances + tax_rate_table = [ + (10000, 0.015, 0.0), + (20000, 0.027, 150.00), + (25000, 0.034, 420.00), + (30000, 0.043, 590.00), + (75000, 0.056, 805.00), + (250000, 0.065, 3325.00), + (float('inf'), 0.099, 14700.00), + ] + + ### ANNUAL ### + elif schedule_pay == 'annually': + wages -= 1000.00 * allowances + tax_rate_table = [ + (20000, 0.015, 0.0), + (40000, 0.027, 300.00), + (50000, 0.034, 840.00), + (60000, 0.043, 1180.00), + (150000, 0.056, 1610.00), + (250000, 0.065, 6650.00), + (float('inf'), 0.099, 29400.00), + ] + +#### RATE 'E' #### +elif rate_table == 'E': + ### WEEKLY ### + if schedule_pay == 'weekly': + wages -= 19.20 * allowances + tax_rate_table = [ + (384, 0.015, 0.0), + (673, 0.02, 5.76), + (1923, 0.058, 11.54), + (9615, 0.065, 84.04), + (float('inf'), 0.099, 584.02), + ] + + ### BI-WEEKLY ### + elif schedule_pay == 'bi-weekly': + wages -= 38.40 * allowances + tax_rate_table = [ + (769, 0.015, 0.0), + (1346, 0.02, 11.54), + (3846, 0.058, 23.08), + (19231, 0.065, 168.08), + (float('inf'), 0.099, 1168.11), + ] + + ### SEMI-MONTHLY ### + elif schedule_pay == 'semi-monthly': + wages -= 41.60 * allowances + tax_rate_table = [ + (833, 0.015, 0.0), + (1458, 0.02, 12.50), + (4166, 0.058, 25.00), + (20833, 0.065, 182.06), + (float('inf'), 0.099, 1265.42), + ] + + ### MONTHLY ### + elif schedule_pay == 'monthly': + wages -= 83.30 * allowances + tax_rate_table = [ + (1666, 0.015, 0.0), + (2916, 0.02, 24.99), + (8333, 0.058, 49.99), + (41667, 0.065, 364.18), + (float('inf'), 0.099, 2530.89), + ] + + ### QUARTERLY ### + elif schedule_pay == 'quarterly': + wages -= 250.00 * allowances + tax_rate_table = [ + (5000, 0.015, 0.0), + (8750, 0.02, 75.00), + (25000, 0.058, 150.00), + (125000, 0.065, 1092.50), + (float('inf'), 0.099, 7592.50), + ] + + ### SEMI-ANNUAL ### + elif schedule_pay == 'semi-annual': + wages -= 500.00 * allowances + tax_rate_table = [ + (10000, 0.015, 0.0), + (17500, 0.02, 150.00), + (50000, 0.058, 300.00), + (250000, 0.065, 2185.00), + (float('inf'), 0.099, 15,185.00), + ] + + ### ANNUAL ### + elif schedule_pay == 'annually': + wages -= 1000.00 * allowances + tax_rate_table = [ + (20000, 0.015, 0.0), + (35000, 0.02, 300.00), + (100000, 0.058, 600.00), + (500000, 0.065, 4370.00), + (float('inf'), 0.099, 30370.00), + ] + + +over = 0.0 +tax = 0.0 +for row in tax_rate_table: + if wages <= row[0]: + tax = ((wages - over) * row[1]) + row[2] + tax += additional_withholding + break + over = row[0] + +result = -tax + + + + + + + diff --git a/l10n_us_nj_hr_payroll/tests/__init__.py b/l10n_us_nj_hr_payroll/tests/__init__.py new file mode 100755 index 00000000..02adeeae --- /dev/null +++ b/l10n_us_nj_hr_payroll/tests/__init__.py @@ -0,0 +1 @@ +from . import test_us_nj_payslip_2018 diff --git a/l10n_us_nj_hr_payroll/tests/test_us_nj_payslip_2018.py b/l10n_us_nj_hr_payroll/tests/test_us_nj_payslip_2018.py new file mode 100755 index 00000000..eb9f4e61 --- /dev/null +++ b/l10n_us_nj_hr_payroll/tests/test_us_nj_payslip_2018.py @@ -0,0 +1,135 @@ +from odoo.addons.l10n_us_hr_payroll.tests.test_us_payslip import TestUsPayslip, process_payslip +from odoo.addons.l10n_us_hr_payroll.l10n_us_hr_payroll import USHrContract + + +class TestUsNJPayslip(TestUsPayslip): + ### + # 2018 Taxes and Rates + ### + NJ_UNEMP_MAX_WAGE = 33700.0 + + # Examples found on page 24 of http://www.state.nj.us/treasury/taxation/pdf/current/njwt.pdf + def test_2018_taxes_example1(self): + salary = 300 + schedule_pay = 'weekly' + allowances = 1 + additional_withholding = 0 + + # Tax Percentage Method for Single, taxable pay over $58, under $346 + wh = -4.21 + + employee = self._createEmployee() + employee.company_id.nj_unemp_employee = 0.3825 + employee.company_id.nj_unemp_company = 3.4 + employee.company_id.nj_sdi_employee = 0.19 + employee.company_id.nj_sdi_company = 0.5 + employee.company_id.nj_fli = 0.09 + employee.company_id.nj_wf = 0.0 + + contract = self._createContract(employee, + salary, + struct_id=self.ref( + 'l10n_us_nj_hr_payroll.hr_payroll_salary_structure_us_nj_employee'), + schedule_pay=schedule_pay) + contract.nj_njw4_allowances = allowances + contract.nj_additional_withholding = additional_withholding + contract.nj_njw4_filing_status = 'single' + contract.nj_njw4_rate_table = 'A' + + # tax rates + nj_unemp_employee = contract.nj_unemp_employee_rate(2018) / -100.0 + nj_unemp_company = contract.nj_unemp_company_rate(2018) / -100.0 + nj_sdi_employee = contract.nj_sdi_employee_rate(2018) / -100.0 + nj_sdi_company = contract.nj_sdi_company_rate(2018) / -100.0 + nj_fli = contract.nj_fli_rate(2018) / -100.0 + nj_wf = contract.nj_wf_rate(2018) / -100.0 + + self.assertEqual(contract.schedule_pay, 'weekly') + + self._log('2018 New Jersey tax first payslip:') + payslip = self._createPayslip(employee, '2018-01-01', '2018-01-31') + + payslip.compute_sheet() + + cats = self._getCategories(payslip) + + self.assertPayrollEqual(cats['NJ_UNEMP_WAGES'], salary) + self.assertPayrollEqual(cats['NJ_UNEMP_EMPLOYEE'], round(cats['NJ_UNEMP_WAGES'] * nj_unemp_employee, 2)) + self.assertPayrollEqual(cats['NJ_UNEMP_COMPANY'], cats['NJ_UNEMP_WAGES'] * nj_unemp_company) + self.assertPayrollEqual(cats['NJ_SDI_EMPLOYEE'], cats['NJ_SDI_WAGES'] * nj_sdi_employee) + self.assertPayrollEqual(cats['NJ_SDI_COMPANY'], cats['NJ_SDI_WAGES'] * nj_sdi_company) + self.assertPayrollEqual(cats['NJ_FLI'], cats['NJ_FLI_WAGES'] * nj_fli) + self.assertPayrollEqual(cats['NJ_WF'], cats['NJ_WF_WAGES'] * nj_wf) + self.assertPayrollEqual(cats['NJ_WITHHOLD'], wh) + + process_payslip(payslip) + + # Make a new payslip, this one will have maximums + + remaining_nj_unemp_wages = self.NJ_UNEMP_MAX_WAGE - salary if (self.NJ_UNEMP_MAX_WAGE - 2 * salary < salary) \ + else salary + + self._log('2018 New Jersey tax second payslip:') + payslip = self._createPayslip(employee, '2018-02-01', '2018-02-28') + + payslip.compute_sheet() + + cats = self._getCategories(payslip) + + self.assertPayrollEqual(cats['NJ_UNEMP_WAGES'], remaining_nj_unemp_wages) + self.assertPayrollEqual(cats['NJ_UNEMP_COMPANY'], remaining_nj_unemp_wages * nj_unemp_company) + self.assertPayrollEqual(cats['NJ_UNEMP_EMPLOYEE'], remaining_nj_unemp_wages * nj_unemp_employee) + + def test_2018_taxes_example2(self): + salary = 1400.00 + schedule_pay = 'weekly' + allowances = 3 + additional_withholding = 0 + + # Tax Percentage Method for Single, taxable pay over $58, under $346 + wh = -27.60 + + employee = self._createEmployee() + employee.company_id.nj_unemp_employee = 0.3825 + employee.company_id.nj_unemp_company = 3.4 + employee.company_id.nj_sdi_employee = 0.19 + employee.company_id.nj_sdi_company = 0.5 + employee.company_id.nj_fli = 0.09 + employee.company_id.nj_wf = 0.0 + + contract = self._createContract(employee, + salary, + struct_id=self.ref( + 'l10n_us_nj_hr_payroll.hr_payroll_salary_structure_us_nj_employee'), + schedule_pay=schedule_pay) + contract.nj_njw4_allowances = allowances + contract.nj_additional_withholding = additional_withholding + contract.nj_njw4_filing_status = 'married_joint' + + # tax rates + nj_unemp_employee = contract.nj_unemp_employee_rate(2018) / -100.0 + nj_unemp_company = contract.nj_unemp_company_rate(2018) / -100.0 + nj_sdi_employee = contract.nj_sdi_employee_rate(2018) / -100.0 + nj_sdi_company = contract.nj_sdi_company_rate(2018) / -100.0 + nj_fli = contract.nj_fli_rate(2018) / -100.0 + nj_wf = contract.nj_wf_rate(2018) / -100.0 + + self.assertEqual(contract.schedule_pay, 'weekly') + + self._log('2018 New Jersey tax first payslip:') + payslip = self._createPayslip(employee, '2018-01-01', '2018-01-31') + + payslip.compute_sheet() + + cats = self._getCategories(payslip) + + self.assertPayrollEqual(cats['NJ_UNEMP_WAGES'], salary) + self.assertPayrollEqual(cats['NJ_UNEMP_EMPLOYEE'], round((cats['NJ_UNEMP_WAGES'] * nj_unemp_employee), 2)) + self.assertPayrollEqual(cats['NJ_UNEMP_COMPANY'], cats['NJ_UNEMP_WAGES'] * nj_unemp_company) + self.assertPayrollEqual(cats['NJ_SDI_EMPLOYEE'], cats['NJ_SDI_WAGES'] * nj_sdi_employee) + self.assertPayrollEqual(cats['NJ_SDI_COMPANY'], cats['NJ_SDI_WAGES'] * nj_sdi_company) + self.assertPayrollEqual(cats['NJ_FLI'], cats['NJ_FLI_WAGES'] * nj_fli) + self.assertPayrollEqual(cats['NJ_WF'], cats['NJ_WF_WAGES'] * nj_wf) + self.assertPayrollEqual(cats['NJ_WITHHOLD'], wh) + + process_payslip(payslip) diff --git a/l10n_us_nj_hr_payroll/us_nj_hr_payroll.py b/l10n_us_nj_hr_payroll/us_nj_hr_payroll.py new file mode 100755 index 00000000..567aa1f2 --- /dev/null +++ b/l10n_us_nj_hr_payroll/us_nj_hr_payroll.py @@ -0,0 +1,92 @@ +from odoo import models, fields, api + + +class USNJHrContract(models.Model): + _inherit = 'hr.contract' + + nj_njw4_allowances = fields.Integer(string="New Jersey NJ-W4 Allowances", + default=0, + help="Allowances claimed on NJ W-4") + nj_additional_withholding = fields.Float(string="Additional Withholding", + default=0.0, + help='Additional withholding from line 5 of form NJ-W4') + nj_njw4_filing_status = fields.Selection([ + ('single', 'Single'), + ('married_separate', 'Married/Civil Union partner Separate'), + ('married_joint', 'Married/Civil Union Couple Joint'), + ('widower', 'Widower/Surviving Civil Union Partner'), + ('head_household', 'Head of Household') + ], string='NJ Filing Status', default='single') + nj_njw4_rate_table = fields.Char(string='Wage Chart Letter', + help='Wage Chart Letter from line 3 of form NJ-W4.') + + def nj_unemp_employee_rate(self, year): + self.ensure_one() + if self.futa_type == self.FUTA_TYPE_BASIC: + return 0.0 + + if hasattr(self.employee_id.company_id, 'nj_unemp_employee_rate_' + str(year)): + return self.employee_id.company_id['nj_unemp_employee_rate_' + str(year)] + + raise NotImplemented('Year (' + str(year) + ') Not implemented for US New Jersey.') + + def nj_unemp_company_rate(self, year): + self.ensure_one() + if self.futa_type == self.FUTA_TYPE_BASIC: + return 0.0 + + if hasattr(self.employee_id.company_id, 'nj_unemp_company_rate_' + str(year)): + return self.employee_id.company_id['nj_unemp_company_rate_' + str(year)] + + raise NotImplemented('Year (' + str(year) + ') Not implemented for US New Jersey.') + + def nj_sdi_company_rate(self, year): + self.ensure_one() + if self.futa_type == self.FUTA_TYPE_BASIC: + return 0.0 + + if hasattr(self.employee_id.company_id, 'nj_sdi_company_rate_' + str(year)): + return self.employee_id.company_id['nj_sdi_company_rate_' + str(year)] + + raise NotImplemented('Year (' + str(year) + ') Not implemented for US New Jersey.') + + def nj_sdi_employee_rate(self, year): + self.ensure_one() + if self.futa_type == self.FUTA_TYPE_BASIC: + return 0.0 + + if hasattr(self.employee_id.company_id, 'nj_sdi_employee_rate_' + str(year)): + return self.employee_id.company_id['nj_sdi_employee_rate_' + str(year)] + + raise NotImplemented('Year (' + str(year) + ') Not implemented for US New Jersey.') + + def nj_fli_rate(self, year): + self.ensure_one() + if self.futa_type == self.FUTA_TYPE_BASIC: + return 0.0 + + if hasattr(self.employee_id.company_id, 'nj_fli_rate_' + str(year)): + return self.employee_id.company_id['nj_fli_rate_' + str(year)] + + raise NotImplemented('Year (' + str(year) + ') Not implemented for US New Jersey.') + + def nj_wf_rate(self, year): + self.ensure_one() + if self.futa_type == self.FUTA_TYPE_BASIC: + return 0.0 + + if hasattr(self.employee_id.company_id, 'nj_wf_rate_' + str(year)): + return self.employee_id.company_id['nj_wf_rate_' + str(year)] + + raise NotImplemented('Year (' + str(year) + ') Not implemented for US New Jersey.') + + +class NJCompany(models.Model): + _inherit = 'res.company' + + nj_unemp_company_rate_2018 = fields.Float(string="New Jersey Employer State Unemployment Insurance Rate 2018", default=3.4) + nj_unemp_employee_rate_2018 = fields.Float(string="New Jersey Employee State Unemployment Insurance Rate 2018", default=0.3825) + nj_sdi_company_rate_2018 = fields.Float(string="New Jersey Employer State Disability Insurance Rate 2018", default=0.5) + nj_sdi_employee_rate_2018 = fields.Float(string="New Jersey Employee State Disability Insurance Rate 2018", default=0.19) + nj_fli_rate_2018 = fields.Float(string="New Jersey Family Leave Insurance Rate 2018", default=0.09) + nj_wf_rate_2018 = fields.Float(string="New Jersey Workforce Development Rate 2018", default=0.0) diff --git a/l10n_us_nj_hr_payroll/us_nj_hr_payroll_view.xml b/l10n_us_nj_hr_payroll/us_nj_hr_payroll_view.xml new file mode 100755 index 00000000..e8bc9a4f --- /dev/null +++ b/l10n_us_nj_hr_payroll/us_nj_hr_payroll_view.xml @@ -0,0 +1,40 @@ + + + + + res.company.form + res.company + 20 + + + + + + + + + + + + + + + + + hr.contract.form.inherit + hr.contract + 147 + + + + + + + + + + + + + + From 650d88d10ab1036517ca4f5a2ff3c4d3ebe7330b Mon Sep 17 00:00:00 2001 From: Kristen Marie Kulha Date: Fri, 15 Jun 2018 09:27:32 -0700 Subject: [PATCH 02/11] Add README.rst for `l10n_us_nj_hr_payroll` --- l10n_us_nj_hr_payroll/README.rst | 50 ++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 l10n_us_nj_hr_payroll/README.rst diff --git a/l10n_us_nj_hr_payroll/README.rst b/l10n_us_nj_hr_payroll/README.rst new file mode 100644 index 00000000..3a2ca116 --- /dev/null +++ b/l10n_us_nj_hr_payroll/README.rst @@ -0,0 +1,50 @@ +************************************* +Hibou - US Payroll - New Jersey State +************************************* + +Calculations and contribution registers for New Jersey State Payroll. + +For more information and add-ons, visit `Hibou.io `_. + +============= +Main Features +============= + +* New Partner and Contribution Register for New Jersey Department of Taxation +* Company level New Jersey Unemployment Rate +* Company level New Jersey State Disability Insurance Rate +* Contract level New Jersey State Disability Insurance Rate +* Contract level New Jersey Family Leave Insurance Rate +* Contract level New Jersey Workforce Development/Supplemental Workforce Funds + +.. image:: https://user-images.githubusercontent.com/15882954/41478628-533a04e6-707d-11e8-8892-88e65aca231e.png + :alt: 'Employee Contract Detail' + :width: 988 + :align: left + +USA New Jersey Employee Added to Salary Structure Menu + +.. image:: https://user-images.githubusercontent.com/15882954/41478648-62840ce4-707d-11e8-9623-9638b6136f31.png + :alt: 'Computed Pay Slip Detail' + :width: 988 + :align: left + +New Payslip Categories for: + +* New Jersey Income Withholding +* New Jersey Family Leave Insurance Tax - Wages +* New Jersey State Disability Insurance Tax - Wages +* New Jersey Work Force Development - Wages +* New Jersey Unemployment Insurance Tax - Wages +* New Jersey State Workforce/Supplemental Tax +* New Jersey Unemployment Insurance Tax - Employee +* New Jersey Unemployment Insurance Tax - Employer +* New Jersey State Disability Insurance - Employee +* New Jersey State Disability Insurance - Employer +* New Jersey State Family Leave Insurance Tax + +======= +License +======= +Please see `LICENSE `_. +Copyright Hibou Corp. 2018 From a6bab99aa7a81fc70c7b45653bc140b2aa7085e1 Mon Sep 17 00:00:00 2001 From: Kristen Marie Kulha Date: Fri, 6 Jul 2018 13:26:05 -0700 Subject: [PATCH 03/11] Add filing status fields to form views for CA, KS and NJ. --- l10n_us_nj_hr_payroll/us_nj_hr_payroll_view.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/l10n_us_nj_hr_payroll/us_nj_hr_payroll_view.xml b/l10n_us_nj_hr_payroll/us_nj_hr_payroll_view.xml index e8bc9a4f..537a05f8 100755 --- a/l10n_us_nj_hr_payroll/us_nj_hr_payroll_view.xml +++ b/l10n_us_nj_hr_payroll/us_nj_hr_payroll_view.xml @@ -29,6 +29,8 @@ + + From 9b7fcf315be36f814f03aafffb8d410dca47abea Mon Sep 17 00:00:00 2001 From: Jared Kipe Date: Wed, 15 Aug 2018 13:35:20 -0700 Subject: [PATCH 04/11] Guard against 0 New Jersey WorkForce rate. Remove broken New York test. --- l10n_us_nj_hr_payroll/data/rules_2018.xml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/l10n_us_nj_hr_payroll/data/rules_2018.xml b/l10n_us_nj_hr_payroll/data/rules_2018.xml index 0641e08f..c581bd9a 100755 --- a/l10n_us_nj_hr_payroll/data/rules_2018.xml +++ b/l10n_us_nj_hr_payroll/data/rules_2018.xml @@ -201,6 +201,9 @@ else: result_rate = -contract.nj_wf_rate(2018) result = categories.NJ_WF_WAGES + +if result_rate == 0.0: + result = 0.0 From 5c702908ba1a40b87ee1cab73986a4cd2a2425f1 Mon Sep 17 00:00:00 2001 From: Jared Kipe Date: Sun, 9 Dec 2018 11:51:01 -0800 Subject: [PATCH 05/11] Refactor to mitigate the fact that eligible 401(k) contributions reduce taxable wage (gross) but not FICA/FUTA etc. This refactor bases all/most 'wage' categories off of BASIC instead of GROSS to allow all 'Income Tax' rules to continue to be based on GROSS. --- l10n_us_nj_hr_payroll/data/rules_2018.xml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/l10n_us_nj_hr_payroll/data/rules_2018.xml b/l10n_us_nj_hr_payroll/data/rules_2018.xml index c581bd9a..3cd60ec8 100755 --- a/l10n_us_nj_hr_payroll/data/rules_2018.xml +++ b/l10n_us_nj_hr_payroll/data/rules_2018.xml @@ -19,10 +19,10 @@ ytd += contract.external_wages remaining = 33700.0 - ytd if remaining <= 0.0: result = 0 -elif remaining < categories.GROSS: +elif remaining < categories.BASIC: result = remaining else: - result = categories.GROSS + result = categories.BASIC @@ -82,10 +82,10 @@ ytd += contract.external_wages remaining = 33700.0 - ytd if remaining <= 0.0: result = 0 -elif remaining < categories.GROSS: +elif remaining < categories.BASIC: result = remaining else: - result = categories.GROSS + result = categories.BASIC @@ -144,10 +144,10 @@ ytd += contract.external_wages remaining = 33700.0 - ytd if remaining <= 0.0: result = 0 -elif remaining < categories.GROSS: +elif remaining < categories.BASIC: result = remaining else: - result = categories.GROSS + result = categories.BASIC @@ -183,10 +183,10 @@ ytd += contract.external_wages remaining = 33700.0 - ytd if remaining <= 0.0: result = 0 -elif remaining < categories.GROSS: +elif remaining < categories.BASIC: result = remaining else: - result = categories.GROSS + result = categories.BASIC From 90ce56c1ddbd67234784a737d5969213349f1353 Mon Sep 17 00:00:00 2001 From: Jared Kipe Date: Mon, 17 Dec 2018 13:57:31 -0800 Subject: [PATCH 06/11] Fix sequence on `l10n_us_nj_hr_payroll` to correctly deduct before the NET line evaluates. --- l10n_us_nj_hr_payroll/data/rules_2018.xml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/l10n_us_nj_hr_payroll/data/rules_2018.xml b/l10n_us_nj_hr_payroll/data/rules_2018.xml index 3cd60ec8..17c3ab03 100755 --- a/l10n_us_nj_hr_payroll/data/rules_2018.xml +++ b/l10n_us_nj_hr_payroll/data/rules_2018.xml @@ -5,7 +5,7 @@ - + New Jersey Unemployment Insurance Tax - Wages (2018) NJ_UNEMP_WAGES_2018 @@ -27,7 +27,7 @@ else: - + New Jersey Unemployment - Employee(2018) NJ_UNEMP_EMPLOYEE_2018 @@ -68,7 +68,7 @@ if result_rate == 0.0: - + New Jersey State Disability Tax - Wages (2018) NJ_SDI_WAGES_2018 @@ -90,7 +90,7 @@ else: - + New Jersey State Disability Insurance - Employee(2018) NJ_SDI_EMPLOYEE_2018 @@ -130,7 +130,7 @@ if result_rate == 0.0: - + New Jersey Family Leave Insurance Tax - Wages (2018) NJ_FLI_WAGES_2018 @@ -169,7 +169,7 @@ result = categories.NJ_FLI_WAGES - + New Jersey Workforce Development/Supplemental Workforce Funds Tax - Wages (2018) NJ_WF_WAGES_2018 @@ -191,7 +191,7 @@ else: - + New Jersey Workforce Development/Supplemental Workforce Funds(2018) NJ_WF_2018 From 91e15ddf8d0b9630bb1f3fa79d7b99b9293fb5b0 Mon Sep 17 00:00:00 2001 From: Jared Kipe Date: Fri, 21 Dec 2018 09:11:17 -0800 Subject: [PATCH 07/11] Fix `l10n_us_nj_hr_payroll` and `l10n_us_pa_hr_payroll` sequencing on NJ-FLI and PA-Emp.UIT --- l10n_us_nj_hr_payroll/data/rules_2018.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/l10n_us_nj_hr_payroll/data/rules_2018.xml b/l10n_us_nj_hr_payroll/data/rules_2018.xml index 17c3ab03..c4a6faad 100755 --- a/l10n_us_nj_hr_payroll/data/rules_2018.xml +++ b/l10n_us_nj_hr_payroll/data/rules_2018.xml @@ -130,7 +130,7 @@ if result_rate == 0.0: - + New Jersey Family Leave Insurance Tax - Wages (2018) NJ_FLI_WAGES_2018 @@ -152,7 +152,7 @@ else: - + New Jersey Family Leave Insurance(2018) NJ_FLI_2018 From f0ccdf0b7679c7bab3c981ff1c65c623c40bb947 Mon Sep 17 00:00:00 2001 From: Jared Kipe Date: Sun, 6 Jan 2019 17:06:37 -0800 Subject: [PATCH 08/11] Update `l10n_us_hr_payroll` for 2019 Federal Rates and Limits. --- l10n_us_nj_hr_payroll/tests/test_us_nj_payslip_2018.py | 1 - 1 file changed, 1 deletion(-) diff --git a/l10n_us_nj_hr_payroll/tests/test_us_nj_payslip_2018.py b/l10n_us_nj_hr_payroll/tests/test_us_nj_payslip_2018.py index eb9f4e61..24b0dd54 100755 --- a/l10n_us_nj_hr_payroll/tests/test_us_nj_payslip_2018.py +++ b/l10n_us_nj_hr_payroll/tests/test_us_nj_payslip_2018.py @@ -1,5 +1,4 @@ from odoo.addons.l10n_us_hr_payroll.tests.test_us_payslip import TestUsPayslip, process_payslip -from odoo.addons.l10n_us_hr_payroll.l10n_us_hr_payroll import USHrContract class TestUsNJPayslip(TestUsPayslip): From 60584776a085c0d23b34445aa8c5228c2d9c5722 Mon Sep 17 00:00:00 2001 From: Jared Kipe Date: Tue, 8 Jan 2019 17:28:40 -0800 Subject: [PATCH 09/11] Update `l10n_us_nj_hr_payroll` for 2019 refactor (WIP) --- l10n_us_nj_hr_payroll/__init__.py | 2 +- l10n_us_nj_hr_payroll/__manifest__.py | 7 +- l10n_us_nj_hr_payroll/data/base.xml | 44 +++--- l10n_us_nj_hr_payroll/data/rates.xml | 56 ++++++++ .../data/{rules_2018.xml => rules.xml} | 126 ++++++++++-------- l10n_us_nj_hr_payroll/models/__init__.py | 1 + .../models/us_nj_hr_payroll.py | 21 +++ .../tests/test_us_nj_payslip_2018.py | 76 ++++------- l10n_us_nj_hr_payroll/us_nj_hr_payroll.py | 92 ------------- .../us_nj_hr_payroll_views.xml} | 19 --- 10 files changed, 202 insertions(+), 242 deletions(-) create mode 100644 l10n_us_nj_hr_payroll/data/rates.xml rename l10n_us_nj_hr_payroll/data/{rules_2018.xml => rules.xml} (82%) create mode 100644 l10n_us_nj_hr_payroll/models/__init__.py create mode 100755 l10n_us_nj_hr_payroll/models/us_nj_hr_payroll.py delete mode 100755 l10n_us_nj_hr_payroll/us_nj_hr_payroll.py rename l10n_us_nj_hr_payroll/{us_nj_hr_payroll_view.xml => views/us_nj_hr_payroll_views.xml} (53%) diff --git a/l10n_us_nj_hr_payroll/__init__.py b/l10n_us_nj_hr_payroll/__init__.py index 48629d95..0650744f 100755 --- a/l10n_us_nj_hr_payroll/__init__.py +++ b/l10n_us_nj_hr_payroll/__init__.py @@ -1 +1 @@ -from . import us_nj_hr_payroll +from . import models diff --git a/l10n_us_nj_hr_payroll/__manifest__.py b/l10n_us_nj_hr_payroll/__manifest__.py index 6b34c3aa..724ae7df 100755 --- a/l10n_us_nj_hr_payroll/__manifest__.py +++ b/l10n_us_nj_hr_payroll/__manifest__.py @@ -4,7 +4,7 @@ 'license': 'AGPL-3', 'category': 'Localization', 'depends': ['l10n_us_hr_payroll'], - 'version': '11.0.2018.0.0', + 'version': '11.0.2019.0.0', 'description': """ USA::New Jersey Payroll Rules. ============================== @@ -22,9 +22,10 @@ USA::New Jersey Payroll Rules. 'auto_install': False, 'website': 'https://hibou.io/', 'data':[ - 'us_nj_hr_payroll_view.xml', + 'views/us_nj_hr_payroll_views.xml', 'data/base.xml', - 'data/rules_2018.xml', + 'data/rates.xml', + 'data/rules.xml', 'data/final.xml', ], 'installable': True diff --git a/l10n_us_nj_hr_payroll/data/base.xml b/l10n_us_nj_hr_payroll/data/base.xml index 5db83ed6..4d8da28b 100755 --- a/l10n_us_nj_hr_payroll/data/base.xml +++ b/l10n_us_nj_hr_payroll/data/base.xml @@ -90,64 +90,64 @@ - New Jersey Unemployment Insurance Tax - Wages - NJ_UNEMP_WAGES + Wage: US-NJ Unemployment Insurance + WAGE_US_NJ_UNEMP - New Jersey State Disability Insurance Tax - Wages - NJ_SDI_WAGES + Wage: US-NJ State Disability Insurance + WAGE_US_NJ_SDI - New Jersey Family Leave Insurance Tax - Wages - NJ_FLI_WAGES + Wage: US-NJ Family Leave Insurance + WAGE_US_NJ_FLI - New Jersey Work Force Development - Wages - NJ_WF_WAGES + Wage: US-NJ Work Force Development + WAGE_US_NJ_WF - New Jersey Unemployment Insurance Tax - Employee - NJ_UNEMP_EMPLOYEE + EE: US-NJ Unemployment Insurance + EE_US_NJ_UNEMP - New Jersey Unemployment Insurance Tax - Employer - NJ_UNEMP_COMPANY + ER: US-NJ Unemployment Insurance + ER_US_NJ_UNEMP - New Jersey State Disability Insurance - Employer - NJ_SDI_COMPANY + ER: US-NJ State Disability Insurance + ER_US_NJ_SDI - New Jersey State Disability Insurance - Employee - NJ_SDI_EMPLOYEE + EE: US-NJ State Disability Insurance + EE_US_NJ_SDI - New Jersey State Family Leave Insurance Tax - NJ_FLI + EE: US-NJ Family Leave Insurance + EE_US_NJ_FLI - New Jersey State Workforce Development/Suppllemental Tax - NJ_WF + EE: US-NJ Workforce Development + EE_US_NJ_WF - New Jersey Income Withholding - NJ_WITHHOLD + EE: US-NJ Income Withholding + EE_US_NJ_INC_WITHHOLD diff --git a/l10n_us_nj_hr_payroll/data/rates.xml b/l10n_us_nj_hr_payroll/data/rates.xml new file mode 100644 index 00000000..c8173c3d --- /dev/null +++ b/l10n_us_nj_hr_payroll/data/rates.xml @@ -0,0 +1,56 @@ + + + + + US NJ Unemployment (Company) + ER_US_NJ_UNEMP + 3.4 + 2018-01-01 + + + + US NJ Unemployment (Employee) + EE_US_NJ_UNEMP + 0.3825 + 2018-01-01 + + + US NJ State Disability Insurance (Company) + ER_US_NJ_SDI + 0.5 + 2018-01-01 + + + + US NJ State Disability Insurance (Employee) + EE_US_NJ_SDI + 0.24 + 2018-01-01 + + + US NJ Family Leave Insurance (Company) + ER_US_NJ_FLI + 0.00 + 2018-01-01 + + + + US NJ Family Leave Insurance (Employee) + EE_US_NJ_FLI + 0.1 + 2018-01-01 + + + US NJ Workforce Development (Company) + ER_US_NJ_WF + 0.1175 + 2018-01-01 + + + US NJ Workforce Development (Employee) + EE_US_NJ_WF + 0.0425 + 2018-01-01 + + + \ No newline at end of file diff --git a/l10n_us_nj_hr_payroll/data/rules_2018.xml b/l10n_us_nj_hr_payroll/data/rules.xml similarity index 82% rename from l10n_us_nj_hr_payroll/data/rules_2018.xml rename to l10n_us_nj_hr_payroll/data/rules.xml index c4a6faad..e0f90d6e 100755 --- a/l10n_us_nj_hr_payroll/data/rules_2018.xml +++ b/l10n_us_nj_hr_payroll/data/rules.xml @@ -5,18 +5,20 @@ - + - New Jersey Unemployment Insurance Tax - Wages (2018) - NJ_UNEMP_WAGES_2018 + Wage: US-NJ Unemployment Insurance + WAGE_US_NJ_UNEMP python - result = (payslip.date_to[:4] == '2018') + result = (contract.futa_type != contract.FUTA_TYPE_BASIC) code ### -ytd = payslip.sum('NJ_UNEMP_WAGES_2018', '2018-01-01', '2019-01-01') +year = int(payslip.dict.date_from[:4]) +rate = payslip.dict.get_rate('ER_US_NJ_UNEMP') +ytd = payslip.sum('WAGE_US_NJ_UNEMP', str(year) + '-01-01', str(year+1) + '-01-01') ytd += contract.external_wages -remaining = 33700.0 - ytd +remaining = rate.wage_limit_year - ytd if remaining <= 0.0: result = 0 elif remaining < categories.BASIC: @@ -29,14 +31,15 @@ else: - New Jersey Unemployment - Employee(2018) - NJ_UNEMP_EMPLOYEE_2018 + EE: US-NJ Unemployment + EE_US_NJ_UNEMP python - result = (payslip.date_to[:4] == '2018') + result = (contract.futa_type != contract.FUTA_TYPE_BASIC) code -result_rate = -contract.nj_unemp_employee_rate(2018) -result = categories.NJ_UNEMP_WAGES +rate = payslip.dict.get_rate('EE_US_NJ_UNEMP') +result_rate = -rate.rate +result = categories.BASIC # result_rate of 0 implies 100% due to bug if result_rate == 0.0: @@ -48,14 +51,15 @@ if result_rate == 0.0: - New Jersey Unemployment - Employer(2018) - NJ_UNEMP_COMPANY_2018 + ER: US-NJ Unemployment + ER_US_NJ_UNEMP python - result = (payslip.date_to[:4] == '2018') + result = (contract.futa_type != contract.FUTA_TYPE_BASIC) code -result_rate = -contract.nj_unemp_company_rate(2018) -result = categories.NJ_UNEMP_WAGES +rate = payslip.dict.get_rate('ER_US_NJ_UNEMP') +result_rate = -rate.rate +result = categories.WAGE_US_NJ_UNEMP # result_rate of 0 implies 100% due to bug if result_rate == 0.0: @@ -68,18 +72,20 @@ if result_rate == 0.0: - + - New Jersey State Disability Tax - Wages (2018) - NJ_SDI_WAGES_2018 + Wage: US-NJ State Disability Insurance + WAGE_US_NJ_SDI python - result = (payslip.date_to[:4] == '2018') + result = (contract.futa_type != contract.FUTA_TYPE_BASIC) code ### -ytd = payslip.sum('NJ_SDI_WAGES_2018', '2018-01-01', '2019-01-01') +year = int(payslip.dict.date_from[:4]) +rate = payslip.dict.get_rate('ER_US_NJ_SDI') +ytd = payslip.sum('WAGE_US_NJ_SDI', str(year) + '-01-01', str(year+1) + '-01-01') ytd += contract.external_wages -remaining = 33700.0 - ytd +remaining = rate.wage_limit_year - ytd if remaining <= 0.0: result = 0 elif remaining < categories.BASIC: @@ -92,14 +98,15 @@ else: - New Jersey State Disability Insurance - Employee(2018) - NJ_SDI_EMPLOYEE_2018 + EE: US-NJ State Disability Insurance + EE_US_NJ_SDI python - result = (payslip.date_to[:4] == '2018') + result = (contract.futa_type != contract.FUTA_TYPE_BASIC) code -result_rate = -contract.nj_sdi_employee_rate(2018) -result = categories.NJ_SDI_WAGES +rate = payslip.dict.get_rate('EE_US_NJ_SDI') +result_rate = -rate.rate +result = categories.BASIC # result_rate of 0 implies 100% due to bug if result_rate == 0.0: @@ -111,14 +118,15 @@ if result_rate == 0.0: - New Jersey State Disability Insurance - Employer(2018) - NJ_SDI_COMPANY_2018 + ER: US-NJ State Disability Insurance + ER_US_NJ_SDI python - result = (payslip.date_to[:4] == '2018') + result = (contract.futa_type != contract.FUTA_TYPE_BASIC) code -result_rate = -contract.nj_sdi_company_rate(2018) -result = categories.NJ_SDI_WAGES +rate = payslip.dict.get_rate('ER_US_NJ_SDI') +result_rate = -rate.rate +result = categories.WAGE_US_NJ_SDI # result_rate of 0 implies 100% due to bug if result_rate == 0.0: @@ -130,18 +138,20 @@ if result_rate == 0.0: - + - New Jersey Family Leave Insurance Tax - Wages (2018) - NJ_FLI_WAGES_2018 + Wage: US-NJ Family Leave Insurance + WAGE_US_NJ_FLI python - result = (payslip.date_to[:4] == '2018') + result = (contract.futa_type != contract.FUTA_TYPE_BASIC) code ### -ytd = payslip.sum('NJ_FLI_WAGES_2018', '2018-01-01', '2019-01-01') +year = int(payslip.dict.date_from[:4]) +rate = payslip.dict.get_rate('ER_US_NJ_FLI') +ytd = payslip.sum('WAGE_US_NJ_FLI', str(year) + '-01-01', str(year+1) + '-01-01') ytd += contract.external_wages -remaining = 33700.0 - ytd +remaining = rate.wage_limit_year - ytd if remaining <= 0.0: result = 0 elif remaining < categories.BASIC: @@ -154,14 +164,15 @@ else: - New Jersey Family Leave Insurance(2018) - NJ_FLI_2018 + EE: US-NJ Family Leave Insurance + EE_US_NJ_FLI python - result = (payslip.date_to[:4] == '2018') + result = (contract.futa_type != contract.FUTA_TYPE_BASIC) code -result_rate = -contract.nj_fli_rate(2018) -result = categories.NJ_FLI_WAGES +rate = payslip.dict.get_rate('EE_US_NJ_FLI') +result_rate = -rate.rate +result = categories.BASIC @@ -171,16 +182,18 @@ result = categories.NJ_FLI_WAGES - New Jersey Workforce Development/Supplemental Workforce Funds Tax - Wages (2018) - NJ_WF_WAGES_2018 + Wage: US-NJ Workforce Development Funds + WAGE_US_NJ_WF python - result = (payslip.date_to[:4] == '2018') + result = (contract.futa_type != contract.FUTA_TYPE_BASIC) code ### -ytd = payslip.sum('NJ_WF_WAGES_2018', '2018-01-01', '2019-01-01') +year = int(payslip.dict.date_from[:4]) +rate = payslip.dict.get_rate('ER_US_NJ_WF') +ytd = payslip.sum('WAGE_US_NJ_WF', str(year) + '-01-01', str(year+1) + '-01-01') ytd += contract.external_wages -remaining = 33700.0 - ytd +remaining = rate.wage_limit_year - ytd if remaining <= 0.0: result = 0 elif remaining < categories.BASIC: @@ -193,14 +206,15 @@ else: - New Jersey Workforce Development/Supplemental Workforce Funds(2018) - NJ_WF_2018 + EE: US-NJ Workforce Development Funds + EE_US_NJ_WF python - result = (payslip.date_to[:4] == '2018') + result = (contract.futa_type != contract.FUTA_TYPE_BASIC) code -result_rate = -contract.nj_wf_rate(2018) -result = categories.NJ_WF_WAGES +rate = payslip.dict.get_rate('EE_US_NJ_WF') +result_rate = -rate.rate +result = categories.BASIC if result_rate == 0.0: result = 0.0 @@ -213,10 +227,10 @@ if result_rate == 0.0: - New Jersey Income Withholding - NJ_INC_WITHHOLD_2018 + EE: US-NJ Income Withholding + EE_US_NJ_INC_WITHHOLD python - result = (payslip.date_to[:4] == '2018') + result = True code wages = categories.GROSS diff --git a/l10n_us_nj_hr_payroll/models/__init__.py b/l10n_us_nj_hr_payroll/models/__init__.py new file mode 100644 index 00000000..48629d95 --- /dev/null +++ b/l10n_us_nj_hr_payroll/models/__init__.py @@ -0,0 +1 @@ +from . import us_nj_hr_payroll diff --git a/l10n_us_nj_hr_payroll/models/us_nj_hr_payroll.py b/l10n_us_nj_hr_payroll/models/us_nj_hr_payroll.py new file mode 100755 index 00000000..315a9136 --- /dev/null +++ b/l10n_us_nj_hr_payroll/models/us_nj_hr_payroll.py @@ -0,0 +1,21 @@ +from odoo import models, fields, api + + +class USNJHrContract(models.Model): + _inherit = 'hr.contract' + + nj_njw4_allowances = fields.Integer(string="New Jersey NJ-W4 Allowances", + default=0, + help="Allowances claimed on NJ W-4") + nj_additional_withholding = fields.Float(string="Additional Withholding", + default=0.0, + help='Additional withholding from line 5 of form NJ-W4') + nj_njw4_filing_status = fields.Selection([ + ('single', 'Single'), + ('married_separate', 'Married/Civil Union partner Separate'), + ('married_joint', 'Married/Civil Union Couple Joint'), + ('widower', 'Widower/Surviving Civil Union Partner'), + ('head_household', 'Head of Household') + ], string='NJ Filing Status', default='single') + nj_njw4_rate_table = fields.Char(string='Wage Chart Letter', + help='Wage Chart Letter from line 3 of form NJ-W4.') diff --git a/l10n_us_nj_hr_payroll/tests/test_us_nj_payslip_2018.py b/l10n_us_nj_hr_payroll/tests/test_us_nj_payslip_2018.py index 24b0dd54..5e2c6522 100755 --- a/l10n_us_nj_hr_payroll/tests/test_us_nj_payslip_2018.py +++ b/l10n_us_nj_hr_payroll/tests/test_us_nj_payslip_2018.py @@ -6,6 +6,14 @@ class TestUsNJPayslip(TestUsPayslip): # 2018 Taxes and Rates ### NJ_UNEMP_MAX_WAGE = 33700.0 + EE_NJ_UNEMP = -0.3825 / 100.0 + ER_NJ_UNEMP = -3.4 / 100.0 + EE_NJ_SDI = -0.24 / 100.0 + ER_NJ_SDI = -0.5 / 100.0 + EE_NJ_FLI = -0.1 / 100.0 + ER_NJ_FLI = 0.0 + EE_NJ_WF = -0.0425 / 100.0 + ER_NJ_WF = 0.0 # Examples found on page 24 of http://www.state.nj.us/treasury/taxation/pdf/current/njwt.pdf def test_2018_taxes_example1(self): @@ -18,13 +26,6 @@ class TestUsNJPayslip(TestUsPayslip): wh = -4.21 employee = self._createEmployee() - employee.company_id.nj_unemp_employee = 0.3825 - employee.company_id.nj_unemp_company = 3.4 - employee.company_id.nj_sdi_employee = 0.19 - employee.company_id.nj_sdi_company = 0.5 - employee.company_id.nj_fli = 0.09 - employee.company_id.nj_wf = 0.0 - contract = self._createContract(employee, salary, struct_id=self.ref( @@ -35,14 +36,6 @@ class TestUsNJPayslip(TestUsPayslip): contract.nj_njw4_filing_status = 'single' contract.nj_njw4_rate_table = 'A' - # tax rates - nj_unemp_employee = contract.nj_unemp_employee_rate(2018) / -100.0 - nj_unemp_company = contract.nj_unemp_company_rate(2018) / -100.0 - nj_sdi_employee = contract.nj_sdi_employee_rate(2018) / -100.0 - nj_sdi_company = contract.nj_sdi_company_rate(2018) / -100.0 - nj_fli = contract.nj_fli_rate(2018) / -100.0 - nj_wf = contract.nj_wf_rate(2018) / -100.0 - self.assertEqual(contract.schedule_pay, 'weekly') self._log('2018 New Jersey tax first payslip:') @@ -52,14 +45,14 @@ class TestUsNJPayslip(TestUsPayslip): cats = self._getCategories(payslip) - self.assertPayrollEqual(cats['NJ_UNEMP_WAGES'], salary) - self.assertPayrollEqual(cats['NJ_UNEMP_EMPLOYEE'], round(cats['NJ_UNEMP_WAGES'] * nj_unemp_employee, 2)) - self.assertPayrollEqual(cats['NJ_UNEMP_COMPANY'], cats['NJ_UNEMP_WAGES'] * nj_unemp_company) - self.assertPayrollEqual(cats['NJ_SDI_EMPLOYEE'], cats['NJ_SDI_WAGES'] * nj_sdi_employee) - self.assertPayrollEqual(cats['NJ_SDI_COMPANY'], cats['NJ_SDI_WAGES'] * nj_sdi_company) - self.assertPayrollEqual(cats['NJ_FLI'], cats['NJ_FLI_WAGES'] * nj_fli) - self.assertPayrollEqual(cats['NJ_WF'], cats['NJ_WF_WAGES'] * nj_wf) - self.assertPayrollEqual(cats['NJ_WITHHOLD'], wh) + self.assertPayrollEqual(cats['WAGE_US_NJ_UNEMP'], salary) + self.assertPayrollEqual(cats['EE_US_NJ_UNEMP'], round(cats['BASIC'] * self.EE_NJ_UNEMP, 2)) + self.assertPayrollEqual(cats['ER_US_NJ_UNEMP'], cats['WAGE_US_NJ_UNEMP'] * self.ER_NJ_UNEMP) + self.assertPayrollEqual(cats['EE_US_NJ_SDI'], cats['BASIC'] * self.EE_NJ_SDI) + self.assertPayrollEqual(cats['ER_US_NJ_SDI'], cats['WAGE_US_NJ_SDI'] * self.ER_NJ_SDI) + self.assertPayrollEqual(cats['EE_US_NJ_FLI'], cats['BASIC'] * self.EE_NJ_FLI) + self.assertPayrollEqual(cats['EE_US_NJ_WF'], cats['BASIC'] * self.EE_NJ_WF) + self.assertPayrollEqual(cats['EE_US_NJ_INC_WITHHOLD'], wh) process_payslip(payslip) @@ -75,9 +68,9 @@ class TestUsNJPayslip(TestUsPayslip): cats = self._getCategories(payslip) - self.assertPayrollEqual(cats['NJ_UNEMP_WAGES'], remaining_nj_unemp_wages) - self.assertPayrollEqual(cats['NJ_UNEMP_COMPANY'], remaining_nj_unemp_wages * nj_unemp_company) - self.assertPayrollEqual(cats['NJ_UNEMP_EMPLOYEE'], remaining_nj_unemp_wages * nj_unemp_employee) + self.assertPayrollEqual(cats['WAGE_US_NJ_UNEMP'], remaining_nj_unemp_wages) + self.assertPayrollEqual(cats['ER_US_NJ_UNEMP'], remaining_nj_unemp_wages * self.ER_NJ_UNEMP) + self.assertPayrollEqual(cats['EE_US_NJ_UNEMP'], cats['BASIC'] * self.EE_NJ_UNEMP) def test_2018_taxes_example2(self): salary = 1400.00 @@ -89,13 +82,6 @@ class TestUsNJPayslip(TestUsPayslip): wh = -27.60 employee = self._createEmployee() - employee.company_id.nj_unemp_employee = 0.3825 - employee.company_id.nj_unemp_company = 3.4 - employee.company_id.nj_sdi_employee = 0.19 - employee.company_id.nj_sdi_company = 0.5 - employee.company_id.nj_fli = 0.09 - employee.company_id.nj_wf = 0.0 - contract = self._createContract(employee, salary, struct_id=self.ref( @@ -105,14 +91,6 @@ class TestUsNJPayslip(TestUsPayslip): contract.nj_additional_withholding = additional_withholding contract.nj_njw4_filing_status = 'married_joint' - # tax rates - nj_unemp_employee = contract.nj_unemp_employee_rate(2018) / -100.0 - nj_unemp_company = contract.nj_unemp_company_rate(2018) / -100.0 - nj_sdi_employee = contract.nj_sdi_employee_rate(2018) / -100.0 - nj_sdi_company = contract.nj_sdi_company_rate(2018) / -100.0 - nj_fli = contract.nj_fli_rate(2018) / -100.0 - nj_wf = contract.nj_wf_rate(2018) / -100.0 - self.assertEqual(contract.schedule_pay, 'weekly') self._log('2018 New Jersey tax first payslip:') @@ -122,13 +100,13 @@ class TestUsNJPayslip(TestUsPayslip): cats = self._getCategories(payslip) - self.assertPayrollEqual(cats['NJ_UNEMP_WAGES'], salary) - self.assertPayrollEqual(cats['NJ_UNEMP_EMPLOYEE'], round((cats['NJ_UNEMP_WAGES'] * nj_unemp_employee), 2)) - self.assertPayrollEqual(cats['NJ_UNEMP_COMPANY'], cats['NJ_UNEMP_WAGES'] * nj_unemp_company) - self.assertPayrollEqual(cats['NJ_SDI_EMPLOYEE'], cats['NJ_SDI_WAGES'] * nj_sdi_employee) - self.assertPayrollEqual(cats['NJ_SDI_COMPANY'], cats['NJ_SDI_WAGES'] * nj_sdi_company) - self.assertPayrollEqual(cats['NJ_FLI'], cats['NJ_FLI_WAGES'] * nj_fli) - self.assertPayrollEqual(cats['NJ_WF'], cats['NJ_WF_WAGES'] * nj_wf) - self.assertPayrollEqual(cats['NJ_WITHHOLD'], wh) + self.assertPayrollEqual(cats['WAGE_US_NJ_UNEMP'], salary) + self.assertPayrollEqual(cats['EE_US_NJ_UNEMP'], cats['BASIC'] * self.EE_NJ_UNEMP) + self.assertPayrollEqual(cats['ER_US_NJ_UNEMP'], cats['WAGE_US_NJ_UNEMP'] * self.ER_NJ_UNEMP) + self.assertPayrollEqual(cats['EE_US_NJ_SDI'], cats['BASIC'] * self.EE_NJ_SDI) + self.assertPayrollEqual(cats['ER_US_NJ_SDI'], cats['WAGE_US_NJ_SDI'] * self.ER_NJ_SDI) + self.assertPayrollEqual(cats['EE_US_NJ_FLI'], cats['BASIC'] * self.EE_NJ_FLI) + self.assertPayrollEqual(cats['EE_US_NJ_WF'], cats['BASIC'] * self.EE_NJ_WF) + self.assertPayrollEqual(cats['EE_US_NJ_INC_WITHHOLD'], wh) process_payslip(payslip) diff --git a/l10n_us_nj_hr_payroll/us_nj_hr_payroll.py b/l10n_us_nj_hr_payroll/us_nj_hr_payroll.py deleted file mode 100755 index 567aa1f2..00000000 --- a/l10n_us_nj_hr_payroll/us_nj_hr_payroll.py +++ /dev/null @@ -1,92 +0,0 @@ -from odoo import models, fields, api - - -class USNJHrContract(models.Model): - _inherit = 'hr.contract' - - nj_njw4_allowances = fields.Integer(string="New Jersey NJ-W4 Allowances", - default=0, - help="Allowances claimed on NJ W-4") - nj_additional_withholding = fields.Float(string="Additional Withholding", - default=0.0, - help='Additional withholding from line 5 of form NJ-W4') - nj_njw4_filing_status = fields.Selection([ - ('single', 'Single'), - ('married_separate', 'Married/Civil Union partner Separate'), - ('married_joint', 'Married/Civil Union Couple Joint'), - ('widower', 'Widower/Surviving Civil Union Partner'), - ('head_household', 'Head of Household') - ], string='NJ Filing Status', default='single') - nj_njw4_rate_table = fields.Char(string='Wage Chart Letter', - help='Wage Chart Letter from line 3 of form NJ-W4.') - - def nj_unemp_employee_rate(self, year): - self.ensure_one() - if self.futa_type == self.FUTA_TYPE_BASIC: - return 0.0 - - if hasattr(self.employee_id.company_id, 'nj_unemp_employee_rate_' + str(year)): - return self.employee_id.company_id['nj_unemp_employee_rate_' + str(year)] - - raise NotImplemented('Year (' + str(year) + ') Not implemented for US New Jersey.') - - def nj_unemp_company_rate(self, year): - self.ensure_one() - if self.futa_type == self.FUTA_TYPE_BASIC: - return 0.0 - - if hasattr(self.employee_id.company_id, 'nj_unemp_company_rate_' + str(year)): - return self.employee_id.company_id['nj_unemp_company_rate_' + str(year)] - - raise NotImplemented('Year (' + str(year) + ') Not implemented for US New Jersey.') - - def nj_sdi_company_rate(self, year): - self.ensure_one() - if self.futa_type == self.FUTA_TYPE_BASIC: - return 0.0 - - if hasattr(self.employee_id.company_id, 'nj_sdi_company_rate_' + str(year)): - return self.employee_id.company_id['nj_sdi_company_rate_' + str(year)] - - raise NotImplemented('Year (' + str(year) + ') Not implemented for US New Jersey.') - - def nj_sdi_employee_rate(self, year): - self.ensure_one() - if self.futa_type == self.FUTA_TYPE_BASIC: - return 0.0 - - if hasattr(self.employee_id.company_id, 'nj_sdi_employee_rate_' + str(year)): - return self.employee_id.company_id['nj_sdi_employee_rate_' + str(year)] - - raise NotImplemented('Year (' + str(year) + ') Not implemented for US New Jersey.') - - def nj_fli_rate(self, year): - self.ensure_one() - if self.futa_type == self.FUTA_TYPE_BASIC: - return 0.0 - - if hasattr(self.employee_id.company_id, 'nj_fli_rate_' + str(year)): - return self.employee_id.company_id['nj_fli_rate_' + str(year)] - - raise NotImplemented('Year (' + str(year) + ') Not implemented for US New Jersey.') - - def nj_wf_rate(self, year): - self.ensure_one() - if self.futa_type == self.FUTA_TYPE_BASIC: - return 0.0 - - if hasattr(self.employee_id.company_id, 'nj_wf_rate_' + str(year)): - return self.employee_id.company_id['nj_wf_rate_' + str(year)] - - raise NotImplemented('Year (' + str(year) + ') Not implemented for US New Jersey.') - - -class NJCompany(models.Model): - _inherit = 'res.company' - - nj_unemp_company_rate_2018 = fields.Float(string="New Jersey Employer State Unemployment Insurance Rate 2018", default=3.4) - nj_unemp_employee_rate_2018 = fields.Float(string="New Jersey Employee State Unemployment Insurance Rate 2018", default=0.3825) - nj_sdi_company_rate_2018 = fields.Float(string="New Jersey Employer State Disability Insurance Rate 2018", default=0.5) - nj_sdi_employee_rate_2018 = fields.Float(string="New Jersey Employee State Disability Insurance Rate 2018", default=0.19) - nj_fli_rate_2018 = fields.Float(string="New Jersey Family Leave Insurance Rate 2018", default=0.09) - nj_wf_rate_2018 = fields.Float(string="New Jersey Workforce Development Rate 2018", default=0.0) diff --git a/l10n_us_nj_hr_payroll/us_nj_hr_payroll_view.xml b/l10n_us_nj_hr_payroll/views/us_nj_hr_payroll_views.xml similarity index 53% rename from l10n_us_nj_hr_payroll/us_nj_hr_payroll_view.xml rename to l10n_us_nj_hr_payroll/views/us_nj_hr_payroll_views.xml index 537a05f8..ec2f564d 100755 --- a/l10n_us_nj_hr_payroll/us_nj_hr_payroll_view.xml +++ b/l10n_us_nj_hr_payroll/views/us_nj_hr_payroll_views.xml @@ -1,25 +1,6 @@ - - res.company.form - res.company - 20 - - - - - - - - - - - - - - - hr.contract.form.inherit hr.contract From 5b35926f6db2746cb18d850bc8c4044cae4ed861 Mon Sep 17 00:00:00 2001 From: Jared Kipe Date: Wed, 16 Jan 2019 09:47:58 -0800 Subject: [PATCH 10/11] FIX Correct payslip wage base for payslips in two years. Add 2019 Ohio Tax Withholding rate. --- l10n_us_nj_hr_payroll/data/rules.xml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/l10n_us_nj_hr_payroll/data/rules.xml b/l10n_us_nj_hr_payroll/data/rules.xml index e0f90d6e..45b095dc 100755 --- a/l10n_us_nj_hr_payroll/data/rules.xml +++ b/l10n_us_nj_hr_payroll/data/rules.xml @@ -14,7 +14,7 @@ code ### -year = int(payslip.dict.date_from[:4]) +year = int(payslip.dict.date_to[:4]) rate = payslip.dict.get_rate('ER_US_NJ_UNEMP') ytd = payslip.sum('WAGE_US_NJ_UNEMP', str(year) + '-01-01', str(year+1) + '-01-01') ytd += contract.external_wages @@ -81,7 +81,7 @@ if result_rate == 0.0: code ### -year = int(payslip.dict.date_from[:4]) +year = int(payslip.dict.date_to[:4]) rate = payslip.dict.get_rate('ER_US_NJ_SDI') ytd = payslip.sum('WAGE_US_NJ_SDI', str(year) + '-01-01', str(year+1) + '-01-01') ytd += contract.external_wages @@ -147,7 +147,7 @@ if result_rate == 0.0: code ### -year = int(payslip.dict.date_from[:4]) +year = int(payslip.dict.date_to[:4]) rate = payslip.dict.get_rate('ER_US_NJ_FLI') ytd = payslip.sum('WAGE_US_NJ_FLI', str(year) + '-01-01', str(year+1) + '-01-01') ytd += contract.external_wages @@ -189,7 +189,7 @@ result = categories.BASIC code ### -year = int(payslip.dict.date_from[:4]) +year = int(payslip.dict.date_to[:4]) rate = payslip.dict.get_rate('ER_US_NJ_WF') ytd = payslip.sum('WAGE_US_NJ_WF', str(year) + '-01-01', str(year+1) + '-01-01') ytd += contract.external_wages From 498f4c379a9a8671e25847298373c9dcf14c2824 Mon Sep 17 00:00:00 2001 From: Jared Kipe Date: Sun, 10 Feb 2019 15:59:18 -0800 Subject: [PATCH 11/11] MIG `l10n_us_nj_hr_payroll` to 12.0 --- l10n_us_nj_hr_payroll/__manifest__.py | 2 +- l10n_us_nj_hr_payroll/data/rules.xml | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/l10n_us_nj_hr_payroll/__manifest__.py b/l10n_us_nj_hr_payroll/__manifest__.py index 724ae7df..d93a3b11 100755 --- a/l10n_us_nj_hr_payroll/__manifest__.py +++ b/l10n_us_nj_hr_payroll/__manifest__.py @@ -4,7 +4,7 @@ 'license': 'AGPL-3', 'category': 'Localization', 'depends': ['l10n_us_hr_payroll'], - 'version': '11.0.2019.0.0', + 'version': '12.0.2019.0.0', 'description': """ USA::New Jersey Payroll Rules. ============================== diff --git a/l10n_us_nj_hr_payroll/data/rules.xml b/l10n_us_nj_hr_payroll/data/rules.xml index 45b095dc..7a9e7c83 100755 --- a/l10n_us_nj_hr_payroll/data/rules.xml +++ b/l10n_us_nj_hr_payroll/data/rules.xml @@ -14,7 +14,7 @@ code ### -year = int(payslip.dict.date_to[:4]) +year = payslip.dict.date_to.year rate = payslip.dict.get_rate('ER_US_NJ_UNEMP') ytd = payslip.sum('WAGE_US_NJ_UNEMP', str(year) + '-01-01', str(year+1) + '-01-01') ytd += contract.external_wages @@ -81,7 +81,7 @@ if result_rate == 0.0: code ### -year = int(payslip.dict.date_to[:4]) +year = payslip.dict.date_to.year rate = payslip.dict.get_rate('ER_US_NJ_SDI') ytd = payslip.sum('WAGE_US_NJ_SDI', str(year) + '-01-01', str(year+1) + '-01-01') ytd += contract.external_wages @@ -147,7 +147,7 @@ if result_rate == 0.0: code ### -year = int(payslip.dict.date_to[:4]) +year = payslip.dict.date_to.year rate = payslip.dict.get_rate('ER_US_NJ_FLI') ytd = payslip.sum('WAGE_US_NJ_FLI', str(year) + '-01-01', str(year+1) + '-01-01') ytd += contract.external_wages @@ -189,7 +189,7 @@ result = categories.BASIC code ### -year = int(payslip.dict.date_to[:4]) +year = payslip.dict.date_to.year rate = payslip.dict.get_rate('ER_US_NJ_WF') ytd = payslip.sum('WAGE_US_NJ_WF', str(year) + '-01-01', str(year+1) + '-01-01') ytd += contract.external_wages