diff --git a/l10n_us_hr_payroll/__init__.py b/l10n_us_hr_payroll/__init__.py index 09434554..013f4e73 100755 --- a/l10n_us_hr_payroll/__init__.py +++ b/l10n_us_hr_payroll/__init__.py @@ -1,3 +1,12 @@ # Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details. from . import models + +def _post_install_hook(cr, registry): + """ + This method will set the default for the Payslip Sum Behavior + """ + cr.execute("SELECT id FROM ir_config_parameter WHERE key = 'hr_payroll.payslip.sum_behavior';") + existing = cr.fetchall() + if not existing: + cr.execute("INSERT INTO ir_config_parameter (key, value) VALUES ('hr_payroll.payslip.sum_behavior', 'date');") diff --git a/l10n_us_hr_payroll/__manifest__.py b/l10n_us_hr_payroll/__manifest__.py index 5ed771ee..3c0e0c48 100755 --- a/l10n_us_hr_payroll/__manifest__.py +++ b/l10n_us_hr_payroll/__manifest__.py @@ -1,10 +1,13 @@ -# -*- encoding: utf-8 -*- { 'name': 'USA - Payroll', 'author': 'Hibou Corp. ', 'category': 'Localization', - 'depends': ['hr_payroll', 'hr_payroll_rate'], - 'version': '11.0.2020.1.0', + 'depends': [ + 'hr_payroll', + 'hr_payroll_rate', + 'hibou_professional', + ], + 'version': '11.0.2020.2.2', 'description': """ USA Payroll Rules. ================== @@ -29,19 +32,62 @@ USA Payroll Rules. 'data/federal/fed_941_fica_rules.xml', 'data/federal/fed_941_fit_parameters.xml', 'data/federal/fed_941_fit_rules.xml', + 'data/state/ak_alaska.xml', + 'data/state/al_alabama.xml', + 'data/state/ar_arkansas.xml', + 'data/state/az_arizona.xml', + 'data/state/ca_california.xml', + 'data/state/co_colorado.xml', + 'data/state/ct_connecticut.xml', + 'data/state/de_delaware.xml', 'data/state/fl_florida.xml', 'data/state/ga_georgia.xml', + 'data/state/hi_hawaii.xml', + 'data/state/ia_iowa.xml', + 'data/state/id_idaho.xml', + 'data/state/il_illinois.xml', + 'data/state/in_indiana.xml', + 'data/state/ks_kansas.xml', + 'data/state/ky_kentucky.xml', + 'data/state/la_louisiana.xml', + 'data/state/me_maine.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', + 'data/state/nc_northcarolina.xml', + 'data/state/nd_north_dakota.xml', + 'data/state/ne_nebraska.xml', + 'data/state/nh_new_hampshire.xml', + 'data/state/nj_newjersey.xml', + 'data/state/nm_new_mexico.xml', + 'data/state/nv_nevada.xml', + 'data/state/ny_new_york.xml', 'data/state/oh_ohio.xml', + 'data/state/ok_oklahoma.xml', 'data/state/pa_pennsylvania.xml', + 'data/state/ri_rhode_island.xml', + 'data/state/sc_south_carolina.xml', + 'data/state/sd_south_dakota.xml', + 'data/state/tn_tennessee.xml', 'data/state/tx_texas.xml', + 'data/state/ut_utah.xml', + 'data/state/vt_vermont.xml', 'data/state/va_virginia.xml', 'data/state/wa_washington.xml', + 'data/state/wi_wisconsin.xml', + 'data/state/wv_west_virginia.xml', + 'data/state/wy_wyoming.xml', 'data/final.xml', 'views/hr_contract_views.xml', + 'views/res_config_settings_views.xml', 'views/us_payroll_config_views.xml', ], 'installable': True, + 'demo': [ + ], + 'auto_install': False, + 'post_init_hook': '_post_install_hook', 'license': 'OPL-1', } diff --git a/l10n_us_hr_payroll/data/base.xml b/l10n_us_hr_payroll/data/base.xml index 71203f74..f951d57b 100644 --- a/l10n_us_hr_payroll/data/base.xml +++ b/l10n_us_hr_payroll/data/base.xml @@ -20,25 +20,89 @@ - + + + + + Wage: US FIT Exempt + ALW_FIT_EXEMPT + + + + + Wage: US FIT & FICA Exempt + ALW_FIT_FICA_EXEMPT + + + + + Wage: US FIT & FUTA Exempt + ALW_FIT_FUTA_EXEMPT + + + + + Wage: US FIT & FICA & FUTA Exempt + ALW_FIT_FICA_FUTA_EXEMPT + + + + + Wage: US FICA Exempt + ALW_FICA_EXEMPT + + + + + Wage: US FICA & FUTA Exempt + ALW_FICA_FUTA_EXEMPT + + + + + Wage: US FUTA Exempt + ALW_FUTA_EXEMPT + + + - - + - Deduction: US Federal Income Tax Exempt + Deduction: US FIT Exempt DED_FIT_EXEMPT - - - + + + Deduction: US FIT & FICA Exempt + DED_FIT_FICA_EXEMPT + + + + + Deduction: US FIT & FUTA Exempt + DED_FIT_FUTA_EXEMPT + + + + + Deduction: US FIT & FICA & FUTA Exempt + DED_FIT_FICA_FUTA_EXEMPT + + + Deduction: US FICA Exempt DED_FICA_EXEMPT - - + + + Deduction: US FICA & FUTA Exempt + DED_FICA_FUTA_EXEMPT + + + Deduction: US FUTA Exempt DED_FUTA_EXEMPT diff --git a/l10n_us_hr_payroll/data/final.xml b/l10n_us_hr_payroll/data/final.xml index 9bdeeef6..0ba91196 100644 --- a/l10n_us_hr_payroll/data/final.xml +++ b/l10n_us_hr_payroll/data/final.xml @@ -16,11 +16,73 @@ ref('hr_payroll_rule_ee_fed_941_fit'), + ref('hr_payroll_rule_er_us_ak_suta'), + ref('hr_payroll_rule_ee_us_ak_suta'), + + ref('hr_payroll_rule_er_us_al_suta'), + ref('hr_payroll_rule_ee_us_al_sit'), + + ref('hr_payroll_rule_er_us_ar_suta'), + ref('hr_payroll_rule_ee_us_ar_sit'), + + ref('hr_payroll_rule_er_us_az_suta'), + ref('hr_payroll_rule_ee_us_az_sit'), + + ref('hr_payroll_rule_er_us_ca_suta'), + ref('hr_payroll_rule_er_us_ca_suta_ett'), + ref('hr_payroll_rule_ee_us_ca_suta_sdi'), + ref('hr_payroll_rule_ee_us_ca_sit'), + + ref('hr_payroll_rule_er_us_co_suta'), + ref('hr_payroll_rule_ee_us_co_sit'), + + ref('hr_payroll_rule_er_us_ct_suta'), + ref('hr_payroll_rule_ee_us_ct_sit'), + + ref('hr_payroll_rule_er_us_de_suta'), + ref('hr_payroll_rule_ee_us_de_sit'), + ref('hr_payroll_rule_er_us_fl_suta'), ref('hr_payroll_rule_er_us_ga_suta'), ref('hr_payroll_rule_ee_us_ga_sit'), + ref('hr_payroll_rule_er_us_hi_suta'), + ref('hr_payroll_rule_ee_us_hi_sit'), + + ref('hr_payroll_rule_er_us_ia_suta'), + ref('hr_payroll_rule_ee_us_ia_sit'), + + ref('hr_payroll_rule_er_us_id_suta'), + ref('hr_payroll_rule_ee_us_id_sit'), + + ref('hr_payroll_rule_er_us_il_suta'), + ref('hr_payroll_rule_ee_us_il_sit'), + + ref('hr_payroll_rule_er_us_in_suta'), + ref('hr_payroll_rule_ee_us_in_sit'), + + ref('hr_payroll_rule_er_us_ks_suta'), + ref('hr_payroll_rule_ee_us_ks_sit'), + + ref('hr_payroll_rule_er_us_ky_suta'), + ref('hr_payroll_rule_ee_us_ky_sit'), + + ref('hr_payroll_rule_er_us_la_suta'), + ref('hr_payroll_rule_ee_us_la_sit'), + + ref('hr_payroll_rule_er_us_me_suta'), + ref('hr_payroll_rule_ee_us_me_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'), + + ref('hr_payroll_rule_er_us_mo_suta'), + ref('hr_payroll_rule_ee_us_mo_sit'), + ref('hr_payroll_rule_er_us_ms_suta'), ref('hr_payroll_rule_ee_us_ms_sit'), @@ -28,26 +90,84 @@ ref('hr_payroll_rule_er_us_mt_suta_aft'), ref('hr_payroll_rule_ee_us_mt_sit'), + ref('hr_payroll_rule_er_us_nc_suta'), + ref('hr_payroll_rule_ee_us_nc_sit'), + + ref('hr_payroll_rule_er_us_nd_suta'), + ref('hr_payroll_rule_ee_us_nd_sit'), + + ref('hr_payroll_rule_er_us_ne_suta'), + ref('hr_payroll_rule_ee_us_ne_sit'), + + ref('hr_payroll_rule_er_us_nh_suta'), + + ref('hr_payroll_rule_er_us_nj_suta'), + ref('hr_payroll_rule_ee_us_nj_suta'), + ref('hr_payroll_rule_er_us_nj_sdi'), + ref('hr_payroll_rule_ee_us_nj_sdi'), + ref('hr_payroll_rule_er_us_nj_wf'), + ref('hr_payroll_rule_ee_us_nj_wf'), + ref('hr_payroll_rule_er_us_nj_fli'), + ref('hr_payroll_rule_ee_us_nj_fli'), + ref('hr_payroll_rule_ee_us_nj_sit'), + + ref('hr_payroll_rule_er_us_nm_suta'), + ref('hr_payroll_rule_ee_us_nm_sit'), + + ref('hr_payroll_rule_er_us_nv_suta'), + + ref('hr_payroll_rule_er_us_ny_suta'), + ref('hr_payroll_rule_er_us_ny_suta_rsf'), + ref('hr_payroll_rule_er_us_ny_suta_mctmt'), + ref('hr_payroll_rule_ee_us_ny_sit'), + ref('hr_payroll_rule_er_us_oh_suta'), ref('hr_payroll_rule_ee_us_oh_sit'), + ref('hr_payroll_rule_er_us_ok_suta'), + ref('hr_payroll_rule_ee_us_ok_sit'), + ref('hr_payroll_rule_er_us_pa_suta'), ref('hr_payroll_rule_ee_us_pa_suta'), ref('hr_payroll_rule_ee_us_pa_sit'), + ref('hr_payroll_rule_er_us_ri_suta'), + ref('hr_payroll_rule_ee_us_ri_sit'), + + ref('hr_payroll_rule_er_us_sc_suta'), + ref('hr_payroll_rule_ee_us_sc_sit'), + + ref('hr_payroll_rule_er_us_sd_suta'), + + ref('hr_payroll_rule_er_us_tn_suta'), + ref('hr_payroll_rule_er_us_tx_suta'), ref('hr_payroll_rule_er_us_tx_suta_oa'), ref('hr_payroll_rule_er_us_tx_suta_etia'), + ref('hr_payroll_rule_er_us_ut_suta'), + ref('hr_payroll_rule_ee_us_ut_sit'), + ref('hr_payroll_rule_er_us_va_suta'), ref('hr_payroll_rule_ee_us_va_sit'), + ref('hr_payroll_rule_er_us_vt_suta'), + ref('hr_payroll_rule_ee_us_vt_sit'), + ref('hr_payroll_rule_er_us_wa_suta'), ref('hr_payroll_rule_er_us_wa_fml'), ref('hr_payroll_rule_ee_us_wa_fml'), ref('hr_payroll_rule_er_us_wa_lni'), ref('hr_payroll_rule_ee_us_wa_lni'), + ref('hr_payroll_rule_er_us_wi_suta'), + ref('hr_payroll_rule_ee_us_wi_sit'), + + ref('hr_payroll_rule_er_us_wv_suta'), + ref('hr_payroll_rule_ee_us_wv_sit'), + + ref('hr_payroll_rule_er_us_wy_suta'), + ref('hr_salary_rule_commission'), ref('hr_salary_rule_gamification'), ])]" name="rule_ids"/> diff --git a/l10n_us_hr_payroll/data/rules.xml b/l10n_us_hr_payroll/data/rules.xml deleted file mode 100755 index b0abf7cf..00000000 --- a/l10n_us_hr_payroll/data/rules.xml +++ /dev/null @@ -1,1058 +0,0 @@ - - - - - - - - - - Wage: US FICA Social Security - WAGE_US_FICA_SS - python - result = not contract.fica_exempt - code - -### -year = int(payslip.dict.date_to[:4]) -ytd = payslip.sum('WAGE_US_FICA_SS', str(year) + '-01-01', str(year+1) + '-01-01') -ytd += contract.external_wages -rate = payslip.dict.get_rate('US_FICA_SS') -remaining = rate.wage_limit_year - ytd - -if remaining <= 0.0: - result = 0 -elif remaining < categories.BASIC: - result = remaining -else: - result = categories.BASIC - - - - - - - Wage: US FICA Medicare - WAGE_US_FICA_M - python - result = not contract.fica_exempt - code - result = categories.BASIC - - - - - - Wage: US FICA Medicare Additional - WAGE_US_FICA_M_ADD - python - result = not contract.fica_exempt - code - -### -rate = payslip.dict.get_rate('US_FICA_M_ADD') -ADD_M = rate.wage_limit_year -year = int(payslip.dict.date_to[:4]) -norm_med_ytd = payslip.sum('WAGE_US_FICA_M', str(year) + '-01-01', str(year+1) + '-01-01') -norm_med_cur = categories.WAGE_US_FICA_M - -if ADD_M > norm_med_ytd: - diff = ADD_M - norm_med_ytd - if norm_med_cur > diff: - result = norm_med_cur - diff - else: - result = 0 # normal condition -else: - result = norm_med_cur # after YTD wages have passed the max - - - - - - - - EE: US FICA Social Security - EE_US_FICA_SS - python - result = not contract.fica_exempt - code - -rate = payslip.dict.get_rate('US_FICA_SS') -result_rate = -rate.rate -result = categories.WAGE_US_FICA_SS - - - - - - - EE: US FICA Medicare - EE_US_FICA_M - python - result = not contract.fica_exempt - code - -rate = payslip.dict.get_rate('US_FICA_M') -result_rate = -rate.rate -result = categories.WAGE_US_FICA_M - - - - - - - EE: US FICA Medicare Additional - EE_US_FICA_M_ADD - python - result = not contract.fica_exempt - code - -rate = payslip.dict.get_rate('US_FICA_M_ADD') -result_rate = -rate.rate -result = categories.WAGE_US_FICA_M_ADD - - - - - - - - - EE: US Federal Income Tax Withholding - Single - EE_US_FED_INC_WITHHOLD_S - python - result = (contract.w4_filing_status != 'married' and contract.w4_filing_status) - code - -year = int(payslip.dict.date_to[:4]) -wages = categories.GROSS -allowances = contract.w4_allowances -is_nra = contract.w4_is_nonresident_alien -schedule_pay = contract.schedule_pay -val = 0.00 -additional = contract.w4_additional_withholding - -if year == 2018: - ### - # Single WEEKLY - ### - if 'weekly' == schedule_pay: - wages -= allowances * 79.80 - if is_nra: - wages += 151.00 - - if wages > 71 and wages <= 254: - val = 0.00 + ((wages - 71) * 0.10) - - elif wages > 254 and wages <= 815: - val = 18.30 + ((wages - 254) * 0.12) - - elif wages > 815 and wages <= 1658: - val = 85.62 + ((wages - 815) * 0.22) - - elif wages > 1658 and wages <= 3100: - val = 271.08 + ((wages - 1658) * 0.24) - - elif wages > 3100 and wages <= 3917: - val = 617.16 + ((wages - 3100) * 0.32) - - elif wages > 3917 and wages <= 9687: - val = 878.60 + ((wages - 3917) * 0.35) - - elif wages > 9687: - val = 2898.10 + ((wages - 9687) * 0.37) - - ### - # Single BIWEEKLY - ### - elif 'bi-weekly' == schedule_pay: - wages -= allowances * 159.60 - if is_nra: - wages += 301.90 - - if wages > 142 and wages <= 509: - val = 0.00 + ((wages - 142) * 0.10) - - elif wages > 509 and wages <= 1631: - val = 36.70 + ((wages - 509) * 0.12) - - elif wages > 1631 and wages <= 3315: - val = 171.34 + ((wages - 1631) * 0.22) - - elif wages > 3315 and wages <= 6200: - val = 541.82 + ((wages - 3315) * 0.24) - - elif wages > 6200 and wages <= 7835: - val = 1234.22 + ((wages - 6200) * 0.32) - - elif wages > 7835 and wages <= 19373: - val = 1757.42 + ((wages - 7835) * 0.35) - - elif wages > 19373: - val = 5795.72 + ((wages - 19373) * 0.37) - - ### - # Single SEMIMONTHLY - ### - elif 'semi-monthly' == schedule_pay: - wages -= allowances * 172.90 - if is_nra: - wages += 327.10 - - if wages > 154 and wages <= 551: - val = 0.00 + ((wages - 154) * 0.10) - - elif wages > 551 and wages <= 1767: - val = 39.70 + ((wages - 551) * 0.12) - - elif wages > 1767 and wages <= 3592: - val = 185.62 + ((wages - 1767) * 0.22) - - elif wages > 3592 and wages <= 6717: - val = 587.12 + ((wages - 3592) * 0.24) - - elif wages > 6717 and wages <= 8488: - val = 1337.12 + ((wages - 6717) * 0.32) - - elif wages > 8488 and wages <= 20988: - val = 1903.84 + ((wages - 8488) * 0.35) - - elif wages > 20988: - val = 6278.84 + ((wages - 20988) * 0.37) - - ### - # Single MONTHLY - ### - elif 'monthly' == schedule_pay: - wages -= allowances * 345.80 - if is_nra: - wages += 654.20 - - if wages > 308 and wages <= 1102: - val = 0.00 + ((wages - 308) * 0.10) - - elif wages > 1102 and wages <= 3533: - val = 79.40 + ((wages - 1102) * 0.12) - - elif wages > 3533 and wages <= 7183: - val = 371.12 + ((wages - 3533) * 0.22) - - elif wages > 7183 and wages <= 13433: - val = 1174.12 + ((wages - 7183) * 0.24) - - elif wages > 13433 and wages <= 16975: - val = 2674.12 + ((wages - 13433) * 0.32) - - elif wages > 16975 and wages <= 41975: - val = 3807.56 + ((wages - 16975) * 0.35) - - elif wages > 41975: - val = 12557.56 + ((wages - 41975) * 0.37) - - ### - # Single QUARTERLY - ### - elif 'quarterly' == schedule_pay: - wages -= allowances * 1037.50 - if is_nra: - wages += 1962.50 - - if wages > 925 and wages <= 3306: - val = 0.00 + ((wages - 925) * 0.10) - - elif wages > 3306 and wages <= 10600: - val = 238.10 + ((wages - 3306) * 0.12) - - elif wages > 10600 and wages <= 21550: - val = 1113.38 + ((wages - 10600) * 0.22) - - elif wages > 21550 and wages <= 40300: - val = 3522.38 + ((wages - 21550) * 0.24) - - elif wages > 40300 and wages <= 50925: - val = 8022.38 + ((wages - 40300) * 0.32) - - elif wages > 50925 and wages <= 125925: - val = 11422.38 + ((wages - 50925) * 0.35) - - elif wages > 125925: - val = 37672.38 + ((wages - 125925) * 0.37) - - ### - # Single SEMIANNUAL - ### - elif 'semi-annually' == schedule_pay: - wages -= allowances * 2075.00 - if is_nra: - wages += 3925.00 - - if wages > 1850 and wages <= 6613: - val = 0.00 + ((wages - 1850) * 0.10) - - elif wages > 6613 and wages <= 21200: - val = 476.30 + ((wages - 6613) * 0.12) - - elif wages > 21200 and wages <= 43100: - val = 2226.74 + ((wages - 21200) * 0.22) - - elif wages > 43100 and wages <= 80600: - val = 7044.74 + ((wages - 43100) * 0.24) - - elif wages > 80600 and wages <= 101850: - val = 16044.74 + ((wages - 80600) * 0.32) - - elif wages > 101850 and wages <= 251850: - val = 22844.74 + ((wages - 101850) * 0.35) - - elif wages > 251850: - val = 75344.74 + ((wages - 251850) * 0.37) - - ### - # Single ANNUAL - ### - elif 'annually' == schedule_pay: - wages -= allowances * 4150.00 - if is_nra: - wages += 7850.00 - - if wages > 3700 and wages <= 13225: - val = 0.00 + ((wages - 3700) * 0.10) - - elif wages > 13225 and wages <= 42400: - val = 952.50 + ((wages - 13225) * 0.12) - - elif wages > 42400 and wages <= 86200: - val = 4453.50 + ((wages - 42400) * 0.22) - - elif wages > 86200 and wages <= 161200: - val = 14089.50 + ((wages - 86200) * 0.24) - - elif wages > 161200 and wages <= 203700: - val = 32089.50 + ((wages - 161200) * 0.32) - - elif wages > 203700 and wages <= 503700: - val = 45689.50 + ((wages - 203700) * 0.35) - - elif wages > 503700: - val = 150689.50 + ((wages - 503700) * 0.37) - - else: - raise Exception('Invalid schedule_pay="' + schedule_pay + '" for W4 Allowance calculation') -else: - ######## - # 2019 # - ######## - # Single WEEKLY - ### - if 'weekly' == schedule_pay: - wages -= allowances * 80.80 - if is_nra: - wages += 153.80 - - if wages > 73 and wages <= 260: - val = 0.00 + ((wages - 73) * 0.10) - - elif wages > 260 and wages <= 832: - val = 18.70 + ((wages - 260) * 0.12) - - elif wages > 832 and wages <= 1692: - val = 87.34 + ((wages - 832) * 0.22) - - elif wages > 1692 and wages <= 3164: - val = 276.54 + ((wages - 1692) * 0.24) - - elif wages > 3164 and wages <= 3998: - val = 629.82 + ((wages - 3164) * 0.32) - - elif wages > 3998 and wages <= 9887: - val = 896.70 + ((wages - 3998) * 0.35) - - elif wages > 9887: - val = 2957.85 + ((wages - 9887) * 0.37) - - ### - # Single BIWEEKLY - ### - elif 'bi-weekly' == schedule_pay: - wages -= allowances * 161.50 - if is_nra: - wages += 307.70 - - if wages > 146 and wages <= 519: - val = 0.00 + ((wages - 146) * 0.10) - - elif wages > 519 and wages <= 1664: - val = 37.30 + ((wages - 519) * 0.12) - - elif wages > 1664 and wages <= 3385: - val = 174.70 + ((wages - 1664) * 0.22) - - elif wages > 3385 and wages <= 6328: - val = 553.32 + ((wages - 3385) * 0.24) - - elif wages > 6328 and wages <= 7996: - val = 1259.64 + ((wages - 6328) * 0.32) - - elif wages > 7996 and wages <= 19773: - val = 1793.40 + ((wages - 7996) * 0.35) - - elif wages > 19773: - val = 5915.35 + ((wages - 19773) * 0.37) - - ### - # Single SEMIMONTHLY - ### - elif 'semi-monthly' == schedule_pay: - wages -= allowances * 175.00 - if is_nra: - wages += 333.30 - - if wages > 158 and wages <= 563: - val = 0.00 + ((wages - 158) * 0.10) - - elif wages > 563 and wages <= 1803: - val = 40.50 + ((wages - 563) * 0.12) - - elif wages > 1803 and wages <= 3667: - val = 189.30 + ((wages - 1803) * 0.22) - - elif wages > 3667 and wages <= 6855: - val = 599.38 + ((wages - 3667) * 0.24) - - elif wages > 6855 and wages <= 8663: - val = 1364.50 + ((wages - 6855) * 0.32) - - elif wages > 8663 and wages <= 21421: - val = 1943.06 + ((wages - 8663) * 0.35) - - elif wages > 21421: - val = 6408.36 + ((wages - 21421) * 0.37) - - ### - # Single MONTHLY - ### - elif 'monthly' == schedule_pay: - wages -= allowances * 350.00 - if is_nra: - wages += 666.70 - - if wages > 317 and wages <= 1125: - val = 0.00 + ((wages - 317) * 0.10) - - elif wages > 1125 and wages <= 3606: - val = 80.80 + ((wages - 1125) * 0.12) - - elif wages > 3606 and wages <= 7333: - val = 378.52 + ((wages - 3606) * 0.22) - - elif wages > 7333 and wages <= 13710: - val = 1198.46 + ((wages - 7333) * 0.24) - - elif wages > 13710 and wages <= 17325: - val = 2728.94 + ((wages - 13710) * 0.32) - - elif wages > 17325 and wages <= 42842: - val = 3885.74 + ((wages - 17325) * 0.35) - - elif wages > 42842: - val = 12816.69 + ((wages - 42842) * 0.37) - - ### - # Single QUARTERLY - ### - elif 'quarterly' == schedule_pay: - wages -= allowances * 1050.00 - if is_nra: - wages += 2000.0 - - if wages > 950 and wages <= 3375: - val = 0.00 + ((wages - 950) * 0.10) - - elif wages > 3375 and wages <= 10819: - val = 242.50 + ((wages - 3375) * 0.12) - - elif wages > 10819 and wages <= 22000: - val = 1135.78 + ((wages - 10819) * 0.22) - - elif wages > 22000 and wages <= 41131: - val = 3595.60 + ((wages - 22000) * 0.24) - - elif wages > 41131 and wages <= 51975: - val = 8187.04 + ((wages - 41131) * 0.32) - - elif wages > 51975 and wages <= 128525: - val = 11657.12 + ((wages - 51975) * 0.35) - - elif wages > 128525: - val = 38449.62 + ((wages - 128525) * 0.37) - - ### - # Single SEMIANNUAL - ### - elif 'semi-annually' == schedule_pay: - wages -= allowances * 2100.00 - if is_nra: - wages += 4000.00 - - if wages > 1900 and wages <= 6750: - val = 0.00 + ((wages - 1900) * 0.10) - - elif wages > 6750 and wages <= 21638: - val = 485.00 + ((wages - 6750) * 0.12) - - elif wages > 21638 and wages <= 44000: - val = 2271.56 + ((wages - 21638) * 0.22) - - elif wages > 44000 and wages <= 82263: - val = 7191.20 + ((wages - 44000) * 0.24) - - elif wages > 82263 and wages <= 103950: - val = 16374.32 + ((wages - 82263) * 0.32) - - elif wages > 103950 and wages <= 257050: - val = 23314.16 + ((wages - 103950) * 0.35) - - elif wages > 257050: - val = 76899.16 + ((wages - 257050) * 0.37) - - ### - # Single ANNUAL - ### - elif 'annually' == schedule_pay: - wages -= allowances * 4200.00 - if is_nra: - wages += 8000.00 - - if wages > 3800 and wages <= 13500: - val = 0.00 + ((wages - 3800) * 0.10) - - elif wages > 13500 and wages <= 43275: - val = 970.00 + ((wages - 13500) * 0.12) - - elif wages > 43275 and wages <= 88000: - val = 4543.00 + ((wages - 43275) * 0.22) - - elif wages > 88000 and wages <= 164525: - val = 14382.50 + ((wages - 88000) * 0.24) - - elif wages > 164525 and wages <= 207900: - val = 32748.50 + ((wages - 164525) * 0.32) - - elif wages > 207900 and wages <= 514100: - val = 46628.50 + ((wages - 207900) * 0.35) - - elif wages > 514100: - val = 153798.50 + ((wages - 514100) * 0.37) - - else: - raise Exception('Invalid schedule_pay="' + schedule_pay + '" for W4 Allowance calculation') - -result = -(val + additional) - - - - - - - EE: US Federal Income Tax Withholding - Married - EE_US_FED_INC_WITHHOLD_M - python - result = (contract.w4_filing_status == 'married') - code - -year = int(payslip.dict.date_to[:4]) -wages = categories.GROSS -allowances = contract.w4_allowances -is_nra = contract.w4_is_nonresident_alien -schedule_pay = contract.schedule_pay -val = 0.00 -additional = contract.w4_additional_withholding - -if year == 2018: - ### - # Married WEEKLY - ### - if 'weekly' == schedule_pay: - wages -= allowances * 79.80 - if is_nra: - wages += 151.00 - - if wages > 222 and wages <= 588: - val = 0.00 + ((wages - 222) * 0.10) - - elif wages > 588 and wages <= 1711: - val = 36.60 + ((wages - 588) * 0.12) - - elif wages > 1711 and wages <= 3395: - val = 171.36 + ((wages - 1711) * 0.22) - - elif wages > 3395 and wages <= 6280: - val = 541.84 + ((wages - 3395) * 0.24) - - elif wages > 6280 and wages <= 7914: - val = 1234.24 + ((wages - 6280) * 0.32) - - elif wages > 7914 and wages <= 11761: - val = 1757.12 + ((wages - 7914) * 0.35) - - elif wages > 11761: - val = 3103.57 + ((wages - 11761) * 0.37) - - ### - # Married BIWEEKLY - ### - elif 'bi-weekly' == schedule_pay: - wages -= allowances * 159.60 - if is_nra: - wages += 301.90 - - if wages > 444 and wages <= 1177: - val = 0.00 + ((wages - 444) * 0.10) - - elif wages > 1177 and wages <= 3421: - val = 73.30 + ((wages - 1177) * 0.12) - - elif wages > 3421 and wages <= 6790: - val = 342.58 + ((wages - 3421) * 0.22) - - elif wages > 6790 and wages <= 12560: - val = 1083.76 + ((wages - 6790) * 0.24) - - elif wages > 12560 and wages <= 15829: - val = 2468.56 + ((wages - 12560) * 0.32) - - elif wages > 15829 and wages <= 23521: - val = 3514.64 + ((wages - 15829) * 0.35) - - elif wages > 23521: - val = 6206.84 + ((wages - 23521) * 0.37) - - ### - # Married SEMIMONTHLY - ### - elif 'semi-monthly' == schedule_pay: - wages -= allowances * 172.90 - if is_nra: - wages += 327.10 - - if wages > 481 and wages <= 1275: - val = 0.00 + ((wages - 481) * 0.10) - - elif wages > 1275 and wages <= 3706: - val = 79.40 + ((wages - 1275) * 0.12) - - elif wages > 3706 and wages <= 7356: - val = 371.12 + ((wages - 3706) * 0.22) - - elif wages > 7356 and wages <= 13606: - val = 1174.12 + ((wages - 7356) * 0.24) - - elif wages > 13606 and wages <= 17148: - val = 2674.12 + ((wages - 13606) * 0.32) - - elif wages > 17148 and wages <= 25481: - val = 3807.56 + ((wages - 17148) * 0.35) - - elif wages > 25481: - val = 6724.11 + ((wages - 25481) * 0.37) - - ### - # Married MONTHLY - ### - elif 'monthly' == schedule_pay: - wages -= allowances * 345.80 - if is_nra: - wages += 654.20 - - if wages > 963 and wages <= 2550: - val = 0.00 + ((wages - 963) * 0.10) - - elif wages > 2550 and wages <= 7413: - val = 158.70 + ((wages - 2550) * 0.12) - - elif wages > 7413 and wages <= 14713: - val = 742.26 + ((wages - 7413) * 0.22) - - elif wages > 14713 and wages <= 27213: - val = 2348.26 + ((wages - 14713) * 0.24) - - elif wages > 27213 and wages <= 34296: - val = 5348.26 + ((wages - 27213) * 0.32) - - elif wages > 34296 and wages <= 50963: - val = 7614.82 + ((wages - 34296) * 0.35) - - elif wages > 50963: - val = 13448.27 + ((wages - 50963) * 0.37) - - ### - # Married QUARTERLY - ### - elif 'quarterly' == schedule_pay: - wages -= allowances * 1037.50 - if is_nra: - wages += 1962.50 - - if wages > 2888 and wages <= 7650: - val = 0.00 + ((wages - 2888) * 0.10) - - elif wages > 7650 and wages <= 22238: - val = 476.20 + ((wages - 7650) * 0.12) - - elif wages > 22238 and wages <= 44138: - val = 2226.76 + ((wages - 22238) * 0.22) - - elif wages > 44138 and wages <= 81638: - val = 7044.76 + ((wages - 44138) * 0.24) - - elif wages > 81638 and wages <= 102888: - val = 16044.76 + ((wages - 81638) * 0.32) - - elif wages > 102888 and wages <= 152888: - val = 22844.76 + ((wages - 102888) * 0.35) - - elif wages > 152888: - val = 40344.76 + ((wages - 152888) * 0.37) - - ### - # Married SEMIANNUAL - ### - elif 'semi-annually' == schedule_pay: - wages -= allowances * 2075.00 - if is_nra: - wages += 3925.00 - - if wages > 5775 and wages <= 15300: - val = 0.00 + ((wages - 5775) * 0.10) - - elif wages > 15300 and wages <= 44475: - val = 952.50 + ((wages - 15300) * 0.12) - - elif wages > 44475 and wages <= 88275: - val = 4453.50 + ((wages - 44475) * 0.22) - - elif wages > 88275 and wages <= 163275: - val = 14089.50 + ((wages - 88275) * 0.24) - - elif wages > 163275 and wages <= 205775: - val = 32089.50 + ((wages - 163275) * 0.32) - - elif wages > 205775 and wages <= 305775: - val = 45689.50 + ((wages - 205775) * 0.35) - - elif wages > 305775: - val = 80689.50 + ((wages - 305775) * 0.37) - - ### - # Married ANNUAL - ### - elif 'annually' == schedule_pay: - wages -= allowances * 4150.00 - if is_nra: - wages += 7850.00 - - if wages > 11550 and wages <= 30600: - val = 0.00 + ((wages - 11550) * 0.10) - - elif wages > 30600 and wages <= 88950: - val = 1905.00 + ((wages - 30600) * 0.12) - - elif wages > 88950 and wages <= 176550: - val = 8907.00 + ((wages - 88950) * 0.22) - - elif wages > 176550 and wages <= 326550: - val = 28179.00 + ((wages - 176550) * 0.24) - - elif wages > 326550 and wages <= 411550: - val = 64179.00 + ((wages - 326550) * 0.32) - - elif wages > 411550 and wages <= 611550: - val = 91379.00 + ((wages - 411550) * 0.35) - - elif wages > 611550: - val = 161379.00 + ((wages - 611550) * 0.37) - - else: - raise Exception('Invalid schedule_pay="' + schedule_pay + '" for W4 Allowance calculation') -else: - ######## - # 2019 # - ######## - # Married WEEKLY - ### - if 'weekly' == schedule_pay: - wages -= allowances * 80.80 - if is_nra: - wages += 153.80 - - if wages > 227 and wages <= 600: - val = 0.00 + ((wages - 227) * 0.10) - - elif wages > 600 and wages <= 1745: - val = 37.30 + ((wages - 600) * 0.12) - - elif wages > 1745 and wages <= 3465: - val = 174.70 + ((wages - 1745) * 0.22) - - elif wages > 3465 and wages <= 6409: - val = 553.10 + ((wages - 3465) * 0.24) - - elif wages > 6409 and wages <= 8077: - val = 1259.66 + ((wages - 6409) * 0.32) - - elif wages > 8077 and wages <= 12003: - val = 1793.42 + ((wages - 8077) * 0.35) - - elif wages > 12003: - val = 3167.52 + ((wages - 12003) * 0.37) - - ### - # Married BIWEEKLY - ### - elif 'bi-weekly' == schedule_pay: - wages -= allowances * 161.50 - if is_nra: - wages += 307.70 - - if wages > 454 and wages <= 1200: - val = 0.00 + ((wages - 454) * 0.10) - - elif wages > 1200 and wages <= 3490: - val = 74.60 + ((wages - 1200) * 0.12) - - elif wages > 3490 and wages <= 6931: - val = 349.40 + ((wages - 3490) * 0.22) - - elif wages > 6931 and wages <= 12817: - val = 1106.42 + ((wages - 6931) * 0.24) - - elif wages > 12817 and wages <= 16154: - val = 2519.06 + ((wages - 12817) * 0.32) - - elif wages > 16154 and wages <= 24006: - val = 3586.90 + ((wages - 16154) * 0.35) - - elif wages > 24006: - val = 6335.10 + ((wages - 24006) * 0.37) - - ### - # Married SEMIMONTHLY - ### - elif 'semi-monthly' == schedule_pay: - wages -= allowances * 175.00 - if is_nra: - wages += 333.30 - - if wages > 492 and wages <= 1300: - val = 0.00 + ((wages - 492) * 0.10) - - elif wages > 1300 and wages <= 3781: - val = 80.80 + ((wages - 1300) * 0.12) - - elif wages > 3781 and wages <= 7508: - val = 378.52 + ((wages - 3781) * 0.22) - - elif wages > 7508 and wages <= 13885: - val = 1198.46 + ((wages - 7508) * 0.24) - - elif wages > 13885 and wages <= 17500: - val = 2728.94 + ((wages - 13885) * 0.32) - - elif wages > 17500 and wages <= 26006: - val = 3885.74 + ((wages - 17500) * 0.35) - - elif wages > 26006: - val = 6862.84 + ((wages - 26006) * 0.37) - - ### - # Married MONTHLY - ### - elif 'monthly' == schedule_pay: - wages -= allowances * 350.00 - if is_nra: - wages += 666.70 - - if wages > 983 and wages <= 2600: - val = 0.00 + ((wages - 983) * 0.10) - - elif wages > 2600 and wages <= 7563: - val = 161.70 + ((wages - 2600) * 0.12) - - elif wages > 7563 and wages <= 15017: - val = 757.26 + ((wages - 7563) * 0.22) - - elif wages > 15017 and wages <= 27771: - val = 2397.14 + ((wages - 15017) * 0.24) - - elif wages > 27771 and wages <= 35000: - val = 5458.10 + ((wages - 27771) * 0.32) - - elif wages > 35000 and wages <= 50963: - val = 7771.38 + ((wages - 35000) * 0.35) - - elif wages > 52013: - val = 13725.93 + ((wages - 52013) * 0.37) - - ### - # Married QUARTERLY - ### - elif 'quarterly' == schedule_pay: - wages -= allowances * 1050.00 - if is_nra: - wages += 2000.00 - - if wages > 2950 and wages <= 7800: - val = 0.00 + ((wages - 2950) * 0.10) - - elif wages > 7800 and wages <= 22688: - val = 485.00 + ((wages - 7800) * 0.12) - - elif wages > 22688 and wages <= 45050: - val = 2271.56 + ((wages - 22688) * 0.22) - - elif wages > 45050 and wages <= 83313: - val = 7191.20 + ((wages - 45050) * 0.24) - - elif wages > 83313 and wages <= 105000: - val = 16374.32 + ((wages - 83313) * 0.32) - - elif wages > 105000 and wages <= 156038: - val = 23314.16 + ((wages - 105000) * 0.35) - - elif wages > 156038: - val = 41177.46 + ((wages - 156038) * 0.37) - - ### - # Married SEMIANNUAL - ### - elif 'semi-annually' == schedule_pay: - wages -= allowances * 2100.00 - if is_nra: - wages += 4000.00 - - if wages > 5900 and wages <= 15600: - val = 0.00 + ((wages - 5900) * 0.10) - - elif wages > 15600 and wages <= 45375: - val = 970.00 + ((wages - 15600) * 0.12) - - elif wages > 45375 and wages <= 90100: - val = 4543.00 + ((wages - 45375) * 0.22) - - elif wages > 90100 and wages <= 166625: - val = 14382.50 + ((wages - 90100) * 0.24) - - elif wages > 166625 and wages <= 210000: - val = 32748.50 + ((wages - 166625) * 0.32) - - elif wages > 210000 and wages <= 312075: - val = 46628.50 + ((wages - 210000) * 0.35) - - elif wages > 312075: - val = 82354.75 + ((wages - 312075) * 0.37) - - ### - # Married ANNUAL - ### - elif 'annually' == schedule_pay: - wages -= allowances * 4200.00 - if is_nra: - wages += 8000.00 - - if wages > 11800 and wages <= 31200: - val = 0.00 + ((wages - 11800) * 0.10) - - elif wages > 31200 and wages <= 90750: - val = 1940.00 + ((wages - 31200) * 0.12) - - elif wages > 90750 and wages <= 180200: - val = 9086.00 + ((wages - 90750) * 0.22) - - elif wages > 180200 and wages <= 333250: - val = 28765.00 + ((wages - 180200) * 0.24) - - elif wages > 333250 and wages <= 420000: - val = 65497.00 + ((wages - 333250) * 0.32) - - elif wages > 420000 and wages <= 624150: - val = 93257.00 + ((wages - 420000) * 0.35) - - elif wages > 624150: - val = 164709.50 + ((wages - 624150) * 0.37) - - else: - raise Exception('Invalid schedule_pay="' + schedule_pay + '" for W4 Allowance calculation') - -result = -(val + additional) - - - - - - - - Wage: US FUTA Federal Unemployment - WAGE_US_FUTA - python - result = (contract.futa_type != contract.FUTA_TYPE_EXEMPT) - code - -### -rate = payslip.dict.get_futa_rate(contract) -year = int(payslip.dict.date_to[:4]) -ytd = payslip.sum('WAGE_US_FUTA', str(year) + '-01-01', str(year+1) + '-01-01') -ytd += contract.external_wages -remaining = rate.wage_limit_year - ytd -if remaining <= 0.0: - result = 0 -elif remaining < categories.BASIC: - result = remaining -else: - result = categories.BASIC - - - - - - - ER: US FUTA Federal Unemployment - ER_US_FUTA - python - result = (contract.futa_type != contract.FUTA_TYPE_EXEMPT) - code - -year = int(payslip.dict.date_to[:4]) -rate = payslip.dict.get_futa_rate(contract) -result_rate = -(rate.rate) -result = categories.WAGE_US_FUTA - - - - - - - - - - ER: US FICA Social Security - ER_US_FICA_SS - none - code - result = categories.EE_US_FICA_SS - - - - - - - ER: US FICA Medicare - ER_US_FICA_M - none - code - result = categories.EE_US_FICA_M - - - - - - diff --git a/l10n_us_hr_payroll/data/state/ak_alaska.xml b/l10n_us_hr_payroll/data/state/ak_alaska.xml new file mode 100644 index 00000000..d63c387d --- /dev/null +++ b/l10n_us_hr_payroll/data/state/ak_alaska.xml @@ -0,0 +1,89 @@ + + + + + + US AK Alaska SUTA Wage Base + us_ak_suta_wage_base + 39900.00 + + + + US AK Alaska SUTA Wage Base + us_ak_suta_wage_base + 41500.00 + + + + + + + + US AK Alaska SUTA Rate + us_ak_suta_rate + 1.780 + + + + US AK Alaska SUTA Rate + us_ak_suta_rate + 1.590 + + + + + + + US AK Alaska SUTA Rate EE + us_ak_suta_ee_rate + 0.500 + + + + US AK Alaska SUTA Rate EE + us_ak_suta_ee_rate + 0.500 + + + + + + + US Alaska - Department of Labor and Workforce Development (ADLWD) - Unemployment Tax + 1 + + + US Alaska - Department of Labor and Workforce Development (ADLWD) - Unemployment Tax + + + + + + + + + + ER: US AK Alaska State Unemployment + ER_US_AK_SUTA + python + result, _ = general_state_unemployment(payslip, categories, worked_days, inputs, wage_base='us_ak_suta_wage_base', rate='us_ak_suta_rate', state_code='AK') + code + result, result_rate = general_state_unemployment(payslip, categories, worked_days, inputs, wage_base='us_ak_suta_wage_base', rate='us_ak_suta_rate', state_code='AK') + + + + + + + + EE: US AK Alaska State Unemployment (UC-2) + EE_US_AK_SUTA + python + result, _ = general_state_unemployment(payslip, categories, worked_days, inputs, wage_base='us_ak_suta_wage_base', rate='us_ak_suta_ee_rate', state_code='AK') + code + result, result_rate = general_state_unemployment(payslip, categories, worked_days, inputs, wage_base='us_ak_suta_wage_base', rate='us_ak_suta_ee_rate', state_code='AK') + + + + + \ No newline at end of file diff --git a/l10n_us_hr_payroll/data/state/al_alabama.xml b/l10n_us_hr_payroll/data/state/al_alabama.xml new file mode 100644 index 00000000..bf2d0a7f --- /dev/null +++ b/l10n_us_hr_payroll/data/state/al_alabama.xml @@ -0,0 +1,209 @@ + + + + + + US AL Alabama SUTA Wage Base + us_al_suta_wage_base + 8000.0 + + + + US AL Alabama SUTA Wage Base + us_al_suta_wage_base + 8000.0 + + + + + + + + US AL Alabama SUTA Rate + us_al_suta_rate + 2.7 + + + + US AL Alabama SUTA Rate + us_al_suta_rate + 2.7 + + + + + + + US AL Alabama SIT Tax Rate + us_al_sit_tax_rate + { + '0': [ + ( 500, 2), + ( 3000, 4), + ('inf', 5), + ], + 'M': [ + ( 1000, 2), + ( 6000, 4), + ('inf', 5), + ], + } + + + + US AL Alabama SIT Tax Rate + us_al_sit_tax_rate + { + '0' : [ + ( 500, 2), + ( 2500, 4), + ('inf', 5), + ], + 'M': [ + ( 1000, 2), + ( 5000, 4), + ('inf', 5), + ], + } + + + + + + + + + US AL Alabama Dependent Rate + us_al_sit_dependent_rate + [ + ( 1000, 20000), + ( 500, 100000), + ( 300, 'inf'), + ] + + + + + + US AL Alabama Dependent Rate + us_al_sit_dependent_rate + [ + ( 1000, 20000), + ( 500, 100000), + ( 300, 'inf'), + ] + + + + + + + + + US AL Alabama Standard Deduction Rate + us_al_sit_standard_deduction_rate + { + '0': ((23499.0, 2500.0), (33000.0, 2500.0, 25.0, 500.0), ('inf', 2000.0)), + 'S': ((23499.0, 2500.0), (33000.0, 2500.0, 25.0, 500.0), ('inf', 2000.0)), + 'MS': ((10749.0, 3750.0), (15500.0, 3750.0, 88.0, 250.0), ('inf', 2000.0)), + 'M': ((23499.0, 7500.0), (33000.0, 7500.0, 175.0, 500.0), ('inf', 4000.0)), + 'H': ((23499.0, 4700.0), (33000.0, 7500.0, 175.0, 500.0), ('inf', 4000.0)), + } + + + + + + US AL Alabama Standard Deduction Rate + us_al_sit_standard_deduction_rate + { + '0': ((23499.0, 2500.0), (33000.0, 2500.0, 25.0, 500.0), ('inf', 2000.0)), + 'S': ((23499.0, 2500.0), (33000.0, 2500.0, 25.0, 500.0), ('inf', 2000.0)), + 'MS': ((10749.0, 3750.0), (15500.0, 3750.0, 88.0, 250.0), ('inf', 2000.0)), + 'M': ((23499.0, 7500.0), (33000.0, 7500.0, 175.0, 500.0), ('inf', 4000.0)), + 'H': ((23499.0, 4700.0), (33000.0, 7500.0, 175.0, 500.0), ('inf', 4000.0)), + } + + + + + + + + + US AL Alabama Personal Exemption Rate + us_al_sit_personal_exemption_rate + { + '0' : 0, + 'S' : 1500, + 'MS': 1500, + 'M' : 3000, + 'H' : 3000, + } + + + + + + US AL Alabama Personal Exemption Rate + us_al_sit_personal_exemption_rate + { + '0' : 0, + 'S' : 1500, + 'MS': 1500, + 'M' : 3000, + 'H' : 3000, + } + + + + + + + US Alabama - Department of Economic Security (IDES) - Unemployment Tax + 1 + + + US Alabama - Department of Economic Security (IDES) - Unemployment Tax + + + + + US Alabama - Department of Revenue (IDOR) - Income Tax + 1 + + + US Alabama - Department of Revenue (IDOR) - Unemployment Tax + + + + + + + + + + ER: US AL Alabama State Unemployment + ER_US_AL_SUTA + python + result, _ = general_state_unemployment(payslip, categories, worked_days, inputs, wage_base='us_al_suta_wage_base', rate='us_al_suta_rate', state_code='AL') + code + result, result_rate = general_state_unemployment(payslip, categories, worked_days, inputs, wage_base='us_al_suta_wage_base', rate='us_al_suta_rate', state_code='AL') + + + + + + + + EE: US AL Alabama State Income Tax Withholding + EE_US_AL_SIT + python + result, _ = al_alabama_state_income_withholding(payslip, categories, worked_days, inputs) + code + result, result_rate = al_alabama_state_income_withholding(payslip, categories, worked_days, inputs) + + + + + \ No newline at end of file diff --git a/l10n_us_hr_payroll/data/state/ar_arkansas.xml b/l10n_us_hr_payroll/data/state/ar_arkansas.xml new file mode 100644 index 00000000..1940ef85 --- /dev/null +++ b/l10n_us_hr_payroll/data/state/ar_arkansas.xml @@ -0,0 +1,141 @@ + + + + + + US AR Arkansas SUTA Wage Base + us_ar_suta_wage_base + 10000.0 + + + + US AR Arkansas SUTA Wage Base + us_ar_suta_wage_base + 8000.0 + + + + + + + + US AR Arkansas SUTA Rate + us_ar_suta_rate + 3.2 + + + + US AR Arkansas SUTA Rate + us_ar_suta_rate + 2.9 + + + + + + + US AR Arkansas SIT Tax Rate + us_ar_sit_tax_rate + [ + ( 4599, 0.0, 0.00), + ( 9099, 2.0, 91.98), + ( 13699, 3.0, 182.97), + ( 22599, 3.4, 237.77), + ( 37899, 5.0, 421.46), + ( 80800, 5.9, 762.55), + ( 81800, 6.6, 1243.40), + ( 82800, 6.6, 1143.40), + ( 84100, 6.6, 1043.40), + ( 85200, 6.6, 943.40), + ( 86200, 6.6, 843.40), + ( 'inf', 6.6, 803.40), + ] + + + + + + US AR Arkansas SIT Tax Rate + us_ar_sit_tax_rate + [ + ( 4599, 0.0, 0.00), + ( 9099, 2.0, 91.98), + ( 13699, 3.0, 182.97), + ( 22599, 3.4, 237.77), + ( 37899, 5.0, 421.46), + ( 80800, 5.9, 762.55), + ( 81800, 6.6, 1243.40), + ( 82800, 6.6, 1143.40), + ( 84100, 6.6, 1043.40), + ( 85200, 6.6, 943.40), + ( 86200, 6.6, 843.40), + ( 'inf', 6.6, 803.40), + ] + + + + + + + US AR Arkansas Allowances Rate + us_ar_sit_standard_deduction_rate + 2200.0 + + + + US AR Arkansas Allowances Rate + us_ar_sit_standard_deduction_rate + 2200.0 + + + + + + + US Arkansas - Department of Workforce Solutions - Unemployment Tax + 1 + + + US Arkansas - Department of Workforce Solutions - Unemployment Tax + + + + + US Arkansas - Department of Financial Administration - Income Tax + 1 + + + US Arkansas - Department of Financial Administration - Income Tax + + + + + + + + + + ER: US AR Arkansas State Unemployment + ER_US_AR_SUTA + python + result, _ = general_state_unemployment(payslip, categories, worked_days, inputs, wage_base='us_ar_suta_wage_base', rate='us_ar_suta_rate', state_code='AR') + code + result, result_rate = general_state_unemployment(payslip, categories, worked_days, inputs, wage_base='us_ar_suta_wage_base', rate='us_ar_suta_rate', state_code='AR') + + + + + + + + EE: US AR Arkansas State Income Tax Withholding + EE_US_AR_SIT + python + result, _ = ar_arkansas_state_income_withholding(payslip, categories, worked_days, inputs) + code + result, result_rate = ar_arkansas_state_income_withholding(payslip, categories, worked_days, inputs) + + + + + \ No newline at end of file diff --git a/l10n_us_hr_payroll/data/state/az_arizona.xml b/l10n_us_hr_payroll/data/state/az_arizona.xml new file mode 100644 index 00000000..92bb3ef1 --- /dev/null +++ b/l10n_us_hr_payroll/data/state/az_arizona.xml @@ -0,0 +1,83 @@ + + + + + + US AZ Arizona SUTA Wage Base + us_az_suta_wage_base + 7000.0 + + + + US AZ Arizona SUTA Wage Base + us_az_suta_wage_base + 7000.0 + + + + + + + + US AZ Arizona SUTA Rate + us_az_suta_rate + 2.0 + + + + US AZ Arizona SUTA Rate + us_az_suta_rate + 2.0 + + + + + + + US Arizona - Department of Economic Security (ADES) - Unemployment Tax + 1 + + + US Arizona - Department of Economic Security (ADES) - Unemployment Tax + + + + + US Arizona - Department of Revenue (ADOR) - Income Tax + 1 + + + US Arizona - Department of Revenue (ADOR) - Income Tax + + + + + + + + + + ER: US AZ Arizona State Unemployment + ER_US_AZ_SUTA + python + result, _ = general_state_unemployment(payslip, categories, worked_days, inputs, wage_base='us_az_suta_wage_base', rate='us_az_suta_rate', state_code='AZ') + code + result, result_rate = general_state_unemployment(payslip, categories, worked_days, inputs, wage_base='us_az_suta_wage_base', rate='us_az_suta_rate', state_code='AZ') + + + + + + + + EE: US AZ Arizona State Income Tax Withholding + EE_US_AZ_SIT + python + result, _ = az_arizona_state_income_withholding(payslip, categories, worked_days, inputs) + code + result, result_rate = az_arizona_state_income_withholding(payslip, categories, worked_days, inputs) + + + + + \ No newline at end of file diff --git a/l10n_us_hr_payroll/data/state/ca_california.xml b/l10n_us_hr_payroll/data/state/ca_california.xml new file mode 100644 index 00000000..663699bb --- /dev/null +++ b/l10n_us_hr_payroll/data/state/ca_california.xml @@ -0,0 +1,806 @@ + + + + + + US CA California SUTA Wage Base + us_ca_suta_wage_base + 7000.0 + + + + US CA California SUTA Wage Base + us_ca_suta_wage_base + 7000.0 + + + + + + + + US CA California SUTA Rate + us_ca_suta_rate + 3.5 + + + + US CA California SUTA Rate + us_ca_suta_rate + 3.4 + + + + + + + + US CA California SUTA ETT Rate + us_ca_suta_ett_rate + 0.1 + + + + US CA California SUTA ETT Rate + us_ca_suta_ett_rate + 0.1 + + + + + + + + US CA California SUTA SDI Rate + us_ca_suta_sdi_rate + 1.0 + + + + US CA California SUTA SDI Rate + us_ca_suta_sdi_rate + 1.0 + + + + + + + US CA California SIT Tax Rate + us_ca_sit_tax_rate + { + 'head_household': { + 'weekly': ( + ( 316, 0.0110, 0.00), + ( 750, 0.0220, 3.48), + ( 967, 0.0440, 13.03), + ( 1196, 0.0660, 22.58), + ( 1413, 0.0880, 37.69), + ( 7212, 0.1023, 56.79), + ( 8654, 0.1133, 650.03), + (14423, 0.1243, 813.41), + (19231, 0.1353, 1530.50), + ('inf', 0.1463, 2181.02), + ), + 'bi-weekly': ( + ( 632, 0.0110, 0.00), + ( 1500, 0.0220, 6.95), + ( 1934, 0.0440, 26.05), + ( 2392, 0.0660, 45.15), + ( 2826, 0.0880, 75.38), + (14424, 0.1023, 113.57), + (17308, 0.1133, 1300.05), + (28846, 0.1243, 1626.81), + (38462, 0.1353, 3060.98), + ('inf', 0.1463, 4362.02), + ), + 'semi-monthly': ( + ( 686, 0.0110, 0.00), + ( 1625, 0.0220, 7.55), + ( 2094, 0.0440, 28.21), + ( 2592, 0.0660, 48.85), + ( 3062, 0.0880, 81.72), + (15625, 0.1023, 123.08), + (18750, 0.1133, 1408.27), + (31250, 0.1243, 1762.33), + (41667, 0.1353, 3316.08), + ('inf', 0.1463, 4725.50), + ), + 'monthly': ( + ( 1372, 0.0110, 0.00), + ( 3250, 0.0220, 15.09), + ( 4188, 0.0440, 56.41), + ( 5184, 0.0660, 97.68), + ( 6124, 0.0880, 163.42), + (31250, 0.1023, 246.14), + (37500, 0.1133, 2816.53), + (62500, 0.1243, 3524.66), + (83334, 0.1353, 6632.16), + ('inf', 0.1463, 9451.00), + ), + 'quarterly': ( + ( 4114, 0.0110, 0.00), + ( 9748, 0.0220, 45.25), + ( 12566, 0.0440, 169.20), + ( 15552, 0.0660, 293.19), + ( 18369, 0.0880, 490.27), + ( 93751, 0.1023, 738.17), + (112501, 0.1133, 8449.75), + (187501, 0.1243, 10574.13), + (250000, 0.1353, 19896.63), + ( 'inf', 0.1463, 28352.74), + ), + 'semi-annual': ( + ( 8228, 0.0110, 0.00), + ( 19496, 0.0220, 90.51), + ( 25132, 0.0440, 338.41), + ( 31104, 0.0660, 586.39), + ( 36738, 0.0880, 980.54), + (187502, 0.1023, 1476.33), + (225002, 0.1133, 16899.49), + (375002, 0.1243, 21148.24), + (500000, 0.1353, 39793.24), + ( 'inf', 0.1463, 56705.47), + ), + 'annually': ( + ( 16457, 0.0110, 0.00), + ( 38991, 0.0220, 181.03), + ( 50264, 0.0440, 676.78), + ( 62206, 0.0660, 1172.79), + ( 73477, 0.0880, 1960.96), + ( 375002, 0.1023, 2952.81), + ( 450003, 0.1133, 33798.82), + ( 750003, 0.1243, 42296.43), + (1000000, 0.1353, 79586.43), + ( 'inf', 0.1463, 113411.02), + ), + }, + 'married': { + 'weekly': ( + ( 316, 0.0110, 0.00), + ( 750, 0.0220, 3.48), + ( 1184, 0.0440, 13.03), + ( 1642, 0.0660, 32.13), + ( 2076, 0.0880, 62.36), + (10606, 0.1023, 100.55), + (12726, 0.1133, 973.17), + (19231, 0.1243, 1213.37), + (21210, 0.1353, 2021.94), + ('inf', 0.1463, 2289.70), + ), + 'bi-weekly': ( + ( 632, 0.0110, 0.00), + ( 1500, 0.0220, 6.95), + ( 2368, 0.0440, 26.05), + ( 3284, 0.0660, 64.24), + ( 4152, 0.0880, 124.70), + (21212, 0.1023, 201.08), + (25452, 0.1133, 1946.32), + (38462, 0.1243, 2426.71), + (42420, 0.1353, 4043.85), + ('inf', 0.1463, 4579.37), + ), + 'semi-monthly': ( + ( 686, 0.0110, 0.00), + ( 1624, 0.0220, 7.55), + ( 2564, 0.0440, 28.19), + ( 3560, 0.0660, 69.55), + ( 4498, 0.0880, 135.29), + (22978, 0.1023, 217.83), + (27574, 0.1133, 2108.33), + (41667, 0.1243, 2629.06), + (45956, 0.1353, 4380.82), + ('inf', 0.1463, 4961.12), + ), + 'monthly': ( + ( 1372, 0.0110, 0.00), + ( 3248, 0.0220, 15.09), + ( 5128, 0.0440, 56.36), + ( 7120, 0.0660, 139.08), + ( 8996, 0.0880, 270.55), + (45956, 0.1023, 435.64), + (55148, 0.1133, 4216.65), + (83334, 0.1243, 5258.10), + (91912, 0.1353, 8761.62), + ('inf', 0.1463, 9922.22), + ), + 'quarterly': ( + ( 4112, 0.0110, 0.00), + ( 9748, 0.0220, 45.23), + ( 15384, 0.0440, 169.22), + ( 21356, 0.0660, 417.20), + ( 26990, 0.0880, 811.35), + (137870, 0.1023, 1307.14), + (165442, 0.1133, 12650.16), + (250000, 0.1243, 15774.07), + (275736, 0.1353, 26284.63), + ( 'inf', 0.1463, 29766.71), + ), + 'semi-annual': ( + ( 8224, 0.0110, 0.00), + ( 19496, 0.0220, 90.46), + ( 30768, 0.0440, 338.44), + ( 42712, 0.0660, 834.41), + ( 53980, 0.0880, 1622.71), + (275740, 0.1023, 2614.29), + (330884, 0.1133, 25300.34), + (500000, 0.1243, 31548.16), + (551472, 0.1353, 52569.28), + ( 'inf', 0.1463, 59533.44), + ), + 'annually': ( + ( 16446, 0.0110, 0.00), + ( 38990, 0.0220, 180.91), + ( 61538, 0.0440, 676.88), + ( 85422, 0.0660, 1668.99), + ( 107960, 0.0880, 3245.33), + ( 551476, 0.1023, 5228.67), + ( 661768, 0.1133, 50600.36), + (1000000, 0.1243, 63096.44), + (1102946, 0.1353, 105138.68), + ( 'inf', 0.1463, 119067.26), + ), + }, + 'single': { + 'weekly': ( + ( 158, 0.0110, 0.00), + ( 375, 0.0220, 1.74), + ( 592, 0.0440, 6.51), + ( 821, 0.0660, 16.06), + ( 1038, 0.0880, 31.17), + ( 5303, 0.1023, 50.27), + ( 6363, 0.1133, 486.58), + (10605, 0.1243, 606.68), + (19231, 0.1353, 1133.96), + ('inf', 0.1463, 2301.06), + ), + 'bi-weekly': ( + ( 316, 0.0110, 0.00), + ( 750, 0.0220, 3.48), + ( 1184, 0.0440, 13.03), + ( 1642, 0.066, 32.13), + ( 2076, 0.0880, 62.36), + (10606, 0.1023, 100.55), + (12726, 0.1133, 973.17), + (21210, 0.1243, 1213.37), + (38462, 0.1353, 2267.93), + ('inf', 0.1463, 4602.13), + ), + 'semi-monthly': ( + ( 343, 0.0110, 0.00), + ( 812, 0.0220, 3.77), + ( 1282, 0.0440, 14.09), + ( 1780, 0.0660, 34.77), + ( 2249, 0.0880, 67.64), + (11489, 0.1023, 108.91), + (13787, 0.1133, 1054.16), + (22978, 0.1243, 1314.52), + (41667, 0.1353, 2456.96), + ('inf', 0.1463, 4985.58), + ), + 'monthly': ( + ( 686, 0.0110, 0.00), + ( 1624, 0.0220, 7.55), + ( 2564, 0.0440, 28.19), + ( 3560, 0.0660, 69.55), + ( 4498, 0.0880, 135.29), + (22978, 0.1023, 217.83), + (27574, 0.1133, 2108.33), + (45956, 0.1243, 2629.06), + (83334, 0.1353, 4913.94), + ('inf', 0.1463, 9971.18), + ), + 'quarterly': ( + ( 2056, 0.0110, 0.00), + ( 4874, 0.0220, 22.62), + ( 7692, 0.0440, 84.62), + ( 10678, 0.066, 208.61), + ( 13495, 0.0880, 405.69), + ( 68935, 0.1023, 653.59), + ( 82721, 0.1133, 6325.10), + (137868, 0.1243, 7887.05), + (250000, 0.1353, 14741.82), + ( 'inf', 0.1463, 29913.28), + ), + 'semi-annual': ( + ( 4112, 0.0110, 0.00), + ( 9748, 0.0220, 45.23), + ( 15384, 0.0440, 169.22), + ( 21356, 0.0660, 417.20), + ( 26990, 0.0880, 811.35), + (137870, 0.1023, 1307.14), + (165442, 0.1133, 12650.16), + (275736, 0.1243, 15774.07), + (500000, 0.1353, 29483.61), + ('inf', 0.1463, 59826.53), + ), + 'annually': ( + ( 8223, 0.0110, 0.00), + ( 19495, 0.0220, 90.45), + ( 30769, 0.0440, 338.43), + ( 42711, 0.0660, 834.49), + ( 53980, 0.0880, 1622.66), + ( 275738, 0.1023, 2614.33), + ( 330884, 0.1133, 25300.17), + ( 551473, 0.1243, 31548.21), + (1000000, 0.1353, 58967.42), + ( 'inf', 0.1463, 119653.12), + ), + }, + } + + + + US CA California SIT Tax Rate + us_ca_sit_tax_rate + { + 'head_household': { + 'weekly': ( + ( 339, 0.0110, 0.00), + ( 803, 0.0220, 3.73), + ( 1035, 0.0440, 13.93), + ( 1281, 0.0660, 24.15), + ( 1514, 0.0880, 40.39), + ( 7725, 0.1023, 60.89), + ( 9270, 0.1133, 696.28), + (15450, 0.1243, 871.33), + (19231, 0.1353, 1639.50), + ('inf', 0.1463, 2151.07), + ), + 'bi-weekly': ( + ( 678, 0.0110, 0.00), + ( 1606, 0.0220, 7.46), + ( 2070, 0.0440, 27.88), + ( 2562, 0.0660, 48.30), + ( 3028, 0.0880, 80.77), + (15450, 0.1023, 121.78), + (18540, 0.1133, 1392.55), + (30900, 0.1243, 1742.65), + (38462, 0.1353, 3279.00), + ('inf', 0.1463, 4302.14), + ), + 'semi-monthly': ( + ( 735, 0.0110, 0.00), + ( 1740, 0.0220, 8.09), + ( 2243, 0.0440, 30.20), + ( 2777, 0.0660, 52.33), + ( 3280, 0.0880, 87.57), + (16738, 0.1023, 131.83), + (20085, 0.1133, 1508.58), + (33475, 0.1243, 1887.80), + (41667, 0.1353, 3552.18), + ('inf', 0.1463, 4660.56), + ), + 'monthly': ( + ( 1470, 0.0110, 0.00), + ( 3480, 0.0220, 16.17), + ( 4486, 0.0440, 60.39), + ( 5554, 0.0660, 104.65), + ( 6560, 0.0880, 175.14), + (33476, 0.1023, 263.67), + (40170, 0.1133, 3017.18), + (66950, 0.1243, 3775.61), + (83334, 0.1353, 7104.36), + ('inf', 0.1463, 9321.12), + ), + 'quarterly': ( + ( 4407, 0.0110, 0.00), + ( 10442, 0.0220, 48.48), + ( 13461, 0.0440, 181.25), + ( 16659, 0.0660, 314.09), + ( 19678, 0.0880, 525.16), + (100426, 0.1023, 790.83), + (120512, 0.1133, 9051.35), + (200853, 0.1243, 11327.09), + (250000, 0.1353, 21313.48), + ( 'inf', 0.1463, 27963.07), + ), + 'semi-annual': ( + ( 8814, 0.0110, 0.00), + ( 20884, 0.0220, 96.95), + ( 26922, 0.0440, 362.49), + ( 33318, 0.0660, 628.16), + ( 39356, 0.0880, 1050.30), + (200852, 0.1023, 1581.64), + (241024, 0.1133, 18102.68), + (401706, 0.1243, 22654.17), + (500000, 0.1353, 42626.94), + ( 'inf', 0.1463, 55926.12), + ), + 'annually': ( + ( 17629, 0.0110, 0.00), + ( 41768, 0.0220, 193.92), + ( 53843, 0.0440, 724.98), + ( 66636, 0.0660, 1256.28), + ( 78710, 0.0880, 2100.62), + ( 401705, 0.1023, 3163.13), + ( 482047, 0.1133, 36205.52), + ( 803410, 0.1243, 45308.27), + (1000000, 0.1353, 85253.69), + ( 'inf', 0.1463, 111852.32), + ), + }, + 'married': { + 'weekly': ( + ( 338, 0.0110, 0.00), + ( 804, 0.0220, 3.72), + ( 1268, 0.0440, 13.97), + ( 1760, 0.0660, 34.39), + ( 2224, 0.0880, 66.86), + (11360, 0.1023, 107.69), + (13632, 0.1133, 1042.30), + (19231, 0.1243, 1299.72), + (22721, 0.1353, 1995.68), + ('inf', 0.1463, 2467.88), + ), + 'bi-weekly': ( + ( 676, 0.0110, 0.00), + ( 1608, 0.0220, 7.44), + ( 2536, 0.0440, 27.94), + ( 3520, 0.0660, 68.77), + ( 4448, 0.0880, 124.70), + (21212, 0.1023, 201.08), + (25452, 0.1133, 1946.32), + (38462, 0.1243, 2426.71), + (42420, 0.1353, 4043.85), + ('inf', 0.1463, 4579.37), + ), + 'semi-monthly': ( + ( 734, 0.0110, 0.00), + ( 1740, 0.0220, 8.07), + ( 2746, 0.0440, 30.20), + ( 3812, 0.0660, 74.46), + ( 4818, 0.0880, 144.82), + (24614, 0.1023, 233.35), + (29538, 0.1133, 2258.48), + (41667, 0.1243, 2816.37), + (49229, 0.1353, 4324.00), + ('inf', 0.1463, 5347.14), + ), + 'monthly': ( + ( 1468, 0.0110, 0.00), + ( 3480, 0.0220, 16.15), + ( 5492, 0.0440, 60.41), + ( 7624, 0.0660, 148.94), + ( 9636, 0.0880, 289.65), + (49228, 0.1023, 466.71), + (59076, 0.1133, 4516.97), + (83334, 0.1243, 5632.75), + (98458, 0.1353, 8648.02), + ('inf', 0.1463, 10694.30), + ), + 'quarterly': ( + ( 4404, 0.0110, 0.00), + ( 10442, 0.0220, 48.44), + ( 16480, 0.0440, 181.28), + ( 22876, 0.0660, 446.95), + ( 28912, 0.0880, 869.09), + (147686, 0.1023, 1400.26), + (177222, 0.1133, 13550.84), + (250000, 0.1243, 16897.27), + (295371, 0.1353, 25943.58), + ( 'inf', 0.1463, 32082.28), + ), + 'semi-annual': ( + ( 8808, 0.0110, 0.00), + ( 20884, 0.0220, 96.89), + ( 32960, 0.0440, 362.56), + ( 45752, 0.0660, 893.90), + ( 57824, 0.0880, 1738.17), + (295372, 0.1023, 2800.51), + (354444, 0.1133, 27101.67), + (500000, 0.1243, 33794.53), + (590742, 0.1353, 51887.14), + ( 'inf', 0.1463, 64164.53), + ), + 'annually': ( + ( 17618, 0.0110, 0.00), + ( 41766, 0.0220, 193.80), + ( 65920, 0.0440, 725.06), + ( 91506, 0.0660, 1787.84), + ( 115648, 0.0880, 3476.52), + ( 590746, 0.1023, 5601.02), + ( 708890, 0.1133, 54203.55), + (1000000, 0.1243, 67589.27), + (1181484, 0.1353, 103774.24), + ( 'inf', 0.1463, 128329.03), + ), + }, + 'single': { + 'weekly': ( + ( 169, 0.0110, 0.00), + ( 402, 0.0220, 1.86), + ( 634, 0.0440, 6.99), + ( 880, 0.0660, 17.20), + ( 1112, 0.0880, 33.44), + ( 5680, 0.1023, 53.86), + ( 6816, 0.1133, 521.17), + (11360, 0.1243, 649.88), + (19231, 0.1353, 1214.70), + ('inf', 0.1463, 2279.65), + ), + 'bi-weekly': ( + ( 338, 0.0110, 0.00), + ( 804, 0.0220, 3.72), + ( 1268, 0.0440, 13.97), + ( 1760, 0.0660, 34.39), + ( 2224, 0.0880, 66.86), + (11360, 0.1023, 107.69), + (13632, 0.1133, 1042.30), + (22720, 0.1243, 1299.72), + (38462, 0.1353, 2429.36), + ('inf', 0.1463, 4559.25), + ), + 'semi-monthly': ( + ( 367, 0.0110, 0.00), + ( 870, 0.0220, 4.04), + ( 1373, 0.0440, 15.11), + ( 1906, 0.0660, 37.24), + ( 2409, 0.0880, 72.42), + (12307, 0.1023, 116.68), + (14769, 0.1133, 1129.25), + (24614, 0.1243, 1408.19), + (41667, 0.1353, 2631.92), + ('inf', 0.1463, 4939.19), + ), + 'monthly': ( + ( 734, 0.0110, 0.00), + ( 1740, 0.0220, 8.07), + ( 2746, 0.0440, 30.20), + ( 3812, 0.0660, 74.46), + ( 4818, 0.0880, 144.82), + (24614, 0.1023, 233.35), + (29538, 0.1133, 2258.48), + (49228, 0.1243, 2816.37), + (83334, 0.1353, 5263.84), + ('inf', 0.1463, 9878.38), + ), + 'quarterly': ( + ( 2202, 0.0110, 0.00), + ( 5221, 0.0220, 24.22), + ( 8240, 0.0440, 90.64), + ( 11438, 0.0660, 223.48), + ( 14456, 0.0880, 434.55), + ( 73843, 0.1023, 700.13), + ( 88611, 0.1133, 6775.42), + (147686, 0.1243, 8448.63), + (250000, 0.1353, 15791.65), + ( 'inf', 0.1463, 29634.73), + ), + 'semi-annual': ( + ( 4404, 0.0110, 0.00), + ( 10442, 0.0220, 48.44), + ( 16480, 0.0440, 181.28), + ( 22876, 0.0660, 446.95), + ( 28912, 0.0880, 869.09), + (147686, 0.1023, 1400.26), + (177222, 0.1133, 13550.84), + (295372, 0.1243, 16897.27), + (500000, 0.1353, 31583.32), + ( 'inf', 0.1463, 59269.49), + ), + 'annually': ( + ( 8809, 0.0110, 0.00), + ( 20883, 0.0220, 96.90), + ( 32960, 0.0440, 362.53), + ( 45753, 0.0660, 893.92), + ( 57824, 0.0880, 1738.26), + ( 295373, 0.1023, 2800.51), + ( 354445, 0.1133, 27101.77), + ( 590742, 0.1243, 33794.63), + (1000000, 0.1353, 63166.35), + ( 'inf', 0.1463, 118538.96), + ), + }, + } + + + + + + + US CA California Low Income Exemption Rate + us_ca_sit_income_exemption_rate + { + 'weekly': ( 280, 280, 561, 561), + 'bi-weekly': ( 561, 561, 1121, 1121), + 'semi-monthly': ( 607, 607, 1214, 1214), + 'monthly': ( 1214, 1214, 2429, 2429), + 'quarterly': ( 3643, 3643, 7287, 7287), + 'semi-annual': ( 7287, 7287, 14573, 14573), + 'annually': (14573, 14573, 29146, 29146), + } + + + + + + US CA California Low Income Exemption Rate + us_ca_sit_income_exemption_rate + { + 'weekly': ( 289, 289, 579, 579), + 'bi-weekly': ( 579, 579, 1157, 1157), + 'semi-monthly': ( 627, 627, 1253, 1253), + 'monthly': ( 1254, 1254, 2507, 2507), + 'quarterly': ( 3761, 3761, 7521, 7521), + 'semi-annual': ( 7521, 7521, 15042, 15042), + 'annually': (15042, 15042, 30083, 30083), + } + + + + + + + US CA California Estimated Deduction Rate + us_ca_sit_estimated_deduction_rate + { + 'weekly': ( 19, 38, 58, 77, 96, 115, 135, 154, 173, 192), + 'bi-weekly': ( 38, 77, 115, 154, 192, 231, 269, 308, 346, 385), + 'semi-monthly': ( 42, 83, 125, 167, 208, 250, 292, 333, 375, 417), + 'monthly': ( 83, 167, 250, 333, 417, 500, 583, 667, 750, 833), + 'quarterly': ( 250, 500, 750, 1000, 1250, 1500, 1750, 2000, 2250, 2500), + 'semi-annual': ( 500, 1000, 1500, 2000, 2500, 3000, 3500, 4000, 4500, 5000), + 'annually': (1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000, 10000), + } + + + + + + US CA California Estimated Deduction Rate + us_ca_sit_estimated_deduction_rate + { + 'weekly': ( 19, 38, 58, 77, 96, 115, 135, 154, 173, 192), + 'bi-weekly': ( 38, 77, 115, 154, 192, 231, 269, 308, 346, 385), + 'semi-monthly': ( 42, 83, 125, 167, 208, 250, 292, 333, 375, 417), + 'monthly': ( 83, 167, 250, 333, 417, 500, 583, 667, 750, 833), + 'quarterly': ( 250, 500, 750, 1000, 1250, 1500, 1750, 2000, 2250, 2500), + 'semi-annual': ( 500, 1000, 1500, 2000, 2500, 3000, 3500, 4000, 4500, 5000), + 'annually': (1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000, 10000), + } + + + + + + + US CA California Standard Deduction Rate + us_ca_sit_standard_deduction_rate + { + 'weekly': ( 85, 85, 169, 169), + 'bi-weekly': ( 169, 169, 339, 339), + 'semi-monthly': ( 183, 183, 367, 367), + 'monthly': ( 367, 367, 734, 734), + 'quarterly': (1100, 1100, 2201, 2201), + 'semi-annual': (2201, 2201, 4401, 4401), + 'annually': (4401, 4401, 8802, 8802), + } + + + + + + US CA California Standard Deduction Rate + us_ca_sit_standard_deduction_rate + { + 'weekly': ( 87, 87, 175, 175), + 'bi-weekly': ( 175, 175, 349, 349), + 'semi-monthly': ( 189, 189, 378, 378), + 'monthly': ( 378, 378, 756, 756), + 'quarterly': (1134, 1134, 2269, 2269), + 'semi-annual': (2269, 2269, 4537, 4537), + 'annually': (4537, 4537, 9074, 9074), + } + + + + + + + US CA California Exemption Allowance Rate + us_ca_sit_exemption_allowance_rate + { + 'weekly': ( 2.41, 4.82, 7.23, 9.65, 12.06, 14.47, 16.88, 19.29, 21.70, 24.12), + 'bi-weekly': ( 4.82, 9.65, 14.47, 19.29, 24.12, 28.94, 33.76, 38.58, 43.41, 48.23), + 'semi-monthly': ( 5.23, 10.45, 15.68, 20.90, 26.13, 31.35, 36.58, 41.80, 47.03, 52.25), + 'monthly': ( 10.45, 20.90, 31.35, 41.80, 52.25, 62.70, 73.15, 83.60, 94.05, 104.50), + 'quarterly': ( 31.35, 62.70, 94.05, 125.40, 156.75, 188.10, 219.45, 250.80, 282.15, 313.50), + 'semi-annual': ( 62.70, 125.40, 188.10, 250.80, 313.50, 376.20, 438.90, 501.60, 564.30, 627.00), + 'annually': (125.40, 250.80, 376.20, 501.60, 627.00, 752.40, 877.80, 1003.20, 1128.60, 1254.00), + } + + + + + + US CA California Exemption Allowance Rate + us_ca_sit_exemption_allowance_rate + { + 'weekly': ( 2.58, 5.16, 7.74, 10.32, 12.90, 15.48, 18.07, 20.65, 23.23, 25.81), + 'bi-weekly': ( 5.16, 10.32, 15.48, 20.65, 25.81, 30.97, 36.13, 41.29, 46.45, 51.62), + 'semi-monthly': ( 5.59, 11.18, 16.78, 22.37, 27.96, 33.55, 39.14, 44.73, 50.33, 55.92), + 'monthly': ( 11.18, 22.37, 33.55, 44.73, 55.92, 67.10, 78.28, 89.47, 100.65, 111.83), + 'quarterly': ( 33.55, 67.10, 100.65, 134.20, 167.75, 201.30, 234.85, 268.40, 301.95, 335.50), + 'semi-annual': ( 67.10, 134.20, 201.30, 268.40, 335.50, 402.60, 469.70, 536.80, 603.90, 671.00), + 'annually': (134.20, 268.40, 402.60, 536.80, 671.00, 805.20, 939.40, 1073.60, 1207.80, 1342.00), + } + + + + + + + US California - Department of Taxation (CA DE88) - Unemployment Tax + 1 + + + US California - Department of Taxation (CA DE88) - Unemployment Tax + + + + + US California - Department of Taxation - Income Tax + 1 + + + US California - Department of Taxation - Income Tax + + + + + + + + + + ER: US CA California State Unemployment + ER_US_CA_SUTA + python + result, _ = general_state_unemployment(payslip, categories, worked_days, inputs, wage_base='us_ca_suta_wage_base', rate='us_ca_suta_rate', state_code='CA') + code + result, result_rate = general_state_unemployment(payslip, categories, worked_days, inputs, wage_base='us_ca_suta_wage_base', rate='us_ca_suta_rate', state_code='CA') + + + + + + + + ER: US CA California State Employee Training Tax + ER_US_CA_SUTA_ETT + python + result, _ = general_state_unemployment(payslip, categories, worked_days, inputs, wage_base='us_ca_suta_wage_base', rate='us_ca_suta_ett_rate', state_code='CA') + code + result, result_rate = general_state_unemployment(payslip, categories, worked_days, inputs, wage_base='us_ca_suta_wage_base', rate='us_ca_suta_ett_rate', state_code='CA') + + + + + + + + EE: US CA California State Disability Insurance + EE_US_CA_SUTA_SDI + python + result, _ = general_state_unemployment(payslip, categories, worked_days, inputs, wage_base='us_ca_suta_wage_base', rate='us_ca_suta_sdi_rate', state_code='CA') + code + result, result_rate = general_state_unemployment(payslip, categories, worked_days, inputs, wage_base='us_ca_suta_wage_base', rate='us_ca_suta_sdi_rate', state_code='CA') + + + + + + + + EE: US CA California State Income Tax Withholding + EE_US_CA_SIT + python + result, _ = ca_california_state_income_withholding(payslip, categories, worked_days, inputs) + code + result, result_rate = ca_california_state_income_withholding(payslip, categories, worked_days, inputs) + + + + + \ No newline at end of file diff --git a/l10n_us_hr_payroll/data/state/co_colorado.xml b/l10n_us_hr_payroll/data/state/co_colorado.xml new file mode 100644 index 00000000..f28e4f18 --- /dev/null +++ b/l10n_us_hr_payroll/data/state/co_colorado.xml @@ -0,0 +1,89 @@ + + + + + + US CO Colorado SUTA Wage Base + us_co_suta_wage_base + 13600.0 + + + + + + + + US CO Colorado SUTA Rate + us_co_suta_rate + 1.7 + + + + + + + US CO Colorado SIT Tax Rate + us_co_sit_tax_rate + 4.63 + + + + + + + US CO Colorado SIT Exemption Rate + us_co_sit_exemption_rate + 4000 + + + + + + + US Colorado - Department of Labor and Employment - Unemployment Tax + 1 + + + US Colorado - Department of Labor and Employment - Unemployment Tax + + + + + US Colorado - Division of Revenue - Income Tax + 1 + + + US Colorado - Division of Revenue - Income Tax + + + + + + + + + + ER: US CO Colorado State Unemployment + ER_US_CO_SUTA + python + result, _ = general_state_unemployment(payslip, categories, worked_days, inputs, wage_base='us_co_suta_wage_base', rate='us_co_suta_rate', state_code='CO') + code + result, result_rate = general_state_unemployment(payslip, categories, worked_days, inputs, wage_base='us_co_suta_wage_base', rate='us_co_suta_rate', state_code='CO') + + + + + + + + EE: US CO Colorado State Income Tax Withholding + EE_US_CO_SIT + python + result, _ = co_colorado_state_income_withholding(payslip, categories, worked_days, inputs) + code + result, result_rate = co_colorado_state_income_withholding(payslip, categories, worked_days, inputs) + + + + + \ No newline at end of file diff --git a/l10n_us_hr_payroll/data/state/ct_connecticut.xml b/l10n_us_hr_payroll/data/state/ct_connecticut.xml new file mode 100644 index 00000000..d74dc140 --- /dev/null +++ b/l10n_us_hr_payroll/data/state/ct_connecticut.xml @@ -0,0 +1,1224 @@ + + + + + + US CT Connecticut SUTA Wage Base + us_ct_suta_wage_base + 15000.0 + + + + US CT Connecticut SUTA Wage Base + us_ct_suta_wage_base + 15000.0 + + + + + + + + US CT Connecticut SUTA Rate + us_ct_suta_rate + 3.4 + + + + US CT Connecticut SUTA Rate + us_ct_suta_rate + 3.2 + + + + + + + US CT Connecticut SIT Initial Tax Rate + us_ct_sit_initial_tax_rate + { + 'a': [ + ( 10000, 0, 3.00), + ( 50000, 300, 5.00), + (100000, 2300, 5.50), + (200000, 5050, 6.00), + (250000, 11050, 6.50), + (500000, 14300, 6.90), + ( 'inf', 31550, 6.99), + ], + 'b': [ + ( 16000, 0, 3.00), + ( 80000, 480, 5.00), + (160000, 3680, 5.50), + (320000, 8080, 6.00), + (400000, 17680, 6.50), + (800000, 22880, 6.90), + ( 'inf', 50480, 6.99), + ], + 'c': [ + ( 20000, 0, 3.00), + ( 100000, 600, 5.00), + ( 200000, 4600, 5.50), + ( 400000, 10100, 6.00), + ( 500000, 22100, 6.50), + (1000000, 28600, 6.90), + ( 'inf', 63100, 6.99), + ], + 'd': [ + ( 10000, 0, 3.00), + ( 50000, 300, 5.00), + (100000, 2300, 5.50), + (200000, 5050, 6.00), + (250000, 11050, 6.50), + (500000, 14300, 6.90), + ( 'inf', 31550, 6.99), + ], + 'f': [ + ( 10000, 0, 3.00), + ( 50000, 300, 5.00), + (100000, 2300, 5.50), + (200000, 5050, 6.00), + (250000, 11050, 6.50), + (500000, 14300, 6.90), + ( 'inf', 31550, 6.99), + ], + } + + + + + + US CT Connecticut SIT Initial Tax Rate + us_ct_sit_initial_tax_rate + { + 'a': [ + ( 10000, 0, 3.00), + ( 50000, 300, 5.00), + (100000, 2300, 5.50), + (200000, 5050, 6.00), + (250000, 11050, 6.50), + (500000, 14300, 6.90), + ( 'inf', 31550, 6.99), + ], + 'b': [ + ( 16000, 0, 3.00), + ( 80000, 480, 5.00), + (160000, 3680, 5.50), + (320000, 8080, 6.00), + (400000, 17680, 6.50), + (800000, 22880, 6.90), + ( 'inf', 50480, 6.99), + ], + 'c': [ + ( 20000, 0, 3.00), + ( 100000, 600, 5.00), + ( 200000, 4600, 5.50), + ( 400000, 10100, 6.00), + ( 500000, 22100, 6.50), + (1000000, 28600, 6.90), + ( 'inf', 63100, 6.99), + ], + 'd': [ + ( 10000, 0, 3.00), + ( 50000, 300, 5.00), + (100000, 2300, 5.50), + (200000, 5050, 6.00), + (250000, 11050, 6.50), + (500000, 14300, 6.90), + ( 'inf', 31550, 6.99), + ], + 'f': [ + ( 10000, 0, 3.00), + ( 50000, 300, 5.00), + (100000, 2300, 5.50), + (200000, 5050, 6.00), + (250000, 11050, 6.50), + (500000, 14300, 6.90), + ( 'inf', 31550, 6.99), + ], + } + + + + + + + US CT Connecticut Tax Rate + us_ct_sit_tax_rate + { + 'a': [ + (50250, 0), + (52750, 20), + (55250, 40), + (57750, 60), + (60250, 80), + (62750, 100), + (65250, 120), + (67750, 140), + (70250, 160), + (72750, 180), + ('inf', 200), + ], + 'b': [ + ( 78500, 0), + ( 82500, 32), + ( 86500, 64), + ( 90500, 96), + ( 94500, 128), + ( 98500, 160), + (102500, 192), + (106500, 224), + (110500, 256), + (114500, 288), + ( 'inf', 320), + ], + 'c': [ + (100500, 0), + (105500, 40), + (110500, 80), + (115500, 120), + (120500, 160), + (125500, 200), + (130500, 240), + (135500, 280), + (140500, 320), + (145500, 360), + ( 'inf', 400), + + ], + 'd': [ + (50250, 0), + (52750, 20), + (55250, 40), + (57750, 60), + (60250, 80), + (62750, 100), + (65250, 120), + (67750, 140), + (70250, 160), + (72750, 180), + ('inf', 200), + ], + 'f': [ + ( 56500, 0), + ( 61500, 20), + ( 66500, 40), + ( 71500, 60), + ( 76500, 80), + ( 81500, 100), + ( 86500, 120), + ( 91500, 140), + ( 96500, 160), + (101500, 180), + ( 'inf', 200), + ], + } + + + + + + US CT Connecticut Tax Rate + us_ct_sit_tax_rate + { + 'a': [ + (50250, 0), + (52750, 20), + (55250, 40), + (57750, 60), + (60250, 80), + (62750, 100), + (65250, 120), + (67750, 140), + (70250, 160), + (72750, 180), + ('inf', 200), + ], + 'b': [ + ( 78500, 0), + ( 82500, 32), + ( 86500, 64), + ( 90500, 96), + ( 94500, 128), + ( 98500, 160), + (102500, 192), + (106500, 224), + (110500, 256), + (114500, 288), + ( 'inf', 320), + ], + 'c': [ + (100500, 0), + (105500, 40), + (110500, 80), + (115500, 120), + (120500, 160), + (125500, 200), + (130500, 240), + (135500, 280), + (140500, 320), + (145500, 360), + ( 'inf', 400), + + ], + 'd': [ + (50250, 0), + (52750, 20), + (55250, 40), + (57750, 60), + (60250, 80), + (62750, 100), + (65250, 120), + (67750, 140), + (70250, 160), + (72750, 180), + ('inf', 200), + ], + 'f': [ + ( 56500, 0), + ( 61500, 20), + ( 66500, 40), + ( 71500, 60), + ( 76500, 80), + ( 81500, 100), + ( 86500, 120), + ( 91500, 140), + ( 96500, 160), + (101500, 180), + ( 'inf', 200), + ], + } + + + + + + + US CT Connecticut Decimal Rate + us_ct_sit_decimal_rate + { + 'a': [ + (15000, 0.75), + (15500, 0.70), + (16000, 0.65), + (16500, 0.60), + (17000, 0.55), + (17500, 0.50), + (18000, 0.45), + (18500, 0.40), + (20000, 0.35), + (20500, 0.30), + (21000, 0.25), + (21500, 0.20), + (25000, 0.15), + (25500, 0.14), + (26000, 0.13), + (26500, 0.12), + (27000, 0.11), + (48000, 0.10), + (48500, 0.09), + (49000, 0.08), + (49500, 0.08), + (50000, 0.06), + (50500, 0.05), + (51000, 0.03), + (51500, 0.03), + (52000, 0.02), + (52500, 0.01), + ('inf', 0.00), + ], + 'b': [ + (24000, 0.75), + (24500, 0.70), + (25000, 0.65), + (25500, 0.60), + (26000, 0.55), + (26500, 0.50), + (27000, 0.45), + (27500, 0.40), + (34000, 0.35), + (34500, 0.30), + (35000, 0.25), + (35500, 0.20), + (44000, 0.15), + (44500, 0.14), + (45000, 0.13), + (45500, 0.12), + (46000, 0.11), + (74000, 0.10), + (74500, 0.09), + (75000, 0.08), + (75500, 0.08), + (76000, 0.06), + (76500, 0.05), + (77000, 0.03), + (77500, 0.03), + (78000, 0.02), + (78500, 0.01), + ('inf', 0.00), + ], + 'c': [ + (30000, 0.75), + (30500, 0.70), + (31000, 0.65), + (31500, 0.60), + (32000, 0.55), + (32500, 0.50), + (33000, 0.45), + (33500, 0.40), + (40000, 0.35), + (40500, 0.30), + (41000, 0.25), + (41500, 0.20), + (50000, 0.15), + (50500, 0.14), + (51000, 0.13), + (51500, 0.12), + (52000, 0.11), + (96000, 0.10), + (96500, 0.09), + (97000, 0.08), + (97500, 0.08), + (98000, 0.06), + (98500, 0.05), + (99000, 0.03), + (99500, 0.03), + (100000, 0.02), + (100500, 0.01), + ('inf', 0.00), + ], + 'f': [ + (18800, 0.75), + (19300, 0.70), + (19800, 0.65), + (20300, 0.60), + (20800, 0.55), + (21300, 0.50), + (21800, 0.45), + (22300, 0.40), + (25000, 0.35), + (25500, 0.30), + (26000, 0.25), + (26500, 0.20), + (31300, 0.15), + (31800, 0.14), + (32300, 0.13), + (32800, 0.12), + (33300, 0.11), + (60000, 0.10), + (60500, 0.09), + (61000, 0.08), + (61500, 0.08), + (62000, 0.06), + (62500, 0.05), + (63000, 0.03), + (63500, 0.03), + (64000, 0.02), + (64500, 0.01), + ('inf', 0.00), + ], + } + + + + + + US CT Connecticut Decimal Rate + us_ct_sit_decimal_rate + { + 'a': [ + (15000, 0.75), + (15500, 0.70), + (16000, 0.65), + (16500, 0.60), + (17000, 0.55), + (17500, 0.50), + (18000, 0.45), + (18500, 0.40), + (20000, 0.35), + (20500, 0.30), + (21000, 0.25), + (21500, 0.20), + (25000, 0.15), + (25500, 0.14), + (26000, 0.13), + (26500, 0.12), + (27000, 0.11), + (48000, 0.10), + (48500, 0.09), + (49000, 0.08), + (49500, 0.08), + (50000, 0.06), + (50500, 0.05), + (51000, 0.03), + (51500, 0.03), + (52000, 0.02), + (52500, 0.01), + ('inf', 0.00), + ], + 'b': [ + (24000, 0.75), + (24500, 0.70), + (25000, 0.65), + (25500, 0.60), + (26000, 0.55), + (26500, 0.50), + (27000, 0.45), + (27500, 0.40), + (34000, 0.35), + (34500, 0.30), + (35000, 0.25), + (35500, 0.20), + (44000, 0.15), + (44500, 0.14), + (45000, 0.13), + (45500, 0.12), + (46000, 0.11), + (74000, 0.10), + (74500, 0.09), + (75000, 0.08), + (75500, 0.08), + (76000, 0.06), + (76500, 0.05), + (77000, 0.03), + (77500, 0.03), + (78000, 0.02), + (78500, 0.01), + ('inf', 0.00), + ], + 'c': [ + (30000, 0.75), + (30500, 0.70), + (31000, 0.65), + (31500, 0.60), + (32000, 0.55), + (32500, 0.50), + (33000, 0.45), + (33500, 0.40), + (40000, 0.35), + (40500, 0.30), + (41000, 0.25), + (41500, 0.20), + (50000, 0.15), + (50500, 0.14), + (51000, 0.13), + (51500, 0.12), + (52000, 0.11), + (96000, 0.10), + (96500, 0.09), + (97000, 0.08), + (97500, 0.08), + (98000, 0.06), + (98500, 0.05), + (99000, 0.03), + (99500, 0.03), + (100000, 0.02), + (100500, 0.01), + ('inf', 0.00), + ], + 'f': [ + (18800, 0.75), + (19300, 0.70), + (19800, 0.65), + (20300, 0.60), + (20800, 0.55), + (21300, 0.50), + (21800, 0.45), + (22300, 0.40), + (25000, 0.35), + (25500, 0.30), + (26000, 0.25), + (26500, 0.20), + (31300, 0.15), + (31800, 0.14), + (32300, 0.13), + (32800, 0.12), + (33300, 0.11), + (60000, 0.10), + (60500, 0.09), + (61000, 0.08), + (61500, 0.08), + (62000, 0.06), + (62500, 0.05), + (63000, 0.03), + (63500, 0.03), + (64000, 0.02), + (64500, 0.01), + ('inf', 0.00), + ], + } + + + + + + + US CT Connecticut Recapture Rate + us_ct_sit_recapture_rate + { + 'a': [ + (200000, 0), + (205000, 90), + (210000, 180), + (215000, 270), + (220000, 360), + (225000, 450), + (230000, 540), + (235000, 630), + (240000, 720), + (245000, 810), + (250000, 900), + (255000, 990), + (260000, 1080), + (265000, 1170), + (270000, 1260), + (275000, 1350), + (280000, 1440), + (285000, 1530), + (290000, 1620), + (295000, 1710), + (300000, 1800), + (305000, 1890), + (310000, 1980), + (315000, 2070), + (320000, 2160), + (325000, 2250), + (330000, 2340), + (335000, 2430), + (340000, 2520), + (345000, 2610), + (500000, 2700), + (505000, 2750), + (510000, 2800), + (515000, 2850), + (520000, 2900), + (525000, 2950), + (530000, 3000), + (535000, 3050), + (540000, 3100), + ( 'inf', 3150), + ], + 'b': [ + (320000, 0), + (328000, 140), + (336000, 280), + (344000, 420), + (352000, 560), + (360000, 700), + (368000, 840), + (376000, 980), + (384000, 1120), + (392000, 1260), + (400000, 1400), + (408000, 1540), + (416000, 1680), + (424000, 1820), + (432000, 1960), + (440000, 2100), + (448000, 2240), + (456000, 2380), + (464000, 2520), + (472000, 2660), + (480000, 2800), + (488000, 2940), + (496000, 3080), + (504000, 3220), + (512000, 3360), + (520000, 3500), + (528000, 3640), + (536000, 3780), + (544000, 3920), + (552000, 4060), + (800000, 4200), + (808000, 4280), + (816000, 4360), + (824000, 4440), + (832000, 4520), + (840000, 4600), + (848000, 4680), + (856000, 4760), + (864000, 4840), + ( 'inf', 4920), + ], + 'c': [ + ( 400000, 0), + ( 410000, 180), + ( 420000, 360), + ( 430000, 540), + ( 440000, 720), + ( 450000, 900), + ( 460000, 1080), + ( 470000, 1260), + ( 480000, 1440), + ( 490000, 1620), + ( 500000, 1800), + ( 510000, 1980), + ( 520000, 2160), + ( 530000, 2340), + ( 540000, 2520), + ( 550000, 2700), + ( 560000, 2880), + ( 570000, 3060), + ( 580000, 3240), + ( 590000, 3420), + ( 600000, 3600), + ( 610000, 3780), + ( 620000, 3960), + ( 630000, 4140), + ( 640000, 4320), + ( 650000, 4500), + ( 660000, 4680), + ( 670000, 4860), + ( 680000, 5040), + ( 690000, 5220), + (1000000, 5400), + (1010000, 5500), + (1020000, 5600), + (1030000, 5700), + (1040000, 5800), + (1050000, 5900), + (1060000, 6000), + (1070000, 6100), + (1080000, 6200), + ( 'inf', 6300), + ], + 'd': [ + (200000, 0), + (205000, 90), + (210000, 180), + (215000, 270), + (220000, 360), + (225000, 450), + (230000, 540), + (235000, 630), + (240000, 720), + (245000, 810), + (250000, 900), + (255000, 990), + (260000, 1080), + (265000, 1170), + (270000, 1260), + (275000, 1350), + (280000, 1440), + (285000, 1530), + (290000, 1620), + (295000, 1710), + (300000, 1800), + (305000, 1890), + (310000, 1980), + (315000, 2070), + (320000, 2160), + (325000, 2250), + (330000, 2340), + (335000, 2430), + (340000, 2520), + (345000, 2610), + (500000, 2700), + (505000, 2750), + (510000, 2800), + (515000, 2850), + (520000, 2900), + (525000, 2950), + (530000, 3000), + (535000, 3050), + (540000, 3100), + ( 'inf', 3150), + ], + 'f': [ + (200000, 0), + (205000, 90), + (210000, 180), + (215000, 270), + (220000, 360), + (225000, 450), + (230000, 540), + (235000, 630), + (240000, 720), + (245000, 810), + (250000, 900), + (255000, 990), + (260000, 1080), + (265000, 1170), + (270000, 1260), + (275000, 1350), + (280000, 1440), + (285000, 1530), + (290000, 1620), + (295000, 1710), + (300000, 1800), + (305000, 1890), + (310000, 1980), + (315000, 2070), + (320000, 2160), + (325000, 2250), + (330000, 2340), + (335000, 2430), + (340000, 2520), + (345000, 2610), + (500000, 2700), + (505000, 2750), + (510000, 2800), + (515000, 2850), + (520000, 2900), + (525000, 2950), + (530000, 3000), + (535000, 3050), + (540000, 3100), + ( 'inf', 3150), + ], + } + + + + + + US CT Connecticut Recapture Rate + us_ct_sit_recapture_rate + { + 'a': [ + (200000, 0), + (205000, 90), + (210000, 180), + (215000, 270), + (220000, 360), + (225000, 450), + (230000, 540), + (235000, 630), + (240000, 720), + (245000, 810), + (250000, 900), + (255000, 990), + (260000, 1080), + (265000, 1170), + (270000, 1260), + (275000, 1350), + (280000, 1440), + (285000, 1530), + (290000, 1620), + (295000, 1710), + (300000, 1800), + (305000, 1890), + (310000, 1980), + (315000, 2070), + (320000, 2160), + (325000, 2250), + (330000, 2340), + (335000, 2430), + (340000, 2520), + (345000, 2610), + (500000, 2700), + (505000, 2750), + (510000, 2800), + (515000, 2850), + (520000, 2900), + (525000, 2950), + (530000, 3000), + (535000, 3050), + (540000, 3100), + ( 'inf', 3150), + ], + 'b': [ + (320000, 0), + (328000, 140), + (336000, 280), + (344000, 420), + (352000, 560), + (360000, 700), + (368000, 840), + (376000, 980), + (384000, 1120), + (392000, 1260), + (400000, 1400), + (408000, 1540), + (416000, 1680), + (424000, 1820), + (432000, 1960), + (440000, 2100), + (448000, 2240), + (456000, 2380), + (464000, 2520), + (472000, 2660), + (480000, 2800), + (488000, 2940), + (496000, 3080), + (504000, 3220), + (512000, 3360), + (520000, 3500), + (528000, 3640), + (536000, 3780), + (544000, 3920), + (552000, 4060), + (800000, 4200), + (808000, 4280), + (816000, 4360), + (824000, 4440), + (832000, 4520), + (840000, 4600), + (848000, 4680), + (856000, 4760), + (864000, 4840), + ( 'inf', 4920), + ], + 'c': [ + ( 400000, 0), + ( 410000, 180), + ( 420000, 360), + ( 430000, 540), + ( 440000, 720), + ( 450000, 900), + ( 460000, 1080), + ( 470000, 1260), + ( 480000, 1440), + ( 490000, 1620), + ( 500000, 1800), + ( 510000, 1980), + ( 520000, 2160), + ( 530000, 2340), + ( 540000, 2520), + ( 550000, 2700), + ( 560000, 2880), + ( 570000, 3060), + ( 580000, 3240), + ( 590000, 3420), + ( 600000, 3600), + ( 610000, 3780), + ( 620000, 3960), + ( 630000, 4140), + ( 640000, 4320), + ( 650000, 4500), + ( 660000, 4680), + ( 670000, 4860), + ( 680000, 5040), + ( 690000, 5220), + (1000000, 5400), + (1010000, 5500), + (1020000, 5600), + (1030000, 5700), + (1040000, 5800), + (1050000, 5900), + (1060000, 6000), + (1070000, 6100), + (1080000, 6200), + ( 'inf', 6300), + ], + 'd': [ + (200000, 0), + (205000, 90), + (210000, 180), + (215000, 270), + (220000, 360), + (225000, 450), + (230000, 540), + (235000, 630), + (240000, 720), + (245000, 810), + (250000, 900), + (255000, 990), + (260000, 1080), + (265000, 1170), + (270000, 1260), + (275000, 1350), + (280000, 1440), + (285000, 1530), + (290000, 1620), + (295000, 1710), + (300000, 1800), + (305000, 1890), + (310000, 1980), + (315000, 2070), + (320000, 2160), + (325000, 2250), + (330000, 2340), + (335000, 2430), + (340000, 2520), + (345000, 2610), + (500000, 2700), + (505000, 2750), + (510000, 2800), + (515000, 2850), + (520000, 2900), + (525000, 2950), + (530000, 3000), + (535000, 3050), + (540000, 3100), + ( 'inf', 3150), + ], + 'f': [ + (200000, 0), + (205000, 90), + (210000, 180), + (215000, 270), + (220000, 360), + (225000, 450), + (230000, 540), + (235000, 630), + (240000, 720), + (245000, 810), + (250000, 900), + (255000, 990), + (260000, 1080), + (265000, 1170), + (270000, 1260), + (275000, 1350), + (280000, 1440), + (285000, 1530), + (290000, 1620), + (295000, 1710), + (300000, 1800), + (305000, 1890), + (310000, 1980), + (315000, 2070), + (320000, 2160), + (325000, 2250), + (330000, 2340), + (335000, 2430), + (340000, 2520), + (345000, 2610), + (500000, 2700), + (505000, 2750), + (510000, 2800), + (515000, 2850), + (520000, 2900), + (525000, 2950), + (530000, 3000), + (535000, 3050), + (540000, 3100), + ( 'inf', 3150), + ], + } + + + + + + + US CT Connecticut Personal Exemption Rate + us_ct_sit_personal_exemption_rate + { + 'a' : [ + (24000, 12000), + (25000, 11000), + (26000, 10000), + (27000, 9000), + (28000, 8000), + (29000, 7000), + (30000, 6000), + (31000, 5000), + (32000, 4000), + (33000, 3000), + (34000, 2000), + (35000, 1000), + ('inf', 0), + ], + 'b' : [ + (38000, 19000), + (39000, 18000), + (40000, 17000), + (41000, 16000), + (42000, 15000), + (43000, 14000), + (44000, 13000), + (45000, 12000), + (46000, 11000), + (47000, 10000), + (48000, 9000), + (49000, 8000), + (50000, 7000), + (51000, 6000), + (52000, 5000), + (53000, 4000), + (54000, 3000), + (55000, 2000), + (56000, 1000), + ('inf', 0), + ], + 'c': [ + (48000, 24000), + (49000, 23000), + (50000, 22000), + (51000, 21000), + (52000, 20000), + (53000, 19000), + (54000, 18000), + (55000, 17000), + (56000, 16000), + (57000, 15000), + (58000, 14000), + (59000, 13000), + (60000, 12000), + (61000, 11000), + (62000, 10000), + (63000, 9000), + (64000, 8000), + (65000, 7000), + (66000, 6000), + (67000, 5000), + (68000, 4000), + (69000, 3000), + (70000, 2000), + (71000, 1000), + ('inf', 0), + ], + 'f' : [ + (30000, 15000), + (31000, 14000), + (22000, 13000), + (33000, 12000), + (34000, 11000), + (35000, 10000), + (36000, 9000), + (37000, 8000), + (38000, 7000), + (39000, 6000), + (40000, 5000), + (41000, 4000), + (42000, 3000), + (43000, 2000), + (44000, 1000), + ('inf', 0), + ], + } + + + + + + US CT Connecticut Personal Exemption Rate + us_ct_sit_personal_exemption_rate + { + 'a' : [ + (24000, 12000), + (25000, 11000), + (26000, 10000), + (27000, 9000), + (28000, 8000), + (29000, 7000), + (30000, 6000), + (31000, 5000), + (32000, 4000), + (33000, 3000), + (34000, 2000), + (35000, 1000), + ('inf', 0), + ], + 'b' : [ + (38000, 19000), + (39000, 18000), + (40000, 17000), + (41000, 16000), + (42000, 15000), + (43000, 14000), + (44000, 13000), + (45000, 12000), + (46000, 11000), + (47000, 10000), + (48000, 9000), + (49000, 8000), + (50000, 7000), + (51000, 6000), + (52000, 5000), + (53000, 4000), + (54000, 3000), + (55000, 2000), + (56000, 1000), + ('inf', 0), + ], + 'c': [ + (48000, 24000), + (49000, 23000), + (50000, 22000), + (51000, 21000), + (52000, 20000), + (53000, 19000), + (54000, 18000), + (55000, 17000), + (56000, 16000), + (57000, 15000), + (58000, 14000), + (59000, 13000), + (60000, 12000), + (61000, 11000), + (62000, 10000), + (63000, 9000), + (64000, 8000), + (65000, 7000), + (66000, 6000), + (67000, 5000), + (68000, 4000), + (69000, 3000), + (70000, 2000), + (71000, 1000), + ('inf', 0), + ], + 'f' : [ + (30000, 15000), + (31000, 14000), + (22000, 13000), + (33000, 12000), + (34000, 11000), + (35000, 10000), + (36000, 9000), + (37000, 8000), + (38000, 7000), + (39000, 6000), + (40000, 5000), + (41000, 4000), + (42000, 3000), + (43000, 2000), + (44000, 1000), + ('inf', 0), + ], + } + + + + + + + US Connecticut - Department of Labor (CDOL) - Unemployment Tax + 1 + + + US Connecticut - Department of Labor (CDOL) - Unemployment Tax + + + + + US Connecticut - Department of Revenue Services (CDRS) - Income Tax + 1 + + + US Connecticut - Department of Revenue Services (CDRS) - Unemployment Tax + + + + + + + + + + ER: US CT Connecticut State Unemployment + ER_US_CT_SUTA + python + result, _ = general_state_unemployment(payslip, categories, worked_days, inputs, wage_base='us_ct_suta_wage_base', rate='us_ct_suta_rate', state_code='CT') + code + result, result_rate = general_state_unemployment(payslip, categories, worked_days, inputs, wage_base='us_ct_suta_wage_base', rate='us_ct_suta_rate', state_code='CT') + + + + + + + + EE: US CT Connecticut State Income Tax Withholding + EE_US_CT_SIT + python + result, _ = ct_connecticut_state_income_withholding(payslip, categories, worked_days, inputs) + code + result, result_rate = ct_connecticut_state_income_withholding(payslip, categories, worked_days, inputs) + + + + + \ No newline at end of file diff --git a/l10n_us_hr_payroll/data/state/de_delaware.xml b/l10n_us_hr_payroll/data/state/de_delaware.xml new file mode 100644 index 00000000..c37a2df5 --- /dev/null +++ b/l10n_us_hr_payroll/data/state/de_delaware.xml @@ -0,0 +1,107 @@ + + + + + + US DE Delaware SUTA Wage Base + us_de_suta_wage_base + 16500.0 + + + + + + + + US DE Delaware SUTA Rate + us_de_suta_rate + 1.50 + + + + + + + US DE Delaware SIT Tax Rate + us_de_sit_tax_rate + [ + ( 2000, 0.0, 0.00), + ( 5000, 0.0, 2.20), + (10000, 66.0, 3.90), + (20000, 261.0, 4.80), + (25000, 741.0, 5.20), + (60000, 1001.0, 5.55), + ('inf', 2943.0, 6.60), + + ] + + + + + + + US DE Delaware Standard Deduction Rate + us_de_sit_standard_deduction_rate + 3250 + + + + + + + US DE Delaware Personal Exemption Rate + us_de_sit_personal_exemption_rate + 110 + + + + + + + US Delaware - Division of Unemployment Insurance - Unemployment Tax + 1 + + + US Delaware - Division of Unemployment Insurance - Unemployment Tax + + + + + US Delaware - Division of Revenue - Income Tax + 1 + + + US Delaware - Division of Revenue - Unemployment Tax + + + + + + + + + + ER: US DE Delaware State Unemployment + ER_US_DE_SUTA + python + result, _ = general_state_unemployment(payslip, categories, worked_days, inputs, wage_base='us_de_suta_wage_base', rate='us_de_suta_rate', state_code='DE') + code + result, result_rate = general_state_unemployment(payslip, categories, worked_days, inputs, wage_base='us_de_suta_wage_base', rate='us_de_suta_rate', state_code='DE') + + + + + + + + EE: US DE Delaware State Income Tax Withholding + EE_US_DE_SIT + python + result, _ = de_delaware_state_income_withholding(payslip, categories, worked_days, inputs) + code + result, result_rate = de_delaware_state_income_withholding(payslip, categories, worked_days, inputs) + + + + + \ No newline at end of file diff --git a/l10n_us_hr_payroll/data/state/fl_florida.xml b/l10n_us_hr_payroll/data/state/fl_florida.xml index de1cc49a..56265ef8 100644 --- a/l10n_us_hr_payroll/data/state/fl_florida.xml +++ b/l10n_us_hr_payroll/data/state/fl_florida.xml @@ -35,6 +35,7 @@ US Florida - Department of Revenue + 1 diff --git a/l10n_us_hr_payroll/data/state/ga_georgia.xml b/l10n_us_hr_payroll/data/state/ga_georgia.xml index 2d07104a..e53cf36d 100644 --- a/l10n_us_hr_payroll/data/state/ga_georgia.xml +++ b/l10n_us_hr_payroll/data/state/ga_georgia.xml @@ -38,53 +38,597 @@ us_ga_sit_rate { 'married filing joint, both spouses working': { - 'weekly': ((9.50, 0.00, 1.00), (29.00, .10, 2.00), (48.00, .48, 3.00), (67.50, 1.06, 4.00), (96.00, 1.83, 5.00), ('inf', 3.27, 5.75)), - 'bi-weekly': ((19.00, 0.00, 1.00), (57.50, .19, 2.00), (96.00, .96, 3.00), (135.00, 2.12, 4.00), (192.00, 3.65, 5.00), ('inf', 6.54, 5.75)), - 'semi-monthly': ((21.00, 0.00, 1.00), (62.50, .21, 2.00), (104.00, 1.04, 3.00), (146.00, 2.29, 4.00), (208.00, 3.96, 5.00), ('inf', 7.08, 5.75)), - 'monthly': ((41.50, 0.00, 1.00), (125.50, .42, 2.00), (208.00, 2.08, 3.00), (292.00, 4.58, 4.00), (417.00, 7.92, 5.00), ('inf', 14.17, 5.75)), - 'quarterly': ((125.00, 0.00, 1.00), (375.00, 1.25, 2.00), (625.00, 6.25, 3.00), (875.00, 13.75, 4.00), (1250.00, 23.75, 5.00), ('inf', 42.50, 5.75)), - 'semi-annual': ((250.00, 0.00, 1.00), (750.00, 2.50, 2.00), (1250.00, 12.50, 3.00), (1750.00, 27.50, 4.00), (2500.00, 47.50, 5.00), ('inf', 85.00, 5.75)), - 'annual': ((500.00, 0.00, 1.00), (1500.00, 5.00, 2.00), (2500.00, 25.00, 3.00), (3500.00, 55.00, 4.00), (5000.00, 95.00, 5.00), ('inf', 170.00, 5.75)), - }, + 'weekly': ( + ( 9.50, 0.00, 1.00), + (29.00, 0.10, 2.00), + (48.00, 0.48, 3.00), + (67.50, 1.06, 4.00), + (96.00, 1.83, 5.00), + ('inf', 3.27, 5.75), + ), + 'bi-weekly': ( + ( 19.00, 0.00, 1.00), + ( 57.50, 0.19, 2.00), + ( 96.00, 0.96, 3.00), + (135.00, 2.12, 4.00), + (192.00, 3.65, 5.00), + ( 'inf', 6.54, 5.75), + ), + 'semi-monthly': ( + ( 21.00, 0.00, 1.00), + ( 62.50, 0.21, 2.00), + (104.00, 1.04, 3.00), + (146.00, 2.29, 4.00), + (208.00, 3.96, 5.00), + ( 'inf', 7.08, 5.75), + ), + 'monthly': ( + ( 41.50, 0.00, 1.00), + (125.50, 0.42, 2.00), + (208.00, 2.08, 3.00), + (292.00, 4.58, 4.00), + (417.00, 7.92, 5.00), + ( 'inf', 14.17, 5.75), + ), + 'quarterly': ( + ( 125.00, 0.00, 1.00), + ( 375.00, 1.25, 2.00), + ( 625.00, 6.25, 3.00), + ( 875.00, 13.75, 4.00), + (1250.00, 23.75, 5.00), + ( 'inf', 42.50, 5.75), + ), + 'semi-annual': ( + ( 250.00, 0.00, 1.00), + ( 750.00, 2.50, 2.00), + (1250.00, 12.50, 3.00), + (1750.00, 27.50, 4.00), + (2500.00, 47.50, 5.00), + ( 'inf', 85.00, 5.75), + ), + 'annual': ( + ( 500.00, 0.00, 1.00), + (1500.00, 5.00, 2.00), + (2500.00, 25.00, 3.00), + (3500.00, 55.00, 4.00), + (5000.00, 95.00, 5.00), + ( 'inf', 170.00, 5.75), + ), + }, 'married filing joint, one spouse working': { - 'weekly': ((19.00, 0.00, 1.00), (57.50, .19, 2.00), (96.00, .96, 3.00), (135.00, 2.12, 4.00), (192.50, 3.65, 5.00), ('inf', 6.54, 5.75)), - 'bi-weekly': ((38.50, 0.00, 1.00), (115.00, .38, 2.00), (192.00, 1.92, 3.00), (269.00, 4.23, 4.00), (385.00, 7.31, 5.00), ('inf', 13.08, 5.75)), - 'semi-monthly': ((41.50, 0.00, 1.00), (125.00, .42, 2.00), (208.00, 2.08, 3.00), (292.00, 4.58, 4.00), (417.00, 7.92, 5.00), ('inf', 14.17, 5.75)), - 'monthly': ((83.00, 0.00, 1.00), (250.00, .83, 2.00), (417.00, 4.17, 3.00), (583.00, 9.17, 4.00), (833.00, 15.83, 5.00), ('inf', 28.33, 5.75)), - 'quarterly': ((250.00, 0.00, 1.00), (750.00, 2.50, 2.00), (1250.00, 12.50, 3.00), (1750.00, 27.50, 4.00), (2500.00, 47.50, 5.00), ('inf', 85.00, 5.75)), - 'semi-annual': ((500.00, 0.00, 1.00), (1500.00, 5.00, 2.00), (2500.00, 25.00, 3.00), (3500.00, 55.00, 4.00), (5000.00, 95.00, 5.00), ('inf', 170.00, 5.75)), - 'annual': ((1000.00, 0.00, 1.00), (3000.00, 10.00, 2.00), (5000.00, 50.00, 3.00), (7000.00, 110.00, 4.00), (10000.00, 190.00, 5.00), ('inf', 340.00, 5.75)), - }, + 'weekly': ( + ( 19.00, 0.00, 1.00), + ( 57.50, 0.19, 2.00), + ( 96.00, 0.96, 3.00), + (135.00, 2.12, 4.00), + (192.50, 3.65, 5.00), + ( 'inf', 6.54, 5.75), + ), + 'bi-weekly': ( + ( 38.50, 0.00, 1.00), + (115.00, 0.38, 2.00), + (192.00, 1.92, 3.00), + (269.00, 4.23, 4.00), + (385.00, 7.31, 5.00), + ( 'inf', 13.08, 5.75), + ), + 'semi-monthly': ( + ( 41.50, 0.00, 1.00), + (125.00, 0.42, 2.00), + (208.00, 2.08, 3.00), + (292.00, 4.58, 4.00), + (417.00, 7.92, 5.00), + ( 'inf', 14.17, 5.75), + ), + 'monthly': ( + ( 83.00, 0.00, 1.00), + (250.00, 0.83, 2.00), + (417.00, 4.17, 3.00), + (583.00, 9.17, 4.00), + (833.00, 15.83, 5.00), + ( 'inf', 28.33, 5.75), + ), + 'quarterly': ( + ( 250.00, 0.00, 1.00), + ( 750.00, 2.50, 2.00), + (1250.00, 12.50, 3.00), + (1750.00, 27.50, 4.00), + (2500.00, 47.50, 5.00), + ( 'inf', 85.00, 5.75), + ), + 'semi-annual': ( + ( 500.00, 0.00, 1.00), + (1500.00, 5.00, 2.00), + (2500.00, 25.00, 3.00), + (3500.00, 55.00, 4.00), + (5000.00, 95.00, 5.00), + ( 'inf', 170.00, 5.75), + ), + 'annual': ( + ( 1000.00, 0.00, 1.00), + ( 3000.00, 10.00, 2.00), + ( 5000.00, 50.00, 3.00), + ( 7000.00, 110.00, 4.00), + (10000.00, 190.00, 5.00), + ( 'inf', 340.00, 5.75), + ), + }, 'single': { - 'weekly': ((14.50, 0.00, 1.00), (43.50, .14, 2.00), (72.00, .72, 3.00), (101.00, 1.59, 4.00), (135.00, 2.74, 5.00), ('inf', 4.42, 5.75)), - 'bi-weekly': ((29.00, 0.00, 1.00), (86.50, .29, 2.00), (144.00, 1.44, 3.00), (202.00, 3.17, 4.00), (269.00, 5.48, 5.00), ('inf', 8.85, 5.75)), - 'semi-monthly': ((31.00, 0.00, 1.00), (93.50, .31, 2.00), (156.00, 1.56, 3.00), (219.00, 3.34, 4.00), (292.00, 5.94, 5.00), ('inf', 9.58, 5.75)), - 'monthly': ((62.50, 0.00, 1.00), (187.00, .62, 2.00), (312.00, 3.12, 3.00), (437.00, 6.87, 4.00), (583.00, 11.87, 5.00), ('inf', 19.17, 5.75)), - 'quarterly': ((187.50, 0.00, 1.00), (562.50, 1.88, 2.00), (937.50, 9.38, 3.00), (1312.00, 20.63, 4.00), (1750.00, 35.63, 5.00), ('inf', 57.50, 5.75)), - 'semi-annual': ((375.00, 0.00, 1.00), (1125.00, 3.75, 2.00), (1875.00, 18.75, 3.00), (2625.00, 41.25, 4.00), (3500.00, 71.25, 5.00), ('inf', 115.00, 5.75)), - 'annual': ((750.00, 0.00, 1.00), (2250.00, 7.50, 2.00), (3750.00, 37.50, 3.00), (5250.00, 82.50, 4.00), (7000.00, 142.50, 5.00), ('inf', 230.00, 5.75)), - }, + 'weekly': ( + ( 14.50, 0.00, 1.00), + ( 43.50, 0.14, 2.00), + ( 72.00, 0.72, 3.00), + (101.00, 1.59, 4.00), + (135.00, 2.74, 5.00), + ( 'inf', 4.42, 5.75), + ), + 'bi-weekly': ( + ( 29.00, 0.00, 1.00), + ( 86.50, 0.29, 2.00), + (144.00, 1.44, 3.00), + (202.00, 3.17, 4.00), + (269.00, 5.48, 5.00), + ( 'inf', 8.85, 5.75), + ), + 'semi-monthly': ( + ( 31.00, 0.00, 1.00), + ( 93.50, 0.31, 2.00), + (156.00, 1.56, 3.00), + (219.00, 3.34, 4.00), + (292.00, 5.94, 5.00), + ( 'inf', 9.58, 5.75), + ), + 'monthly': ( + ( 62.50, 0.00, 1.00), + (187.00, 0.62, 2.00), + (312.00, 3.12, 3.00), + (437.00, 6.87, 4.00), + (583.00, 11.87, 5.00), + ( 'inf', 19.17, 5.75), + ), + 'quarterly': ( + ( 187.50, 0.00, 1.00), + ( 562.50, 1.88, 2.00), + ( 937.50, 9.38, 3.00), + (1312.00, 20.63, 4.00), + (1750.00, 35.63, 5.00), + ( 'inf', 57.50, 5.75), + ), + 'semi-annual': ( + ( 375.00, 0.00, 1.00), + (1125.00, 3.75, 2.00), + (1875.00, 18.75, 3.00), + (2625.00, 41.25, 4.00), + (3500.00, 71.25, 5.00), + ( 'inf', 115.00, 5.75), + ), + 'annual': ( + ( 750.00, 0.00, 1.00), + (2250.00, 7.50, 2.00), + (3750.00, 37.50, 3.00), + (5250.00, 82.50, 4.00), + (7000.00, 142.50, 5.00), + ( 'inf', 230.00, 5.75), + ), + }, 'head of household': { - 'weekly': ((19.00, 0.00, 1.00), (57.50, .19, 2.00), (96.00, .96, 3.00), (135.00, 2.12, 4.00), (192.50, 3.65, 5.00), ('inf', 6.54, 5.75)), - 'bi-weekly': ((38.50, 0.00, 1.00), (115.00, .38, 2.00), (192.00, 1.92, 3.00), (269.00, 4.23, 4.00), (385.00, 7.31, 5.00), ('inf', 13.08, 5.75)), - 'semi-monthly': ((41.50, 0.00, 1.00), (125.00, .42, 2.00), (208.00, 2.08, 3.00), (292.00, 4.58, 4.00), (417.00, 7.92, 5.00), ('inf', 14.17, 5.75)), - 'monthly': ((83.00, 0.00, 1.00), (250.00, .83, 2.00), (417.00, 4.17, 3.00), (583.00, 9.17, 4.00), (833.00, 15.83, 5.00), ('inf', 28.33, 5.75)), - 'quarterly': ((250.00, 0.00, 1.00), (750.00, 2.50, 2.00), (1250.00, 12.50, 3.00), (1750.00, 27.50, 4.00), (2500.00, 47.50, 5.00), ('inf', 85.00, 5.75)), - 'semi-annual': ((500.00, 0.00, 1.00), (1500.00, 5.00, 2.00), (2500.00, 25.00, 3.00), (3500.00, 55.00, 4.00), (5000.00, 95.00, 5.00), ('inf', 170.00, 5.75)), - 'annual': ((1000.00, 0.00, 1.00), (3000.00, 10.00, 2.00), (5000.00, 50.00, 3.00), (7000.00, 110.00, 4.00), (10000.00, 190.00, 5.00), ('inf', 340.00, 5.75)), - }, + 'weekly': ( + ( 19.00, 0.00, 1.00), + ( 57.50, 0.19, 2.00), + ( 96.00, 0.96, 3.00), + (135.00, 2.12, 4.00), + (192.50, 3.65, 5.00), + ( 'inf', 6.54, 5.75), + ), + 'bi-weekly': ( + ( 38.50, 0.00, 1.00), + (115.00, 0.38, 2.00), + (192.00, 1.92, 3.00), + (269.00, 4.23, 4.00), + (385.00, 7.31, 5.00), + ( 'inf', 13.08, 5.75), + ), + 'semi-monthly': ( + ( 41.50, 0.00, 1.00), + (125.00, 0.42, 2.00), + (208.00, 2.08, 3.00), + (292.00, 4.58, 4.00), + (417.00, 7.92, 5.00), + ( 'inf', 14.17, 5.75), + ), + 'monthly': ( + ( 83.00, 0.00, 1.00), + (250.00, 0.83, 2.00), + (417.00, 4.17, 3.00), + (583.00, 9.17, 4.00), + (833.00, 15.83, 5.00), + ( 'inf', 28.33, 5.75), + ), + 'quarterly': ( + ( 250.00, 0.00, 1.00), + ( 750.00, 2.50, 2.00), + (1250.00, 12.50, 3.00), + (1750.00, 27.50, 4.00), + (2500.00, 47.50, 5.00), + ( 'inf', 85.00, 5.75), + ), + 'semi-annual': ( + ( 500.00, 0.00, 1.00), + (1500.00, 5.00, 2.00), + (2500.00, 25.00, 3.00), + (3500.00, 55.00, 4.00), + (5000.00, 95.00, 5.00), + ( 'inf', 170.00, 5.75), + ), + 'annual': ( + ( 1000.00, 0.00, 1.00), + ( 3000.00, 10.00, 2.00), + ( 5000.00, 50.00, 3.00), + ( 7000.00, 110.00, 4.00), + (10000.00, 190.00, 5.00), + ( 'inf', 340.00, 5.75), + ), + }, 'married filing separate': { - 'weekly': ((9.50, 0.00, 1.00), (29.00, .10, 2.00), (48.00, .48, 3.00), (67.50, 1.06, 4.00), (96.00, 1.83, 5.00), ('inf', 3.27, 5.75)), - 'bi-weekly': ((19.00, 0.00, 1.00), (57.50, .19, 2.00), (96.00, .96, 3.00), (135.00, 2.12, 4.00), (192.00, 3.65, 5.00), ('inf', 6.54, 5.75)), - 'semi-monthly': ((21.00, 0.00, 1.00), (62.50, .21, 2.00), (104.00, 1.04, 3.00), (146.00, 2.29, 4.00), (208.00, 3.96, 5.00), ('inf', 7.08, 5.75)), - 'monthly': ((41.50, 0.00, 1.00), (125.50, .42, 2.00), (208.00, 2.08, 3.00), (292.00, 4.58, 4.00), (417.00, 7.92, 5.00), ('inf', 14.17, 5.75)), - 'quarterly': ((125.00, 0.00, 1.00), (375.00, 1.25, 2.00), (625.00, 6.25, 3.00), (875.00, 13.75, 4.00), (1250.00, 23.75, 5.00), ('inf', 42.50, 5.75)), - 'semi-annual': ((250.00, 0.00, 1.00), (750.00, 2.50, 2.00), (1250.00, 12.50, 3.00), (1750.00, 27.50, 4.00), (2500.00, 47.50, 5.00), ('inf', 85.00, 5.75)), - 'annual': ((500.00, 0.00, 1.00), (1500.00, 5.00, 2.00), (2500.00, 25.00, 3.00), (3500.00, 55.00, 4.00), (5000.00, 95.00, 5.00), ('inf', 170.00, 5.75)), - }, + 'weekly': ( + ( 9.50, 0.00, 1.00), + (29.00, 0.10, 2.00), + (48.00, 0.48, 3.00), + (67.50, 1.06, 4.00), + (96.00, 1.83, 5.00), + ('inf', 3.27, 5.75), + ), + 'bi-weekly': ( + ( 19.00, 0.00, 1.00), + ( 57.50, 0.19, 2.00), + ( 96.00, 0.96, 3.00), + (135.00, 2.12, 4.00), + (192.00, 3.65, 5.00), + ( 'inf', 6.54, 5.75), + ), + 'semi-monthly': ( + ( 21.00, 0.00, 1.00), + ( 62.50, 0.21, 2.00), + (104.00, 1.04, 3.00), + (146.00, 2.29, 4.00), + (208.00, 3.96, 5.00), + ( 'inf', 7.08, 5.75), + ), + 'monthly': ( + ( 41.50, 0.00, 1.00), + (125.50, 0.42, 2.00), + (208.00, 2.08, 3.00), + (292.00, 4.58, 4.00), + (417.00, 7.92, 5.00), + ( 'inf', 14.17, 5.75), + ), + 'quarterly': ( + ( 125.00, 0.00, 1.00), + ( 375.00, 1.25, 2.00), + ( 625.00, 6.25, 3.00), + ( 875.00, 13.75, 4.00), + (1250.00, 23.75, 5.00), + ( 'inf', 42.50, 5.75), + ), + 'semi-annual': ( + ( 250.00, 0.00, 1.00), + ( 750.00, 2.50, 2.00), + (1250.00, 12.50, 3.00), + (1750.00, 27.50, 4.00), + (2500.00, 47.50, 5.00), + ( 'inf', 85.00, 5.75), + ), + 'annual': ( + ( 500.00, 0.00, 1.00), + (1500.00, 5.00, 2.00), + (2500.00, 25.00, 3.00), + (3500.00, 55.00, 4.00), + (5000.00, 95.00, 5.00), + ( 'inf', 170.00, 5.75), + ), + }, } + + + + US GA Georgia SIT Rate Table + us_ga_sit_rate + { + 'married filing joint, both spouses working': { + 'weekly': ( + ( 9.50, 0.00, 1.00), + (29.00, 0.10, 2.00), + (48.00, 0.48, 3.00), + (67.50, 1.06, 4.00), + (96.00, 1.83, 5.00), + ('inf', 3.27, 5.75), + ), + 'bi-weekly': ( + ( 19.00, 0.00, 1.00), + ( 57.50, 0.19, 2.00), + ( 96.00, 0.96, 3.00), + (135.00, 2.12, 4.00), + (192.00, 3.65, 5.00), + ( 'inf', 6.54, 5.75), + ), + 'semi-monthly': ( + ( 21.00, 0.00, 1.00), + ( 62.50, 0.21, 2.00), + (104.00, 1.04, 3.00), + (146.00, 2.29, 4.00), + (208.00, 3.96, 5.00), + ( 'inf', 7.08, 5.75), + ), + 'monthly': ( + ( 41.50, 0.00, 1.00), + (125.50, 0.42, 2.00), + (208.00, 2.08, 3.00), + (292.00, 4.58, 4.00), + (417.00, 7.92, 5.00), + ( 'inf', 14.17, 5.75), + ), + 'quarterly': ( + ( 125.00, 0.00, 1.00), + ( 375.00, 1.25, 2.00), + ( 625.00, 6.25, 3.00), + ( 875.00, 13.75, 4.00), + (1250.00, 23.75, 5.00), + ( 'inf', 42.50, 5.75), + ), + 'semi-annual': ( + ( 250.00, 0.00, 1.00), + ( 750.00, 2.50, 2.00), + (1250.00, 12.50, 3.00), + (1750.00, 27.50, 4.00), + (2500.00, 47.50, 5.00), + ( 'inf', 85.00, 5.75), + ), + 'annual': ( + ( 500.00, 0.00, 1.00), + (1500.00, 5.00, 2.00), + (2500.00, 25.00, 3.00), + (3500.00, 55.00, 4.00), + (5000.00, 95.00, 5.00), + ( 'inf', 170.00, 5.75), + ), + }, + 'married filing joint, one spouse working': { + 'weekly': ( + ( 19.00, 0.00, 1.00), + ( 57.50, 0.19, 2.00), + ( 96.00, 0.96, 3.00), + (135.00, 2.12, 4.00), + (192.50, 3.65, 5.00), + ( 'inf', 6.54, 5.75), + ), + 'bi-weekly': ( + ( 38.50, 0.00, 1.00), + (115.00, 0.38, 2.00), + (192.00, 1.92, 3.00), + (269.00, 4.23, 4.00), + (385.00, 7.31, 5.00), + ( 'inf', 13.08, 5.75), + ), + 'semi-monthly': ( + ( 41.50, 0.00, 1.00), + (125.00, 0.42, 2.00), + (208.00, 2.08, 3.00), + (292.00, 4.58, 4.00), + (417.00, 7.92, 5.00), + ( 'inf', 14.17, 5.75), + ), + 'monthly': ( + ( 83.00, 0.00, 1.00), + (250.00, 0.83, 2.00), + (417.00, 4.17, 3.00), + (583.00, 9.17, 4.00), + (833.00, 15.83, 5.00), + ( 'inf', 28.33, 5.75), + ), + 'quarterly': ( + ( 250.00, 0.00, 1.00), + ( 750.00, 2.50, 2.00), + (1250.00, 12.50, 3.00), + (1750.00, 27.50, 4.00), + (2500.00, 47.50, 5.00), + ( 'inf', 85.00, 5.75), + ), + 'semi-annual': ( + ( 500.00, 0.00, 1.00), + (1500.00, 5.00, 2.00), + (2500.00, 25.00, 3.00), + (3500.00, 55.00, 4.00), + (5000.00, 95.00, 5.00), + ( 'inf', 170.00, 5.75), + ), + 'annual': ( + ( 1000.00, 0.00, 1.00), + ( 3000.00, 10.00, 2.00), + ( 5000.00, 50.00, 3.00), + ( 7000.00, 110.00, 4.00), + (10000.00, 190.00, 5.00), + ( 'inf', 340.00, 5.75), + ), + }, + 'single': { + 'weekly': ( + ( 14.50, 0.00, 1.00), + ( 43.50, 0.14, 2.00), + ( 72.00, 0.72, 3.00), + (101.00, 1.59, 4.00), + (135.00, 2.74, 5.00), + ( 'inf', 4.42, 5.75), + ), + 'bi-weekly': ( + ( 29.00, 0.00, 1.00), + ( 86.50, 0.29, 2.00), + (144.00, 1.44, 3.00), + (202.00, 3.17, 4.00), + (269.00, 5.48, 5.00), + ( 'inf', 8.85, 5.75), + ), + 'semi-monthly': ( + ( 31.00, 0.00, 1.00), + ( 93.50, 0.31, 2.00), + (156.00, 1.56, 3.00), + (219.00, 3.34, 4.00), + (292.00, 5.94, 5.00), + ( 'inf', 9.58, 5.75), + ), + 'monthly': ( + ( 62.50, 0.00, 1.00), + (187.00, 0.62, 2.00), + (312.00, 3.12, 3.00), + (437.00, 6.87, 4.00), + (583.00, 11.87, 5.00), + ( 'inf', 19.17, 5.75), + ), + 'quarterly': ( + ( 187.50, 0.00, 1.00), + ( 562.50, 1.88, 2.00), + ( 937.50, 9.38, 3.00), + (1312.00, 20.63, 4.00), + (1750.00, 35.63, 5.00), + ( 'inf', 57.50, 5.75), + ), + 'semi-annual': ( + ( 375.00, 0.00, 1.00), + (1125.00, 3.75, 2.00), + (1875.00, 18.75, 3.00), + (2625.00, 41.25, 4.00), + (3500.00, 71.25, 5.00), + ( 'inf', 115.00, 5.75), + ), + 'annual': ( + ( 750.00, 0.00, 1.00), + (2250.00, 7.50, 2.00), + (3750.00, 37.50, 3.00), + (5250.00, 82.50, 4.00), + (7000.00, 142.50, 5.00), + ( 'inf', 230.00, 5.75), + ), + }, + 'head of household': { + 'weekly': ( + ( 19.00, 0.00, 1.00), + ( 57.50, 0.19, 2.00), + ( 96.00, 0.96, 3.00), + (135.00, 2.12, 4.00), + (192.50, 3.65, 5.00), + ( 'inf', 6.54, 5.75), + ), + 'bi-weekly': ( + ( 38.50, 0.00, 1.00), + (115.00, 0.38, 2.00), + (192.00, 1.92, 3.00), + (269.00, 4.23, 4.00), + (385.00, 7.31, 5.00), + ( 'inf', 13.08, 5.75), + ), + 'semi-monthly': ( + ( 41.50, 0.00, 1.00), + (125.00, 0.42, 2.00), + (208.00, 2.08, 3.00), + (292.00, 4.58, 4.00), + (417.00, 7.92, 5.00), + ( 'inf', 14.17, 5.75), + ), + 'monthly': ( + ( 83.00, 0.00, 1.00), + (250.00, 0.83, 2.00), + (417.00, 4.17, 3.00), + (583.00, 9.17, 4.00), + (833.00, 15.83, 5.00), + ( 'inf', 28.33, 5.75), + ), + 'quarterly': ( + ( 250.00, 0.00, 1.00), + ( 750.00, 2.50, 2.00), + (1250.00, 12.50, 3.00), + (1750.00, 27.50, 4.00), + (2500.00, 47.50, 5.00), + ( 'inf', 85.00, 5.75), + ), + 'semi-annual': ( + ( 500.00, 0.00, 1.00), + (1500.00, 5.00, 2.00), + (2500.00, 25.00, 3.00), + (3500.00, 55.00, 4.00), + (5000.00, 95.00, 5.00), + ( 'inf', 170.00, 5.75), + ), + 'annual': ( + ( 1000.00, 0.00, 1.00), + ( 3000.00, 10.00, 2.00), + ( 5000.00, 50.00, 3.00), + ( 7000.00, 110.00, 4.00), + (10000.00, 190.00, 5.00), + ( 'inf', 340.00, 5.75), + ), + }, + 'married filing separate': { + 'weekly': ( + ( 9.50, 0.00, 1.00), + (29.00, 0.10, 2.00), + (48.00, 0.48, 3.00), + (67.50, 1.06, 4.00), + (96.00, 1.83, 5.00), + ('inf', 3.27, 5.75), + ), + 'bi-weekly': ( + ( 19.00, 0.00, 1.00), + ( 57.50, 0.19, 2.00), + ( 96.00, 0.96, 3.00), + (135.00, 2.12, 4.00), + (192.00, 3.65, 5.00), + ( 'inf', 6.54, 5.75), + ), + 'semi-monthly': ( + ( 21.00, 0.00, 1.00), + ( 62.50, 0.21, 2.00), + (104.00, 1.04, 3.00), + (146.00, 2.29, 4.00), + (208.00, 3.96, 5.00), + ( 'inf', 7.08, 5.75), + ), + 'monthly': ( + ( 41.50, 0.00, 1.00), + (125.50, 0.42, 2.00), + (208.00, 2.08, 3.00), + (292.00, 4.58, 4.00), + (417.00, 7.92, 5.00), + ( 'inf', 14.17, 5.75), + ), + 'quarterly': ( + ( 125.00, 0.00, 1.00), + ( 375.00, 1.25, 2.00), + ( 625.00, 6.25, 3.00), + ( 875.00, 13.75, 4.00), + (1250.00, 23.75, 5.00), + ( 'inf', 42.50, 5.75), + ), + 'semi-annual': ( + ( 250.00, 0.00, 1.00), + ( 750.00, 2.50, 2.00), + (1250.00, 12.50, 3.00), + (1750.00, 27.50, 4.00), + (2500.00, 47.50, 5.00), + ( 'inf', 85.00, 5.75), + ), + 'annual': ( + ( 500.00, 0.00, 1.00), + (1500.00, 5.00, 2.00), + (2500.00, 25.00, 3.00), + (3500.00, 55.00, 4.00), + (5000.00, 95.00, 5.00), + ( 'inf', 170.00, 5.75), + ), + }, + } + + @@ -140,6 +684,60 @@ } + + + + US GA Georgia SIT Personal Allowance + us_ga_sit_personal_allowance + { + 'married filing joint, both spouses working': { + 'weekly': 142.30, + 'bi-weekly': 284.62, + 'semi-monthly': 308.33, + 'monthly': 616.67, + 'quarterly': 1850.00, + 'semi-annual': 3700.00, + 'annual': 7400.00, + }, + 'married filing joint, one spouse working': { + 'weekly': 142.30, + 'bi-weekly': 284.62, + 'semi-monthly': 308.33, + 'monthly': 616.67, + 'quarterly': 1850.00, + 'semi-annual': 3700.00, + 'annual': 7400.00, + }, + 'single': { + 'weekly': 51.92, + 'bi-weekly': 103.85, + 'semi-monthly': 112.50, + 'monthly': 225.00, + 'quarterly': 675.00, + 'semi-annual': 1350.00, + 'annual': 2700.00, + }, + 'head of household': { + 'weekly': 51.92, + 'bi-weekly': 103.85, + 'semi-monthly': 112.50, + 'monthly': 225.00, + 'quarterly': 675.00, + 'semi-annual': 1350.00, + 'annual': 2700.00, + }, + 'married filing separate': { + 'weekly': 71.15, + 'bi-weekly': 142.30, + 'semi-monthly': 154.16, + 'monthly': 308.33, + 'quarterly': 925.00, + 'semi-annual': 1850.00, + 'annual': 3700.00, + }, + } + + @@ -157,6 +755,22 @@ } + + + + US GA Georgia SIT Dependent Allowance Rate + us_ga_sit_dependent_allowance_rate + { + 'weekly': 57.50, + 'bi-weekly': 115.00, + 'semi-monthly': 125.00, + 'monthly': 250.00, + 'quarterly': 750.00, + 'semi-annual': 1500.00, + 'annual': 3000.00, + } + + @@ -212,11 +826,66 @@ } + + + + US GA Georgia SIT Deduction + us_ga_sit_deduction + { + 'married filing joint, both spouses working': { + 'weekly': 115.50, + 'bi-weekly': 230.75, + 'semi-monthly': 250.00, + 'monthly': 500.00, + 'quarterly': 1500.00, + 'semi-annual': 3000.00, + 'annual': 6000.00, + }, + 'married filing joint, one spouse working': { + 'weekly': 115.50, + 'bi-weekly': 230.75, + 'semi-monthly': 250.00, + 'monthly': 500.00, + 'quarterly': 1500.00, + 'semi-annual': 3000.00, + 'annual': 6000.00, + }, + 'single': { + 'weekly': 88.50, + 'bi-weekly': 177.00, + 'semi-monthly': 191.75, + 'monthly': 383.50, + 'quarterly': 1150.00, + 'semi-annual': 2300.00, + 'annual': 4600.00, + }, + 'head of household': { + 'weekly': 88.50, + 'bi-weekly': 177.00, + 'semi-monthly': 191.75, + 'monthly': 383.50, + 'quarterly': 1150.00, + 'semi-annual': 2300.00, + 'annual': 4600.00, + }, + 'married filing separate': { + 'weekly': 57.75, + 'bi-weekly': 115.50, + 'semi-monthly': 125.00, + 'monthly': 250.00, + 'quarterly': 750.00, + 'semi-annual': 1500.00, + 'annual': 3000.00, + }, + } + + US Georgia - Department of Taxation - Unemployment Tax + 1 @@ -226,6 +895,7 @@ US Georgia - Department of Taxation - Income Tax + 1 diff --git a/l10n_us_hr_payroll/data/state/hi_hawaii.xml b/l10n_us_hr_payroll/data/state/hi_hawaii.xml new file mode 100644 index 00000000..e4c07ab2 --- /dev/null +++ b/l10n_us_hr_payroll/data/state/hi_hawaii.xml @@ -0,0 +1,177 @@ + + + + + + US HI Hawaii SUTA Wage Base + us_hi_suta_wage_base + 46800.0 + + + + US HI Hawaii SUTA Wage Base + us_hi_suta_wage_base + 48100.0 + + + + + + + + US HI Hawaii SUTA Rate + us_hi_suta_rate + 2.40 + + + + US HI Hawaii SUTA Rate + us_hi_suta_rate + 2.40 + + + + + + + US HI Hawaii SIT Tax Rate + us_hi_sit_tax_rate + { + 'single': ( + ( 2400, 0.00, 1.40), + ( 4800, 34.00, 3.20), + ( 9600, 110.00, 5.50), + (14400, 374.00, 6.40), + (19200, 682.00, 6.80), + (24000, 1008.00, 7.20), + (36000, 1354.00, 7.60), + ('inf', 2266.00, 7.90), + ), + 'married': ( + ( 4800, 0.00, 1.40), + ( 9600, 67.00, 3.20), + (19200, 221.00, 5.50), + (28800, 749.00, 6.40), + (38400, 1363.00, 6.80), + (48000, 2016.00, 7.20), + (72000, 2707.00, 7.60), + ('inf', 4531.00, 7.90), + ), + 'head_of_household': ( + ( 2400, 0.00, 1.40), + ( 4800, 34.00, 3.20), + ( 9600, 110.00, 5.50), + (14400, 374.00, 6.40), + (19200, 682.00, 6.80), + (24000, 1008.00, 7.20), + (36000, 1354.00, 7.60), + ('inf', 2266.00, 7.90), + ), + } + + + + + + US HI Hawaii SIT Tax Rate + us_hi_sit_tax_rate + { + 'single': ( + ( 2400, 0.00, 1.40), + ( 4800, 34.00, 3.20), + ( 9600, 110.00, 5.50), + (14400, 374.00, 6.40), + (19200, 682.00, 6.80), + (24000, 1008.00, 7.20), + (36000, 1354.00, 7.60), + ('inf', 2266.00, 7.90), + ), + 'married': ( + ( 4800, 0.00, 1.40), + ( 9600, 67.00, 3.20), + (19200, 221.00, 5.50), + (28800, 749.00, 6.40), + (38400, 1363.00, 6.80), + (48000, 2016.00, 7.20), + (72000, 2707.00, 7.60), + ('inf', 4531.00, 7.90), + ), + 'head_of_household': ( + ( 2400, 0.00, 1.40), + ( 4800, 34.00, 3.20), + ( 9600, 110.00, 5.50), + (14400, 374.00, 6.40), + (19200, 682.00, 6.80), + (24000, 1008.00, 7.20), + (36000, 1354.00, 7.60), + ('inf', 2266.00, 7.90), + ), + } + + + + + + + US HI Hawaii Personal Exemption Rate + us_hi_sit_personal_exemption_rate + 1144 + + + + US HI Hawaii Personal Exemption Rate + us_hi_sit_personal_exemption_rate + 1144 + + + + + + + US Hawaii - Department of Labor and Industrial Relations - Unemployment Tax + 1 + + + US Hawaii - Department of Labor and Industrial Relations - Unemployment Tax + + + + + US Hawaii - Department of Taxation - Income Tax + 1 + + + US Hawaii - Department of Taxation - Income Tax + + + + + + + + + + ER: US HI Hawaii State Unemployment + ER_US_HI_SUTA + python + result, _ = general_state_unemployment(payslip, categories, worked_days, inputs, wage_base='us_hi_suta_wage_base', rate='us_hi_suta_rate', state_code='HI') + code + result, result_rate = general_state_unemployment(payslip, categories, worked_days, inputs, wage_base='us_hi_suta_wage_base', rate='us_hi_suta_rate', state_code='HI') + + + + + + + + EE: US HI Hawaii State Income Tax Withholding + EE_US_HI_SIT + python + result, _ = hi_hawaii_state_income_withholding(payslip, categories, worked_days, inputs) + code + result, result_rate = hi_hawaii_state_income_withholding(payslip, categories, worked_days, inputs) + + + + + \ No newline at end of file diff --git a/l10n_us_hr_payroll/data/state/ia_iowa.xml b/l10n_us_hr_payroll/data/state/ia_iowa.xml new file mode 100644 index 00000000..89e9e036 --- /dev/null +++ b/l10n_us_hr_payroll/data/state/ia_iowa.xml @@ -0,0 +1,297 @@ + + + + + + US IA Iowa SUTA Wage Base + us_ia_suta_wage_base + 30600.0 + + + + US IA Iowa SUTA Wage Base + us_ia_suta_wage_base + 31600.0 + + + + + + + + US IA Iowa SUTA Rate + us_ia_suta_rate + 1.0 + + + + US IA Iowa SUTA Rate + us_ia_suta_rate + 1.0 + + + + + + + US IA Iowa SIT Tax Rate + us_ia_sit_tax_rate + { + 'daily': ( + ( 5.13, 0.0033, 0.00), + ( 10.25, 0.0067, 0.02), + ( 20.50, 0.0225, 0.05), + ( 46.13, 0.0414, 0.28), + ( 76.89, 0.0563, 1.34), + (102.52, 0.0596, 3.07), + (153.78, 0.0625, 4.60), + (230.68, 0.0744, 7.80), + ( 'inf', 0.0853, 13.52), + ), + 'weekly': ( + ( 25.63, 0.0033, 0.00), + ( 51.27, 0.0067, 0.08), + ( 102.52, 0.0225, 0.25), + ( 230.67, 0.0414, 1.40), + ( 384.46, 0.0563, 6.71), + ( 512.62, 0.0596, 15.37), + ( 768.92, 0.0625, 23.01), + (1153.38, 0.0744, 39.03), + ( 'inf', 0.0853, 67.63), + ), + 'bi-weekly': ( + ( 51.27, 0.0033, 0.00), + ( 102.54, 0.0067, 0.17), + ( 205.04, 0.0225, 0.51), + ( 461.35, 0.0414, 2.82), + ( 768.92, 0.0563, 13.43), + (1025.23, 0.0596, 30.75), + (1537.85, 0.0625, 46.03), + (2306.77, 0.0744, 78.07), + ( 'inf', 0.0853, 135.28), + ), + 'semi-monthly': ( + ( 55.54, 0.0033, 0.00), + ( 111.08, 0.0067, 0.18), + ( 222.13, 0.0225, 0.55), + ( 499.79, 0.0414, 3.05), + ( 833.00, 0.0563, 14.59), + (1110.67, 0.0596, 33.31), + (1666.00, 0.0625, 49.86), + (2499.00, 0.0744, 84.57), + ( 'inf', 0.0853, 146.55), + ), + 'monthly': ( + ( 111.08, 0.0033, 0.00), + ( 222.17, 0.0067, 0.37), + ( 444.25, 0.0225, 1.11), + ( 999.58, 0.0414, 6.11), + (1666.00, 0.0563, 29.10), + (2221.33, 0.0596, 62.66), + (3332.00, 0.0625, 99.72), + (4998.00, 0.0744, 169.14), + ( 'inf', 0.0853, 293.09), + ), + 'annual': ( + ( 1333.00, 0.0033, 0.00), + ( 2666.00, 0.0067, 4.40), + ( 5331.00, 0.0225, 13.33), + (11995.00, 0.0414, 73.29), + (19992.00, 0.0563, 349.19), + (26656.00, 0.0596, 799.41), + (39984.00, 0.0625, 1196.58), + (59976.00, 0.0744, 2029.58), + ( 'inf', 0.0853, 3516.98), + ), + } + + + + + + + US IA Iowa SIT Tax Rate + us_ia_sit_tax_rate + { + 'daily': ( + ( 5.69, 0.0033, 0.00), + ( 11.38, 0.0067, 0.02), + ( 22.76, 0.0225, 0.06), + ( 51.22, 0.0414, 0.32), + ( 85.36, 0.0563, 1.50), + (113.81, 0.0596, 3.42), + (170.71, 0.0625, 5.12), + (256.07, 0.0744, 8.68), + ( 'inf', 0.0853, 15.03), + ), + 'weekly': ( + ( 28.46, 0.0033, 0.00), + ( 56.90, 0.0067, 0.09), + ( 113.81, 0.0225, 0.28), + ( 256.08, 0.0414, 1.56), + ( 426.79, 0.0563, 7.45), + ( 569.04, 0.0596, 17.06), + ( 853.56, 0.0625, 25.54), + (1280.35, 0.0744, 43.32), + ( 'inf', 0.0853, 75.07), + ), + 'bi-weekly': ( + ( 56.92, 0.0033, 0.00), + ( 113.81, 0.0067, 0.19), + ( 227.62, 0.0225, 0.57), + ( 512.15, 0.0414, 3.13), + ( 853.58, 0.0563, 14.91), + (1138.08, 0.0596, 34.13), + (1707.12, 0.0625, 51.09), + (2560.69, 0.0744, 86.66), + ( 'inf', 0.0853, 150.17), + ), + 'semi-monthly': ( + ( 61.67, 0.0033, 0.00), + ( 23.29, 0.0067, 0.20), + ( 246.58, 0.0225, 0.61), + ( 554.83, 0.0414, 3.38), + ( 924.71, 0.0563, 16.14), + (1232.92, 0.0596, 36.96), + (1849.38, 0.0625, 55.33), + (2774.08, 0.0744, 93.86), + ( 'inf', 0.0853, 162.66), + ), + 'monthly': ( + ( 123.33, 0.0033, 0.00), + ( 246.58, 0.0067, 0.41), + ( 493.17, 0.0225, 1.24), + (1109.67, 0.0414, 6.79), + (1849.42, 0.0563, 32.31), + (2465.83, 0.0596, 73.96), + (3698.75, 0.0625, 110.70), + (5548.17, 0.0744, 187.76), + ( 'inf', 0.0853, 325.36), + ), + 'annual': ( + ( 1480.00, 0.0033, 0.00), + ( 2959.00, 0.0067, 4.88), + ( 5918.00, 0.0225, 14.79), + (13316.00, 0.0414, 81.37), + (22193.00, 0.0563, 387.65), + (29590.00, 0.0596, 887.43), + (44385.00, 0.0625, 1328.29), + (66578.00, 0.0744, 2252.98), + ( 'inf', 0.0853, 3904.14), + ), + } + + + + + + + US IA Iowa Standard Deduction Rate + us_ia_sit_standard_deduction_rate + { + 'daily': ( 6.50, 16.00), + 'weekly': ( 32.50, 80.00), + 'bi-weekly': ( 65.00, 160.00), + 'semi-monthly': ( 70.42, 173.33), + 'monthly': ( 140.83, 346.67), + 'annually': (1690.00, 4160.00), + } + + + + + + US IA Iowa Standard Deduction Rate + us_ia_sit_standard_deduction_rate + { + 'daily': ( 7.23, 17.81), + 'weekly': ( 36.15, 89.04), + 'bi-weekly': ( 72.31, 178.08), + 'semi-monthly': ( 78.33, 192.92), + 'monthly': ( 156.67, 385.83), + 'annually': (1880.00, 4630.00), + } + + + + + + + US IA Iowa Deduction Allowance Rate + us_ia_sit_deduction_allowance_rate + { + 'daily': 0.15, + 'weekly': 0.77, + 'bi-weekly': 1.54, + 'semi-monthly': 1.67, + 'monthly': 3.33, + 'annually': 40.00, + } + + + + + + US IA Iowa Deduction Allowance Rate + us_ia_sit_deduction_allowance_rate + { + 'daily': 0.15, + 'weekly': 0.77, + 'bi-weekly': 1.54, + 'semi-monthly': 1.67, + 'monthly': 3.33, + 'annually': 40.00, + } + + + + + + + US Iowa - Workforce Development - Unemployment Tax + 1 + + + US Iowa - Workforce Development - Unemployment Tax + + + + + US Iowa - Department of Revenue - Income Tax + 1 + + + US Iowa - Department of Revenue - Income Tax + + + + + + + + + + ER: US IA Iowa State Unemployment + ER_US_IA_SUTA + python + result, _ = general_state_unemployment(payslip, categories, worked_days, inputs, wage_base='us_ia_suta_wage_base', rate='us_ia_suta_rate', state_code='IA') + code + result, result_rate = general_state_unemployment(payslip, categories, worked_days, inputs, wage_base='us_ia_suta_wage_base', rate='us_ia_suta_rate', state_code='IA') + + + + + + + + EE: US IA Iowa State Income Tax Withholding + EE_US_IA_SIT + python + result, _ = ia_iowa_state_income_withholding(payslip, categories, worked_days, inputs) + code + result, result_rate = ia_iowa_state_income_withholding(payslip, categories, worked_days, inputs) + + + + + \ No newline at end of file diff --git a/l10n_us_hr_payroll/data/state/id_idaho.xml b/l10n_us_hr_payroll/data/state/id_idaho.xml new file mode 100644 index 00000000..7331326e --- /dev/null +++ b/l10n_us_hr_payroll/data/state/id_idaho.xml @@ -0,0 +1,444 @@ + + + + + + US ID Idaho SUTA Wage Base + us_id_suta_wage_base + 40000.0 + + + + US ID Idaho SUTA Wage Base + us_id_suta_wage_base + 41600.0 + + + + + + + + US ID Idaho SUTA Rate + us_id_suta_rate + 1.0 + + + + US ID Idaho SUTA Rate + us_id_suta_rate + 1.0 + + + + + + + US ID Idaho SIT Tax Rate + us_id_sit_tax_rate + { + 'single': { + 'weekly': ( + ( 235, 0.00, 0.000), + ( 264, 0.00, 1.125), + ( 294, 0.00, 3.125), + ( 324, 1.00, 3.625), + ( 353, 2.00, 4.625), + ( 383, 4.00, 5.625), + ( 457, 5.00, 6.625), + ('inf', 10.00, 6.925), + ), + 'bi-weekly': ( + ( 469, 0.00, 0.000), + ( 529, 0.00, 1.125), + ( 588, 1.00, 3.125), + ( 647, 3.00, 3.625), + ( 706, 5.00, 4.625), + ( 766, 7.00, 5.625), + ( 914, 11.00, 6.625), + ('inf', 21.00, 6.925), + ), + 'semi-monthly': ( + ( 508, 0.00, 0.000), + ( 573, 0.00, 1.125), + ( 637, 1.00, 3.125), + ( 701, 3.00, 3.625), + ( 765, 5.00, 4.625), + ( 829, 8.00, 5.625), + ( 990, 12.00, 6.625), + ('inf', 22.00, 6.925), + ), + 'monthly': ( + ( 1017, 0.00, 0.000), + ( 1145, 0.00, 1.125), + ( 1273, 1.00, 3.125), + ( 1402, 5.00, 3.625), + ( 1530, 10.00, 4.625), + ( 1659, 16.00, 5.625), + ( 1980, 23.00, 6.625), + ('inf', 45.00, 6.925), + ), + 'annually': ( + (12200, 0.00, 0.000), + (13741, 0.00, 1.125), + (15281, 17.00, 3.125), + (16822, 65.00, 3.625), + (18362, 121.00, 4.625), + (19903, 192.00, 5.625), + (23754, 279.00, 6.625), + ('inf', 534.00, 6.925), + ), + }, + 'married': { + 'weekly': ( + ( 469, 0.00, 0.000), + ( 529, 0.00, 1.125), + ( 588, 0.00, 3.125), + ( 647, 1.00, 3.625), + ( 706, 2.00, 4.625), + ( 766, 4.00, 5.625), + ( 914, 5.00, 6.625), + ('inf', 10.00, 6.925), + ), + 'bi-weekly': ( + ( 938, 0.00, 0.000), + ( 1057, 0.00, 1.125), + ( 1175, 1.00, 3.125), + ( 1294, 5.00, 3.625), + ( 1412, 9.00, 4.625), + ( 1531, 15.00, 5.625), + ( 1827, 21.00, 6.625), + ('inf', 41.00, 6.925), + ), + 'semi-monthly': ( + ( 1017, 0.00, 0.000), + ( 1145, 0.00, 1.125), + ( 1273, 1.00, 3.125), + ( 1402, 5.00, 3.625), + ( 1530, 10.00, 4.625), + ( 1659, 16.00, 5.625), + ( 1980, 23.00, 6.625), + ('inf', 45.00, 6.925), + ), + 'monthly': ( + ( 2033, 0.00, 0.000), + ( 2290, 0.00, 1.125), + ( 2547, 3.00, 3.125), + ( 2804, 11.00, 3.625), + ( 3060, 20.00, 4.625), + ( 3317, 32.00, 5.625), + ( 3959, 47.00, 6.625), + ('inf', 89.00, 6.925), + ), + 'annually': ( + (24400, 0.00, 0.000), + (27482, 0.00, 1.125), + (30562, 35.00, 3.125), + (33644, 131.00, 3.625), + (36724, 243.00, 4.625), + (39806, 385.00, 5.625), + (47508, 558.00, 6.625), + ('inf', 1068.00, 6.925), + ), + }, + 'head of household': { + 'weekly': ( + ( 235, 0.00, 0.000), + ( 264, 0.00, 1.125), + ( 294, 0.00, 3.125), + ( 324, 1.00, 3.625), + ( 353, 2.00, 4.625), + ( 383, 4.00, 5.625), + ( 457, 5.00, 6.625), + ('inf', 10.00, 6.925), + ), + 'bi-weekly': ( + ( 469, 0.00, 0.000), + ( 529, 0.00, 1.125), + ( 588, 1.00, 3.125), + ( 647, 3.00, 3.625), + ( 706, 5.00, 4.625), + ( 766, 7.00, 5.625), + ( 914, 11.00, 6.625), + ('inf', 21.00, 6.925), + ), + 'semi-monthly': ( + ( 508, 0.00, 0.000), + ( 573, 0.00, 1.125), + ( 637, 1.00, 3.125), + ( 701, 3.00, 3.625), + ( 765, 5.00, 4.625), + ( 829, 8.00, 5.625), + ( 990, 12.00, 6.625), + ('inf', 22.00, 6.925), + ), + 'monthly': ( + ( 1017, 0.00, 0.000), + ( 1145, 0.00, 1.125), + ( 1273, 1.00, 3.125), + ( 1402, 5.00, 3.625), + ( 1530, 10.00, 4.625), + ( 1659, 16.00, 5.625), + ( 1980, 23.00, 6.625), + ('inf', 45.00, 6.925), + ), + 'annually': ( + (12200, 0.00, 0.000), + (13741, 0.00, 1.125), + (15281, 17.00, 3.125), + (16822, 65.00, 3.625), + (18362, 121.00, 4.625), + (19903, 192.00, 5.625), + (23754, 279.00, 6.625), + ('inf', 534.00, 6.925), + ), + }, + } + + + + + + US ID Idaho SIT Tax Rate + us_id_sit_tax_rate + { + 'single': { + 'weekly': ( + ( 238, 0.00, 0.000), + ( 269, 0.00, 1.125), + ( 299, 0.00, 3.125), + ( 329, 1.00, 3.625), + ( 359, 2.00, 4.625), + ( 389, 4.00, 5.625), + ( 465, 5.00, 6.625), + ('inf', 10.00, 6.925), + ), + 'bi-weekly': ( + ( 477, 0.00, 0.000), + ( 537, 0.00, 1.125), + ( 598, 1.00, 3.125), + ( 658, 3.00, 3.625), + ( 718, 5.00, 4.625), + ( 778, 8.00, 5.625), + ( 929, 11.00, 6.625), + ('inf', 21.00, 6.925), + ), + 'semi-monthly': ( + ( 517, 0.00, 0.000), + ( 582, 0.00, 1.125), + ( 647, 1.00, 3.125), + ( 713, 3.00, 3.625), + ( 778, 5.00, 4.625), + ( 843, 8.00, 5.625), + ( 1007, 12.00, 6.625), + ('inf', 23.00, 6.925), + ), + 'monthly': ( + ( 1033, 0.00, 0.000), + ( 1164, 0.00, 1.125), + ( 1295, 1.00, 3.125), + ( 1425, 6.00, 3.625), + ( 1556, 10.00, 4.625), + ( 1687, 16.00, 5.625), + ( 2013, 24.00, 6.625), + ('inf', 45.00, 6.925), + ), + 'annually': ( + (12400, 0.00, 0.000), + (13968, 0.00, 1.125), + (15536, 18.00, 3.125), + (17104, 67.00, 3.625), + (18672, 124.00, 4.625), + (20240, 197.00, 5.625), + (24160, 285.00, 6.625), + ('inf', 545.00, 6.925), + ), + }, + 'married': { + 'weekly': ( + ( 477, 0.00, 0.000), + ( 537, 0.00, 1.125), + ( 598, 0.00, 3.125), + ( 658, 1.00, 3.625), + ( 718, 3.00, 4.625), + ( 778, 5.00, 5.625), + ( 929, 11.00, 6.625), + ('inf', 21.00, 6.925), + ), + 'bi-weekly': ( + ( 954, 0.00, 0.000), + ( 1074, 0.00, 1.125), + ( 1195, 1.00, 3.125), + ( 1316, 5.00, 3.625), + ( 1436, 9.00, 4.625), + ( 1557, 15.00, 5.625), + ( 1858, 22.00, 6.625), + ('inf', 42.00, 6.925), + ), + 'semi-monthly': ( + ( 1033, 0.00, 0.000), + ( 1164, 0.00, 1.125), + ( 1295, 1.00, 3.125), + ( 1425, 6.00, 3.625), + ( 1556, 10.00, 4.625), + ( 1687, 16.00, 5.625), + ( 2013, 24.00, 6.625), + ('inf', 45.00, 6.925), + ), + 'monthly': ( + ( 2067, 0.00, 0.000), + ( 2328, 0.00, 1.125), + ( 2589, 3.00, 3.125), + ( 2851, 11.00, 3.625), + ( 3112, 21.00, 4.625), + ( 3373, 33.00, 5.625), + ( 4027, 47.00, 6.625), + ('inf', 91.00, 6.925), + ), + 'annually': ( + (24400, 0.00, 0.000), + (27482, 0.00, 1.125), + (30562, 35.00, 3.125), + (33644, 131.00, 3.625), + (36724, 243.00, 4.625), + (39806, 385.00, 5.625), + (47508, 558.00, 6.625), + ('inf', 1068.00, 6.925), + ), + }, + 'head of household': { + 'weekly': ( + ( 238, 0.00, 0.000), + ( 269, 0.00, 1.125), + ( 299, 0.00, 3.125), + ( 329, 1.00, 3.625), + ( 359, 2.00, 4.625), + ( 389, 4.00, 5.625), + ( 465, 5.00, 6.625), + ('inf', 10.00, 6.925), + ), + 'bi-weekly': ( + ( 477, 0.00, 0.000), + ( 537, 0.00, 1.125), + ( 598, 1.00, 3.125), + ( 658, 3.00, 3.625), + ( 718, 5.00, 4.625), + ( 778, 8.00, 5.625), + ( 929, 11.00, 6.625), + ('inf', 21.00, 6.925), + ), + 'semi-monthly': ( + ( 517, 0.00, 0.000), + ( 582, 0.00, 1.125), + ( 647, 1.00, 3.125), + ( 713, 3.00, 3.625), + ( 778, 5.00, 4.625), + ( 843, 8.00, 5.625), + ( 1007, 12.00, 6.625), + ('inf', 23.00, 6.925), + ), + 'monthly': ( + ( 1033, 0.00, 0.000), + ( 1164, 0.00, 1.125), + ( 1295, 1.00, 3.125), + ( 1425, 6.00, 3.625), + ( 1556, 10.00, 4.625), + ( 1687, 16.00, 5.625), + ( 2013, 24.00, 6.625), + ('inf', 45.00, 6.925), + ), + 'annually': ( + (12400, 0.00, 0.000), + (13968, 0.00, 1.125), + (15536, 18.00, 3.125), + (17104, 67.00, 3.625), + (18672, 124.00, 4.625), + (20240, 197.00, 5.625), + (24160, 285.00, 6.625), + ('inf', 545.00, 6.925), + ), + }, + } + + + + + + + US ID Idaho Child Tax Credit Allowance Rate + us_id_sit_ictcat_rate + { + 'weekly': 56.92, + 'bi-weekly': 113.85, + 'semi-monthly': 123.33, + 'monthly': 246.67, + 'annually': 2960.00, + } + + + + + + US ID Idaho Child Tax Credit Allowance Rate + us_id_sit_ictcat_rate + { + 'weekly': 56.92, + 'bi-weekly': 113.85, + 'semi-monthly': 123.33, + 'monthly': 246.67, + 'annually': 2960.00, + } + + + + + + + + US Idaho - Department of Labor (IDOL) - Unemployment Tax + 1 + + + US Idaho - Department of Labor (IDOL) - Unemployment Tax + + + + + US Idaho - State Tax Commission (ISTC) - Income Tax + 1 + + + US Idaho - State Tax Commission (ISTC) - Income Tax + + + + + + + + + + ER: US ID Idaho State Unemployment + ER_US_ID_SUTA + python + result, _ = general_state_unemployment(payslip, categories, worked_days, inputs, wage_base='us_id_suta_wage_base', rate='us_id_suta_rate', state_code='ID') + code + result, result_rate = general_state_unemployment(payslip, categories, worked_days, inputs, wage_base='us_id_suta_wage_base', rate='us_id_suta_rate', state_code='ID') + + + + + + + + EE: US ID Idaho State Income Tax Withholding + EE_US_ID_SIT + python + result, _ = id_idaho_state_income_withholding(payslip, categories, worked_days, inputs) + code + result, result_rate = id_idaho_state_income_withholding(payslip, categories, worked_days, inputs) + + + + + \ No newline at end of file diff --git a/l10n_us_hr_payroll/data/state/il_illinois.xml b/l10n_us_hr_payroll/data/state/il_illinois.xml new file mode 100644 index 00000000..2dbcac77 --- /dev/null +++ b/l10n_us_hr_payroll/data/state/il_illinois.xml @@ -0,0 +1,113 @@ + + + + + + US IL Illinois SUTA Wage Base + us_il_suta_wage_base + 12960.0 + + + + US IL Illinois SUTA Wage Base + us_il_suta_wage_base + 12740.0 + + + + + + + + US IL Illinois SUTA Rate + us_il_suta_rate + 3.175 + + + + US IL Illinois SUTA Rate + us_il_suta_rate + 3.125 + + + + + + + US IL Illinois Basic Allowances Rate + us_il_sit_basic_allowances_rate + 2275.0 + + + + US IL Illinois Basic Allowances Rate + us_il_sit_basic_allowances_rate + 2325.0 + + + + + + + US IL Illinois Additional Allowances Rate + us_il_sit_additional_allowances_rate + 1000.0 + + + + US IL Illinois Additional Allowances Rate + us_il_sit_additional_allowances_rate + 1000.0 + + + + + + + US Illinois - Department of Economic Security (IDES) - Unemployment Tax + 1 + + + US Illinois - Department of Economic Security (IDES) - Unemployment Tax + + + + + US Illinois - Department of Revenue (IDOR) - Income Tax + 1 + + + US Illinois - Department of Revenue (IDOR) - Income Tax + + + + + + + + + + ER: US IL Illinois State Unemployment + ER_US_IL_SUTA + python + result, _ = general_state_unemployment(payslip, categories, worked_days, inputs, wage_base='us_il_suta_wage_base', rate='us_il_suta_rate', state_code='IL') + code + result, result_rate = general_state_unemployment(payslip, categories, worked_days, inputs, wage_base='us_il_suta_wage_base', rate='us_il_suta_rate', state_code='IL') + + + + + + + + EE: US IL Illinois State Income Tax Withholding + EE_US_IL_SIT + python + result, _ = il_illinois_state_income_withholding(payslip, categories, worked_days, inputs) + code + result, result_rate = il_illinois_state_income_withholding(payslip, categories, worked_days, inputs) + + + + + \ No newline at end of file diff --git a/l10n_us_hr_payroll/data/state/in_indiana.xml b/l10n_us_hr_payroll/data/state/in_indiana.xml new file mode 100644 index 00000000..8a860e13 --- /dev/null +++ b/l10n_us_hr_payroll/data/state/in_indiana.xml @@ -0,0 +1,110 @@ + + + + + + US IN Indiana SUTA Wage Base + us_in_suta_wage_base + 9500.00 + + + + + + + + US IN Indiana SUTA Rate + us_in_suta_rate + 2.5 + + + + + + + US IN Indiana SUTA Income Rate + us_in_suta_income_rate + 3.23 + + + + + + + US IN Indiana SIT Personal Exemption Rate + us_in_sit_personal_exemption_rate + { + 'daily': ( 2.74, 5.48, 8.22, 10.96, 13.70, 16.44), + 'weekly': ( 19.23, 38.46, 57.69, 76.92, 96.15, 115.38), + 'bi-weekly': ( 38.46, 76.92, 115.38, 153.85, 192.31, 230.77), + 'semi-monthly': ( 41.67, 83.33, 125.00, 166.67, 208.33, 250.00), + 'monthly': ( 83.33, 166.67, 250.00, 333.33, 416.67, 500.00), + } + + + + + + + US IN Indiana SIT Dependent Exemption Rate + us_in_sit_dependent_exemption_rate + { + 'daily': ( 4.11, 8.22, 12.33, 16.44, 20.55), + 'weekly': ( 28.85, 57.69, 86.54, 115.38, 144.23), + 'bi-weekly': ( 57.69, 115.38, 173.08, 230.77, 288.46), + 'semi-monthly': ( 62.50, 125.00, 187.50, 250.00, 312.50), + 'monthly': (125.00, 250.00, 375.00, 500.00, 625.00), + } + + + + + + + US Indiana - Department of Workforce Development - Unemployment Tax + 1 + + + US Indiana - Department of Workforce Development - Unemployment Tax + + + + + US Indiana - Department of Revenue - Income Tax + 1 + + + US Indiana - Department of Revenue - Income Tax + + + + + + + + + + ER: US IN Indiana State Unemployment + ER_US_IN_SUTA + python + result, _ = general_state_unemployment(payslip, categories, worked_days, inputs, wage_base='us_in_suta_wage_base', rate='us_in_suta_rate', state_code='IN') + code + result, result_rate = general_state_unemployment(payslip, categories, worked_days, inputs, wage_base='us_in_suta_wage_base', rate='us_in_suta_rate', state_code='IN') + + + + + + + + EE: US IN Indiana State Income Tax Withholding + EE_US_IN_SIT + python + result, _ = in_indiana_state_income_withholding(payslip, categories, worked_days, inputs) + code + result, result_rate = in_indiana_state_income_withholding(payslip, categories, worked_days, inputs) + + + + + diff --git a/l10n_us_hr_payroll/data/state/ks_kansas.xml b/l10n_us_hr_payroll/data/state/ks_kansas.xml new file mode 100644 index 00000000..5ad8de4c --- /dev/null +++ b/l10n_us_hr_payroll/data/state/ks_kansas.xml @@ -0,0 +1,186 @@ + + + + + + US KS Kansas SUTA Wage Base + us_ks_suta_wage_base + 14000.0 + + + + + + + + US KS Kansas SUTA Rate + us_ks_suta_rate + 2.7 + + + + + + + + US KS Kansas Allowances Rate + us_ks_sit_allowances_rate + { + 'weekly' : 43.27, + 'bi-weekly' : 86.54, + 'semi-monthly': 93.75, + 'monthly' : 187.50, + 'quarterly' : 562.50, + 'semi-annual': 1125.00, + 'annually': 2250.00, + } + + + + + + + + US KS Kansas SIT Tax Rate + us_ks_sit_tax_rate + { + 'single': { + 'weekly': ( + ( 58, 0.00, 0.00), + ( 346, 3.10, 0.00), + ( 635, 5.25, 8.94), + ('inf', 5.70, 24.09), + ), + 'bi-weekly': ( + ( 115, 0.00, 0.00), + ( 692, 3.10, 0.00), + ( 1269, 5.25, 17.88), + ('inf', 5.70, 48.17), + ), + 'semi-monthly': ( + ( 125, 0.00, 0.00), + ( 750, 3.10, 0.00), + ( 1375, 5.25, 19.38), + ('inf', 5.70, 52.19), + ), + 'monthly': ( + ( 250, 0.00, 0.00), + ( 1500, 3.10, 0.00), + ( 2750, 5.25, 38.75), + ('inf', 5.70, 104.38), + ), + 'quarterly': ( + ( 750, 0.00, 0.00), + ( 4500, 3.10, 0.00), + (8250, 5.25, 116.25), + ('inf', 5.70, 313.13), + ), + 'semi-annual': ( + ( 1500, 0.00, 0.00), + ( 9000, 3.10, 0.00), + (16500, 5.25, 232.50), + ('inf', 5.70, 626.25), + ), + 'annually': ( + ( 3000, 0.00, 0.00), + (18000, 3.10, 0.00), + (33000, 5.25, 465.00), + ('inf', 5.70, 1252.50), + ), + }, + 'married': { + 'weekly': ( + ( 144, 0.00, 0.00), + ( 721, 3.10, 0.00), + (1298, 5.25, 17.88), + ('inf', 5.70, 48.17), + ), + 'bi-weekly': ( + ( 288, 0.00, 0.00), + ( 1442, 3.10, 0.00), + ( 2596, 5.25, 35.77), + ('inf', 5.70, 96.35), + ), + 'semi-monthly': ( + ( 313, 0.00, 0.00), + ( 1563, 3.10, 0.00), + ( 2813, 5.25, 38.75), + ('inf', 5.70, 104.38), + ), + 'monthly': ( + ( 625, 0.00, 0.00), + ( 3125, 3.10, 0.00), + ( 5625, 5.25, 77.50), + ('inf', 5.70, 208.75), + ), + 'quarterly': ( + ( 1875, 0.00, 0.00), + ( 9375, 3.10, 0.00), + (16875, 5.25, 232.50), + ('inf', 5.70, 626.25), + ), + 'semi-annual': ( + ( 3750, 0.00, 0.00), + (18750, 3.10, 0.00), + (33750, 5.25, 465.00), + ('inf', 5.70, 1252.50), + ), + 'annually': ( + ( 7500, 0.00, 0.00), + (37500, 3.10, 0.00), + (67500, 5.25, 930.00), + ('inf', 5.70, 2505.00), + ), + }, + } + + + + + + + US Kansas - Department of Labor - Unemployment Tax + 1 + + + US Kansas - Department of Labor - Unemployment Tax + + + + + US Kansas - Department of Revenue - Income Tax + 1 + + + US Kansas - Department of Revenue - Income Tax + + + + + + + + ER: US KS Kansas State Unemployment + ER_US_KS_SUTA + python + result, _ = general_state_unemployment(payslip, categories, worked_days, inputs, wage_base='us_ks_suta_wage_base', rate='us_ks_suta_rate', state_code='KS') + code + result, result_rate = general_state_unemployment(payslip, categories, worked_days, inputs, wage_base='us_ks_suta_wage_base', rate='us_ks_suta_rate', state_code='KS') + + + + + + + + EE: US KS Kansas State Income Tax Withholding + EE_US_KS_SIT + python + result, _ = ks_kansas_state_income_withholding(payslip, categories, worked_days, inputs) + code + result, result_rate = ks_kansas_state_income_withholding(payslip, categories, worked_days, inputs) + + + + + \ No newline at end of file diff --git a/l10n_us_hr_payroll/data/state/ky_kentucky.xml b/l10n_us_hr_payroll/data/state/ky_kentucky.xml new file mode 100644 index 00000000..53eb3190 --- /dev/null +++ b/l10n_us_hr_payroll/data/state/ky_kentucky.xml @@ -0,0 +1,91 @@ + + + + + + US KY Kentucky SUTA Wage Base + us_ky_suta_wage_base + 10800.0 + + + + + + + + US KY Kentucky SUTA Rate + us_ky_suta_rate + 2.7 + + + + + + + + US KY Kentucky Standard Deduction Rate + us_ky_sit_standard_deduction_rate + 2650 + + + + + + + + US KY Kentucky SIT Tax Rate + us_ky_sit_tax_rate + 5.0 + + + + + + + US Kentucky - Office of Unemployment Insurance - Unemployment Tax + 1 + + + US Kentucky - Office of Unemployment Insurance - Unemployment Tax + + + + + US Kentucky - Department of Revenue - Income Tax + 1 + + + US Kentucky - Department of Revenue - Income Tax + + + + + + + + + + ER: US KY Kentucky State Unemployment + ER_US_KY_SUTA + python + result, _ = general_state_unemployment(payslip, categories, worked_days, inputs, wage_base='us_ky_suta_wage_base', rate='us_ky_suta_rate', state_code='KY') + code + result, result_rate = general_state_unemployment(payslip, categories, worked_days, inputs, wage_base='us_ky_suta_wage_base', rate='us_ky_suta_rate', state_code='KY') + + + + + + + + EE: US KY Kentucky State Income Tax Withholding + EE_US_KY_SIT + python + result, _ = ky_kentucky_state_income_withholding(payslip, categories, worked_days, inputs) + code + result, result_rate = ky_kentucky_state_income_withholding(payslip, categories, worked_days, inputs) + + + + + \ No newline at end of file diff --git a/l10n_us_hr_payroll/data/state/la_louisiana.xml b/l10n_us_hr_payroll/data/state/la_louisiana.xml new file mode 100644 index 00000000..78cd6069 --- /dev/null +++ b/l10n_us_hr_payroll/data/state/la_louisiana.xml @@ -0,0 +1,148 @@ + + + + + + US LA Louisiana SUTA Wage Base + us_la_suta_wage_base + 7700.0 + + + + US LA Louisiana SUTA Wage Base + us_la_suta_wage_base + 7700.0 + + + + + + + + US LA Louisiana SUTA Rate + us_la_suta_rate + 1.14 + + + + US LA Louisiana SUTA Rate + us_la_suta_rate + 1.14 + + + + + + + US LA Louisiana SIT Tax Rate + us_la_sit_tax_rate + { + 'single': ( + (12500.00, 2.10), + (50000.00, 1.60), + ( 'inf', 1.35), + ), + 'married': ( + ( 25000.00, 2.10), + (100000.00, 1.65), + ( 'inf', 1.35), + ), + } + + + + US LA Louisiana SIT Tax Rate + us_la_sit_tax_rate + { + 'single': ( + (12500.00, 2.10), + (50000.00, 1.60), + ( 'inf', 1.35) + ), + 'married': ( + ( 25000.00, 2.10), + (100000.00, 1.65), + ( 'inf', 1.35) + ), + } + + + + + + + US LA Louisiana Personal Exemption Rate + us_la_sit_personal_exemption_rate + 4500 + + + + US LA Louisiana Personal Exemption Rate + us_la_sit_personal_exemption_rate + 4500 + + + + + + + US LA Louisiana Dependent Rate + us_la_sit_dependent_rate + 1000.0 + + + + US LA Louisiana Dependent Rate + us_la_sit_dependent_rate + 1000.0 + + + + + + + US Louisiana - Workforce Commission (LWC) - Unemployment Tax + 1 + + + US Louisiana - Workforce Commission (LWC) - Unemployment Tax + + + + + US Louisiana - Department of Revenue (LDOR) - Income Tax + 1 + + + US Louisiana - Department of Revenue (LDOR) - Income Tax + + + + + + + + ER: US LA Louisiana State Unemployment + ER_US_LA_SUTA + python + result, _ = general_state_unemployment(payslip, categories, worked_days, inputs, wage_base='us_la_suta_wage_base', rate='us_la_suta_rate', state_code='LA') + code + result, result_rate = general_state_unemployment(payslip, categories, worked_days, inputs, wage_base='us_la_suta_wage_base', rate='us_la_suta_rate', state_code='LA') + + + + + + + + EE: US LA Louisiana State Income Tax Withholding + EE_US_LA_SIT + python + result, _ = la_louisiana_state_income_withholding(payslip, categories, worked_days, inputs) + code + result, result_rate = la_louisiana_state_income_withholding(payslip, categories, worked_days, inputs) + + + + + diff --git a/l10n_us_hr_payroll/data/state/me_maine.xml b/l10n_us_hr_payroll/data/state/me_maine.xml new file mode 100644 index 00000000..15fadbb9 --- /dev/null +++ b/l10n_us_hr_payroll/data/state/me_maine.xml @@ -0,0 +1,119 @@ + + + + + + US ME Maine SUTA Wage Base + us_me_suta_wage_base + 12000.0 + + + + + + + + US ME Maine SUTA Rate + us_me_suta_rate + 1.92 + + + + + + + US ME Maine SIT Tax Rate + us_me_sit_tax_rate + { + 'single': ( + ( 22200, 0, 5.80), + ( 52600, 1288, 6.75), + ( 'inf', 3340, 7.15), + ), + 'married': ( + ( 44450, 0, 5.80), + ( 105200, 2578, 6.75), + ( 'inf', 6679, 7.15), + ), + } + + + + + + + US ME Maine Standard Deduction Rate + us_me_sit_standard_deduction_rate + { + 'single': { + ( 82900, 9550), + (157900, 75000), + }, + 'married': { + (165800, 21950), + (315800, 150000), + }, + } + + + + + + + US ME Maine Personal Exemption Rate + us_me_sit_personal_exemption_rate + 4300 + + + + + + + + US Maine - Department Of Labor | ReEmploy - Unemployment Tax + 1 + + + US Maine - Department Of Labor | ReEmploy - Unemployment Tax + + + + + US Maine - Department Of Revenue Services - Income Tax + 1 + + + US Maine - Department Of Revenue Services - Income Tax + + + + + + + + + + ER: US ME Maine State Unemployment + ER_US_ME_SUTA + python + result, _ = general_state_unemployment(payslip, categories, worked_days, inputs, wage_base='us_me_suta_wage_base', rate='us_me_suta_rate', state_code='ME') + code + result, result_rate = general_state_unemployment(payslip, categories, worked_days, inputs, wage_base='us_me_suta_wage_base', rate='us_me_suta_rate', state_code='ME') + + + + + + + + EE: US ME Maine State Income Tax Withholding + EE_US_ME_SIT + python + result, _ = me_maine_state_income_withholding(payslip, categories, worked_days, inputs) + code + result, result_rate = me_maine_state_income_withholding(payslip, categories, worked_days, inputs) + + + + + \ No newline at end of file diff --git a/l10n_us_hr_payroll/data/state/mi_michigan.xml b/l10n_us_hr_payroll/data/state/mi_michigan.xml new file mode 100644 index 00000000..df0f6352 --- /dev/null +++ b/l10n_us_hr_payroll/data/state/mi_michigan.xml @@ -0,0 +1,96 @@ + + + + + + US MI Michigan SUTA Wage Base + us_mi_suta_wage_base + 9500.0 + + + + US MI Michigan SUTA Wage Base + us_mi_suta_wage_base + 9000.0 + + + + + + + + US MI Michigan SUTA Rate + us_mi_suta_rate + 2.7 + + + + US MI Michigan SUTA Rate + us_mi_suta_rate + 2.7 + + + + + + + US MI Michigan Exemption Rate + us_mi_sit_exemption_rate + 4400.0 + + + + US MI Michigan Exemption Rate + us_mi_sit_exemption_rate + 4750.0 + + + + + + + US Michigan - Unemployment Insurance Agency - Unemployment Tax + + + US Michigan - Unemployment Insurance Agency - Unemployment Tax + + + + + US Michigan - Department of Treasury - Income Tax + + + US Michigan - Department of Treasury - Income Tax + + + + + + + + + + ER: US MI Michigan State Unemployment + ER_US_MI_SUTA + python + result, _ = general_state_unemployment(payslip, categories, worked_days, inputs, wage_base='us_mi_suta_wage_base', rate='us_mi_suta_rate', state_code='MI') + code + result, result_rate = general_state_unemployment(payslip, categories, worked_days, inputs, wage_base='us_mi_suta_wage_base', rate='us_mi_suta_rate', state_code='MI') + + + + + + + + EE: US MI Michigan State Income Tax Withholding + EE_US_MI_SIT + python + result, _ = mi_michigan_state_income_withholding(payslip, categories, worked_days, inputs) + code + result, result_rate = mi_michigan_state_income_withholding(payslip, categories, worked_days, inputs) + + + + + \ No newline at end of file diff --git a/l10n_us_hr_payroll/data/state/mn_minnesota.xml b/l10n_us_hr_payroll/data/state/mn_minnesota.xml new file mode 100644 index 00000000..6408358c --- /dev/null +++ b/l10n_us_hr_payroll/data/state/mn_minnesota.xml @@ -0,0 +1,141 @@ + + + + + + US MN Minnesota SUTA Wage Base + us_mn_suta_wage_base + 34000.0 + + + + US MN Minnesota SUTA Wage Base + us_mn_suta_wage_base + 35000.0 + + + + + + + + US MN Minnesota SUTA Rate + us_mn_suta_rate + 1.11 + + + + US MN Minnesota SUTA Rate + us_mn_suta_rate + 1.11 + + + + + + + US MN Minnesota SIT Tax Rate + us_mn_sit_tax_rate + { + '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), + ), + } + + + + + + US MN Minnesota SIT Tax Rate + us_mn_sit_tax_rate + { + '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), + ), + } + + + + + + + US MN Minnesota Allowances Rate + us_mn_sit_allowances_rate + 4250.0 + + + + + + US MN Minnesota Allowances Rate + us_mn_sit_allowances_rate + 4300.0 + + + + + + + US Minnesota - Unemployment Insurance Agency - Unemployment Tax + + + US Minnesota - Unemployment Insurance Agency - Unemployment Tax + + + + + US Minnesota - Department of Treasury - Income Tax + + + US Minnesota - Department of Treasury - Income Tax + + + + + + + + + + ER: US MN Minnesota State Unemployment + ER_US_MN_SUTA + 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') + code + 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') + + + + + + + + EE: US MN Minnesota State Income Tax Withholding + EE_US_MN_SIT + python + result, _ = mn_minnesota_state_income_withholding(payslip, categories, worked_days, inputs) + code + result, result_rate = mn_minnesota_state_income_withholding(payslip, categories, worked_days, inputs) + + + + + \ No newline at end of file diff --git a/l10n_us_hr_payroll/data/state/mo_missouri.xml b/l10n_us_hr_payroll/data/state/mo_missouri.xml new file mode 100644 index 00000000..500126b2 --- /dev/null +++ b/l10n_us_hr_payroll/data/state/mo_missouri.xml @@ -0,0 +1,147 @@ + + + + + + US MO Missouri SUTA Wage Base + us_mo_suta_wage_base + 12000.0 + + + + US MO Missouri SUTA Wage Base + us_mo_suta_wage_base + 11500.0 + + + + + + + + US MO Missouri SUTA Rate + us_mo_suta_rate + 2.376 + + + + US MO Missouri SUTA Rate + us_mo_suta_rate + 2.376 + + + + + + + + US MO Missouri SIT Rate Table + us_mo_sit_rate + [ + (1053.0, 1.5), + (1053.0, 2.0), + (1053.0, 2.5), + (1053.0, 3.0), + (1053.0, 3.5), + (1053.0, 4.0), + (1053.0, 4.5), + (1053.0, 5.0), + ( 'inf', 5.4), + ] + + + + + + US MO Missouri SIT Rate Table + us_mo_sit_rate + [ + (1073.0, 1.5), + (1073.0, 2.0), + (1073.0, 2.5), + (1073.0, 3.0), + (1073.0, 3.5), + (1073.0, 4.0), + (1073.0, 4.5), + (1073.0, 5.0), + ( 'inf', 5.4), + ] + + + + + + + + US MO Missouri SIT Deduction + us_mo_sit_deduction + { + 'single': 12400.0, + 'married': 24800.0, + 'head_of_household': 18650.0, + } + + + + + + US MO Missouri SIT Deduction + us_mo_sit_deduction + { + 'single': 12400.0, + 'married': 24800.0, + 'head_of_household': 18650.0, + } + + + + + + + US Missouri - Department of Taxation - Unemployment Tax + + + + US Missouri - Department of Taxation - Unemployment Tax + + + + + US Missouri - Department of Taxation - Income Tax + + + + US Missouri - Department of Taxation - Income Tax + + + + + + + + + + ER: US MO Missouri State Unemployment + ER_US_MO_SUTA + python + result, _ = general_state_unemployment(payslip, categories, worked_days, inputs, wage_base='us_mo_suta_wage_base', rate='us_mo_suta_rate', state_code='MO') + code + result, result_rate = general_state_unemployment(payslip, categories, worked_days, inputs, wage_base='us_mo_suta_wage_base', rate='us_mo_suta_rate', state_code='MO') + + + + + + + + EE: US MO Missouri State Income Tax Withholding + EE_US_MO_SIT + python + result, _ = mo_missouri_state_income_withholding(payslip, categories, worked_days, inputs) + code + result, result_rate = mo_missouri_state_income_withholding(payslip, categories, worked_days, inputs) + + + + + \ No newline at end of file diff --git a/l10n_us_hr_payroll/data/state/ms_mississippi.xml b/l10n_us_hr_payroll/data/state/ms_mississippi.xml index 7a94150d..fd9d670d 100644 --- a/l10n_us_hr_payroll/data/state/ms_mississippi.xml +++ b/l10n_us_hr_payroll/data/state/ms_mississippi.xml @@ -43,6 +43,8 @@ ] + + US MS Mississippi SIT Rate Table us_ms_sit_rate @@ -67,6 +69,19 @@ } + + + + US MS Mississippi SIT Deduction + us_ms_sit_deduction + { + 'single': 2300.0, + 'head_of_household': 3400.0, + 'married_dual': 2300.0, + 'married': 4600.0, + } + + diff --git a/l10n_us_hr_payroll/data/state/mt_montana.xml b/l10n_us_hr_payroll/data/state/mt_montana.xml index 7cca142a..d73c74f3 100644 --- a/l10n_us_hr_payroll/data/state/mt_montana.xml +++ b/l10n_us_hr_payroll/data/state/mt_montana.xml @@ -52,39 +52,78 @@ US MT Montana SIT Rate Table us_mt_sit_rate { - 'weekly': [ + 'weekly': ( ( 135.00, 0.0, 1.80), ( 288.00, 2.0, 4.40), ( 2308.00, 9.0, 6.00), ( 'inf', 130.0, 6.60), - ], - 'bi-weekly': [ + ), + 'bi-weekly': ( ( 269.00, 0.0, 1.80), ( 577.00, 5.0, 4.40), ( 4615.00, 18.0, 6.00), ( 'inf', 261.0, 6.60), - ], - 'semi-monthly': [ + ), + 'semi-monthly': ( ( 292.00, 0.0, 1.80), ( 625.00, 5.0, 4.40), ( 5000.00, 20.0, 6.00), ( 'inf', 282.0, 6.60), - ], - 'monthly': [ + ), + 'monthly': ( ( 583.00, 0.0, 1.80), ( 1250.00, 11.0, 4.40), ( 10000.00, 40.0, 6.00), ( 'inf', 565.0, 6.60), - ], - 'annually': [ + ), + 'annually': ( ( 7000.00, 0.0, 1.80), ( 15000.00, 126.0, 4.40), ( 120000.00, 478.0, 6.00), ( 'inf', 6778.0, 6.60), - ], + ), } + + + + US MT Montana SIT Rate Table + us_mt_sit_rate + { + 'weekly': ( + ( 135.00, 0.0, 1.80), + ( 288.00, 2.0, 4.40), + ( 2308.00, 9.0, 6.00), + ( 'inf', 130.0, 6.60), + ), + 'bi-weekly': ( + ( 269.00, 0.0, 1.80), + ( 577.00, 5.0, 4.40), + ( 4615.00, 18.0, 6.00), + ( 'inf', 261.0, 6.60), + ), + 'semi-monthly': ( + ( 292.00, 0.0, 1.80), + ( 625.00, 5.0, 4.40), + ( 5000.00, 20.0, 6.00), + ( 'inf', 282.0, 6.60), + ), + 'monthly': ( + ( 583.00, 0.0, 1.80), + ( 1250.00, 11.0, 4.40), + ( 10000.00, 40.0, 6.00), + ( 'inf', 565.0, 6.60), + ), + 'annually': ( + ( 7000.00, 0.0, 1.80), + ( 15000.00, 126.0, 4.40), + ( 120000.00, 478.0, 6.00), + ( 'inf', 6778.0, 6.60), + ), + } + + @@ -100,6 +139,20 @@ } + + + + US MT Montana SIT Exemption Rate Table + us_mt_sit_exemption_rate + { + 'weekly': 37.0, + 'bi-weekly': 73.0, + 'semi-monthly': 79.0, + 'monthly': 158.0, + 'annually': 1900.0, + } + + diff --git a/l10n_us_hr_payroll/data/state/nc_northcarolina.xml b/l10n_us_hr_payroll/data/state/nc_northcarolina.xml new file mode 100644 index 00000000..4e032b89 --- /dev/null +++ b/l10n_us_hr_payroll/data/state/nc_northcarolina.xml @@ -0,0 +1,110 @@ + + + + + + US NC North Carolina SUTA Wage Base + us_nc_suta_wage_base + 24300.0 + + + + US NC North Carolina SUTA Wage Base + us_nc_suta_wage_base + 25200.0 + + + + + + + + US NC North Carolina SUTA Rate + us_nc_suta_rate + 1.0 + + + + US NC North Carolina SUTA Rate + us_nc_suta_rate + 1.0 + + + + + + + + + US NC North Carolina Allowance Rate + us_nc_sit_allowance_rate + { + 'weekly': {'allowance': 48.08, 'standard_deduction': 192.31, 'standard_deduction_hh': 288.46}, + 'bi-weekly': {'allowance': 96.15, 'standard_deduction': 384.62, 'standard_deduction_hh': 576.92}, + 'semi-monthly': {'allowance': 104.17, 'standard_deduction': 416.67, 'standard_deduction_hh': 625.00}, + 'monthly': {'allowance': 208.33, 'standard_deduction': 833.33, 'standard_deduction_hh': 1250.00}, + } + + + + + + US NC North Carolina Allowance Rate + us_nc_sit_allowance_rate + { + 'weekly': {'allowance': 48.08, 'standard_deduction': 206.73, 'standard_deduction_hh': 310.10}, + 'bi-weekly': {'allowance': 96.15, 'standard_deduction': 413.46, 'standard_deduction_hh': 620.19}, + 'semi-monthly': {'allowance': 104.17, 'standard_deduction': 447.92, 'standard_deduction_hh': 671.88}, + 'monthly': {'allowance': 208.33, 'standard_deduction': 895.83, 'standard_deduction_hh': 1343.75}, + } + + + + + + + US North Carolina - Department of Taxation - Unemployment Tax + + + US North Carolina - Department of Taxation - Unemployment Tax + + + + + US North Carolina - Department of Taxation - Income Tax + + + US North Carolina - Department of Taxation - Income Tax + + + + + + + + + + ER: US NC North Carolina State Unemployment + ER_US_NC_SUTA + python + result, _ = general_state_unemployment(payslip, categories, worked_days, inputs, wage_base='us_nc_suta_wage_base', rate='us_nc_suta_rate', state_code='NC') + code + result, result_rate = general_state_unemployment(payslip, categories, worked_days, inputs, wage_base='us_nc_suta_wage_base', rate='us_nc_suta_rate', state_code='NC') + + + + + + + + EE: US NC North Carolina State Income Tax Withholding + EE_US_NC_SIT + python + result, _ = nc_northcarolina_state_income_withholding(payslip, categories, worked_days, inputs) + code + result, result_rate = nc_northcarolina_state_income_withholding(payslip, categories, worked_days, inputs) + + + + + \ No newline at end of file diff --git a/l10n_us_hr_payroll/data/state/nd_north_dakota.xml b/l10n_us_hr_payroll/data/state/nd_north_dakota.xml new file mode 100644 index 00000000..37f129b9 --- /dev/null +++ b/l10n_us_hr_payroll/data/state/nd_north_dakota.xml @@ -0,0 +1,272 @@ + + + + + + US ND North Dakota SUTA Wage Base + us_nd_suta_wage_base + 37900.0 + + + + + + + + US ND North Dakota SUTA Rate + us_nd_suta_rate + 1.02 + + + + + + + US ND North Dakota SIT Tax Rate + us_nd_sit_tax_rate + { + 'single': { + 'weekly': ( + ( 119, 0.00, 0.00), + ( 891, 0.00, 1.10), + ( 1988, 8.49, 2.04), + ( 4016, 30.87, 2.27), + ( 8592, 76.91, 2.64), + ('inf', 197.71, 2.90), + ), + 'bi-weekly': ( + ( 238, 0.00, 0.00), + ( 1782, 0.00, 1.10), + ( 3975, 16.98, 2.04), + ( 8033, 61.72, 2.27), + ( 17185, 153.84, 2.64), + ( 'inf', 395.45, 2.90), + ), + 'semi-monthly': ( + ( 258, 0.00, 0.00), + ( 1930, 0.00, 1.10), + ( 4306, 18.39, 2.04), + ( 8702, 66.86, 2.27), + ( 18617, 166.65, 2.64), + ( 'inf', 428.41, 2.90), + ), + 'monthly': ( + ( 517, 0.00, 0.00), + ( 3860, 0.00, 1.10), + ( 8613, 36.77, 2.04), + ( 17404, 133.73, 2.27), + ( 37233, 333.29, 2.64), + ( 'inf', 856.78, 2.90), + ), + 'quarterly': ( + ( 1550, 0.00, 0.00), + ( 11581, 0.00, 1.10), + ( 25838, 110.34, 2.04), + ( 52213, 401.18, 2.27), + ( 111700, 999.90, 2.64), + ( 'inf', 2570.35, 2.90), + ), + 'semi-annual': ( + ( 3100, 0.00, 0.00), + ( 23163, 0.00, 1.10), + ( 51675, 220.69, 2.04), + ( 104425, 802.34, 2.27), + ( 223400, 1999.76, 2.64), + ( 'inf', 5140.70, 2.90), + ), + 'annual': ( + ( 6200, 0.00, 0.00), + ( 46325, 0.00, 1.10), + ( 103350, 441.38, 2.04), + ( 208850, 1604.69, 2.27), + ( 446800, 3999.54, 2.64), + ( 'inf', 10281.42, 2.90), + ), + }, + 'married': { + 'weekly': ( + ( 238, 0.00, 0.00), + ( 883, 0.00, 1.10), + ( 1796, 7.10, 2.04), + ( 2611, 25.72, 2.27), + ( 4475, 44.22, 2.64), + ('inf', 93.43, 2.90), + ), + 'bi-weekly': ( + ( 477, 0.00, 0.00), + ( 1766, 0.00, 1.10), + ( 3591, 14.18, 2.04), + ( 5221, 51.41, 2.27), + ( 8950, 88.41, 2.64), + ( 'inf', 186.86, 2.90), + ), + 'semi-monthly': ( + ( 517, 0.00, 0.00), + ( 1914, 0.00, 1.10), + ( 3891, 15.37, 2.04), + ( 5656, 55.70, 2.27), + ( 9696, 95.76, 2.64), + ( 'inf', 202.42, 2.90), + ), + 'monthly': ( + ( 1033, 0.00, 0.00), + ( 3827, 0.00, 1.10), + ( 7781, 30.73, 2.04), + ( 11313, 111.40, 2.27), + ( 19392, 191.57, 2.64), + ( 'inf', 404.86, 2.90), + ), + 'quarterly': ( + ( 3100, 0.00, 0.00), + ( 11481, 0.00, 1.10), + ( 23344, 92.19, 2.04), + ( 33938, 334.20, 2.27), + ( 58175, 574.68, 2.64), + ( 'inf', 1214.54, 2.90), + ), + 'semi-annual': ( + ( 6200, 0.00, 0.00), + ( 22963, 0.00, 1.10), + ( 46688, 184.39, 2.04), + ( 67875, 668.38, 2.27), + ( 116350, 1149.33, 2.64), + ( 'inf', 2429.07, 2.90), + ), + 'annual': ( + ( 12400, 0.00, 0.00), + ( 45925, 0.00, 1.10), + ( 93375, 368.78, 2.04), + ( 135750, 1336.76, 2.27), + ( 232700, 2298.67, 2.64), + ( 'inf', 4858.15, 2.90), + ), + }, + 'head_household':{ + 'weekly': ( + ( 119, 0.00, 0.00), + ( 891, 0.00, 1.10), + ( 1988, 8.49, 2.04), + ( 4016, 30.87, 2.27), + ( 8592, 76.91, 2.64), + ('inf', 197.71, 2.90), + ), + 'bi-weekly': ( + ( 238, 0.00, 0.00), + ( 1782, 0.00, 1.10), + ( 3975, 16.98, 2.04), + ( 8033, 61.72, 2.27), + ( 17185, 153.84, 2.64), + ( 'inf', 395.45, 2.90), + ), + 'semi-monthly': ( + ( 258, 0.00, 0.00), + ( 1930, 0.00, 1.10), + ( 4306, 18.39, 2.04), + ( 8702, 66.86, 2.27), + ( 18617, 166.65, 2.64), + ( 'inf', 428.41, 2.90), + ), + 'monthly': ( + ( 517, 0.00, 0.00), + ( 3860, 0.00, 1.10), + ( 8613, 36.77, 2.04), + ( 17404, 133.73, 2.27), + ( 37233, 333.29, 2.64), + ( 'inf', 856.78, 2.90), + ), + 'quarterly': ( + ( 1550, 0.00, 0.00), + ( 11581, 0.00, 1.10), + ( 25838, 110.34, 2.04), + ( 52213, 401.18, 2.27), + ( 111700, 999.90, 2.64), + ( 'inf', 2570.35, 2.90), + ), + 'semi-annual': ( + ( 3100, 0.00, 0.00), + ( 23163, 0.00, 1.10), + ( 51675, 220.69, 2.04), + ( 104425, 802.34, 2.27), + ( 223400, 1999.76, 2.64), + ( 'inf', 5140.70, 2.90), + ), + 'annual': ( + ( 6200, 0.00, 0.00), + ( 46325, 0.00, 1.10), + ( 103350, 441.38, 2.04), + ( 208850, 1604.69, 2.27), + ( 446800, 3999.54, 2.64), + ( 'inf', 10281.42, 2.90), + ), + }, + } + + + + + + + US ND North Dakota Allowances Rate + us_nd_sit_allowances_rate + { + 'weekly' : 83.00, + 'bi-weekly' : 165.00, + 'semi-monthly': 179.00, + 'monthly' : 358.00, + 'quarterly' : 1075.00, + 'semi-annual': 2150.00, + 'annually': 4300.00, + } + + + + + + + US North Dakota - Office of State Tax Commissioner - Unemployment Tax + 1 + + + US North Dakota - Office of State Tax Commissioner - Unemployment Tax + + + + + US North Dakota - Taxpayer Access Point - Income Tax + 1 + + + US North Dakota - Taxpayer Access Point - Income Tax + + + + + + + + + + ER: US ND North Dakota State Unemployment + ER_US_ND_SUTA + python + result, _ = general_state_unemployment(payslip, categories, worked_days, inputs, wage_base='us_nd_suta_wage_base', rate='us_nd_suta_rate', state_code='ND') + code + result, result_rate = general_state_unemployment(payslip, categories, worked_days, inputs, wage_base='us_nd_suta_wage_base', rate='us_nd_suta_rate', state_code='ND') + + + + + + + + EE: US ND North Dakota State Income Tax Withholding + EE_US_ND_SIT + python + result, _ = nd_north_dakota_state_income_withholding(payslip, categories, worked_days, inputs) + code + result, result_rate = nd_north_dakota_state_income_withholding(payslip, categories, worked_days, inputs) + + + + + \ No newline at end of file diff --git a/l10n_us_hr_payroll/data/state/ne_nebraska.xml b/l10n_us_hr_payroll/data/state/ne_nebraska.xml new file mode 100644 index 00000000..bd35fe1f --- /dev/null +++ b/l10n_us_hr_payroll/data/state/ne_nebraska.xml @@ -0,0 +1,230 @@ + + + + + + US NE Nebraska SUTA Wage Base + us_ne_suta_wage_base + 9000.0 + + + + + + + + US NE Nebraska SUTA Rate + us_ne_suta_rate + 1.25 + + + + + + + + US NE Nebraska SIT Tax Rate + us_ne_sit_tax_rate + { + 'single': { + 'weekly': ( + ( 57, 0.00, 0.00), + ( 105, 0.00, 2.26), + ( 342, 1.08, 3.22), + ( 496, 8.71, 4.91), + ( 629, 16.27, 6.20), + ( 1182, 24.52, 6.59), + ('inf', 60.96, 6.95), + ), + 'bi-weekly': ( + ( 114, 0.00, 0.00), + ( 211, 0.00, 2.26), + ( 684, 2.19, 3.22), + ( 992, 17.42, 4.91), + ( 1259, 32.54, 6.20), + ( 2364, 49.09, 6.59), + ('inf', 121.91, 6.95), + ), + 'semi-monthly': ( + ( 124, 0.00, 0.00), + ( 228, 0.00, 2.26), + ( 741, 2.35, 3.22), + ( 1074, 18.87, 4.91), + ( 1364, 35.22, 6.20), + ( 2561, 53.20, 6.59), + ('inf', 132.08, 6.95), + ), + 'monthly': ( + ( 248, 0.00, 0.00), + ( 457, 0.00, 2.26), + ( 1483, 4.72, 3.22), + ( 2148, 37.76, 4.91), + ( 2728, 70.41, 6.20), + ( 5123, 106.37, 6.59), + ('inf', 264.20, 6.95), + ), + 'quarterly': ( + ( 744, 0.00, 0.00), + ( 1370, 0.00, 2.26), + ( 4448, 14.15, 3.22), + ( 6445, 113.26, 4.91), + ( 8183, 211.31, 6.20), + ( 15368, 319.07, 6.59), + ( 'inf', 792.56, 6.95), + ), + 'semi-annual': ( + ( 1488, 0.00, 0.00), + ( 2740, 0.00, 2.26), + ( 8895, 28.30, 3.22), + ( 12890, 226.49, 4.91), + ( 16365, 422.64, 6.20), + ( 30735, 638.09, 6.59), + ( 'inf', 1585.07, 6.95), + ), + 'annually': ( + ( 2975, 0.00, 0.00), + ( 5480, 0.00, 2.26), + ( 17790, 56.61, 3.22), + ( 25780, 452.99, 4.91), + ( 32730, 845.30, 6.20), + ( 61470, 1276.20, 6.59), + ( 'inf', 3170.17, 6.95), + ), + }, + 'married': { + 'weekly': ( + ( 137, 0.00, 0.00), + ( 204, 0.00, 2.26), + ( 508, 1.51, 3.22), + ( 790, 11.30, 4.91), + ( 981, 25.15, 6.20), + ( 1300, 36.99, 6.59), + ('inf', 58.01, 6.95), + ), + 'bi-weekly': ( + ( 273, 0.00, 0.00), + ( 408, 0.00, 2.26), + ( 1016, 3.05, 3.22), + ( 1581, 22.63, 4.91), + ( 1961, 50.37, 6.20), + ( 2601, 73.93, 6.59), + ('inf', 116.11, 6.95), + ), + 'semi-monthly': ( + ( 296, 0.00, 0.00), + ( 442, 0.00, 2.26), + ( 1101, 3.30, 3.22), + ( 1713, 24.52, 4.91), + ( 2125, 54.57, 6.20), + ( 2818, 80.11, 6.59), + ('inf', 125.78, 6.95), + ), + 'monthly': ( + ( 592, 0.00, 0.00), + ( 884, 0.00, 2.26), + ( 2202, 6.60, 3.22), + ( 3425, 49.04, 4.91), + ( 4249, 109.09, 6.20), + ( 5635, 160.18, 6.59), + ('inf', 251.52, 6.95), + ), + 'quarterly': ( + ( 1775, 0.00, 0.00), + ( 2653, 0.00, 2.26), + ( 6605, 19.84, 3.22), + ( 10275, 147.09, 4.91), + ( 12748, 327.29, 6.20), + ( 16905, 480.62, 6.59), + ( 'inf', 754.57, 6.95), + ), + 'semi-annual': ( + ( 3550, 0.00, 0.00), + ( 5305, 0.00, 2.26), + ( 13210, 39.66, 3.22), + ( 20550, 294.20, 4.91), + ( 25495, 654.59, 6.20), + ( 33810, 961.18, 6.59), + ( 'inf', 1509.14, 6.95), + ), + 'annually': ( + ( 7100, 0.00, 0.00), + ( 10610, 0.00, 2.26), + ( 26420, 79.33, 3.22), + ( 41100, 588.41, 4.91), + ( 50990, 1309.20, 6.20), + ( 67620, 1992.38, 6.59), + ( 'inf', 3018.30, 6.95), + ), + }, + } + + + + + + + US NE Nebraska Allowances Rate + us_ne_sit_allowances_rate + { + 'weekly' : 37.69, + 'bi-weekly' : 75.38, + 'semi-monthly': 81.67, + 'monthly' : 163.33, + 'quarterly' : 490.00, + 'semi-annual': 980.00, + 'annually': 1960.00, + } + + + + + + + + US Nebraska - Nebraska Department of Labor - Unemployment Tax + 1 + + + US Nebraska - Nebraska Department of Labor - Unemployment Tax + + + + + US Nebraska - Nebraska Department of Revenue - Income Tax + 1 + + + US Nebraska - Nebraska Department of Revenue - Income Tax + + + + + + + + + + ER: US NE Nebraska State Unemployment + ER_US_NE_SUTA + python + result, _ = general_state_unemployment(payslip, categories, worked_days, inputs, wage_base='us_ne_suta_wage_base', rate='us_ne_suta_rate', state_code='NE') + code + result, result_rate = general_state_unemployment(payslip, categories, worked_days, inputs, wage_base='us_ne_suta_wage_base', rate='us_ne_suta_rate', state_code='NE') + + + + + + + + EE: US NE Nebraska State Income Tax Withholding + EE_US_NE_SIT + python + result, _ = ne_nebraska_state_income_withholding(payslip, categories, worked_days, inputs) + code + result, result_rate = ne_nebraska_state_income_withholding(payslip, categories, worked_days, inputs) + + + + + \ No newline at end of file diff --git a/l10n_us_hr_payroll/data/state/nh_new_hampshire.xml b/l10n_us_hr_payroll/data/state/nh_new_hampshire.xml new file mode 100644 index 00000000..74504122 --- /dev/null +++ b/l10n_us_hr_payroll/data/state/nh_new_hampshire.xml @@ -0,0 +1,47 @@ + + + + + + US NH New Hampshire SUTA Wage Base + us_nh_suta_wage_base + 14000.00 + + + + + + + + US NH New Hampshire SUTA Rate + us_nh_suta_rate + 1.2 + + + + + + + US New Hampshire - Department of Employment Security - Unemployment Tax + 1 + + + US New Hampshire - Department of Employment Security - Unemployment Tax + + + + + + + + ER: US NH New Hampshire State Unemployment + ER_US_NH_SUTA + python + result, _ = general_state_unemployment(payslip, categories, worked_days, inputs, wage_base='us_nh_suta_wage_base', rate='us_nh_suta_rate', state_code='NH') + code + result, result_rate = general_state_unemployment(payslip, categories, worked_days, inputs, wage_base='us_nh_suta_wage_base', rate='us_nh_suta_rate', state_code='NH') + + + + + diff --git a/l10n_us_hr_payroll/data/state/nj_newjersey.xml b/l10n_us_hr_payroll/data/state/nj_newjersey.xml new file mode 100644 index 00000000..acd3729e --- /dev/null +++ b/l10n_us_hr_payroll/data/state/nj_newjersey.xml @@ -0,0 +1,1016 @@ + + + + + + US NJ NewJersey SUTA Wage Base + us_nj_suta_wage_base + 34400.00 + + + + US NJ NewJersey SUTA Wage Base + us_nj_suta_wage_base + 35300.00 + + + + + + + + + US NJ New Jersey Employer Unemployment SUTA Rate + us_nj_suta_rate + 2.6825 + + + + US NJ New Jersey Employer Unemployment SUTA Rate + us_nj_suta_rate + 2.6825 + + + + + + + US NJ New Jersey Employee Unemployment SUTA Rate + us_nj_suta_ee_rate + 0.3825 + + + + US NJ New Jersey Employee Unemployment SUTA Rate + us_nj_suta_ee_rate + 0.3825 + + + + + + + + US NJ New Jersey Employer State Disability Insurance Rate + us_nj_sdi_rate + 0.5 + + + + US NJ New Jersey Employer State Disability Insurance Rate + us_nj_sdi_rate + 0.5 + + + + + + + US NJ New Jersey Employee State Disability Insurance Rate + us_nj_sdi_ee_rate + 0.17 + + + + US NJ New Jersey Employee State Disability Insurance Rate + us_nj_sdi_ee_rate + 0.26 + + + + + + + + US NJ New Jersey Employer Workforce Development Rate + us_nj_wf_rate + 0.1175 + + + + US NJ New Jersey Employer Workforce Development Rate + us_nj_wf_rate + 0.1175 + + + + + + + US NJ New Jersey Employee Workforce Development Rate + us_nj_wf_ee_rate + 0.0425 + + + + US NJ New Jersey Employee Workforce Development Rate + us_nj_wf_ee_rate + 0.0425 + + + + + + + + US NJ New Jersey Employer Family Leave Insurance Rate + us_nj_fli_rate + 0.0 + + + + US NJ New Jersey Employer Family Leave Insurance Rate + us_nj_fli_rate + 0.0 + + + + + + + US NJ New Jersey Employee Family Leave Insurance Rate + us_nj_fli_ee_rate + 0.08 + + + + US NJ New Jersey Employee Family Leave Insurance Rate + us_nj_fli_ee_rate + 0.16 + + + + + + + + US NJ NewJersey SIT Rate Table + us_nj_sit_rate + { + 'A': { + 'weekly': ( + ( 385, 0.00, 1.50), + ( 673, 5.77, 2.00), + ( 769, 11.54, 3.90), + ( 1442, 15.29, 6.10), + ( 9615, 56.34, 7.00), + (96154, 628.46, 9.90), + ('inf', 9195.77, 11.80), + ), + 'bi-weekly': ( + ( 769, 0.00, 1.50), + ( 1346, 12.00, 2.00), + ( 1538, 23.00, 3.90), + ( 2885, 31.00, 6.10), + ( 19231, 113.00, 7.00), + (192308, 1257.00, 9.90), + ( 'inf', 18392.00, 11.80), + ), + 'semi-monthly': ( + ( 833, 0.00, 1.50), + ( 1458, 13.00, 2.00), + ( 1667, 25.00, 3.90), + ( 3125, 33.00, 6.10), + ( 20833, 122.00, 7.00), + (208333, 1362.00, 9.90), + ( 'inf', 19924.00, 11.80), + ), + 'monthly': ( + ( 1667, 0.00, 1.50), + ( 2917, 25.00, 2.00), + ( 3333, 50.00, 3.90), + ( 6250, 66.00, 6.10), + ( 41667, 244.00, 7.00), + (416667, 2723.00, 9.90), + ( 'inf', 39848.00, 11.80), + ), + 'quarterly': ( + ( 5000, 0.00, 1.50), + ( 8750, 75.00, 2.00), + ( 10000, 150.00, 3.90), + ( 18750, 198.75, 6.10), + ( 125000, 732.50, 7.00), + (1250000, 8170.00, 9.90), + ( 'inf', 119545.00, 11.80), + ), + 'semi-annual': ( + ( 10000, 0.00, 1.50), + ( 17500, 150.00, 2.00), + ( 20000, 300.00, 3.90), + ( 37500, 397.50, 6.10), + ( 250000, 1465.00, 7.00), + (2500000, 16340.00, 9.90), + ( 'inf', 239090.00, 11.80), + ), + 'annual': ( + ( 20000, 0.00, 1.50), + ( 35000, 300.00, 2.00), + ( 40000, 600.00, 3.90), + ( 75000, 795.00, 6.10), + ( 500000, 2930.00, 7.00), + (5000000, 32680.00, 9.90), + ( 'inf', 478180.00, 11.80), + ), + }, + 'B': { + 'weekly': ( + ( 385, 0.00, 1.50), + ( 962, 5.77, 2.00), + ( 1346, 17.31, 2.70), + ( 1538, 27.69, 3.90), + ( 2885, 35.19, 6.10), + ( 9615, 117.31, 7.00), + (96154, 588.46, 9.90), + ('inf', 9155.77, 11.80), + ), + 'bi-weekly': ( + ( 769, 0.00, 1.50), + ( 1923, 12.00, 2.00), + ( 2692, 35.00, 2.70), + ( 3076, 55.00, 3.90), + ( 5769, 70.00, 6.10), + ( 19231, 235.00, 7.00), + (192308, 1177.00, 9.90), + ( 'inf', 18312.00, 11.80), + ), + 'semi-monthly': ( + ( 833, 0.00, 1.50), + ( 2083, 12.50, 2.00), + ( 2917, 37.50, 2.70), + ( 3333, 59.99, 3.90), + ( 6250, 76.25, 6.10), + ( 20833, 254.19, 7.00), + (208333, 1275.00, 9.90), + ( 'inf', 19838.00, 11.80), + ), + 'monthly': ( + ( 1667, 0.00, 1.50), + ( 4167, 25.00, 2.00), + ( 5833, 75.00, 2.70), + ( 6667, 120.00, 3.90), + ( 12500, 153.00, 6.10), + ( 41667, 508.00, 7.00), + (416667, 2550.00, 9.90), + ( 'inf', 39675.00, 11.80), + ), + 'quarterly': ( + ( 5000, 0.00, 1.50), + ( 12500, 75.00, 2.00), + ( 17500, 225.00, 2.70), + ( 20000, 360.00, 3.90), + ( 37500, 397.50, 6.10), + ( 125000, 1525.00, 7.00), + (1250000, 7650.00, 9.90), + ( 'inf', 119025.00, 11.80), + ), + 'semi-annual': ( + ( 10000, 0.00, 1.50), + ( 25000, 150.00, 2.00), + ( 35000, 450.00, 2.70), + ( 40000, 720.00, 3.90), + ( 75000, 915.00, 6.10), + ( 250000, 3050.00, 7.00), + (2500000, 15300.00, 9.90), + ( 'inf', 238050.00, 11.80), + ), + 'annual': ( + ( 20000, 0.00, 1.50), + ( 50000, 300.00, 2.00), + ( 70000, 900.00, 2.70), + (80000, 1440.00, 3.90), + ( 150000, 1830.00, 6.10), + ( 500000, 6100.00, 7.00), + (5000000, 30600.00, 9.90), + ( 'inf', 476100.00, 11.80), + ), + }, + 'C': { + 'weekly': ( + ( 385, 0.00, 1.50), + ( 769, 5.77, 2.30), + ( 962, 14.62, 2.80), + ( 1154, 20.00, 3.50), + ( 2885, 26.73, 5.60), + ( 9615, 123.65, 6.60), + (96154, 567.88, 9.90), + ('inf', 9135.19, 11.80), + ), + 'bi-weekly': ( + ( 769, 0.00, 1.50), + ( 1538, 11.54, 2.30), + ( 1923, 29.23, 2.80), + ( 2308, 40.00, 3.50), + ( 5769, 53.46, 5.60), + ( 19231, 247.31, 6.60), + (192308, 1135.77, 9.90), + ( 'inf', 18270.38, 11.80), + ), + 'semi-monthly': ( + ( 833, 0.00, 1.50), + ( 1667, 12.50, 2.30), + ( 2083, 31.67, 2.80), + ( 2500, 43.33, 3.50), + ( 6250, 57.92, 5.60), + ( 20833, 267.92, 6.60), + (208333, 1230.42, 9.90), + ( 'inf', 19792.92, 11.80), + ), + 'monthly': ( + ( 1667, 0.00, 1.50), + ( 3333, 25.00, 2.30), + ( 4167, 63.33, 2.80), + ( 5000, 86.67, 3.50), + ( 12500, 115.83, 5.60), + ( 41667, 535.85, 6.60), + (416667, 2460.83, 9.90), + ( 'inf', 39585.83, 11.80), + ), + 'quarterly': ( + ( 5000, 0.00, 1.50), + ( 10000, 75.00, 2.30), + ( 12500, 190.00, 2.80), + ( 15000, 260.00, 3.50), + ( 37500, 347.50, 5.60), + ( 125000, 1607.50, 6.60), + (1250000, 7382.50, 9.90), + ( 'inf', 118757.50, 11.80), + ), + 'semi-annual': ( + ( 10000, 0.00, 1.50), + ( 20000, 150.00, 2.30), + ( 25000, 380.00, 2.80), + ( 30000, 520.00, 3.50), + ( 75000, 695.00, 5.60), + ( 250000, 3215.00, 6.60), + (2500000, 14765.00, 9.90), + ( 'inf', 237515.00, 11.80), + ), + 'annual': ( + ( 20000, 0.00, 1.50), + ( 40000, 300.00, 2.30), + ( 50000, 760.00, 2.80), + ( 60000, 1040.00, 3.50), + ( 150000, 1390.00, 5.60), + ( 500000, 6430.00, 6.60), + (5000000, 29530.00, 9.90), + ( 'inf', 475030.00, 11.80), + ), + }, + 'D': { + 'weekly': ( + ( 385, 0.00, 1.50), + ( 769, 5.77, 2.70), + ( 962, 16.15, 3.40), + ( 1154, 22.69, 4.30), + ( 2885, 30.96, 5.60), + ( 9615, 127.88, 6.50), + ( 96154, 565.38, 9.90), + ( 'inf', 9132.69, 11.80), + ), + 'bi-weekly': ( + ( 769, 0.00, 1.50), + ( 1538, 11.54, 2.70), + ( 1923, 32.31, 3.40), + ( 2308, 45.38, 4.30), + ( 5769, 61.92, 5.60), + ( 19231, 255.77, 6.50), + (192308, 1130.77, 9.90), + ( 'inf', 18265.38, 11.80), + ), + 'semi-monthly': ( + ( 833, 0.00, 1.50), + ( 1667, 12.50, 2.70), + ( 2083, 35.00, 3.40), + ( 2500, 49.17, 4.30), + ( 6250, 67.08, 5.60), + ( 20833, 277.08, 6.50), + (208333, 1225.00, 9.90), + ( 'inf', 19787.50, 11.80), + ), + 'monthly': ( + ( 1667, 0.00, 1.50), + ( 3333, 25.00, 2.70), + ( 4167, 70.00, 3.40), + ( 5000, 98.33, 4.00), + ( 12500, 134.17, 5.60), + ( 41667, 554.17, 6.50), + (416667, 2450.00, 9.90), + ( 'inf', 39575.00, 11.80), + ), + 'quarterly': ( + ( 5000, 0.00, 1.50), + ( 10000, 75.00, 2.07), + ( 12500, 210.00, 3.40), + ( 15000, 295.00, 4.30), + ( 37500, 402.50, 5.60), + ( 125000, 1662.50, 6.50), + (1250000, 7350.00, 9.90), + ( 'inf', 118725.00, 11.80), + ), + 'semi-annual': ( + ( 10000, 0.00, 1.50), + ( 20000, 150.00, 2.70), + ( 25000, 420.00, 3.40), + ( 30000, 590.00, 4.30), + ( 75000, 805.00, 5.60), + ( 250000, 3325.00, 6.50), + (2500000, 14700.00, 9.90), + ( 'inf', 237450.00, 11.80), + ), + 'annual': ( + ( 20000, 0.00, 1.50), + ( 40000, 300.00, 2.70), + ( 50000, 840.00, 3.40), + ( 60000, 1180.00, 4.30), + ( 150000, 1610.00, 5.60), + ( 250000, 6650.00, 6.50), + (2500000, 29400.00, 9.90), + ( 'inf', 474900.00, 11.80), + ), + }, + 'E': { + 'weekly': ( + ( 385, 0.00, 1.50), + ( 673, 5.77, 2.00), + ( 1923, 11.54, 5.80), + ( 9615, 84.04, 6.50), + ( 96154, 584.04, 9.90), + ( 'inf', 9151.35, 11.80), + ), + 'bi-weekly': ( + ( 769, 0.00, 1.50), + ( 1346, 12.00, 2.00), + ( 3846, 23.00, 5.80), + ( 19231, 168.00, 6.50), + (192308, 1168.00, 9.90), + ( 'inf', 18303.00, 11.80), + ), + 'semi-monthly': ( + ( 833, 0.00, 1.50), + ( 1458, 13.00, 2.00), + ( 4167, 25.00, 5.80), + ( 20833, 182.00, 6.50), + (208333, 1265.00, 9.90), + ( 'inf', 19828.00, 11.80), + ), + 'monthly': ( + ( 1667, 0.00, 1.50), + ( 2916, 25.00, 2.00), + ( 8333, 50.00, 5.80), + ( 41667, 364.00, 6.50), + (416667, 2531.00, 9.90), + ( 'inf', 39656.00, 11.80), + ), + 'quarterly': ( + ( 5000, 0.00, 1.50), + ( 8750, 75.00, 2.00), + ( 25000, 150.00, 5.80), + ( 125000, 1092.50, 6.50), + (1250000, 7592.50, 9.90), + ( 'inf', 118967.50, 11.80), + ), + 'semi-annual': ( + ( 10000, 0.00, 1.50), + ( 17500, 150.00, 2.00), + ( 50000, 300.00, 5.80), + ( 250000, 2185.00, 6.50), + (2500000, 15185.00, 9.90), + ( 'inf', 237935.00, 11.80), + ), + 'annual': ( + ( 20000, 0.00, 1.50), + ( 35000, 300.00, 2.00), + ( 100000, 600.00, 5.80), + ( 500000, 4370.00, 6.50), + (5000000, 30370.00, 9.90), + ( 'inf', 475870.00, 11.80), + ), + }, + } + + + + + US NJ NewJersey SIT Rate Table + us_nj_sit_rate + { + 'A': { + 'weekly': ( + ( 385, 0.00, 1.50), + ( 673, 5.77, 2.00), + ( 769, 11.54, 3.90), + ( 1442, 15.29, 6.10), + ( 9615, 56.34, 7.00), + (96154, 628.46, 9.90), + ('inf', 9195.77, 11.80), + ), + 'bi-weekly': ( + ( 769, 0.00, 1.50), + ( 1346, 12.00, 2.00), + ( 1538, 23.00, 3.90), + ( 2885, 31.00, 6.10), + ( 19231, 113.00, 7.00), + (192308, 1257.00, 9.90), + ( 'inf', 18392.00, 11.80), + ), + 'semi-monthly': ( + ( 833, 0.00, 1.50), + ( 1458, 13.00, 2.00), + ( 1667, 25.00, 3.90), + ( 3125, 33.00, 6.10), + ( 20833, 122.00, 7.00), + (208333, 1362.00, 9.90), + ( 'inf', 19924.00, 11.80), + ), + 'monthly': ( + ( 1667, 0.00, 1.50), + ( 2917, 25.00, 2.00), + ( 3333, 50.00, 3.90), + ( 6250, 66.00, 6.10), + ( 41667, 244.00, 7.00), + (416667, 2723.00, 9.90), + ( 'inf', 39848.00, 11.80), + ), + 'quarterly': ( + ( 5000, 0.00, 1.50), + ( 8750, 75.00, 2.00), + ( 10000, 150.00, 3.90), + ( 18750, 198.75, 6.10), + ( 125000, 732.50, 7.00), + (1250000, 8170.00, 9.90), + ( 'inf', 119545.00, 11.80), + ), + 'semi-annual': ( + ( 10000, 0.00, 1.50), + ( 17500, 150.00, 2.00), + ( 20000, 300.00, 3.90), + ( 37500, 397.50, 6.10), + ( 250000, 1465.00, 7.00), + (2500000, 16340.00, 9.90), + ( 'inf', 239090.00, 11.80), + ), + 'annual': ( + ( 20000, 0.00, 1.50), + ( 35000, 300.00, 2.00), + ( 40000, 600.00, 3.90), + ( 75000, 795.00, 6.10), + ( 500000, 2930.00, 7.00), + (5000000, 32680.00, 9.90), + ( 'inf', 478180.00, 11.80), + ), + }, + 'B': { + 'weekly': ( + ( 385, 0.00, 1.50), + ( 962, 5.77, 2.00), + ( 1346, 17.31, 2.70), + ( 1538, 27.69, 3.90), + ( 2885, 35.19, 6.10), + ( 9615, 117.31, 7.00), + (96154, 588.46, 9.90), + ('inf', 9155.77, 11.80), + ), + 'bi-weekly': ( + ( 769, 0.00, 1.50), + ( 1923, 12.00, 2.00), + ( 2692, 35.00, 2.70), + ( 3076, 55.00, 3.90), + ( 5769, 70.00, 6.10), + ( 19231, 235.00, 7.00), + (192308, 1177.00, 9.90), + ( 'inf', 18312.00, 11.80), + ), + 'semi-monthly': ( + ( 833, 0.00, 1.50), + ( 2083, 12.50, 2.00), + ( 2917, 37.50, 2.70), + ( 3333, 59.99, 3.90), + ( 6250, 76.25, 6.10), + ( 20833, 254.19, 7.00), + (208333, 1275.00, 9.90), + ( 'inf', 19838.00, 11.80), + ), + 'monthly': ( + ( 1667, 0.00, 1.50), + ( 4167, 25.00, 2.00), + ( 5833, 75.00, 2.70), + ( 6667, 120.00, 3.90), + ( 12500, 153.00, 6.10), + ( 41667, 508.00, 7.00), + (416667, 2550.00, 9.90), + ( 'inf', 39675.00, 11.80), + ), + 'quarterly': ( + ( 5000, 0.00, 1.50), + ( 12500, 75.00, 2.00), + ( 17500, 225.00, 2.70), + ( 20000, 360.00, 3.90), + ( 37500, 397.50, 6.10), + ( 125000, 1525.00, 7.00), + (1250000, 7650.00, 9.90), + ( 'inf', 119025.00, 11.80), + ), + 'semi-annual': ( + ( 10000, 0.00, 1.50), + ( 25000, 150.00, 2.00), + ( 35000, 450.00, 2.70), + ( 40000, 720.00, 3.90), + ( 75000, 915.00, 6.10), + ( 250000, 3050.00, 7.00), + (2500000, 15300.00, 9.90), + ( 'inf', 238050.00, 11.80), + ), + 'annual': ( + ( 20000, 0.00, 1.50), + ( 50000, 300.00, 2.00), + ( 70000, 900.00, 2.70), + (80000, 1440.00, 3.90), + ( 150000, 1830.00, 6.10), + ( 500000, 6100.00, 7.00), + (5000000, 30600.00, 9.90), + ( 'inf', 476100.00, 11.80), + ), + }, + 'C': { + 'weekly': ( + ( 385, 0.00, 1.50), + ( 769, 5.77, 2.30), + ( 962, 14.62, 2.80), + ( 1154, 20.00, 3.50), + ( 2885, 26.73, 5.60), + ( 9615, 123.65, 6.60), + (96154, 567.88, 9.90), + ('inf', 9135.19, 11.80), + ), + 'bi-weekly': ( + ( 769, 0.00, 1.50), + ( 1538, 11.54, 2.30), + ( 1923, 29.23, 2.80), + ( 2308, 40.00, 3.50), + ( 5769, 53.46, 5.60), + ( 19231, 247.31, 6.60), + (192308, 1135.77, 9.90), + ( 'inf', 18270.38, 11.80), + ), + 'semi-monthly': ( + ( 833, 0.00, 1.50), + ( 1667, 12.50, 2.30), + ( 2083, 31.67, 2.80), + ( 2500, 43.33, 3.50), + ( 6250, 57.92, 5.60), + ( 20833, 267.92, 6.60), + (208333, 1230.42, 9.90), + ( 'inf', 19792.92, 11.80), + ), + 'monthly': ( + ( 1667, 0.00, 1.50), + ( 3333, 25.00, 2.30), + ( 4167, 63.33, 2.80), + ( 5000, 86.67, 3.50), + ( 12500, 115.83, 5.60), + ( 41667, 535.85, 6.60), + (416667, 2460.83, 9.90), + ( 'inf', 39585.83, 11.80), + ), + 'quarterly': ( + ( 5000, 0.00, 1.50), + ( 10000, 75.00, 2.30), + ( 12500, 190.00, 2.80), + ( 15000, 260.00, 3.50), + ( 37500, 347.50, 5.60), + ( 125000, 1607.50, 6.60), + (1250000, 7382.50, 9.90), + ( 'inf', 118757.50, 11.80), + ), + 'semi-annual': ( + ( 10000, 0.00, 1.50), + ( 20000, 150.00, 2.30), + ( 25000, 380.00, 2.80), + ( 30000, 520.00, 3.50), + ( 75000, 695.00, 5.60), + ( 250000, 3215.00, 6.60), + (2500000, 14765.00, 9.90), + ( 'inf', 237515.00, 11.80), + ), + 'annual': ( + ( 20000, 0.00, 1.50), + ( 40000, 300.00, 2.30), + ( 50000, 760.00, 2.80), + ( 60000, 1040.00, 3.50), + ( 150000, 1390.00, 5.60), + ( 500000, 6430.00, 6.60), + (5000000, 29530.00, 9.90), + ( 'inf', 475030.00, 11.80), + ), + }, + 'D': { + 'weekly': ( + ( 385, 0.00, 1.50), + ( 769, 5.77, 2.70), + ( 962, 16.15, 3.40), + ( 1154, 22.69, 4.30), + ( 2885, 30.96, 5.60), + ( 9615, 127.88, 6.50), + ( 96154, 565.38, 9.90), + ( 'inf', 9132.69, 11.80), + ), + 'bi-weekly': ( + ( 769, 0.00, 1.50), + ( 1538, 11.54, 2.70), + ( 1923, 32.31, 3.40), + ( 2308, 45.38, 4.30), + ( 5769, 61.92, 5.60), + ( 19231, 255.77, 6.50), + (192308, 1130.77, 9.90), + ( 'inf', 18265.38, 11.80), + ), + 'semi-monthly': ( + ( 833, 0.00, 1.50), + ( 1667, 12.50, 2.70), + ( 2083, 35.00, 3.40), + ( 2500, 49.17, 4.30), + ( 6250, 67.08, 5.60), + ( 20833, 277.08, 6.50), + (208333, 1225.00, 9.90), + ( 'inf', 19787.50, 11.80), + ), + 'monthly': ( + ( 1667, 0.00, 1.50), + ( 3333, 25.00, 2.70), + ( 4167, 70.00, 3.40), + ( 5000, 98.33, 4.00), + ( 12500, 134.17, 5.60), + ( 41667, 554.17, 6.50), + (416667, 2450.00, 9.90), + ( 'inf', 39575.00, 11.80), + ), + 'quarterly': ( + ( 5000, 0.00, 1.50), + ( 10000, 75.00, 2.07), + ( 12500, 210.00, 3.40), + ( 15000, 295.00, 4.30), + ( 37500, 402.50, 5.60), + ( 125000, 1662.50, 6.50), + (1250000, 7350.00, 9.90), + ( 'inf', 118725.00, 11.80), + ), + 'semi-annual': ( + ( 10000, 0.00, 1.50), + ( 20000, 150.00, 2.70), + ( 25000, 420.00, 3.40), + ( 30000, 590.00, 4.30), + ( 75000, 805.00, 5.60), + ( 250000, 3325.00, 6.50), + (2500000, 14700.00, 9.90), + ( 'inf', 237450.00, 11.80), + ), + 'annual': ( + ( 20000, 0.00, 1.50), + ( 40000, 300.00, 2.70), + ( 50000, 840.00, 3.40), + ( 60000, 1180.00, 4.30), + ( 150000, 1610.00, 5.60), + ( 250000, 6650.00, 6.50), + (2500000, 29400.00, 9.90), + ( 'inf', 474900.00, 11.80), + ), + }, + 'E': { + 'weekly': ( + ( 385, 0.00, 1.50), + ( 673, 5.77, 2.00), + ( 1923, 11.54, 5.80), + ( 9615, 84.04, 6.50), + ( 96154, 584.04, 9.90), + ( 'inf', 9151.35, 11.80), + ), + 'bi-weekly': ( + ( 769, 0.00, 1.50), + ( 1346, 12.00, 2.00), + ( 3846, 23.00, 5.80), + ( 19231, 168.00, 6.50), + (192308, 1168.00, 9.90), + ( 'inf', 18303.00, 11.80), + ), + 'semi-monthly': ( + ( 833, 0.00, 1.50), + ( 1458, 13.00, 2.00), + ( 4167, 25.00, 5.80), + ( 20833, 182.00, 6.50), + (208333, 1265.00, 9.90), + ( 'inf', 19828.00, 11.80), + ), + 'monthly': ( + ( 1667, 0.00, 1.50), + ( 2916, 25.00, 2.00), + ( 8333, 50.00, 5.80), + ( 41667, 364.00, 6.50), + (416667, 2531.00, 9.90), + ( 'inf', 39656.00, 11.80), + ), + 'quarterly': ( + ( 5000, 0.00, 1.50), + ( 8750, 75.00, 2.00), + ( 25000, 150.00, 5.80), + ( 125000, 1092.50, 6.50), + (1250000, 7592.50, 9.90), + ( 'inf', 118967.50, 11.80), + ), + 'semi-annual': ( + ( 10000, 0.00, 1.50), + ( 17500, 150.00, 2.00), + ( 50000, 300.00, 5.80), + ( 250000, 2185.00, 6.50), + (2500000, 15185.00, 9.90), + ( 'inf', 237935.00, 11.80), + ), + 'annual': ( + ( 20000, 0.00, 1.50), + ( 35000, 300.00, 2.00), + ( 100000, 600.00, 5.80), + ( 500000, 4370.00, 6.50), + (5000000, 30370.00, 9.90), + ( 'inf', 475870.00, 11.80), + ), + }, + } + + + + + + + US NJ NewJersey SIT Allowance Rate + us_nj_sit_allowance_rate + { + 'weekly': 19.20, + 'bi-weekly': 38.40, + 'semi-monthly': 41.60, + 'monthly': 83.30, + 'quarterly': 250.00, + 'semi-annual': 500.00, + 'annual': 1000.00, + 'daily or miscellaneous': 2.70, + } + + + + + US NJ NewJersey SIT Allowance Rate + us_nj_sit_allowance_rate + { + 'weekly': 19.20, + 'bi-weekly': 38.40, + 'semi-monthly': 41.60, + 'monthly': 83.30, + 'quarterly': 250.00, + 'semi-annual': 500.00, + 'annual': 1000.00, + 'daily or miscellaneous': 2.70, + } + + + + + + + US New Jersey - Division of Taxation - Unemployment Tax + + + + US New Jersey - Division of Taxation - Income Tax + + + + US New Jersey - Division of Taxation - Unemployment Tax + + + + + US New Jersey - Division of Taxation - Income Tax + + + + + + + + + ER: US NJ New Jersey State Unemployment + ER_US_NJ_SUTA + python + result, _ = general_state_unemployment(payslip, categories, worked_days, inputs, wage_base='us_nj_suta_wage_base', rate='us_nj_suta_rate', state_code='NJ') + code + result, result_rate = general_state_unemployment(payslip, categories, worked_days, inputs, wage_base='us_nj_suta_wage_base', rate='us_nj_suta_rate', state_code='NJ') + + + + + + + + EE: US NJ New Jersey State Unemployment + EE_US_NJ_SUTA + python + result, _ = general_state_unemployment(payslip, categories, worked_days, inputs, wage_base='us_nj_suta_wage_base', rate='us_nj_suta_ee_rate', state_code='NJ') + code + result, result_rate = general_state_unemployment(payslip, categories, worked_days, inputs, wage_base='us_nj_suta_wage_base', rate='us_nj_suta_ee_rate', state_code='NJ') + + + + + + + + + ER: US NJ New Jersey State Disability Insurance + ER_US_NJ_SDI + python + result, _ = general_state_unemployment(payslip, categories, worked_days, inputs, wage_base='us_nj_suta_wage_base', rate='us_nj_sdi_rate', state_code='NJ') + code + result, result_rate = general_state_unemployment(payslip, categories, worked_days, inputs, wage_base='us_nj_suta_wage_base', rate='us_nj_sdi_rate', state_code='NJ') + + + + + + + + EE: US NJ New Jersey State Disability Insurance + EE_US_NJ_SDI + python + result, _ = general_state_unemployment(payslip, categories, worked_days, inputs, wage_base='us_nj_suta_wage_base', rate='us_nj_sdi_ee_rate', state_code='NJ') + code + result, result_rate = general_state_unemployment(payslip, categories, worked_days, inputs, wage_base='us_nj_suta_wage_base', rate='us_nj_sdi_ee_rate', state_code='NJ') + + + + + + + + + ER: US NJ New Jersey Workforce Development + ER_US_NJ_WF + python + result, _ = general_state_unemployment(payslip, categories, worked_days, inputs, wage_base='us_nj_suta_wage_base', rate='us_nj_wf_rate', state_code='NJ') + code + result, result_rate = general_state_unemployment(payslip, categories, worked_days, inputs, wage_base='us_nj_suta_wage_base', rate='us_nj_wf_rate', state_code='NJ') + + + + + + + + EE: US NJ New Jersey Workforce Development + EE_US_NJ_WF + python + result, _ = general_state_unemployment(payslip, categories, worked_days, inputs, wage_base='us_nj_suta_wage_base', rate='us_nj_wf_ee_rate', state_code='NJ') + code + result, result_rate = general_state_unemployment(payslip, categories, worked_days, inputs, wage_base='us_nj_suta_wage_base', rate='us_nj_wf_ee_rate', state_code='NJ') + + + + + + + + + ER: US NJ New Jersey Family Leave Insurance + ER_US_NJ_FLI + python + result, _ = general_state_unemployment(payslip, categories, worked_days, inputs, wage_base='us_nj_suta_wage_base', rate='us_nj_fli_rate', state_code='NJ') + code + result, result_rate = general_state_unemployment(payslip, categories, worked_days, inputs, wage_base='us_nj_suta_wage_base', rate='us_nj_fli_rate', state_code='NJ') + + + + + + + + EE: US NJ New Jersey Family Leave Insurance + EE_US_NJ_FLI + python + result, _ = general_state_unemployment(payslip, categories, worked_days, inputs, wage_base='us_nj_suta_wage_base', rate='us_nj_fli_ee_rate', state_code='NJ') + code + result, result_rate = general_state_unemployment(payslip, categories, worked_days, inputs, wage_base='us_nj_suta_wage_base', rate='us_nj_fli_ee_rate', state_code='NJ') + + + + + + + + EE: US NJ New Jersey State Income Tax Withholding + EE_US_NJ_SIT + python + result, _ = nj_newjersey_state_income_withholding(payslip, categories, worked_days, inputs) + code + result, result_rate = nj_newjersey_state_income_withholding(payslip, categories, worked_days, inputs) + + + + + \ No newline at end of file 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..9a8238f7 --- /dev/null +++ b/l10n_us_hr_payroll/data/state/nm_new_mexico.xml @@ -0,0 +1,297 @@ + + + + + + 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 Workforce Solutions - Unemployment Tax + + + + + US New Mexico - Department of Taxation and Revenue - Income Tax + + + US New Mexico - Department of Taxation and Revenue - Unemployment 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/data/state/nv_nevada.xml b/l10n_us_hr_payroll/data/state/nv_nevada.xml new file mode 100644 index 00000000..59022d7c --- /dev/null +++ b/l10n_us_hr_payroll/data/state/nv_nevada.xml @@ -0,0 +1,49 @@ + + + + + + US NV Nevada SUTA Wage Base + us_nv_suta_wage_base + 32500.00 + + + + + + + + US NV Nevada SUTA Rate + us_nv_suta_rate + 2.95 + + + + + + + US Nevada - Department of Employment, Training, and Rehabilitation, Employment Security Division - Unemployment Tax + 1 + + + US Nevada - Department of Employment, Training, and Rehabilitation, Employment Security Division - Unemployment Tax + + + + + + + + + + ER: US NV Nevada State Unemployment (RT-6) + ER_US_NV_SUTA + python + result, _ = general_state_unemployment(payslip, categories, worked_days, inputs, wage_base='us_nv_suta_wage_base', rate='us_nv_suta_rate', state_code='NV') + code + result, result_rate = general_state_unemployment(payslip, categories, worked_days, inputs, wage_base='us_nv_suta_wage_base', rate='us_nv_suta_rate', state_code='NV') + + + + + \ No newline at end of file diff --git a/l10n_us_hr_payroll/data/state/ny_new_york.xml b/l10n_us_hr_payroll/data/state/ny_new_york.xml new file mode 100644 index 00000000..73010b8b --- /dev/null +++ b/l10n_us_hr_payroll/data/state/ny_new_york.xml @@ -0,0 +1,420 @@ + + + + + + US NY New York SUTA Wage Base + us_ny_suta_wage_base + 11400.0 + + + + US NY New York SUTA Wage Base + us_ny_suta_wage_base + 11600.0 + + + + + + + + US NY New York SUTA Rate + us_ny_suta_rate + 2.5 + + + + US NY New York SUTA Rate + us_ny_suta_rate + 2.5 + + + + + + + US NY New York SUTA RSF Rate + us_ny_suta_rsf_rate + 0.075 + + + + US NY New York SUTA RSF Rate + us_ny_suta_rsf_rate + 0.075 + + + + + + + US NY New York SUTA MCTMT Rate + us_ny_suta_mctmt_rate + 0.0 + + + + US NY New York SUTA MCTMT Rate + us_ny_suta_mctmt_rate + 0.0 + + + + + + + US NY New York SIT Tax Rate + us_ny_sit_tax_rate + { + 'single': { + 'weekly': ((163, 0.0400, 0.0), (225, 0.0450, 6.54), (267, 0.0525, 9.31), (412, 0.0590, 11.54), (1551, 0.0633, 20.04), (1862, 0.0657, 92.17), (2070, 0.0758, 112.58), (3032, 0.0808, 128.38), (4142, 0.0707, 206.08), (5104, 0.0856, 284.60), (20722, 0.0735, 366.90), (21684, 0.5208, 1514.85), ('inf', 0.0962, 2015.62)), + 'bi-weekly': ((327, 0.0400, 0.0), (450, 0.0450, 13.08), (535, 0.0525, 18.62), (823, 0.0590, 23.08), (3102, 0.0633, 40.08), (3723, 0.0657, 184.35), (4140, 0.0758, 225.15), (6063, 0.0808, 256.77), (8285, 0.0707, 412.15), (10208, 0.0856, 569.19), (41444, 0.0735, 733.81), (43367, 0.5208, 3029.69), ('inf', 0.0962, 4021.23)), + 'semi-monthly': ((354, 0.0400, 0.0), (488, 0.0450, 14.17), (579, 0.0525, 20.17), (892, 0.0590, 25.00), (3360, 0.0633, 43.42), (4033, 0.0657, 199.71), (4485, 0.0758, 243.92), (6569, 0.0808, 278.17), (8975, 0.0707, 446.50), (11058, 0.0856, 616.63), (44898, 0.0735, 794.96), (46981, 0.5208, 3282.17), ('inf', 0.0962, 4367.17)), + 'monthly': ((708, 0.0400, 0.0), (975, 0.0450, 28.33), (1158, 0.0525, 40.33), (1783, 0.0590, 50.00), (6721, 0.0633, 86.83), (8067, 0.0657, 399.42), (8971, 0.0758, 487.83), (13138, 0.0808, 556.33), (17950, 0.0707, 893.00), (22117, 0.0856, 1233.25), (89796, 0.0735, 1589.92), (93963, 0.5208, 6564.33), ('inf', 0.0962, 8734.33)), + 'annually': ((8500, 0.0400, 0.0), (11700, 0.0450, 340.00), (13900, 0.0525, 484.00), (21400, 0.0590, 600.00), (80650, 0.0633, 1042.00), (96800, 0.0657, 4793.00), (107650, 0.0758, 5854.00), (157650, 0.0808, 6676.00), (215400, 0.0707, 10716.00), (265400, 0.0856, 14799.00), (1077550, 0.0735, 19079.00), (1127550, 0.5208, 78772.00), ('inf', 0.0962, 104812.00)), + }, + 'married': { + 'weekly': ((163, 0.0400, 0.0), (225, 0.0450, 6.54), (267, 0.0525, 9.31), (412, 0.0590, 11.54), (1551, 0.0633, 20.04), (1862, 0.0657, 92.17), (2070, 0.0783, 112.58), (3032, 0.0833, 128.90), (4068, 0.0785, 209.00), (6215, 0.0707, 290.37), (7177, 0.0916, 442.17), (20722, 0.0735, 530.25), (41449, 0.0765, 1525.83), (42411, 0.9454, 3111.42), ('inf', 0.0962, 4020.46)), + 'bi-weekly': ((327, 0.0400, 0.0), (450, 0.0450, 13.08), (535, 0.0525, 18.62), (823, 0.0590, 23.08), (3102, 0.0633, 40.08), (3723, 0.0657, 184.35), (4140, 0.0783, 225.15), (6063, 0.0833, 257.81), (8137, 0.0785, 418.00), (12431, 0.0707, 580.73), (14354, 0.0916, 884.35), (41444, 0.0735, 1060.50), (82898, 0.0765, 3051.65), (84821, 0.9454, 6222.85), ('inf', 0.0962, 8040.92)), + 'semi-monthly': ((354, 0.0400, 0.0), (488, 0.0450, 14.17), (579, 0.0525, 20.17), (892, 0.0590, 25.00), (3360, 0.0633, 43.42), (4033, 0.0657, 199.71), (4485, 0.0783, 243.92), (6569, 0.0833, 279.29), (8815, 0.0785, 452.83), (13476, 0.0707, 629.13), (15550, 0.0916, 958.04), (44898, 0.0735, 1148.88), (89806, 0.0765, 3305.96), (91890, 0.9454, 6741.42), ('inf', 0.0962, 8711.00)), + 'monthly': ((708, 0.0400, 0.0), (975, 0.0450, 28.33), (1158, 0.0525, 40.33), (1783, 0.0590, 50.00), (6721, 0.0633, 86.83), (8067, 0.0657, 399.42), (8971, 0.0783, 487.83), (13138, 0.0833, 558.58), (17629, 0.0785, 905.67), (26933, 0.0707, 1258.25), (31100, 0.0916, 1916.08), (89796, 0.0735, 2297.75), (179613, 0.0765, 6611.92), (183779, 0.9454, 13482.83), ('inf', 0.0962, 17422.00)), + 'annually': ((8500, 0.0400, 0.0), (11700, 0.0450, 340.00), (13900, 0.0525, 484.00), (21400, 0.0590, 600.00), (80650, 0.0633, 1042.00), (96800, 0.0657, 4793.00), (107650, 0.0783, 5854.00), (157650, 0.0833, 6703.00), (211550, 0.0785, 10868.00), (323200, 0.0707, 15099.00), (373200, 0.0916, 22993.00), (1077550, 0.0735, 27573.00), (2155350, 0.0765, 79343.00), (2205350, 0.9454, 161794.00), ('inf', 0.0962, 209064.00)), + } + } + + + + US NY New York SIT Tax Rate + us_ny_sit_tax_rate + { + 'single': { + 'weekly': ( + ( 163, 0.0400, 0.00), + ( 225, 0.0450, 6.54), + ( 267, 0.0525, 9.31), + ( 412, 0.0590, 11.54), + ( 1551, 0.0609, 20.04), + ( 1862, 0.0641, 89.42), + ( 2070, 0.0745, 109.35), + ( 3032, 0.0795, 124.88), + ( 4142, 0.0691, 201.33), + ( 5104, 0.0925, 278.06), + (20722, 0.0735, 367.00), + (21684, 0.5208, 1514.94), + ('inf', 0.0962, 2015.71), + ), + 'bi-weekly': ( + ( 327, 0.0400, 0.00), + ( 450, 0.0450, 13.08), + ( 535, 0.0525, 18.62), + ( 823, 0.0590, 23.08), + ( 3102, 0.0609, 40.08), + ( 3723, 0.0641, 178.85), + ( 4140, 0.0745, 218.69), + ( 6063, 0.0795, 249.77), + ( 8285, 0.0691, 402.65), + (10208, 0.0925, 556.12), + (41444, 0.0735, 734.00), + (43367, 0.5208, 3029.88), + ('inf', 0.0962, 4031.42), + ), + 'semi-monthly': ( + ( 354, 0.0400, 0.00), + ( 488, 0.0450, 14.17), + ( 579, 0.0525, 20.17), + ( 892, 0.0590, 25.00), + ( 3360, 0.0609, 43.42), + ( 4033, 0.0641, 193.75), + ( 4485, 0.0745, 236.92), + ( 6569, 0.0795, 270.58), + ( 8975, 0.0691, 436.21), + (11058, 0.0925, 602.46), + (44898, 0.0735, 795.17), + (46981, 0.5208, 3282.38), + ('inf', 0.0962, 4367.38), + ), + 'monthly': ( + ( 708, 0.0400, 0.00), + ( 975, 0.0450, 28.33), + ( 1158, 0.0525, 40.33), + ( 1783, 0.0590, 50.00), + ( 6721, 0.0609, 86.83), + ( 8067, 0.0641, 387.50), + ( 8971, 0.0745, 473.83), + (13138, 0.0795, 541.17), + (17950, 0.0691, 872.42), + (22117, 0.0925, 1204.92), + (89796, 0.0735, 1590.33), + (93963, 0.5208, 6564.75), + ('inf', 0.0962, 8734.75), + ), + 'annually': ( + ( 8500, 0.0400, 0.00), + ( 11700, 0.0450, 340.00), + ( 13900, 0.0525, 484.00), + ( 21400, 0.0590, 600.00), + ( 80650, 0.0609, 1042.00), + ( 96800, 0.0641, 4650.00), + ( 107650, 0.0745, 5686.00), + ( 157650, 0.0795, 6494.00), + ( 215400, 0.0691, 10469.00), + ( 265400, 0.0925, 14459.00), + (1077550, 0.0735, 19084.00), + (1127550, 0.5208, 78777.00), + ( 'inf', 0.0962, 104817.00), + ), + }, + 'married': { + 'weekly': ( + ( 163, 0.0400, 0.00), + ( 225, 0.0450, 6.54), + ( 267, 0.0525, 9.31), + ( 412, 0.0590, 11.54), + ( 1551, 0.0609, 20.04), + ( 1862, 0.0641, 89.42), + ( 2070, 0.0746, 109.35), + ( 3032, 0.0796, 124.90), + ( 4068, 0.0794, 201.44), + ( 6215, 0.0691, 283.75), + ( 7177, 0.1019, 432.12), + (20722, 0.0735, 530.10), + (41449, 0.0765, 1525.65), + (42411, 0.9454, 3111.27), + ('inf', 0.0962, 4020.31), + ), + 'bi-weekly': ( + ( 327, 0.0400, 0.00), + ( 450, 0.0450, 13.08), + ( 535, 0.0525, 18.62), + ( 823, 0.0590, 23.08), + ( 3102, 0.0609, 40.08), + ( 3723, 0.0641, 178.85), + ( 4140, 0.0746, 218.69), + ( 6063, 0.0796, 249.81), + ( 8137, 0.0794, 402.88), + (12431, 0.0691, 567.50), + (14354, 0.1019, 864.23), + (41444, 0.0735, 1060.19), + (82898, 0.0765, 3051.31), + (84821, 0.9454, 6222.54), + ('inf', 0.0962, 8040.62), + ), + 'semi-monthly': ( + ( 354, 0.0400, 0.00), + ( 488, 0.0450, 14.17), + ( 579, 0.0525, 20.17), + ( 892, 0.0590, 25.00), + ( 3360, 0.0609, 43.42), + ( 4033, 0.0641, 193.75), + ( 4485, 0.0746, 236.92), + ( 6569, 0.0796, 270.63), + ( 8815, 0.0794, 436.46), + (13467, 0.0691, 614.79), + (15550, 0.1019, 936.25), + (44898, 0.0735, 1148.54), + (89806, 0.0765, 3305.58), + (91890, 0.9454, 6741.08), + ('inf', 0.0962, 8710.67), + ), + 'monthly': ( + ( 708, 0.0400, 0.00), + ( 975, 0.0450, 28.33), + ( 1158, 0.0525, 40.33), + ( 1783, 0.0590, 50.00), + ( 6721, 0.0609, 86.83), + ( 8067, 0.0641, 387.50), + ( 8971, 0.0746, 473.83), + ( 13138, 0.0796, 541.25), + ( 17629, 0.0794, 872.92), + ( 26933, 0.0691, 1229.58), + ( 31100, 0.1019, 1872.50), + ( 89796, 0.0735, 2297.08), + (179613, 0.0765, 6611.17), + (183779, 0.9454, 13482.17), + ( 'inf', 0.0962, 17421.33), + ), + 'annually': ( + ( 8500, 0.0400, 0.00), + ( 11700, 0.0450, 340.00), + ( 13900, 0.0525, 484.00), + ( 21400, 0.0590, 600.00), + ( 80650, 0.0609, 1042.00), + ( 96800, 0.0641, 4650.00), + ( 107650, 0.0746, 5686.00), + ( 157650, 0.0796, 6495.00), + ( 211550, 0.0794, 10475.00), + ( 323200, 0.0691, 14755.00), + ( 373200, 0.1019, 22470.00), + (1077550, 0.0735, 27565.00), + (2155350, 0.0765, 79334.00), + (2205350, 0.9454, 161786.00), + ( 'inf', 0.0962, 209056.00), + ), + }, + } + + + + + + + US NY New York Over 10 Exemption Rate + us_ny_sit_over_10_exemption_rate + { + 'weekly': (142.30, 152.90, 19.25), + 'bi-weekly': (284.60, 305.80, 38.50), + 'semi-monthly': (308.35, 331.25, 41.65), + 'monthly': (616.70, 662.50, 83.30), + 'annual': (7400, 7950, 1000), + } + + + + US NY New York Over 10 Exemption Rate + us_ny_sit_over_10_exemption_rate + { + 'weekly': (142.30, 152.90, 19.25), + 'bi-weekly': (284.60, 305.80, 38.50), + 'semi-monthly': (308.35, 331.25, 41.65), + 'monthly': (616.70, 662.50, 83.30), + 'annual': (7400, 7950, 1000), + } + + + + + + + US NY New York Deduction Exemption Rate + us_ny_sit_deduction_exemption_rate + { + 'single': { + 'weekly': (142.30, 161.55, 180.80, 200.05, 219.30, 238.55, 257.80, 277.05, 296.30, 315.55, 334.80), + 'bi-weekly': (284.60, 323.10, 361.60, 400.10, 438.60, 477.10, 515.60, 544.10, 592.60, 631.10, 669.60), + 'semi-monthly': (308.35, 350.0, 391.65, 433.30, 474.95, 516.60, 558.25, 599.90, 641.55, 683.20, 724.85), + 'monthly': (616.70, 700, 783.30, 866.60, 949.90, 1033.20, 1116.50, 1199.80, 1283.10, 1366.40, 1449.70), + 'annually': (7400, 8400, 9400, 10400, 11400, 12400, 13400, 14400, 15400, 16400, 17400), + }, + 'married': { + 'weekly': (152.90, 172.15, 191.40, 210.65, 229.90, 249.15, 268.40, 287.65, 306.90, 326.15, 345.40), + 'bi-weekly': (305.80, 344.30, 382.80, 421.30, 459.80, 498.30, 536.80, 575.30, 613.80, 652.30, 690.80), + 'semi-monthly': (331.25, 372.90, 414.55, 456.20, 497.85, 539.50, 581.15, 622.80, 664.45, 706.10, 747.75), + 'monthly': (662.50, 745.80, 829.10, 912.40, 995.70, 1079.00, 1162.30, 1245.60, 1328.90, 1412.20, 1495.50), + 'annually': (7950, 8950, 9950, 10950, 11950, 12950, 13950, 14950, 15950, 16950, 17950), + }, + } + + + + US NY New York Deduction Exemption Rate + us_ny_sit_deduction_exemption_rate + { + 'single': { + 'weekly': (142.30, 161.55, 180.80, 200.05, 219.30, 238.55, 257.80, 277.05, 296.30, 315.55, 334.80), + 'bi-weekly': (284.60, 323.10, 361.60, 400.10, 438.60, 477.10, 515.60, 544.10, 592.60, 631.10, 669.60), + 'semi-monthly': (308.35, 350.0, 391.65, 433.30, 474.95, 516.60, 558.25, 599.90, 641.55, 683.20, 724.85), + 'monthly': (616.70, 700, 783.30, 866.60, 949.90, 1033.20, 1116.50, 1199.80, 1283.10, 1366.40, 1449.70), + 'annually': (7400, 8400, 9400, 10400, 11400, 12400, 13400, 14400, 15400, 16400, 17400), + }, + 'married': { + 'weekly': (152.90, 172.15, 191.40, 210.65, 229.90, 249.15, 268.40, 287.65, 306.90, 326.15, 345.40), + 'bi-weekly': (305.80, 344.30, 382.80, 421.30, 459.80, 498.30, 536.80, 575.30, 613.80, 652.30, 690.80), + 'semi-monthly': (331.25, 372.90, 414.55, 456.20, 497.85, 539.50, 581.15, 622.80, 664.45, 706.10, 747.75), + 'monthly': (662.50, 745.80, 829.10, 912.40, 995.70, 1079.00, 1162.30, 1245.60, 1328.90, 1412.20, 1495.50), + 'annually': (7950, 8950, 9950, 10950, 11950, 12950, 13950, 14950, 15950, 16950, 17950), + }, + } + + + + + + + US New York - Department of Taxation and Finance - Unemployment Tax + + + US New York - Department of Taxation and Finance - Unemployment Tax + + + + + US New York - Department of Taxation and Finance - Re-employment Service Fund + + + US New York - Department of Taxation and Finance - Re-employment Service Fund + + + + + US New York - Department of Taxation and Finance - Metropolitan Commuter Transportation Mobility Tax + + + US New York - Department of Taxation and Finance - Metropolitan Commuter Transportation Mobility Tax + + + + + US New York - Department of Taxation and Finance - Income Tax + + + US New York - Department of Taxation and Finance - Income Tax + + + + + + + + + + ER: US NY New York State Unemployment + ER_US_NY_SUTA + python + result, _ = general_state_unemployment(payslip, categories, worked_days, inputs, wage_base='us_ny_suta_wage_base', rate='us_ny_suta_rate', state_code='NY') + code + result, result_rate = general_state_unemployment(payslip, categories, worked_days, inputs, wage_base='us_ny_suta_wage_base', rate='us_ny_suta_rate', state_code='NY') + + + + + + + + ER: US NY New York State Re-employment Service Fund + ER_US_NY_SUTA_RSF + python + result, _ = general_state_unemployment(payslip, categories, worked_days, inputs, wage_base='us_ny_suta_wage_base', rate='us_ny_suta_rsf_rate', state_code='NY') + code + result, result_rate = general_state_unemployment(payslip, categories, worked_days, inputs, wage_base='us_ny_suta_wage_base', rate='us_ny_suta_rsf_rate', state_code='NY') + + + + + + + + ER: US NY New York State Metropolitan Commuter Transportation Mobility Tax + ER_US_NY_SUTA_MCTMT + python + result, _ = general_state_unemployment(payslip, categories, worked_days, inputs, wage_base='us_ny_suta_wage_base', rate='us_ny_suta_mctmt_rate', state_code='NY') + code + result, result_rate = general_state_unemployment(payslip, categories, worked_days, inputs, wage_base='us_ny_suta_wage_base', rate='us_ny_suta_mctmt_rate', state_code='NY') + + + + + + + + EE: US NY New York State Income Tax Withholding + EE_US_NY_SIT + python + result, _ = ny_new_york_state_income_withholding(payslip, categories, worked_days, inputs) + code + result, result_rate = ny_new_york_state_income_withholding(payslip, categories, worked_days, inputs) + + + + + diff --git a/l10n_us_hr_payroll/data/state/ok_oklahoma.xml b/l10n_us_hr_payroll/data/state/ok_oklahoma.xml new file mode 100644 index 00000000..86deb82d --- /dev/null +++ b/l10n_us_hr_payroll/data/state/ok_oklahoma.xml @@ -0,0 +1,294 @@ + + + + + + US OK Oklahoma SUTA Wage Base + us_ok_suta_wage_base + 18700.0 + + + + + + + + US OK Oklahoma SUTA Rate + us_ok_suta_rate + 1.5 + + + + + + + US OK Oklahoma Allowances Rate + us_ok_sit_allowances_rate + { + 'weekly' : 19.23, + 'bi-weekly' : 38.46, + 'semi-monthly': 41.67, + 'monthly' : 83.33, + 'quarterly' : 250.00, + 'semi-annual': 500.00, + 'annually': 1000.00, + } + + + + + + + + US OK Oklahoma SIT Tax Rate + us_ok_sit_tax_rate + { + 'single': { + 'weekly': ( + ( 122, 0.00, 0.00), + ( 141, 0.50, 0.00), + ( 170, 1.00, 0.10), + ( 194, 2.00, 0.38), + ( 216, 3.00, 0.87), + ( 261, 4.00, 1.53), + ('inf', 5.00, 3.30), + ), + 'bi-weekly': ( + ( 244, 0.00, 0.00), + ( 283, 0.50, 0.00), + ( 340, 1.00, 0.19), + ( 388, 2.00, 0.77), + ( 433, 3.00, 1.73), + ( 521, 4.00, 3.06), + ('inf', 5.00, 6.60), + ), + 'semi-monthly': ( + ( 265, 0.00, 0.00), + ( 306, 0.50, 0.00), + ( 369, 1.00, 0.21), + ( 421, 2.00, 0.83), + ( 469, 3.00, 1.88), + ( 565, 4.00, 3.31), + ('inf', 5.00, 7.15), + ), + 'monthly': ( + ( 529, 0.00, 0.00), + ( 613, 0.50, 0.00), + ( 738, 1.00, 0.42), + ( 842, 2.00, 1.67), + ( 938, 3.00, 3.75), + (1129, 4.00, 6.63), + ('inf', 5.00, 14.29), + ), + 'quarterly': ( + ( 1588, 0.00, 0.00), + ( 1838, 0.50, 0.00), + ( 2213, 1.00, 1.25), + ( 2525, 2.00, 5.00), + ( 2813, 3.00, 11.25), + ( 3388, 4.00, 19.88), + ('inf', 5.00, 42.88), + ), + 'semi-annual': ( + ( 3175, 0.00, 0.00), + ( 3675, 0.50, 0.00), + ( 4425, 1.00, 2.50), + ( 5050, 2.00, 10.00), + (5625, 3.00, 22.50), + ( 6775, 4.00, 39.75), + ('inf', 5.00, 85.75), + ), + 'annually': ( + ( 6350, 0.00, 0.00), + ( 7350, 0.50, 0.00), + ( 8850, 1.00, 5.00), + (10100, 2.00, 20.00), + (11250, 3.00, 45.00), + (13550, 4.00, 79.50), + ('inf', 5.00, 171.50), + ), + }, + 'married': { + 'weekly': ( + ( 244, 0.00, 0.00), + ( 283, 0.50, 0.00), + ( 340, 1.00, 0.19), + ( 388, 2.00, 0.77), + ( 433, 3.00, 1.73), + ( 479, 4.00, 3.06), + ('inf', 5.00, 4.90), + ), + 'bi-weekly': ( + ( 488, 0.00, 0.00), + ( 565, 0.50, 0.00), + ( 681, 1.00, 0.38), + ( 777, 2.00, 1.54), + ( 865, 3.00, 3.46), + ( 958, 4.00, 6.12), + ('inf', 5.00, 9.81), + ), + 'semi-monthly': ( + ( 529, 0.00, 0.00), + ( 613, 0.50, 0.00), + ( 738, 1.00, 0.42), + ( 842, 2.00, 1.67), + ( 938, 3.00, 3.75), + ( 1038, 4.00, 6.63), + ('inf', 5.00, 10.63), + ), + 'monthly': ( + ( 1058, 0.00, 0.00), + ( 1225, 0.50, 0.00), + ( 1475, 1.00, 0.83), + ( 1683, 2.00, 3.33), + ( 1875, 3.00, 7.50), + ( 2075, 4.00, 13.25), + ('inf', 5.00, 21.25), + ), + 'quarterly': ( + ( 3175, 0.00, 0.00), + ( 3675, 0.50, 0.00), + ( 4425, 1.00, 2.50), + ( 5050, 2.00, 10.00), + ( 5625, 3.00, 22.50), + ( 6225, 4.00, 39.75), + ('inf', 5.00, 63.75), + ), + 'semi-annual': ( + ( 6350, 0.00, 0.00), + ( 7350, 0.50, 0.00), + ( 8850, 1.00, 5.00), + ( 10100, 2.00, 20.00), + ( 11250, 3.00, 45.00), + ( 12450, 4.00, 79.50), + ( 'inf', 5.00, 127.50), + ), + 'annually': ( + ( 12700, 0.00, 0.00), + ( 14700, 0.50, 0.00), + ( 17700, 1.00, 10.00), + ( 20200, 2.00, 40.00), + ( 22500, 3.00, 90.00), + ( 24900, 4.00, 159.00), + ( 'inf', 5.00, 255.00), + ), + }, + 'head_household': { + 'weekly': ( + ( 122, 0.00, 0.00), + ( 141, 0.50, 0.00), + ( 170, 1.00, 0.10), + ( 194, 2.00, 0.38), + ( 216, 3.00, 0.87), + ( 261, 4.00, 1.53), + ('inf', 5.00, 3.30), + ), + 'bi-weekly': ( + ( 244, 0.00, 0.00), + ( 283, 0.50, 0.00), + ( 340, 1.00, 0.19), + ( 388, 2.00, 0.77), + ( 433, 3.00, 1.73), + ( 521, 4.00, 3.06), + ('inf', 5.00, 6.60), + ), + 'semi-monthly': ( + ( 265, 0.00, 0.00), + ( 306, 0.50, 0.00), + ( 369, 1.00, 0.21), + ( 421, 2.00, 0.83), + ( 469, 3.00, 1.88), + ( 565, 4.00, 3.31), + ('inf', 5.00, 7.15), + ), + 'monthly': ( + ( 529, 0.00, 0.00), + ( 613, 0.50, 0.00), + ( 738, 1.00, 0.42), + ( 842, 2.00, 1.67), + ( 938, 3.00, 3.75), + ( 1129, 4.00, 6.63), + ('inf', 5.00, 14.29), + ), + 'quarterly': ( + ( 1588, 0.00, 0.00), + ( 1838, 0.50, 0.00), + ( 2213, 1.00, 1.25), + ( 2525, 2.00, 5.00), + ( 2813, 3.00, 11.25), + ( 3388, 4.00, 19.88), + ('inf', 5.00, 42.88), + ), + 'semi-annual': ( + ( 3175, 0.00, 0.00), + ( 3675, 0.50, 0.00), + ( 4425, 1.00, 2.50), + ( 5050, 2.00, 10.00), + ( 5625, 3.00, 22.50), + ( 6775, 4.00, 39.75), + ('inf', 5.00, 85.75), + ), + 'annually': ( + ( 6350, 0.00, 0.00), + ( 7350, 0.50, 0.00), + ( 8850, 1.00, 5.00), + (10100, 2.00, 20.00), + (11250, 3.00, 45.00), + (13550, 4.00, 79.50), + ('inf', 5.00, 171.50), + ), + }, + } + + + + + + + US Oklahoma - Employment Security Commission - Unemployment Tax + 1 + + + US Oklahoma - Employment Security Commission - Unemployment Tax + + + + + US Oklahoma - Tax Commission - Income Tax + 1 + + + US Oklahoma - Tax Commission - Income Tax + + + + + + + + + + ER: US OK Oklahoma State Unemployment + ER_US_OK_SUTA + python + result, _ = general_state_unemployment(payslip, categories, worked_days, inputs, wage_base='us_ok_suta_wage_base', rate='us_ok_suta_rate', state_code='OK') + code + result, result_rate = general_state_unemployment(payslip, categories, worked_days, inputs, wage_base='us_ok_suta_wage_base', rate='us_ok_suta_rate', state_code='OK') + + + + + + + + EE: US OK Oklahoma State Income Tax Withholding + EE_US_OK_SIT + python + result, _ = ok_oklahoma_state_income_withholding(payslip, categories, worked_days, inputs) + code + result, result_rate = ok_oklahoma_state_income_withholding(payslip, categories, worked_days, inputs) + + + + + \ No newline at end of file diff --git a/l10n_us_hr_payroll/data/state/ri_rhode_island.xml b/l10n_us_hr_payroll/data/state/ri_rhode_island.xml new file mode 100644 index 00000000..35b6041a --- /dev/null +++ b/l10n_us_hr_payroll/data/state/ri_rhode_island.xml @@ -0,0 +1,135 @@ + + + + + + US RI Rhode Island SUTA Wage Base + us_ri_suta_wage_base + 24000.0 + + + + + + + + US RI Rhode Island SUTA Rate + us_ri_suta_rate + 1.06 + + + + + + + + US RI Rhode Island Exemption Rate + us_ri_sit_exemption_rate + { + 'weekly' : (( 0.00, 19.23), ( 4451.92, 0.00)), + 'bi-weekly' : (( 0.00, 38.46), ( 8903.85, 0.00)), + 'semi-monthly': (( 0.00, 41.67), ( 9645.83, 0.00)), + 'monthly' : (( 0.00, 83.33), ( 19291.67, 0.00)), + 'quarterly' : (( 0.00, 250.00), ( 57875.00, 0.00)), + 'semi-annually': (( 0.00, 500.00), ( 115750.00, 0.00)), + 'annually': (( 0.00, 1000.0), ( 231500.00, 0000)), + } + + + + + + + US RI Rhode Island SIT Tax Rate + us_ri_sit_tax_rate + { + 'weekly': ( + ( 1255, 0.00, 3.75), + ( 2853, 47.06, 4.75), + ('inf', 122.97, 5.99), + ), + 'bi-weekly': ( + ( 2510, 0.00, 3.75), + ( 5706, 94.13, 4.75), + ('inf', 245.94, 5.99), + ), + 'semi-monthly': ( + ( 2719, 0.00, 3.75), + ( 6181, 101.96, 4.75), + ('inf', 266.41, 5.99), + ), + 'monthly': ( + ( 5438, 0.00, 3.75), + (12363, 203.93, 4.75), + ('inf', 532.87, 5.99), + ), + 'quarterly': ( + (16313, 0.00, 3.75), + (37088, 611.74, 4.75), + ('inf', 1598.55, 5.99), + ), + 'semi-annually': ( + (32625, 0.00, 3.75), + (74175, 1223.44, 4.75), + ('inf', 3197.07, 5.99), + ), + 'annually': ( + ( 65250, 0.00, 3.75), + (148350, 2446.88, 4.75), + ( 'inf', 6394.13, 5.99), + ), + } + + + + + + + US Rhode Island - Department of Labor and Training - Unemployment Tax + 1 + + + US Rhode Island - Department of Labor and Training - Unemployment Tax + + + + + US Rhode Island - Division of Taxations - Income Tax + 1 + + + US Rhode Island - Division of Taxations - Income Tax + + + + + + + + + + + ER: US RI Rhode Island State Unemployment + ER_US_RI_SUTA + python + result, _ = general_state_unemployment(payslip, categories, worked_days, inputs, wage_base='us_ri_suta_wage_base', rate='us_ri_suta_rate', state_code='RI') + code + result, result_rate = general_state_unemployment(payslip, categories, worked_days, inputs, wage_base='us_ri_suta_wage_base', rate='us_ri_suta_rate', state_code='RI') + + + + + + + + EE: US RI Rhode Island State Income Tax Withholding + EE_US_RI_SIT + python + result, _ = ri_rhode_island_state_income_withholding(payslip, categories, worked_days, inputs) + code + result, result_rate = ri_rhode_island_state_income_withholding(payslip, categories, worked_days, inputs) + + + + + \ No newline at end of file diff --git a/l10n_us_hr_payroll/data/state/sc_south_carolina.xml b/l10n_us_hr_payroll/data/state/sc_south_carolina.xml new file mode 100644 index 00000000..add7ed8d --- /dev/null +++ b/l10n_us_hr_payroll/data/state/sc_south_carolina.xml @@ -0,0 +1,146 @@ + + + + + + US SC South Carolina SUTA Wage Base + us_sc_suta_wage_base + 14000.0 + + + + US SC South Carolina SUTA Wage Base + us_sc_suta_wage_base + 14000.0 + + + + + + + + US SC South Carolina SUTA Rate + us_sc_suta_rate + 1.09 + + + + + US SC South Carolina SUTA Rate + us_sc_suta_rate + 0.55 + + + + + + + US SC South Carolina SIT Tax Rate + us_sc_sit_tax_rate + [ + ( 2450, 1.1, 0.0), + ( 4900, 3.0, 26.95), + ( 7350, 4.0, 100.45), + ( 9800, 5.0, 198.45), + (12250, 6.0, 320.95), + ('inf', 7.0, 467.95), + ] + + + + + US SC South Carolina SIT Tax Rate + us_sc_sit_tax_rate + [ + ( 2620, 0.8, 0.0), + ( 5240, 3.0, 57.64), + ( 7860, 4.0, 110.04), + (10490, 5.0, 188.64), + (13110, 6.0, 293.54), + ('inf', 7.0, 424.64), + ] + + + + + + + US SC South Carolina Personal Exemption Rate + us_sc_sit_personal_exemption_rate + 2510 + + + + US SC South Carolina Personal Exemption Rate + us_sc_sit_personal_exemption_rate + 2590 + + + + + + + US SC South Carolina Standard Deduction Rate + us_sc_sit_standard_deduction_rate + 3470.0 + + + + US SC South Carolina Standard Deduction Rate + us_sc_sit_standard_deduction_rate + 3820.0 + + + + + + + US South Carolina - Department of Labor and Industrial Relations - Unemployment Tax + 1 + + + US South Carolina - Department of Labor and Industrial Relations - Unemployment Tax + + + + + + US South Carolina - Department of Taxation - Income Tax + 1 + + + US South Carolina - Department of Taxation - Income Tax + + + + + + + + + + + ER: US SC South Carolina State Unemployment + ER_US_SC_SUTA + python + result, _ = general_state_unemployment(payslip, categories, worked_days, inputs, wage_base='us_sc_suta_wage_base', rate='us_sc_suta_rate', state_code='SC') + code + result, result_rate = general_state_unemployment(payslip, categories, worked_days, inputs, wage_base='us_sc_suta_wage_base', rate='us_sc_suta_rate', state_code='SC') + + + + + + + + EE: US SC South Carolina State Income Tax Withholding + EE_US_SC_SIT + python + result, _ = sc_south_carolina_state_income_withholding(payslip, categories, worked_days, inputs) + code + result, result_rate = sc_south_carolina_state_income_withholding(payslip, categories, worked_days, inputs) + + + + + \ No newline at end of file diff --git a/l10n_us_hr_payroll/data/state/sd_south_dakota.xml b/l10n_us_hr_payroll/data/state/sd_south_dakota.xml new file mode 100644 index 00000000..21505ae4 --- /dev/null +++ b/l10n_us_hr_payroll/data/state/sd_south_dakota.xml @@ -0,0 +1,48 @@ + + + + + + US SD South Dakota SUTA Wage Base + us_sd_suta_wage_base + 15000.00 + + + + + + + + US SD South Dakota SUTA Rate + us_sd_suta_rate + 1.75 + + + + + + + US South Dakota - Department of Labor - Unemployment Tax + 1 + + + US South Dakota - Department of Labor - Unemployment Tax + + + + + + + + + ER: US SD South Dakota State Unemployment + ER_US_SD_SUTA + python + result, _ = general_state_unemployment(payslip, categories, worked_days, inputs, wage_base='us_sd_suta_wage_base', rate='us_sd_suta_rate', state_code='SD') + code + result, result_rate = general_state_unemployment(payslip, categories, worked_days, inputs, wage_base='us_sd_suta_wage_base', rate='us_sd_suta_rate', state_code='SD') + + + + + diff --git a/l10n_us_hr_payroll/data/state/tn_tennessee.xml b/l10n_us_hr_payroll/data/state/tn_tennessee.xml new file mode 100644 index 00000000..0083b391 --- /dev/null +++ b/l10n_us_hr_payroll/data/state/tn_tennessee.xml @@ -0,0 +1,48 @@ + + + + + + US TN Tennessee SUTA Wage Base + us_tn_suta_wage_base + 7000.00 + + + + + + + + US TN Tennessee SUTA Rate + us_tn_suta_rate + 2.7 + + + + + + + US Tennessee - Department of Revenue - Unemployment Tax + 1 + + + US Tennessee - Department of Revenue - Unemployment Tax + + + + + + + + + ER: US TN Tennessee State Unemployment + ER_US_TN_SUTA + python + result, _ = general_state_unemployment(payslip, categories, worked_days, inputs, wage_base='us_tn_suta_wage_base', rate='us_tn_suta_rate', state_code='TN') + code + result, result_rate = general_state_unemployment(payslip, categories, worked_days, inputs, wage_base='us_tn_suta_wage_base', rate='us_tn_suta_rate', state_code='TN') + + + + + diff --git a/l10n_us_hr_payroll/data/state/ut_utah.xml b/l10n_us_hr_payroll/data/state/ut_utah.xml new file mode 100644 index 00000000..b1928223 --- /dev/null +++ b/l10n_us_hr_payroll/data/state/ut_utah.xml @@ -0,0 +1,153 @@ + + + + + + US UT Utah SUTA Wage Base + us_ut_suta_wage_base + 36600.0 + + + + + + + + US UT Utah SUTA Rate + us_ut_suta_rate + 0.1 + + + + + + + US UT Utah TAX Rate + us_ut_tax_rate + 0.0495 + + + + + + + + US UT Utah Allowances Rate + us_ut_sit_allowances_rate + { + 'single': { + 'weekly' : 7, + 'bi-weekly' : 14, + 'semi-monthly': 15, + 'monthly' : 30, + 'quarterly' : 90, + 'semi-annual': 180, + 'annually': 360, + }, + 'married': { + 'weekly' : 14, + 'bi-weekly' : 28, + 'semi-monthly': 30, + 'monthly' : 60, + 'quarterly' : 180, + 'semi-annual': 360, + 'annually': 720, + }, + 'head_household': { + 'weekly' : 7, + 'bi-weekly' : 14, + 'semi-monthly': 15, + 'monthly' : 30, + 'quarterly' : 90, + 'semi-annual': 180, + 'annually': 360, + }, + } + + + + + + + US UT Utah SIT Tax Rate + us_ut_sit_tax_rate + { + 'single': { + 'weekly': ((137, 1.3)), + 'bi-weekly': ((274, 1.3)), + 'semi-monthly': ((297, 1.3)), + 'monthly': ((594, 1.3)), + 'quarterly': ((1782, 1.3)), + 'semi-annual': ((3564, 1.3)), + 'annually': ((7128, 1.3)), + }, + 'married': { + 'weekly': ((274, 1.3)), + 'bi-weekly': (548, 1.3), + 'semi-monthly': ((594, 1.3)), + 'monthly': ((1188, 1.3)), + 'quarterly': ((3564, 1.3)), + 'semi-annual': ((7128, 1.3)), + 'annually': ((14256, 1.3)), + }, + 'head_household': { + 'weekly': ((137, 1.3)), + 'bi-weekly': ((274, 1.3)), + 'semi-monthly': ((297, 1.3)), + 'monthly': ((594, 1.3)), + 'quarterly': ((1782, 1.3)), + 'semi-annual': ((3564, 1.3)), + 'annually': ((7128, 1.3)), + }, + } + + + + + + + US Utah - Employment Security Commission - Unemployment Tax + 1 + + + US Utah - Employment Security Commission - Unemployment Tax + + + + + US Utah - Tax Commission - Income Tax + 1 + + + US Utah - Tax Commission - Income Tax + + + + + + + + ER: US UT Utah State Unemployment + ER_US_UT_SUTA + python + result, _ = general_state_unemployment(payslip, categories, worked_days, inputs, wage_base='us_ut_suta_wage_base', rate='us_ut_suta_rate', state_code='UT') + code + result, result_rate = general_state_unemployment(payslip, categories, worked_days, inputs, wage_base='us_ut_suta_wage_base', rate='us_ut_suta_rate', state_code='UT') + + + + + + + + EE: US UT Utah State Income Tax Withholding + EE_US_UT_SIT + python + result, _ = ut_utah_state_income_withholding(payslip, categories, worked_days, inputs) + code + result, result_rate = ut_utah_state_income_withholding(payslip, categories, worked_days, inputs) + + + + + \ No newline at end of file diff --git a/l10n_us_hr_payroll/data/state/vt_vermont.xml b/l10n_us_hr_payroll/data/state/vt_vermont.xml new file mode 100644 index 00000000..a6df6085 --- /dev/null +++ b/l10n_us_hr_payroll/data/state/vt_vermont.xml @@ -0,0 +1,185 @@ + + + + + + US VT Vermont SUTA Wage Base + us_vt_suta_wage_base + 16100.0 + + + + + + + + US VT Vermont SUTA Rate + us_vt_suta_rate + 1.0 + + + + + + + US VT Vermont Allowances Rate + us_vt_sit_allowances_rate + { + 'weekly' : 83.65, + 'bi-weekly' : 167.31, + 'semi-monthly': 181.25, + 'monthly' : 362.50, + 'quarterly' : 1087.50, + 'annually': 4350.00, + } + + + + + + + US VT Vermont SIT Tax Rate + us_vt_sit_tax_rate + { + 'single': { + 'weekly': ( + ( 60, 0.00, 0.00), + ( 836, 0.00, 3.35), + ( 1941, 26.00, 6.60), + ( 3983, 98.93, 7.60), + ('inf', 254.12, 8.75), + ), + 'bi-weekly': ( + ( 120, 0.00, 0.00), + ( 1672, 0.00, 3.35), + ( 3882, 51.99, 6.60), + ( 7966, 197.85, 7.60), + ('inf', 508.24, 8.75), + ), + 'semi-monthly': ( + ( 130, 0.00, 0.00), + ( 1811, 0.00, 3.35), + ( 4205, 56.31, 6.60), + ( 8630, 214.32, 7.60), + ('inf', 550.62, 8.75), + ), + 'monthly': ( + ( 260, 0.00, 0.00), + ( 3623, 0.00, 3.35), + ( 8410, 112.66, 6.60), + (17260, 428.60, 7.60), + ('inf', 1101.20, 8.75), + ), + 'quarterly': ( + ( 781, 0.00, 0.00), + (10869, 0.00, 3.35), + (25231, 337.95, 6.60), + (51781, 1285.84, 7.60), + ('inf', 3303.64, 8.75), + ), + 'annually': ( + ( 3125, 0.00, 0.00), + ( 43475, 0.00, 3.35), + (100925, 1351.73, 6.60), + (207125, 5143.43, 7.60), + ( 'inf', 13214.63, 8.75), + ), + }, + 'married': { + 'weekly': ( + ( 180, 0.00, 0.00), + ( 1477, 0.00, 3.35), + ( 3315, 43.45, 6.60), + ( 4956, 164.76, 7.60), + ('inf', 289.47, 8.75), + ), + 'bi-weekly': ( + ( 361, 0.00, 0.00), + ( 2955, 0.00, 3.35), + ( 6630, 86.90, 6.60), + (9913, 329.45, 7.60), + ('inf', 578.96, 8.75), + ), + 'semi-monthly': ( + ( 391, 0.00, 0.00), + ( 3201, 0.00, 3.35), + ( 7182, 94.14, 6.60), + (10739, 356.88, 7.60), + ('inf', 627.21, 8.75), + ), + 'monthly': ( + ( 781, 0.00, 0.00), + ( 6402, 0.00, 3.35), + (14365, 188.30, 6.60), + (21477, 713.86, 7.60), + ('inf', 1254.37, 8.75), + ), + 'quarterly': ( + ( 2344, 0.00, 0.00), + (19206, 0.00, 3.35), + (43094, 564.88, 6.60), + (64431, 2141.49, 7.60), + ('inf', 3763.10, 8.75), + ), + 'annually': ( + ( 9375, 0.00, 0.00), + ( 76825, 0.00, 3.35), + (172375, 2259.58, 6.60), + (257725, 8565.88, 7.60), + ( 'inf', 15052.48, 8.75), + ), + }, + } + + + + + + + US Vermont - Employment Security Commission - Unemployment Tax + 1 + + + US Vermont - Employment Security Commission - Unemployment Tax + + + + + + US Vermont - Tax Commission - Income Tax + 1 + + + US Vermont - Tax Commission - Income Tax + + + + + + + + + ER: US VT Vermont State Unemployment + ER_US_VT_SUTA + python + result, _ = general_state_unemployment(payslip, categories, worked_days, inputs, wage_base='us_vt_suta_wage_base', rate='us_vt_suta_rate', state_code='VT') + code + result, result_rate = general_state_unemployment(payslip, categories, worked_days, inputs, wage_base='us_vt_suta_wage_base', rate='us_vt_suta_rate', state_code='VT') + + + + + + + + EE: US VT Vermont State Income Tax Withholding + EE_US_VT_SIT + python + result, _ = vt_vermont_state_income_withholding(payslip, categories, worked_days, inputs) + code + result, result_rate = vt_vermont_state_income_withholding(payslip, categories, worked_days, inputs) + + + + + \ No newline at end of file diff --git a/l10n_us_hr_payroll/data/state/wi_wisconsin.xml b/l10n_us_hr_payroll/data/state/wi_wisconsin.xml new file mode 100644 index 00000000..add50523 --- /dev/null +++ b/l10n_us_hr_payroll/data/state/wi_wisconsin.xml @@ -0,0 +1,109 @@ + + + + + + US WI Wisconsin SUTA Wage Base + us_wi_suta_wage_base + 14000.00 + + + + + + + + + US WI Wisconsin SUTA Rate + us_wi_suta_rate + 3.05 + + + + + + + US WI Wisconsin Exemption Rate + us_wi_sit_exemption_rate + 22 + + + + + + + + US WI Wisconsin SIT Tax Rate + us_wi_sit_tax_rate + { + 'single': ( + ( 5730, 0.0000, 0.00), + ( 15200, 4.0000, 0.00), + ( 16486, 4.4800, 378.80), + ( 26227, 6.5408, 436.41), + ( 62950, 7.0224, 1073.55), + (240190, 6.2700, 3652.39), + ( 'inf', 7.6500, 14765.34), + ), + 'married': ( + ( 7870, 0.0000, 0.00), + ( 18780, 4.0000, 0.00), + ( 21400, 5.8400, 436.40), + ( 28308, 7.0080, 589.41), + ( 60750, 7.5240, 1073.52), + (240190, 6.2700, 3514.46), + ( 'inf', 7.6500, 14765.35), + ), + } + + + + + + + US Wisconsin - Department of Workforce Development - Unemployment Tax + 1 + + + US Wisconsin - Department of Workforce Development - Unemployment Tax + + + + + US Wisconsin - Department of Revenue - Income Tax + 1 + + + US Wisconsin - Department of Revenue - Income Tax + + + + + + + + + ER: US WI Wisconsin State Unemployment + ER_US_WI_SUTA + python + result, _ = general_state_unemployment(payslip, categories, worked_days, inputs, wage_base='us_wi_suta_wage_base', rate='us_wi_suta_rate', state_code='WI') + code + result, result_rate = general_state_unemployment(payslip, categories, worked_days, inputs, wage_base='us_wi_suta_wage_base', rate='us_wi_suta_rate', state_code='WI') + + + + + + + + EE: US WI Wisconsin State Income Tax Withholding + EE_US_WI_SIT + python + result, _ = wi_wisconsin_state_income_withholding(payslip, categories, worked_days, inputs) + code + result, result_rate = wi_wisconsin_state_income_withholding(payslip, categories, worked_days, inputs) + + + + + diff --git a/l10n_us_hr_payroll/data/state/wv_west_virginia.xml b/l10n_us_hr_payroll/data/state/wv_west_virginia.xml new file mode 100644 index 00000000..4cf6eeb5 --- /dev/null +++ b/l10n_us_hr_payroll/data/state/wv_west_virginia.xml @@ -0,0 +1,209 @@ + + + + + + US WV West Virginia SUTA Wage Base + us_wv_suta_wage_base + 12000.0 + + + + + + + + US WV West Virginia SUTA Rate + us_wv_suta_rate + 2.7 + + + + + + + + US WV West Virginia Exemption Rate + us_wv_sit_exemption_rate + { + 'weekly' : 38.46, + 'bi-weekly' : 76.92, + 'semi-monthly': 83.33, + 'monthly' : 166.67, + 'annually': 2000.00, + } + + + + + + + + US WV West Virginia SIT Tax Rate + us_wv_sit_tax_rate + { + 'single': { + 'weekly':( + ( 192, 0.00, 3.0), + ( 481, 5.76, 4.0), + ( 769, 17.32, 4.5), + ( 1154, 30.28, 6.0), + ('inf', 53.38, 6.5), + ), + 'bi-weekly':( + ( 385, 0.00, 3.0), + ( 962, 11.55, 4.0), + ( 1538, 34.63, 4.5), + ( 2308, 60.55, 6.0), + ('inf', 106.75, 6.5), + ), + 'semi-monthly':( + ( 417, 0.00, 3.0), + ( 1042 , 12.51, 4.0), + ( 1667, 37.51, 4.5), + ( 2500, 65.64, 6.0), + ('inf', 115.62, 6.5), + ), + 'monthly':( + ( 833, 0.00, 3.0), + ( 2083, 24.99, 4.0), + ( 3333, 74.99, 4.5), + ( 5000, 131.24, 6.0), + ('inf', 231.26, 6.5), + ), + 'annually':( + ( 10000, 0.00, 3.0), + ( 25000, 300.00, 4.0), + ( 40000, 900.00, 4.5), + ( 60000, 1575.00, 6.0), + ( 'inf', 2775.00, 6.5), + ), + }, + 'married': { + 'weekly':( + ( 115, 0.00, 3.0), + ( 288, 3.45, 4.0), + ( 462, 10.37, 4.5), + ( 692, 18.20, 6.0), + ('inf', 32.00, 6.5), + ), + 'bi-weekly':( + ( 231, 0.00, 3.0), + ( 577, 6.93, 4.0), + ( 923, 20.77, 4.5), + ( 1385, 36.34, 6.0), + ('inf', 64.06, 6.5), + ), + 'semi-monthly':( + ( 250, 0.00, 3.0), + ( 625, 7.50, 4.0), + ( 1000, 22.50, 4.5), + ( 1500, 39.38, 6.0), + ('inf', 69.38, 6.5), + ), + 'monthly':( + ( 500, 0.00, 3.0), + ( 1250, 15.00, 4.0), + ( 2000, 45.00, 4.5), + ( 3000, 78.75, 6.0), + ('inf', 138.75, 6.5), + ), + 'annually':( + ( 6000, 0.00, 3.0), + (15000, 180.00, 4.0), + (24000, 540.00, 4.5), + (36000, 945.00, 6.0), + ('inf', 1665.00, 6.5), + ), + }, + 'head_household': { + 'weekly':( + ( 192, 0.00, 3.0), + ( 481, 5.76, 4.0), + ( 769, 17.32, 4.5), + ( 1154, 30.28, 6.0), + ('inf', 53.38, 6.5), + ), + 'bi-weekly':( + ( 385, 0.00, 3.0), + ( 962, 11.55, 4.0), + ( 1538, 34.63, 4.5), + ( 2308, 60.55, 6.0), + ('inf', 106.75, 6.5), + ), + 'semi-monthly':( + ( 417, 0.00, 3.0), + ( 1042, 12.51, 4.0), + ( 1667, 37.51, 4.5), + ( 2500, 65.64, 6.0), + ('inf', 115.62, 6.5), + ), + 'monthly':( + ( 833, 0.00, 3.0), + ( 2083, 24.99, 4.0), + ( 3333, 74.99, 4.5), + ( 5000, 131.24, 6.0), + ('inf', 231.26, 6.5), + ), + 'annually':( + ( 10000, 0.00, 3.0), + ( 25000, 300.00, 4.0), + ( 40000, 900.00, 4.5), + ( 60000, 1575.00, 6.0), + ( 'inf', 2775.00, 6.5), + ), + }, + } + + + + + + + US West Virginia - WorkForce - Unemployment Tax + 1 + + + US West Virginia - WorkForce - Unemployment Tax + + + + + US West Virginia - Department of Revenue - Income Tax + 1 + + + US West Virginia - Department of Revenue - Income Tax + + + + + + + + + + ER: US WV West Virginia State Unemployment + ER_US_WV_SUTA + python + result, _ = general_state_unemployment(payslip, categories, worked_days, inputs, wage_base='us_wv_suta_wage_base', rate='us_wv_suta_rate', state_code='WV') + code + result, result_rate = general_state_unemployment(payslip, categories, worked_days, inputs, wage_base='us_wv_suta_wage_base', rate='us_wv_suta_rate', state_code='WV') + + + + + + + + EE: US WV West Virginia State Income Tax Withholding + EE_US_WV_SIT + python + result, _ = wv_west_virginia_state_income_withholding(payslip, categories, worked_days, inputs) + code + result, result_rate = wv_west_virginia_state_income_withholding(payslip, categories, worked_days, inputs) + + + + + \ No newline at end of file diff --git a/l10n_us_hr_payroll/data/state/wy_wyoming.xml b/l10n_us_hr_payroll/data/state/wy_wyoming.xml new file mode 100644 index 00000000..ac62e3f0 --- /dev/null +++ b/l10n_us_hr_payroll/data/state/wy_wyoming.xml @@ -0,0 +1,60 @@ + + + + + + US WY Wyoming SUTA Wage Base + us_wy_suta_wage_base + 25400.00 + + + + US WY Wyoming SUTA Wage Base + us_wy_suta_wage_base + 26400.00 + + + + + + + + US WY Wyoming SUTA Rate + us_wy_suta_rate + 2.10 + + + + US WY Wyoming SUTA Rate + us_wy_suta_rate + 8.5 + + + + + + + US Wyoming - Department of Workforce Services (WDWS) - Unemployment Tax + 1 + + + US Wyoming - Department of Workforce Services (WDWS) - Unemployment Tax + + + + + + + + + ER: US WY Wyoming State Unemployment + ER_US_WY_SUTA + python + result, _ = general_state_unemployment(payslip, categories, worked_days, inputs, wage_base='us_wy_suta_wage_base', rate='us_wy_suta_rate', state_code='WY') + code + result, result_rate = general_state_unemployment(payslip, categories, worked_days, inputs, wage_base='us_wy_suta_wage_base', rate='us_wy_suta_rate', state_code='WY') + + + + + diff --git a/l10n_us_hr_payroll/migrations/data.py b/l10n_us_hr_payroll/migrations/data.py index b6d8d204..674d2ebe 100644 --- a/l10n_us_hr_payroll/migrations/data.py +++ b/l10n_us_hr_payroll/migrations/data.py @@ -33,6 +33,28 @@ FIELDS_CONTRACT_TO_US_PAYROLL_FORMS_2020 = { 'ga_g4_additional_allowances': 'ga_g4_sit_additional_allowances', 'ga_g4_additional_wh': 'state_income_tax_additional_withholding', + 'ia_w4_allowances': 'ia_w4_sit_allowances', + 'ia_w4_additional_wh': 'state_income_tax_additional_withholding', + 'ia_w4_tax_exempt': 'state_income_tax_exempt', + + 'id_w4_filing_status': 'id_w4_sit_filing_status', + 'id_w4_allowances': 'id_w4_sit_allowances', + + 'il_w4_basic_allowances': 'il_w4_sit_basic_allowances', + 'il_w4_additional_allowances': 'il_w4_sit_additional_allowances', + 'il_w4_additional_wh': 'state_income_tax_additional_withholding', + + 'mi_w4_exemptions': 'mi_w4_sit_exemptions', + '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', + 'ms_89_350_filing_status': 'ms_89_350_sit_filing_status', 'ms_89_350_exemption': 'ms_89_350_sit_exemption_value', 'ms_89_350_additional_withholding': 'state_income_tax_additional_withholding', @@ -41,6 +63,15 @@ FIELDS_CONTRACT_TO_US_PAYROLL_FORMS_2020 = { 'mt_mw4_exemptions': 'mt_mw4_sit_exemptions', 'mt_mw4_exempt': 'mt_mw4_sit_exempt', + 'nc_nc4_filing_status': 'nc_nc4_sit_filing_status', + 'nc_nc4_allowances': 'nc_nc4_sit_allowances', + 'nc_nc4_additional_wh': 'state_income_tax_additional_withholding', + + 'nj_njw4_filing_status': 'nj_njw4_sit_filing_status', + 'nj_njw4_allowances': 'nj_njw4_sit_allowances', + 'nj_njw4_rate_table': 'nj_njw4_sit_rate_table', + 'nj_additional_withholding': 'state_income_tax_additional_withholding', + 'oh_additional_withholding': 'state_income_tax_additional_withholding', 'oh_income_allowances': 'oh_it4_sit_exemptions', @@ -67,6 +98,44 @@ XMLIDS_TO_REMOVE_2020 = [ 'l10n_us_hr_payroll.hr_payroll_rules_futa_wages_2018', 'l10n_us_hr_payroll.hr_payroll_rules_fed_inc_withhold_2018_married', # State + 'l10n_us_ak_hr_payroll.hr_payroll_ak_unemp_wages', + 'l10n_us_ak_hr_payroll.hr_payroll_ak_unemp', + 'l10n_us_ak_hr_payroll.hr_payroll_ak_unemp_ee', + 'l10n_us_ak_hr_payroll.hr_payroll_rules_ak_unemp_wages', + + 'l10n_us_al_hr_payroll.hr_payroll_al_unemp_wages', + 'l10n_us_al_hr_payroll.hr_payroll_al_unemp', + 'l10n_us_al_hr_payroll.hr_payroll_al_income_withhold', + 'l10n_us_al_hr_payroll.hr_payroll_rules_al_unemp_wages', + + 'l10n_us_ar_hr_payroll.hr_payroll_ar_unemp_wages', + 'l10n_us_ar_hr_payroll.hr_payroll_ar_unemp', + 'l10n_us_ar_hr_payroll.hr_payroll_ar_income_withhold', + 'l10n_us_ar_hr_payroll.hr_payroll_rules_ar_unemp_wages', + + 'l10n_us_az_hr_payroll.hr_payroll_az_unemp_wages', + 'l10n_us_az_hr_payroll.hr_payroll_az_unemp', + 'l10n_us_az_hr_payroll.hr_payroll_az_income_withhold', + 'l10n_us_az_hr_payroll.hr_payroll_rules_az_unemp_wages', + + 'l10n_us_ca_hr_payroll.res_partner_cador_ett', + 'l10n_us_ca_hr_payroll.res_partner_cador_sdi', + 'l10n_us_ca_hr_payroll.hr_payroll_ca_uit_wages', + 'l10n_us_ca_hr_payroll.hr_payroll_ca_uit', + 'l10n_us_ca_hr_payroll.hr_payroll_ca_ett_wages', + 'l10n_us_ca_hr_payroll.hr_payroll_ca_ett', + 'l10n_us_ca_hr_payroll.hr_payroll_ca_sdi_wages', + 'l10n_us_ca_hr_payroll.hr_payroll_ca_sdi', + 'l10n_us_ca_hr_payroll.hr_payroll_ca_income_withhold', + 'l10n_us_ca_hr_payroll.hr_payroll_rules_ca_uit_wages_2018', + 'l10n_us_ca_hr_payroll.hr_payroll_rules_ca_ett_wages_2018', + 'l10n_us_ca_hr_payroll.hr_payroll_rules_ca_sdi_wages_2018', + + 'l10n_us_ct_hr_payroll.hr_payroll_ct_unemp_wages', + 'l10n_us_ct_hr_payroll.hr_payroll_ct_unemp', + 'l10n_us_ct_hr_payroll.hr_payroll_ct_income_withhold', + 'l10n_us_ct_hr_payroll.hr_payroll_rules_ct_unemp_wages', + 'l10n_us_fl_hr_payroll.hr_payroll_fl_unemp_wages', 'l10n_us_fl_hr_payroll.hr_payroll_fl_unemp', 'l10n_us_fl_hr_payroll.hr_payroll_rules_fl_unemp_wages_2018', @@ -76,6 +145,36 @@ XMLIDS_TO_REMOVE_2020 = [ 'l10n_us_ga_hr_payroll.hr_payroll_ga_income_withhold', 'l10n_us_ga_hr_payroll.hr_payroll_rules_ga_unemp_wages', + 'l10n_us_ia_hr_payroll.hr_payroll_ia_unemp_wages', + 'l10n_us_ia_hr_payroll.hr_payroll_ia_unemp', + 'l10n_us_ia_hr_payroll.hr_payroll_ia_income_withhold', + 'l10n_us_ia_hr_payroll.hr_payroll_rules_ia_unemp_wages', + + 'l10n_us_id_hr_payroll.hr_payroll_id_unemp_wages', + 'l10n_us_id_hr_payroll.hr_payroll_id_unemp', + 'l10n_us_id_hr_payroll.hr_payroll_id_income_withhold', + 'l10n_us_id_hr_payroll.hr_payroll_rules_id_unemp_wages', + + 'l10n_us_il_hr_payroll.hr_payroll_il_unemp_wages', + 'l10n_us_il_hr_payroll.hr_payroll_il_unemp', + 'l10n_us_il_hr_payroll.hr_payroll_il_income_withhold', + 'l10n_us_il_hr_payroll.hr_payroll_rules_il_unemp_wages', + + 'l10n_us_mi_hr_payroll.hr_payroll_mi_unemp_wages', + 'l10n_us_mi_hr_payroll.hr_payroll_mi_unemp', + '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', + 'l10n_us_mo_hr_payroll.hr_payroll_rules_mo_unemp_wages_2018', + 'l10n_us_ms_hr_payroll.hr_payroll_ms_unemp_wages', 'l10n_us_ms_hr_payroll.hr_payroll_ms_unemp', 'l10n_us_ms_hr_payroll.hr_payroll_ms_income_withhold', @@ -86,6 +185,38 @@ XMLIDS_TO_REMOVE_2020 = [ 'l10n_us_mt_hr_payroll.hr_payroll_mt_income_withhold', 'l10n_us_mt_hr_payroll.hr_payroll_rules_mt_unemp_wages', + 'l10n_us_nc_hr_payroll.hr_payroll_nc_unemp_wages', + 'l10n_us_nc_hr_payroll.hr_payroll_nc_unemp', + 'l10n_us_nc_hr_payroll.hr_payroll_nc_income_withhold', + 'l10n_us_nc_hr_payroll.hr_payroll_rules_nc_unemp_wages_2018', + + 'l10n_us_nj_hr_payroll.res_partner_njdor_unemp_company', + 'l10n_us_nj_hr_payroll.res_partner_njdor_sdi_employee', + 'l10n_us_nj_hr_payroll.res_partner_njdor_sdi_company', + 'l10n_us_nj_hr_payroll.res_partner_njdor_fli', + 'l10n_us_nj_hr_payroll.res_partner_njdor_wf', + 'l10n_us_nj_hr_payroll.contrib_register_njdor_unemp_company', + 'l10n_us_nj_hr_payroll.contrib_register_njdor_sdi_employee', + 'l10n_us_nj_hr_payroll.contrib_register_njdor_sdi_company', + 'l10n_us_nj_hr_payroll.contrib_register_njdor_fli', + 'l10n_us_nj_hr_payroll.contrib_register_njdor_wf', + 'l10n_us_nj_hr_payroll.hr_payroll_nj_unemp_wages', + 'l10n_us_nj_hr_payroll.hr_payroll_nj_sdi_wages', + 'l10n_us_nj_hr_payroll.hr_payroll_nj_fli_wages', + 'l10n_us_nj_hr_payroll.hr_payroll_nj_wf_wages', + 'l10n_us_nj_hr_payroll.hr_payroll_nj_unemp_employee', + 'l10n_us_nj_hr_payroll.hr_payroll_nj_unemp_company', + 'l10n_us_nj_hr_payroll.hr_payroll_nj_sdi_company', + 'l10n_us_nj_hr_payroll.hr_payroll_nj_sdi_employee', + 'l10n_us_nj_hr_payroll.hr_payroll_nj_fli', + 'l10n_us_nj_hr_payroll.hr_payroll_nj_wf', + 'l10n_us_nj_hr_payroll.hr_payroll_nj_wf_company', + 'l10n_us_nj_hr_payroll.hr_payroll_nj_income_withhold', + 'l10n_us_nj_hr_payroll.hr_payroll_rules_nj_unemp_wages_2018', + 'l10n_us_nj_hr_payroll.hr_payroll_rules_nj_sdi_wages_2018', + 'l10n_us_nj_hr_payroll.hr_payroll_rules_nj_fli_wages_2018', + 'l10n_us_nj_hr_payroll.hr_payroll_rules_nj_wf_wages_2018', + 'l10n_us_oh_hr_payroll.hr_payroll_oh_unemp_wages', 'l10n_us_oh_hr_payroll.hr_payroll_oh_unemp', 'l10n_us_oh_hr_payroll.hr_payroll_oh_income_withhold', @@ -100,6 +231,11 @@ XMLIDS_TO_REMOVE_2020 = [ 'l10n_us_pa_hr_payroll.hr_payroll_rules_pa_unemp_wages_2018', 'l10n_us_pa_hr_payroll.hr_payroll_rules_pa_inc_withhold_add', + 'l10n_us_sc_hr_payroll.hr_payroll_sc_unemp_wages', + 'l10n_us_sc_hr_payroll.hr_payroll_sc_unemp', + 'l10n_us_sc_hr_payroll.hr_payroll_sc_income_withhold', + 'l10n_us_sc_hr_payroll.hr_payroll_rules_sc_unemp_wages', + 'l10n_us_tx_hr_payroll.contrib_register_txdor', 'l10n_us_tx_hr_payroll.hr_payroll_tx_unemp_wages', 'l10n_us_tx_hr_payroll.hr_payroll_tx_unemp', @@ -118,6 +254,10 @@ XMLIDS_TO_REMOVE_2020 = [ 'l10n_us_wa_hr_payroll.hr_payroll_wa_lni_withhold', 'l10n_us_wa_hr_payroll.hr_payroll_rules_wa_unemp_wages_2018', + 'l10n_us_wy_hr_payroll.hr_payroll_wy_unemp_wages', + 'l10n_us_wy_hr_payroll.hr_payroll_wy_unemp', + 'l10n_us_wy_hr_payroll.hr_payroll_rules_wy_unemp_wages' + ] XMLIDS_TO_RENAME_2020 = { @@ -134,6 +274,48 @@ XMLIDS_TO_RENAME_2020 = { 'l10n_us_hr_payroll.hr_payroll_rules_fica_comp_m': 'l10n_us_hr_payroll.hr_payroll_rule_er_fed_941_m', 'l10n_us_hr_payroll.hr_payroll_rules_fed_inc_withhold_2018_single': 'l10n_us_hr_payroll.hr_payroll_rule_ee_fed_941_fit', # State + 'l10n_us_ak_hr_payroll.res_partner_ak_dlwd_unemp': 'l10n_us_hr_payroll.res_partner_us_ak_dor', + 'l10n_us_ak_hr_payroll.contrib_register_ak_dlwd_unemp': 'l10n_us_hr_payroll.contrib_register_us_ak_dor', + 'l10n_us_ak_hr_payroll.hr_payroll_rules_ak_unemp': 'l10n_us_hr_payroll.hr_payroll_rule_er_us_ak_suta', + 'l10n_us_ak_hr_payroll.hr_payroll_rules_ak_unemp_ee': 'l10n_us_hr_payroll.hr_payroll_rule_ee_us_ak_sit', + + 'l10n_us_al_hr_payroll.res_partner_al_dol_unemp': 'l10n_us_hr_payroll.res_partner_us_al_dor', + 'l10n_us_al_hr_payroll.res_partner_al_dor_withhold': 'l10n_us_hr_payroll.res_partner_us_al_dor_sit', + 'l10n_us_al_hr_payroll.contrib_register_al_dol_unemp': 'l10n_us_hr_payroll.contrib_register_us_al_dor', + 'l10n_us_al_hr_payroll.contrib_register_al_dor_withhold': 'l10n_us_hr_payroll.contrib_register_us_al_dor_sit', + 'l10n_us_al_hr_payroll.hr_payroll_rules_al_unemp': 'l10n_us_hr_payroll.hr_payroll_rules_az_unemp', + 'l10n_us_al_hr_payroll.hr_payroll_rules_al_inc_withhold': 'l10n_us_hr_payroll.hr_payroll_rules_az_inc_withhold', + + 'l10n_us_ar_hr_payroll.res_partner_ar_dws_unemp': 'l10n_us_hr_payroll.res_partner_us_ar_dor', + 'l10n_us_ar_hr_payroll.res_partner_ar_dfa_withhold': 'l10n_us_hr_payroll.res_partner_us_ar_dor_sit', + 'l10n_us_ar_hr_payroll.contrib_register_ar_dws_unemp': 'l10n_us_hr_payroll.contrib_register_us_ar_dor', + 'l10n_us_ar_hr_payroll.contrib_register_ar_dfa_withhold': 'l10n_us_hr_payroll.contrib_register_us_ar_dor_sit', + 'l10n_us_ar_hr_payroll.hr_payroll_rules_ar_unemp': 'l10n_us_hr_payroll.hr_payroll_rule_er_us_ar_suta', + 'l10n_us_ar_hr_payroll.hr_payroll_rules_ar_inc_withhold': 'l10n_us_hr_payroll.hr_payroll_rule_ee_us_ar_sit', + + 'l10n_us_az_hr_payroll.res_partner_az_des_unemp': 'l10n_us_hr_payroll.res_partner_us_az_dor', + 'l10n_us_az_hr_payroll.res_partner_az_dor_withhold': 'l10n_us_hr_payroll.res_partner_us_az_dor_sit', + 'l10n_us_az_hr_payroll.contrib_register_az_des_unemp': 'l10n_us_hr_payroll.contrib_register_us_az_dor', + 'l10n_us_az_hr_payroll.contrib_register_az_dor_withhold': 'l10n_us_hr_payroll.contrib_register_us_az_dor_sit', + 'l10n_us_az_hr_payroll.hr_payroll_az_unemp': 'l10n_us_hr_payroll.hr_payroll_rule_er_us_az_suta', + 'l10n_us_az_hr_payroll.hr_payroll_az_income_withhold': 'l10n_us_hr_payroll.hr_payroll_rule_ee_us_az_sit', + + 'l10n_us_ca_hr_payroll.res_partner_cador_uit': 'l10n_us_hr_payroll.res_partner_us_ca_dor', + 'l10n_us_ca_hr_payroll.res_partner_cador_withhold': 'l10n_us_hr_payroll.res_partner_us_ca_dor_sit', + 'l10n_us_ca_hr_payroll.contrib_register_cador_uit': 'l10n_us_hr_payroll.contrib_register_us_ca_dor', + 'l10n_us_ca_hr_payroll.contrib_register_cador_withhold': 'l10n_us_hr_payroll.contrib_register_us_ca_dor_sit', + 'l10n_us_ca_hr_payroll.hr_payroll_rules_ca_uit_2018': 'l10n_us_hr_payroll.hr_payroll_rule_er_us_ca_suta', + 'l10n_us_ca_hr_payroll.hr_payroll_rules_ca_ett_2018': 'l10n_us_hr_payroll.hr_payroll_rule_er_us_ca_ett_suta', + 'l10n_us_ca_hr_payroll.hr_payroll_rules_ca_sdi_2018': 'l10n_us_hr_payroll.hr_payroll_rule_ee_us_ca_sdi_sit', + 'l10n_us_ca_hr_payroll.hr_payroll_rules_ca_inc_withhold_2018': 'l10n_us_hr_payroll.hr_payroll_rule_ee_us_ca_sit', + + 'l10n_us_ct_hr_payroll.res_partner_ct_dol_unemp': 'l10n_us_hr_payroll.res_partner_us_ct_dor', + 'l10n_us_ct_hr_payroll.res_partner_ct_drs_withhold': 'l10n_us_hr_payroll.res_partner_us_ct_dor_sit', + 'l10n_us_ct_hr_payroll.contrib_register_ct_dol_unemp': 'l10n_us_hr_payroll.contrib_register_us_ct_dor', + 'l10n_us_ct_hr_payroll.contrib_register_ct_drs_withhold': 'l10n_us_hr_payroll.contrib_register_us_ct_dor_sit', + 'l10n_us_ct_hr_payroll.hr_payroll_rules_ct_unemp': 'l10n_us_hr_payroll.hr_payroll_rule_er_us_ct_suta', + 'l10n_us_ct_hr_payroll.hr_payroll_rules_ct_inc_withhold': 'l10n_us_hr_payroll.hr_payroll_rule_ee_us_ct_sit', + 'l10n_us_fl_hr_payroll.hr_payroll_rules_fl_unemp_2018': 'l10n_us_hr_payroll.hr_payroll_rule_er_us_fl_suta', 'l10n_us_fl_hr_payroll.res_partner_fldor': 'l10n_us_hr_payroll.res_partner_us_fl_dor', 'l10n_us_fl_hr_payroll.contrib_register_fldor': 'l10n_us_hr_payroll.contrib_register_us_fl_dor', @@ -145,6 +327,48 @@ XMLIDS_TO_RENAME_2020 = { 'l10n_us_ga_hr_payroll.hr_payroll_rules_ga_unemp': 'l10n_us_hr_payroll.hr_payroll_rule_er_us_ga_suta', 'l10n_us_ga_hr_payroll.hr_payroll_rules_ga_inc_withhold': 'l10n_us_hr_payroll.hr_payroll_rule_ee_us_ga_sit', + 'l10n_us_ia_hr_payroll.res_partner_ia_wd_unemp': 'l10n_us_hr_payroll.res_partner_us_ia_dor', + 'l10n_us_ia_hr_payroll.res_partner_ia_dor_withhold': 'l10n_us_hr_payroll.res_partner_us_ia_dor_sit', + 'l10n_us_ia_hr_payroll.contrib_register_ia_wd_unemp': 'l10n_us_hr_payroll.contrib_register_us_ia_dor', + 'l10n_us_ia_hr_payroll.contrib_register_ia_dor_withhold': 'l10n_us_hr_payroll.contrib_register_us_ia_dor_sit', + 'l10n_us_ia_hr_payroll.hr_payroll_rules_ia_unemp': 'l10n_us_hr_payroll.hr_payroll_rule_er_us_ia_suta', + 'l10n_us_ia_hr_payroll.hr_payroll_rules_ia_inc_withhold': 'l10n_us_hr_payroll.hr_payroll_rule_ee_us_ia_sit', + + 'l10n_us_id_hr_payroll.res_partner_id_dol_unemp':'l10n_us_hr_payroll.res_partner_us_id_dor', + 'l10n_us_id_hr_payroll.res_partner_id_stc_withhold': 'l10n_us_hr_payroll.res_partner_us_id_dor_sit', + 'l10n_us_id_hr_payroll.contrib_register_id_dol_unemp': 'l10n_us_hr_payroll.contrib_register_us_id_dor', + 'l10n_us_id_hr_payroll.contrib_register_id_stc_withhold': 'l10n_us_hr_payroll.contrib_register_us_id_dor_sit', + 'l10n_us_id_hr_payroll.hr_payroll_rules_id_unemp': 'l10n_us_hr_payroll.hr_payroll_rule_er_us_id_suta', + 'l10n_us_id_hr_payroll.hr_payroll_rules_id_inc_withhold': 'l10n_us_hr_payroll.hr_payroll_rule_ee_us_id_sit', + + 'l10n_us_il_hr_payroll.res_partner_il_des_unemp': 'l10n_us_hr_payroll.res_partner_us_il_dor', + 'l10n_us_il_hr_payroll.res_partner_il_dor_withhold': 'l10n_us_hr_payroll.res_partner_us_il_dor_sit', + 'l10n_us_il_hr_payroll.contrib_register_il_des_unemp': 'l10n_us_hr_payroll.contrib_register_us_il_dor', + 'l10n_us_il_hr_payroll.contrib_register_il_dor_withhold': 'l10n_us_hr_payroll.contrib_register_us_il_dor_sit', + 'l10n_us_il_hr_payroll.hr_payroll_rules_il_unemp': 'l10n_us_hr_payroll.hr_payroll_rule_er_us_il_suta', + 'l10n_us_il_hr_payroll.hr_payroll_rules_il_inc_withhold': 'l10n_us_hr_payroll.hr_payroll_rule_ee_us_il_sit', + + 'l10n_us_mi_hr_payroll.res_partner_mi_uia_unemp': 'l10n_us_hr_payroll.res_partner_us_mi_dor', + 'l10n_us_mi_hr_payroll.res_partner_mi_dot_withhold': 'l10n_us_hr_payroll.res_partner_us_mi_dor_sit', + 'l10n_us_mi_hr_payroll.contrib_register_mi_uia_unemp': 'l10n_us_hr_payroll.contrib_register_us_mi_dor', + 'l10n_us_mi_hr_payroll.contrib_register_mi_dot_withhold': 'l10n_us_hr_payroll.contrib_register_us_mi_dor_sit', + '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', + 'l10n_us_mo_hr_payroll.contrib_register_modor_withhold': 'l10n_us_hr_payroll.contrib_register_us_mo_dor_sit', + 'l10n_us_mo_hr_payroll.hr_payroll_rules_mo_unemp_2018': 'l10n_us_hr_payroll.hr_payroll_rule_er_us_mo_suta', + 'l10n_us_mo_hr_payroll.hr_payroll_rules_mo_inc_withhold_2018': 'l10n_us_hr_payroll.hr_payroll_rule_ee_us_mo_sit', + 'l10n_us_ms_hr_payroll.res_partner_msdor_unemp': 'l10n_us_hr_payroll.res_partner_us_ms_dor', 'l10n_us_ms_hr_payroll.res_partner_msdor_withhold': 'l10n_us_hr_payroll.res_partner_us_ms_dor_sit', 'l10n_us_ms_hr_payroll.contrib_register_msdor_unemp': 'l10n_us_hr_payroll.contrib_register_us_ms_dor', @@ -159,6 +383,26 @@ XMLIDS_TO_RENAME_2020 = { 'l10n_us_mt_hr_payroll.hr_payroll_rules_mt_unemp': 'l10n_us_hr_payroll.hr_payroll_rule_er_us_mt_suta', 'l10n_us_mt_hr_payroll.hr_payroll_rules_mt_inc_withhold': 'l10n_us_hr_payroll.hr_payroll_rule_ee_us_mt_sit', + 'l10n_us_nc_hr_payroll.res_partner_ncdor_unemp':'l10n_us_hr_payroll.res_partner_us_nc_dor', + 'l10n_us_nc_hr_payroll.res_partner_ncdor_withhold': 'l10n_us_hr_payroll.res_partner_us_nc_dor_sit', + 'l10n_us_nc_hr_payroll.contrib_register_ncdor_unemp': 'l10n_us_hr_payroll.contrib_register_us_nc_dor', + 'l10n_us_nc_hr_payroll.contrib_register_ncdor_withhold': 'l10n_us_hr_payroll.contrib_register_us_nc_dor_sit', + 'l10n_us_nc_hr_payroll.hr_payroll_rules_nc_unemp_2018': 'l10n_us_hr_payroll.hr_payroll_rule_er_us_nc_suta', + 'l10n_us_nc_hr_payroll.hr_payroll_rules_nc_inc_withhold_2018': 'l10n_us_hr_payroll.hr_payroll_rule_ee_us_nc_sit', + + 'l10n_us_nj_hr_payroll.res_partner_njdor_unemp_employee': 'l10n_us_hr_payroll.res_partner_us_nj_dor', + 'l10n_us_nj_hr_payroll.res_partner_njdor_withhold': 'l10n_us_hr_payroll.res_partner_us_nj_dor_sit', + 'l10n_us_nj_hr_payroll.contrib_register_njdor_unemp_employee': 'l10n_us_hr_payroll.contrib_register_us_nj_dor', + 'l10n_us_nj_hr_payroll.contrib_register_njdor_withhold': 'l10n_us_hr_payroll.contrib_register_us_nj_dor_sit', + 'l10n_us_nj_hr_payroll.hr_payroll_rules_nj_unemp_employee_2018': 'l10n_us_hr_payroll.hr_payroll_rule_ee_us_nj_suta', + 'l10n_us_nj_hr_payroll.hr_payroll_rules_nj_unemp_company_2018': 'l10n_us_hr_payroll.hr_payroll_rule_er_us_nj_suta', + 'l10n_us_nj_hr_payroll.hr_payroll_rules_nj_sdi_employee_2018': 'l10n_us_hr_payroll.hr_payroll_rule_ee_us_nj_sdi', + 'l10n_us_nj_hr_payroll.hr_payroll_rules_nj_sdi_company_2018': 'l10n_us_hr_payroll.hr_payroll_rule_er_us_nj_sdi', + 'l10n_us_nj_hr_payroll.hr_payroll_rules_nj_fli_2018': 'l10n_us_hr_payroll.hr_payroll_rule_ee_us_nj_fli', + 'l10n_us_nj_hr_payroll.hr_payroll_rules_nj_wf_2018': 'l10n_us_hr_payroll.hr_payroll_rule_ee_us_nj_wf', + 'l10n_us_nj_hr_payroll.hr_payroll_rules_nj_wf_er': 'l10n_us_hr_payroll.hr_payroll_rule_er_us_nj_wf', + 'l10n_us_nj_hr_payroll.hr_payroll_rules_nj_inc_withhold_2018': 'l10n_us_hr_payroll.hr_payroll_rule_ee_us_nj_sit', + 'l10n_us_oh_hr_payroll.res_partner_ohdor_unemp': 'l10n_us_hr_payroll.res_partner_us_oh_dor', 'l10n_us_oh_hr_payroll.res_partner_ohdor_withhold': 'l10n_us_hr_payroll.res_partner_us_oh_dor_sit', 'l10n_us_oh_hr_payroll.res_partner_ohdor_unemp': 'l10n_us_hr_payroll.res_partner_us_oh_dor', @@ -174,6 +418,13 @@ XMLIDS_TO_RENAME_2020 = { 'l10n_us_pa_hr_payroll.hr_payroll_rules_pa_unemp_company_2018': 'l10n_us_hr_payroll.hr_payroll_rule_er_us_pa_suta', 'l10n_us_pa_hr_payroll.hr_payroll_rules_pa_inc_withhold_2018': 'l10n_us_hr_payroll.hr_payroll_rule_ee_us_pa_sit', + 'l10n_us_sc_hr_payroll.res_partner_sc_dew_unemp': 'l10n_us_hr.payroll.res_partner_us_sc_dor', + 'l10n_us_sc_hr_payroll.res_partner_sc_dor_withhold': 'l10n_us_hr.payroll.res_partner_us_sc_dor_sit', + 'l10n_us_sc_hr_payroll.contrib_register_sc_dew_unemp': 'l10n_us_hr.payroll.contrib_register_us_sc_dor', + 'l10n_us_sc_hr_payroll.contrib_register_sc_dor_withhold': 'l10n_us_hr.payroll.contrib_register_us_sc_dor_sit', + 'l10n_us_sc_hr_payroll.hr_payroll_rules_sc_unemp': 'l10n_us_hr.payroll.hr_payroll_rule_er_us_sc_suta', + 'l10n_us_sc_hr_payroll.hr_payroll_rules_sc_inc_withhold': 'l10n_us_hr.payroll.hr_payroll_rule_ee_us_sc_sit', + 'l10n_us_tx_hr_payroll.res_partner_txdor': 'l10n_us_hr_payroll.res_partner_us_tx_dor', 'l10n_us_tx_hr_payroll.contrib_register_txdor': 'l10n_us_hr_payroll.contrib_register_us_tx_dor', 'l10n_us_tx_hr_payroll.hr_payroll_rules_tx_unemp_2018': 'l10n_us_hr_payroll.hr_payroll_rule_er_us_tx_suta', @@ -195,12 +446,19 @@ XMLIDS_TO_RENAME_2020 = { 'l10n_us_wa_hr_payroll.hr_payroll_rules_wa_lni_withhold': 'l10n_us_hr_payroll.hr_payroll_rule_ee_us_wa_lni', 'l10n_us_wa_hr_payroll.hr_payroll_rules_wa_lni': 'l10n_us_hr_payroll.hr_payroll_rule_er_us_wa_lni', + 'l10n_us_wy_hr_payroll.res_partner_wy_dws_unemp': 'l10n_us_hr_payroll.res_partner_us_wy_dor', + 'l10n_us_wy_hr_payroll.contrib_register_wy_dws_unemp': 'l10n_us_hr_payroll.contrib_register_us_wy_dor', + 'l10n_us_wy_hr_payroll.hr_payroll_rules_wy_unemp': 'l10n_us_hr_payroll.hr_payroll_rule_er_us_wy_suta', + } XMLIDS_COPY_ACCOUNTING_2020 = { 'l10n_us_hr_payroll.hr_payroll_rule_er_us_mt_suta': [ 'l10n_us_hr_payroll.hr_payroll_rule_er_us_mt_suta_aft', ], + 'l10n_us_hr_payroll.hr_payroll_rule_er_us_nj_wf': [ + 'l10n_us_hr_payroll.hr_payroll_rule_er_us_nj_fli', + ], 'l10n_us_hr_payroll.hr_payroll_rule_er_us_wa_lni': [ 'l10n_us_hr_payroll.hr_payroll_rule_er_us_wa_fml', ], diff --git a/l10n_us_hr_payroll/models/__init__.py b/l10n_us_hr_payroll/models/__init__.py index c208ca19..34f516ee 100644 --- a/l10n_us_hr_payroll/models/__init__.py +++ b/l10n_us_hr_payroll/models/__init__.py @@ -3,4 +3,6 @@ from . import hr_contract from . import hr_payslip from . import hr_salary_rule +from . import res_config_settings +from . import update from . import us_payroll_config diff --git a/l10n_us_hr_payroll/models/federal/fed_940.py b/l10n_us_hr_payroll/models/federal/fed_940.py index 816c88d5..85987ed9 100644 --- a/l10n_us_hr_payroll/models/federal/fed_940.py +++ b/l10n_us_hr_payroll/models/federal/fed_940.py @@ -1,9 +1,53 @@ # Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details. + +def futa_wage(payslip, categories): + """ + Returns FUTA eligible wage for current Payslip (no wage_base, just by categories) + WAGE = GROSS - ALW_FUTA_EXEMPT + DED_FUTA_EXEMPT + :return: wage + """ + wage = categories.GROSS + + wage -= categories.ALW_FUTA_EXEMPT + \ + categories.ALW_FIT_FUTA_EXEMPT + \ + categories.ALW_FIT_FICA_FUTA_EXEMPT + \ + categories.ALW_FICA_FUTA_EXEMPT + + wage += categories.DED_FUTA_EXEMPT + \ + categories.DED_FIT_FUTA_EXEMPT + \ + categories.DED_FIT_FICA_FUTA_EXEMPT + \ + categories.DED_FICA_FUTA_EXEMPT + + return wage + + +def futa_wage_ytd(payslip, categories): + """ + Returns Year to Date FUTA eligible wages + WAGE = GROSS - ALW_FUTA_EXEMPT + DED_FUTA_EXEMPT + :return: wage + """ + year = payslip.dict.get_year() + ytd_wage = payslip.sum_category('GROSS', str(year) + '-01-01', str(year+1) + '-01-01') + + ytd_wage -= payslip.sum_category('ALW_FUTA_EXEMPT', str(year) + '-01-01', str(year+1) + '-01-01') + \ + payslip.sum_category('ALW_FIT_FUTA_EXEMPT', str(year) + '-01-01', str(year+1) + '-01-01') + \ + payslip.sum_category('ALW_FIT_FICA_FUTA_EXEMPT', str(year) + '-01-01', str(year+1) + '-01-01') + \ + payslip.sum_category('ALW_FICA_FUTA_EXEMPT', str(year) + '-01-01', str(year+1) + '-01-01') + + ytd_wage += payslip.sum_category('DED_FUTA_EXEMPT', str(year) + '-01-01', str(year+1) + '-01-01') + \ + payslip.sum_category('DED_FIT_FUTA_EXEMPT', str(year) + '-01-01', str(year+1) + '-01-01') + \ + payslip.sum_category('DED_FIT_FICA_FUTA_EXEMPT', str(year) + '-01-01', str(year+1) + '-01-01') + \ + payslip.sum_category('DED_FICA_FUTA_EXEMPT', str(year) + '-01-01', str(year+1) + '-01-01') + + ytd_wage += payslip.dict.contract_id.external_wages + return ytd_wage + + def er_us_940_futa(payslip, categories, worked_days, inputs): """ Returns FUTA eligible wage and rate. - WAGE = GROSS + DED_FUTA_EXEMPT :return: result, result_rate (wage, percent) """ @@ -17,16 +61,14 @@ def er_us_940_futa(payslip, categories, worked_days, inputs): result_rate = -payslip.dict.rule_parameter('fed_940_futa_rate_normal') # Determine Wage - year = payslip.dict.get_year() - ytd_wage = payslip.sum_category('GROSS', str(year) + '-01-01', str(year+1) + '-01-01') - ytd_wage += payslip.sum_category('DED_FUTA_EXEMPT', str(year) + '-01-01', str(year+1) + '-01-01') - ytd_wage += payslip.dict.contract_id.external_wages + wage = futa_wage(payslip, categories) + if not wage: + return 0.0, 0.0 + ytd_wage = futa_wage_ytd(payslip, categories) wage_base = payslip.dict.rule_parameter('fed_940_futa_wage_base') remaining = wage_base - ytd_wage - wage = categories.GROSS + categories.DED_FUTA_EXEMPT - if remaining < 0.0: result = 0.0 elif remaining < wage: diff --git a/l10n_us_hr_payroll/models/federal/fed_941.py b/l10n_us_hr_payroll/models/federal/fed_941.py index 41019465..cbe6a0fa 100644 --- a/l10n_us_hr_payroll/models/federal/fed_941.py +++ b/l10n_us_hr_payroll/models/federal/fed_941.py @@ -4,10 +4,55 @@ # _logger = logging.getLogger(__name__) +def fica_wage(payslip, categories): + """ + Returns FICA eligible wage for current Payslip (no wage_base, just by categories) + WAGE = GROSS - ALW_FICA_EXEMPT + DED_FICA_EXEMPT + :return: wage + """ + wage = categories.GROSS + + + less_exempt = categories.ALW_FICA_EXEMPT + \ + categories.ALW_FIT_FICA_EXEMPT + \ + categories.ALW_FIT_FICA_FUTA_EXEMPT + \ + categories.ALW_FICA_FUTA_EXEMPT + + plus_exempt = categories.DED_FICA_EXEMPT + \ + categories.DED_FIT_FICA_EXEMPT + \ + categories.DED_FIT_FICA_FUTA_EXEMPT + \ + categories.DED_FICA_FUTA_EXEMPT + # _logger.info('fica wage GROSS: %0.2f less exempt ALW: %0.2f plus exempt DED: %0.2f' % (wage, less_exempt, plus_exempt)) + return wage - less_exempt + plus_exempt + + +def fica_wage_ytd(payslip, categories): + """ + Returns Year to Date FICA eligible wages + WAGE = GROSS - ALW_FICA_EXEMPT + DED_FICA_EXEMPT + :return: wage + """ + year = payslip.dict.get_year() + ytd_wage = payslip.sum_category('GROSS', str(year) + '-01-01', str(year+1) + '-01-01') + + less_exempt = payslip.sum_category('ALW_FICA_EXEMPT', str(year) + '-01-01', str(year+1) + '-01-01') + \ + payslip.sum_category('ALW_FIT_FICA_EXEMPT', str(year) + '-01-01', str(year+1) + '-01-01') + \ + payslip.sum_category('ALW_FIT_FICA_FUTA_EXEMPT', str(year) + '-01-01', str(year+1) + '-01-01') + \ + payslip.sum_category('ALW_FICA_FUTA_EXEMPT', str(year) + '-01-01', str(year+1) + '-01-01') + + plus_exempt = payslip.sum_category('DED_FICA_EXEMPT', str(year) + '-01-01', str(year+1) + '-01-01') + \ + payslip.sum_category('DED_FIT_FICA_EXEMPT', str(year) + '-01-01', str(year+1) + '-01-01') + \ + payslip.sum_category('DED_FIT_FICA_FUTA_EXEMPT', str(year) + '-01-01', str(year+1) + '-01-01') + \ + payslip.sum_category('DED_FICA_FUTA_EXEMPT', str(year) + '-01-01', str(year+1) + '-01-01') + + external_wages = payslip.dict.contract_id.external_wages + # _logger.info('fica ytd wage GROSS: %0.2f less exempt ALW: %0.2f plus exempt DED: %0.2f plus external: %0.2f' % (ytd_wage, less_exempt, plus_exempt, external_wages)) + return ytd_wage - less_exempt + plus_exempt + external_wages + + def ee_us_941_fica_ss(payslip, categories, worked_days, inputs): """ Returns FICA Social Security eligible wage and rate. - WAGE = GROSS + DED_FICA_EXEMPT :return: result, result_rate (wage, percent) """ exempt = payslip.dict.contract_id.us_payroll_config_value('fed_941_fica_exempt') @@ -18,16 +63,14 @@ def ee_us_941_fica_ss(payslip, categories, worked_days, inputs): result_rate = -payslip.dict.rule_parameter('fed_941_fica_ss_rate') # Determine Wage - year = payslip.dict.get_year() - ytd_wage = payslip.sum_category('GROSS', str(year) + '-01-01', str(year+1) + '-01-01') - ytd_wage += payslip.sum_category('DED_FICA_EXEMPT', str(year) + '-01-01', str(year+1) + '-01-01') - ytd_wage += payslip.dict.contract_id.external_wages + wage = fica_wage(payslip, categories) + if not wage: + return 0.0, 0.0 + ytd_wage = fica_wage_ytd(payslip, categories) wage_base = payslip.dict.rule_parameter('fed_941_fica_ss_wage_base') remaining = wage_base - ytd_wage - wage = categories.GROSS + categories.DED_FICA_EXEMPT - if remaining < 0.0: result = 0.0 elif remaining < wage: @@ -44,7 +87,6 @@ er_us_941_fica_ss = ee_us_941_fica_ss def ee_us_941_fica_m(payslip, categories, worked_days, inputs): """ Returns FICA Medicare eligible wage and rate. - WAGE = GROSS + DED_FICA_EXEMPT :return: result, result_rate (wage, percent) """ exempt = payslip.dict.contract_id.us_payroll_config_value('fed_941_fica_exempt') @@ -55,16 +97,14 @@ def ee_us_941_fica_m(payslip, categories, worked_days, inputs): result_rate = -payslip.dict.rule_parameter('fed_941_fica_m_rate') # Determine Wage - year = payslip.dict.get_year() - ytd_wage = payslip.sum_category('GROSS', str(year) + '-01-01', str(year+1) + '-01-01') - ytd_wage += payslip.sum_category('DED_FICA_EXEMPT', str(year) + '-01-01', str(year+1) + '-01-01') - ytd_wage += payslip.dict.contract_id.external_wages + wage = fica_wage(payslip, categories) + if not wage: + return 0.0, 0.0 + ytd_wage = fica_wage_ytd(payslip, categories) wage_base = float(payslip.dict.rule_parameter('fed_941_fica_m_wage_base')) # inf remaining = wage_base - ytd_wage - wage = categories.GROSS + categories.DED_FICA_EXEMPT - if remaining < 0.0: result = 0.0 elif remaining < wage: @@ -81,8 +121,6 @@ er_us_941_fica_m = ee_us_941_fica_m def ee_us_941_fica_m_add(payslip, categories, worked_days, inputs): """ Returns FICA Medicare Additional eligible wage and rate. - Note that this wage is not capped like the above rules. - WAGE = GROSS - WAGE_FICA_EXEMPT :return: result, result_rate (wage, percent) """ exempt = payslip.dict.contract_id.us_payroll_config_value('fed_941_fica_exempt') @@ -93,16 +131,14 @@ def ee_us_941_fica_m_add(payslip, categories, worked_days, inputs): result_rate = -payslip.dict.rule_parameter('fed_941_fica_m_add_rate') # Determine Wage - year = payslip.dict.get_year() - ytd_wage = payslip.sum_category('GROSS', str(year) + '-01-01', str(year+1) + '-01-01') - ytd_wage += payslip.sum_category('DED_FICA_EXEMPT', str(year) + '-01-01', str(year+1) + '-01-01') - ytd_wage += payslip.dict.contract_id.external_wages + wage = fica_wage(payslip, categories) + if not wage: + return 0.0, 0.0 + ytd_wage = fica_wage_ytd(payslip, categories) wage_start = payslip.dict.rule_parameter('fed_941_fica_m_add_wage_start') existing_wage = ytd_wage - wage_start - wage = categories.GROSS + categories.DED_FICA_EXEMPT - if existing_wage >= 0.0: result = wage elif wage + existing_wage > 0.0: @@ -113,11 +149,54 @@ def ee_us_941_fica_m_add(payslip, categories, worked_days, inputs): return result, result_rate +def fit_wage(payslip, categories): + """ + Returns FIT eligible wage for current Payslip (no wage_base, just by categories) + WAGE = GROSS - ALW_FIT_EXEMPT + DED_FIT_EXEMPT + :return: wage + """ + wage = categories.GROSS + + wage -= categories.ALW_FIT_EXEMPT + \ + categories.ALW_FIT_FICA_EXEMPT + \ + categories.ALW_FIT_FICA_FUTA_EXEMPT + \ + categories.ALW_FIT_FUTA_EXEMPT + + wage += categories.DED_FIT_EXEMPT + \ + categories.DED_FIT_FICA_EXEMPT + \ + categories.DED_FIT_FICA_FUTA_EXEMPT + \ + categories.DED_FIT_FUTA_EXEMPT + + return wage + + +def fit_wage_ytd(payslip, categories): + """ + Returns Year to Date FIT eligible wages + WAGE = GROSS - ALW_FIT_EXEMPT + DED_FIT_EXEMPT + :return: wage + """ + year = payslip.dict.get_year() + ytd_wage = payslip.sum_category('GROSS', str(year) + '-01-01', str(year+1) + '-01-01') + + ytd_wage -= payslip.sum_category('ALW_FIT_EXEMPT', str(year) + '-01-01', str(year+1) + '-01-01') + \ + payslip.sum_category('ALW_FIT_FICA_EXEMPT', str(year) + '-01-01', str(year+1) + '-01-01') + \ + payslip.sum_category('ALW_FIT_FICA_FUTA_EXEMPT', str(year) + '-01-01', str(year+1) + '-01-01') + \ + payslip.sum_category('ALW_FIT_FUTA_EXEMPT', str(year) + '-01-01', str(year+1) + '-01-01') + + ytd_wage += payslip.sum_category('DED_FIT_EXEMPT', str(year) + '-01-01', str(year+1) + '-01-01') + \ + payslip.sum_category('DED_FIT_FICA_EXEMPT', str(year) + '-01-01', str(year+1) + '-01-01') + \ + payslip.sum_category('DED_FIT_FICA_FUTA_EXEMPT', str(year) + '-01-01', str(year+1) + '-01-01') + \ + payslip.sum_category('DED_FIT_FUTA_EXEMPT', str(year) + '-01-01', str(year+1) + '-01-01') + + ytd_wage += payslip.dict.contract_id.external_wages + return ytd_wage + + # Federal Income Tax def ee_us_941_fit(payslip, categories, worked_days, inputs): """ Returns Wage and rate that is computed given the amount to withhold. - WAGE = GROSS + DED_FIT_EXEMPT :return: result, result_rate (wage, percent) """ filing_status = payslip.dict.contract_id.us_payroll_config_value('fed_941_fit_w4_filing_status') @@ -125,7 +204,10 @@ def ee_us_941_fit(payslip, categories, worked_days, inputs): return 0.0, 0.0 schedule_pay = payslip.dict.contract_id.schedule_pay - wage = categories.GROSS + categories.DED_FIT_EXEMPT + wage = fit_wage(payslip, categories) + if not wage: + return 0.0, 0.0 + #_logger.warn('initial gross wage: ' + str(wage)) year = payslip.dict.get_year() if year >= 2020: diff --git a/l10n_us_hr_payroll/models/hr_payslip.py b/l10n_us_hr_payroll/models/hr_payslip.py index 98e74198..eeae69d7 100644 --- a/l10n_us_hr_payroll/models/hr_payslip.py +++ b/l10n_us_hr_payroll/models/hr_payslip.py @@ -14,13 +14,45 @@ from .federal.fed_941 import ee_us_941_fica_ss, \ from .state.general import general_state_unemployment, \ general_state_income_withholding, \ is_us_state +from .state.al_alabama import al_alabama_state_income_withholding +from .state.ar_arkansas import ar_arkansas_state_income_withholding +from .state.az_arizona import az_arizona_state_income_withholding +from .state.ca_california import ca_california_state_income_withholding +from .state.co_colorado import co_colorado_state_income_withholding +from .state.ct_connecticut import ct_connecticut_state_income_withholding +from .state.de_delaware import de_delaware_state_income_withholding from .state.ga_georgia import ga_georgia_state_income_withholding +from .state.hi_hawaii import hi_hawaii_state_income_withholding +from .state.ia_iowa import ia_iowa_state_income_withholding +from .state.id_idaho import id_idaho_state_income_withholding +from .state.il_illinois import il_illinois_state_income_withholding +from .state.in_indiana import in_indiana_state_income_withholding +from .state.ks_kansas import ks_kansas_state_income_withholding +from .state.ky_kentucky import ky_kentucky_state_income_withholding +from .state.la_louisiana import la_louisiana_state_income_withholding +from .state.me_maine import me_maine_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 +from .state.nc_northcarolina import nc_northcarolina_state_income_withholding +from .state.nd_north_dakota import nd_north_dakota_state_income_withholding +from .state.ne_nebraska import ne_nebraska_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.ny_new_york import ny_new_york_state_income_withholding from .state.oh_ohio import oh_ohio_state_income_withholding +from .state.ok_oklahoma import ok_oklahoma_state_income_withholding +from .state.ri_rhode_island import ri_rhode_island_state_income_withholding +from .state.sc_south_carolina import sc_south_carolina_state_income_withholding +from .state.ut_utah import ut_utah_state_income_withholding +from .state.vt_vermont import vt_vermont_state_income_withholding from .state.va_virginia import va_virginia_state_income_withholding from .state.wa_washington import wa_washington_fml_er, \ wa_washington_fml_ee +from .state.wi_wisconsin import wi_wisconsin_state_income_withholding +from .state.wv_west_virginia import wv_west_virginia_state_income_withholding class HRPayslip(models.Model): @@ -53,13 +85,45 @@ class HRPayslip(models.Model): 'general_state_unemployment': general_state_unemployment, 'general_state_income_withholding': general_state_income_withholding, 'is_us_state': is_us_state, + 'al_alabama_state_income_withholding': al_alabama_state_income_withholding, + 'ar_arkansas_state_income_withholding': ar_arkansas_state_income_withholding, + 'az_arizona_state_income_withholding': az_arizona_state_income_withholding, + 'ca_california_state_income_withholding': ca_california_state_income_withholding, + 'co_colorado_state_income_withholding': co_colorado_state_income_withholding, + 'ct_connecticut_state_income_withholding': ct_connecticut_state_income_withholding, + 'de_delaware_state_income_withholding': de_delaware_state_income_withholding, 'ga_georgia_state_income_withholding': ga_georgia_state_income_withholding, + 'hi_hawaii_state_income_withholding': hi_hawaii_state_income_withholding, + 'ia_iowa_state_income_withholding': ia_iowa_state_income_withholding, + 'id_idaho_state_income_withholding': id_idaho_state_income_withholding, + 'il_illinois_state_income_withholding': il_illinois_state_income_withholding, + 'in_indiana_state_income_withholding': in_indiana_state_income_withholding, + 'ks_kansas_state_income_withholding': ks_kansas_state_income_withholding, + 'ky_kentucky_state_income_withholding':ky_kentucky_state_income_withholding, + 'la_louisiana_state_income_withholding': la_louisiana_state_income_withholding, + 'me_maine_state_income_withholding': me_maine_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, + 'nc_northcarolina_state_income_withholding': nc_northcarolina_state_income_withholding, + 'nd_north_dakota_state_income_withholding': nd_north_dakota_state_income_withholding, + 'ne_nebraska_state_income_withholding': ne_nebraska_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, + 'ny_new_york_state_income_withholding': ny_new_york_state_income_withholding, 'oh_ohio_state_income_withholding': oh_ohio_state_income_withholding, + 'ok_oklahoma_state_income_withholding': ok_oklahoma_state_income_withholding, + 'ri_rhode_island_state_income_withholding': ri_rhode_island_state_income_withholding, + 'sc_south_carolina_state_income_withholding': sc_south_carolina_state_income_withholding, + 'ut_utah_state_income_withholding': ut_utah_state_income_withholding, + 'vt_vermont_state_income_withholding': vt_vermont_state_income_withholding, 'va_virginia_state_income_withholding': va_virginia_state_income_withholding, 'wa_washington_fml_er': wa_washington_fml_er, 'wa_washington_fml_ee': wa_washington_fml_ee, + 'wi_wisconsin_state_income_withholding': wi_wisconsin_state_income_withholding, + 'wv_west_virginia_state_income_withholding': wv_west_virginia_state_income_withholding, } def get_year(self): @@ -82,34 +146,52 @@ class HRPayslip(models.Model): self.employee_id = employee_id self.dict = dict self.env = env + # Customization to allow changing the behavior of the discrete browsable objects. + # you can think of this as 'compiling' the query based on the configuration. + sum_field = env['ir.config_parameter'].sudo().get_param('hr_payroll.payslip.sum_behavior', 'date_from') + if sum_field == 'date' and 'date' not in env['hr.payslip']: + # missing attribute, closest by definition + sum_field = 'date_to' + if not sum_field: + sum_field = 'date_from' + self._compile_browsable_query(sum_field) def __getattr__(self, attr): return attr in self.dict and self.dict.__getitem__(attr) or 0.0 + def _compile_browsable_query(self, sum_field): + pass + class InputLine(BrowsableObject): """a class that will be used into the python code, mainly for usability purposes""" - def sum(self, code, from_date, to_date=None): - if to_date is None: - to_date = fields.Date.today() - self.env.cr.execute(""" + + def _compile_browsable_query(self, sum_field): + self.__browsable_query = """ SELECT sum(amount) as sum FROM hr_payslip as hp, hr_payslip_input as pi WHERE hp.employee_id = %s AND hp.state = 'done' - AND hp.date_from >= %s AND hp.date_to <= %s AND hp.id = pi.payslip_id AND pi.code = %s""", - (self.employee_id, from_date, to_date, code)) + AND hp.{sum_field} >= %s AND hp.date_to <= %s AND hp.id = pi.payslip_id AND pi.code = %s""".format(sum_field=sum_field) + + def sum(self, code, from_date, to_date=None): + if to_date is None: + to_date = fields.Date.today() + self.env.cr.execute(self.__browsable_query, (self.employee_id, from_date, to_date, code)) return self.env.cr.fetchone()[0] or 0.0 class WorkedDays(BrowsableObject): """a class that will be used into the python code, mainly for usability purposes""" - def _sum(self, code, from_date, to_date=None): - if to_date is None: - to_date = fields.Date.today() - self.env.cr.execute(""" + + def _compile_browsable_query(self, sum_field): + self.__browsable_query = """ SELECT sum(number_of_days) as number_of_days, sum(number_of_hours) as number_of_hours FROM hr_payslip as hp, hr_payslip_worked_days as pi WHERE hp.employee_id = %s AND hp.state = 'done' - AND hp.date_from >= %s AND hp.date_to <= %s AND hp.id = pi.payslip_id AND pi.code = %s""", - (self.employee_id, from_date, to_date, code)) + AND hp.{sum_field} >= %s AND hp.date_to <= %s AND hp.id = pi.payslip_id AND pi.code = %s""".format(sum_field=sum_field) + + def _sum(self, code, from_date, to_date=None): + if to_date is None: + to_date = fields.Date.today() + self.env.cr.execute(self.__browsable_query, (self.employee_id, from_date, to_date, code)) return self.env.cr.fetchone() def sum(self, code, from_date, to_date=None): @@ -123,28 +205,64 @@ class HRPayslip(models.Model): class Payslips(BrowsableObject): """a class that will be used into the python code, mainly for usability purposes""" + def _compile_browsable_query(self, sum_field): + # Note that the core odoo has this as `hp.credit_note = False` but what if it is NULL? + # reverse of the desired behavior. + self.__browsable_query_rule = """ + SELECT sum(case when hp.credit_note is not True then (pl.total) else (-pl.total) end) + FROM hr_payslip as hp, hr_payslip_line as pl + WHERE hp.employee_id = %s AND hp.state = 'done' + AND hp.{sum_field} >= %s AND hp.date_to <= %s AND hp.id = pl.slip_id AND pl.code = %s""".format(sum_field=sum_field) + + # Original (non-recursive) + # self.__browsable_query_category = """ + # SELECT sum(case when hp.credit_note is not True then (pl.total) else (-pl.total) end) + # FROM hr_payslip as hp, hr_payslip_line as pl, hr_salary_rule_category as rc + # WHERE hp.employee_id = %s AND hp.state = 'done' + # AND hp.{sum_field} >= %s AND hp.date_to <= %s AND hp.id = pl.slip_id + # AND rc.id = pl.category_id AND rc.code = %s""".format(sum_field=sum_field) + + # Hibou Recursive version + self.__browsable_query_category = """ + WITH RECURSIVE + category_by_code as ( + SELECT id + FROM hr_salary_rule_category + WHERE code = %s + ), + category_ids as ( + SELECT COALESCE((SELECT id FROM category_by_code), -1) AS id + UNION ALL + SELECT rc.id + FROM hr_salary_rule_category AS rc + JOIN category_ids AS rcs ON rcs.id = rc.parent_id + ) + + SELECT sum(case when hp.credit_note is not True then (pl.total) else (-pl.total) end) + FROM hr_payslip as hp, hr_payslip_line as pl + WHERE hp.employee_id = %s AND hp.state = 'done' + AND hp.{sum_field} >= %s AND hp.date_to <= %s AND hp.id = pl.slip_id + AND pl.category_id in (SELECT id from category_ids)""".format(sum_field=sum_field) + def sum(self, code, from_date, to_date=None): if to_date is None: to_date = fields.Date.today() - self.env.cr.execute("""SELECT sum(case when hp.credit_note = False then (pl.total) else (-pl.total) end) - FROM hr_payslip as hp, hr_payslip_line as pl - WHERE hp.employee_id = %s AND hp.state = 'done' - AND hp.date_from >= %s AND hp.date_to <= %s AND hp.id = pl.slip_id AND pl.code = %s""", - (self.employee_id, from_date, to_date, code)) + self.env.cr.execute(self.__browsable_query_rule, (self.employee_id, from_date, to_date, code)) res = self.env.cr.fetchone() return res and res[0] or 0.0 + def rule_parameter(self, code): + return self.env['hr.rule.parameter']._get_parameter_from_code(code, self.dict.date_to) + def sum_category(self, code, from_date, to_date=None): # Hibou Backport if to_date is None: to_date = fields.Date.today() - self.env.cr.execute("""SELECT sum(case when hp.credit_note is not True then (pl.total) else (-pl.total) end) - FROM hr_payslip as hp, hr_payslip_line as pl, hr_salary_rule_category as rc - WHERE hp.employee_id = %s AND hp.state = 'done' - AND hp.date_from >= %s AND hp.date_to <= %s AND hp.id = pl.slip_id - AND rc.id = pl.category_id AND rc.code = %s""", - (self.employee_id, from_date, to_date, code)) + # standard version + # self.env.cr.execute(self.__browsable_query_category, (self.employee_id, from_date, to_date, code)) + # recursive category version + self.env.cr.execute(self.__browsable_query_category, (code, self.employee_id, from_date, to_date)) res = self.env.cr.fetchone() return res and res[0] or 0.0 diff --git a/l10n_us_hr_payroll/models/hr_salary_rule.py b/l10n_us_hr_payroll/models/hr_salary_rule.py index a98029ec..64f0ce8e 100644 --- a/l10n_us_hr_payroll/models/hr_salary_rule.py +++ b/l10n_us_hr_payroll/models/hr_salary_rule.py @@ -1,3 +1,5 @@ +# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details. + from odoo import api, fields, models, _ from odoo.tools.safe_eval import safe_eval from odoo.exceptions import UserError diff --git a/l10n_us_hr_payroll/models/res_config_settings.py b/l10n_us_hr_payroll/models/res_config_settings.py new file mode 100644 index 00000000..05af9430 --- /dev/null +++ b/l10n_us_hr_payroll/models/res_config_settings.py @@ -0,0 +1,24 @@ +# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details. + +from odoo import fields, models + + +class ResConfigSettings(models.TransientModel): + _inherit = 'res.config.settings' + + payslip_sum_type = fields.Selection([ + ('date_from', 'Date From'), + ('date_to', 'Date To'), + ('date', 'Accounting Date'), + ], 'Payslip Sum Behavior', help="Behavior for what payslips are considered " + "during rule execution. Stock Odoo behavior " + "would not consider a payslip starting on 2019-12-30 " + "ending on 2020-01-07 when summing a 2020 payslip category.\n\n" + "Accounting Date requires Payroll Accounting and will " + "fall back to date_to as the 'closest behavior'.", + config_parameter='hr_payroll.payslip.sum_behavior') + + def set_values(self): + super(ResConfigSettings, self).set_values() + self.env['ir.config_parameter'].set_param('hr_payroll.payslip.sum_behavior', + self.payslip_sum_type or 'date_from') diff --git a/l10n_us_hr_payroll/models/state/al_alabama.py b/l10n_us_hr_payroll/models/state/al_alabama.py new file mode 100644 index 00000000..31e084e2 --- /dev/null +++ b/l10n_us_hr_payroll/models/state/al_alabama.py @@ -0,0 +1,80 @@ +# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details. + +from .general import _state_applies, sit_wage + + +def al_alabama_state_income_withholding(payslip, categories, worked_days, inputs): + """ + Returns SIT eligible wage and rate. + + :return: result, result_rate (wage, percent) + """ + state_code = 'AL' + 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 + + exemptions = payslip.contract_id.us_payroll_config_value('al_a4_sit_exemptions') + if not exemptions: + return 0.0, 0.0 + + personal_exempt = payslip.dict.contract_id.us_payroll_config_value('state_income_tax_exempt') + if personal_exempt: + return 0.0, 0.0 + + pay_periods = payslip.dict.get_pay_periods_in_year() + additional = payslip.dict.contract_id.us_payroll_config_value('state_income_tax_additional_withholding') + tax_table = payslip.dict.rule_parameter('us_al_sit_tax_rate') + dependent_rate = payslip.dict.rule_parameter('us_al_sit_dependent_rate') + standard_deduction = payslip.dict.rule_parameter('us_al_sit_standard_deduction_rate').get(exemptions, 0.0) + personal_exemption = payslip.dict.rule_parameter('us_al_sit_personal_exemption_rate').get(exemptions, 0.0) + dependent = payslip.dict.contract_id.us_payroll_config_value('al_a4_sit_dependents') + fed_withholding = categories.EE_US_941_FIT + + annual_wage = wage * pay_periods + standard_deduction_amt = 0.0 + personal_exemption_amt = 0.0 + dependent_amt = 0.0 + withholding = 0.0 + + if standard_deduction: + row = standard_deduction + last_amt = 0.0 + for data in row: + if annual_wage < float(data[0]): + if len(data) > 3: + increment_count = (- (wage - last_amt) // data[3]) + standard_deduction_amt = data[1] - (increment_count * data[2]) + else: + standard_deduction_amt = data[1] + else: + last_amt = data[0] + after_deduction = annual_wage - standard_deduction_amt + after_fed_withholding = (fed_withholding * pay_periods) + after_deduction + if not personal_exempt: + personal_exemption_amt = personal_exemption + after_personal_exemption = after_fed_withholding - personal_exemption_amt + for row in dependent_rate: + if annual_wage < float(row[1]): + dependent_amt = row[0] * dependent + break + + taxable_amount = after_personal_exemption - dependent_amt + last = 0.0 + tax_table = tax_table['M'] if exemptions == 'M' else tax_table['0'] + for row in tax_table: + if taxable_amount < float(row[0]): + withholding = withholding + ((taxable_amount - last) * (row[1] / 100)) + break + withholding = withholding + ((row[0] - last) * (row[1] / 100)) + last = row[0] + + if withholding < 0.0: + withholding = 0.0 + withholding /= pay_periods + withholding += additional + return wage, -((withholding / wage) * 100.0) diff --git a/l10n_us_hr_payroll/models/state/ar_arkansas.py b/l10n_us_hr_payroll/models/state/ar_arkansas.py new file mode 100644 index 00000000..4e3a008e --- /dev/null +++ b/l10n_us_hr_payroll/models/state/ar_arkansas.py @@ -0,0 +1,47 @@ +# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details. + +from .general import _state_applies, sit_wage + + +def ar_arkansas_state_income_withholding(payslip, categories, worked_days, inputs): + """ + Returns SIT eligible wage and rate. + + :return: result, result_rate (wage, percent) + """ + state_code = 'AR' + if not _state_applies(payslip, state_code): + return 0.0, 0.0 + + if payslip.dict.contract_id.us_payroll_config_value('state_income_tax_exempt'): + return 0.0, 0.0 + + # Determine Wage + wage = sit_wage(payslip, categories) + if not wage: + return 0.0, 0.0 + + 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_ar_sit_tax_rate') + standard_deduction = payslip.dict.rule_parameter('us_ar_sit_standard_deduction_rate') + allowances = payslip.dict.contract_id.us_payroll_config_value('ar_ar4ec_sit_allowances') + + allowances_amt = allowances * 26.0 + taxable_income = (wage * pay_periods) - standard_deduction + if taxable_income < 87001.0: + taxable_income = (taxable_income // 50) * 50.0 + 50.0 + + withholding = 0.0 + for row in sit_tax_rate: + cap, rate, adjust_amount = row + cap = float(cap) + if cap > taxable_income: + withholding = (((rate / 100.0) * taxable_income) - adjust_amount) - allowances_amt + break + + # In case withholding or taxable_income is negative + withholding = max(withholding, 0.0) + withholding = round(withholding / pay_periods) + withholding += additional + return wage, -((withholding / wage) * 100.0) diff --git a/l10n_us_hr_payroll/models/state/az_arizona.py b/l10n_us_hr_payroll/models/state/az_arizona.py new file mode 100644 index 00000000..5878a7b9 --- /dev/null +++ b/l10n_us_hr_payroll/models/state/az_arizona.py @@ -0,0 +1,35 @@ +# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details. + +from .general import _state_applies, sit_wage + + +def az_arizona_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 = 'AZ' + 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 + + schedule_pay = payslip.dict.contract_id.schedule_pay + additional = payslip.dict.contract_id.us_payroll_config_value('state_income_tax_additional_withholding') + withholding_percent = payslip.dict.contract_id.us_payroll_config_value('az_a4_sit_withholding_percentage') + + if withholding_percent <= 0.0: + return 0.0, 0.0 + + wh_percentage = withholding_percent / 100.0 + withholding = wage * wh_percentage + + if withholding < 0.0: + withholding = 0.0 + withholding += additional + return wage, -((withholding / wage) * 100.0) diff --git a/l10n_us_hr_payroll/models/state/ca_california.py b/l10n_us_hr_payroll/models/state/ca_california.py new file mode 100644 index 00000000..e2bb5b23 --- /dev/null +++ b/l10n_us_hr_payroll/models/state/ca_california.py @@ -0,0 +1,98 @@ +# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details. + +from .general import _state_applies, sit_wage + +MAX_ALLOWANCES = 10 + + +def ca_california_state_income_withholding(payslip, categories, worked_days, inputs): + """ + Returns SIT eligible wage and rate. + + :return: result, result_rate (wage, percent) + """ + + state_code = 'CA' + 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.dict.contract_id.us_payroll_config_value('ca_de4_sit_filing_status') + if not filing_status: + return 0.0, 0.0 + + schedule_pay = payslip.dict.contract_id.schedule_pay + additional = payslip.dict.contract_id.us_payroll_config_value('state_income_tax_additional_withholding') + sit_allowances = payslip.dict.contract_id.us_payroll_config_value('ca_de4_sit_allowances') + additional_allowances = payslip.dict.contract_id.us_payroll_config_value('ca_de4_sit_additional_allowances') + low_income_exemption = payslip.dict.rule_parameter('us_ca_sit_income_exemption_rate')[schedule_pay] + estimated_deduction = payslip.dict.rule_parameter('us_ca_sit_estimated_deduction_rate')[schedule_pay] + tax_table = payslip.dict.rule_parameter('us_ca_sit_tax_rate')[filing_status].get(schedule_pay) + standard_deduction = payslip.dict.rule_parameter('us_ca_sit_standard_deduction_rate')[schedule_pay] + exemption_allowances = payslip.dict.rule_parameter('us_ca_sit_exemption_allowance_rate')[schedule_pay] + + low_income = False + if filing_status == 'head_household': + _, _, _, income = low_income_exemption + if wage <= income: + low_income = True + elif filing_status == 'married': + if sit_allowances >= 2: + _, _, income, _ = low_income_exemption + if wage <= income: + low_income = True + else: + _, income, _, _ = low_income_exemption + if wage <= income: + low_income = True + else: + income, _, _, _ = low_income_exemption + if wage <= income: + low_income = True + + withholding = 0.0 + taxable_wage = wage + if not low_income: + allowance_index = max(additional_allowances - 1, 0) + if additional_allowances > MAX_ALLOWANCES: + deduction = (estimated_deduction[0] * additional_allowances) + taxable_wage -= deduction + elif additional_allowances > 0: + deduction = estimated_deduction[allowance_index] + taxable_wage -= deduction + + if filing_status == 'head_household': + _, _, _, deduction = standard_deduction + taxable_wage -= deduction + elif filing_status == 'married': + if sit_allowances >= 2: + _, _, deduction, _ = standard_deduction + taxable_wage -= deduction + else: + _, deduction, _, _ = standard_deduction + taxable_wage -= deduction + else: + deduction, _, _, _ = standard_deduction + taxable_wage -= deduction + + over = 0.0 + for row in tax_table: + if taxable_wage <= row[0]: + withholding = ((taxable_wage - over) * row[1]) + row[2] + break + over = row[0] + + allowance_index = sit_allowances - 1 + if sit_allowances > MAX_ALLOWANCES: + deduction = exemption_allowances[0] * sit_allowances + withholding -= deduction + elif sit_allowances > 0: + deduction = exemption_allowances[allowance_index] + withholding -= deduction + + withholding += additional + return wage, -((withholding / wage) * 100.0) diff --git a/l10n_us_hr_payroll/models/state/co_colorado.py b/l10n_us_hr_payroll/models/state/co_colorado.py new file mode 100644 index 00000000..5fc625b2 --- /dev/null +++ b/l10n_us_hr_payroll/models/state/co_colorado.py @@ -0,0 +1,45 @@ +# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details. + +from .general import _state_applies, sit_wage + + +def co_colorado_state_income_withholding(payslip, categories, worked_days, inputs): + """ + Returns SIT eligible wage and rate. + + :return: result, result_rate (wage, percent) + """ + state_code = 'CO' + 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.dict.contract_id.us_payroll_config_value('fed_941_fit_w4_filing_status') + if not filing_status: + return 0.0, 0.0 + + state_exempt = payslip.dict.contract_id.us_payroll_config_value('state_income_tax_exempt') + if state_exempt: + return 0.0, 0.0 + + pay_periods = payslip.dict.get_pay_periods_in_year() + additional = payslip.dict.contract_id.us_payroll_config_value('state_income_tax_additional_withholding') + exemption_rate = payslip.dict.rule_parameter('us_co_sit_exemption_rate') + tax_rate = payslip.dict.rule_parameter('us_co_sit_tax_rate') + + taxable_income = wage * pay_periods + if filing_status == 'married': + taxable_income -= exemption_rate * 2 + else: + taxable_income -= exemption_rate + + withholding = taxable_income * (tax_rate / 100) + + withholding = max(withholding, 0.0) + withholding = withholding / pay_periods + withholding += additional + return wage, -((withholding / wage) * 100.0) diff --git a/l10n_us_hr_payroll/models/state/ct_connecticut.py b/l10n_us_hr_payroll/models/state/ct_connecticut.py new file mode 100644 index 00000000..a3034fec --- /dev/null +++ b/l10n_us_hr_payroll/models/state/ct_connecticut.py @@ -0,0 +1,76 @@ +# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details. + +from .general import _state_applies, sit_wage + + +def ct_connecticut_state_income_withholding(payslip, categories, worked_days, inputs): + """ + Returns SIT eligible wage and rate. + + :return: result, result_rate (wage, percent) + """ + state_code = 'CT' + 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 + + pay_periods = payslip.dict.get_pay_periods_in_year() + additional = payslip.dict.contract_id.us_payroll_config_value('state_income_tax_additional_withholding') + withholding_code = payslip.dict.contract_id.us_payroll_config_value('ct_w4na_sit_code') + exemption_table = payslip.dict.rule_parameter('us_ct_sit_personal_exemption_rate').get(withholding_code, [('inf', 0.0)]) + initial_tax_tbl = payslip.dict.rule_parameter('us_ct_sit_initial_tax_rate').get(withholding_code, [('inf', 0.0, 0.0)]) + tax_table = payslip.dict.rule_parameter('us_ct_sit_tax_rate').get(withholding_code, [('inf', 0.0)]) + recapture_table = payslip.dict.rule_parameter('us_ct_sit_recapture_rate').get(withholding_code, [('inf', 0.0)]) + decimal_table = payslip.dict.rule_parameter('us_ct_sit_decimal_rate').get(withholding_code, [('inf', 0.0)]) + + annual_wages = wage * pay_periods + personal_exemption = 0.0 + for bracket in exemption_table: + if annual_wages <= float(bracket[0]): + personal_exemption = bracket[1] + break + + withholding = 0.0 + taxable_income = annual_wages - personal_exemption + if taxable_income < 0.0: + taxable_income = 0.0 + + if taxable_income: + initial_tax = 0.0 + last = 0.0 + for bracket in initial_tax_tbl: + if taxable_income <= float(bracket[0]): + initial_tax = bracket[1] + ((bracket[2] / 100.0) * (taxable_income - last)) + break + last = bracket[0] + + tax_add_back = 0.0 + for bracket in tax_table: + if annual_wages <= float(bracket[0]): + tax_add_back = bracket[1] + break + + recapture_amount = 0.0 + for bracket in recapture_table: + if annual_wages <= float(bracket[0]): + recapture_amount = bracket[1] + break + + withholding = initial_tax + tax_add_back + recapture_amount + decimal_amount = 1.0 + for bracket in decimal_table: + if annual_wages <= float(bracket[0]): + decimal_amount= bracket[1] + break + + withholding = withholding * (1.00 - decimal_amount) + if withholding < 0.0: + withholding = 0.0 + withholding /= pay_periods + + withholding += additional + return wage, -((withholding / wage) * 100.0) diff --git a/l10n_us_hr_payroll/models/state/de_delaware.py b/l10n_us_hr_payroll/models/state/de_delaware.py new file mode 100644 index 00000000..cb24edf5 --- /dev/null +++ b/l10n_us_hr_payroll/models/state/de_delaware.py @@ -0,0 +1,49 @@ +# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details. + +from .general import _state_applies, sit_wage + + +def de_delaware_state_income_withholding(payslip, categories, worked_days, inputs): + """ + Returns SIT eligible wage and rate. + + :return: result, result_rate (wage, percent) + """ + state_code = 'DE' + 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.dict.contract_id.us_payroll_config_value('de_w4_sit_filing_status') + if not filing_status: + return 0.0, 0.0 + + pay_periods = payslip.dict.get_pay_periods_in_year() + additional = payslip.dict.contract_id.us_payroll_config_value('state_income_tax_additional_withholding') + tax_table = payslip.dict.rule_parameter('us_de_sit_tax_rate') + personal_exemption = payslip.dict.rule_parameter('us_de_sit_personal_exemption_rate') + allowances = payslip.dict.contract_id.us_payroll_config_value('de_w4_sit_dependent') + standard_deduction = payslip.dict.rule_parameter('us_de_sit_standard_deduction_rate') + + taxable_income = wage * pay_periods + if filing_status == 'single': + taxable_income -= standard_deduction + else: + taxable_income -= standard_deduction * 2 + + 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)) - (allowances * personal_exemption)) + break + last = row[0] + + withholding = max(withholding, 0.0) + withholding = withholding / pay_periods + withholding += additional + return wage, -((withholding / wage) * 100.0) diff --git a/l10n_us_hr_payroll/models/state/ga_georgia.py b/l10n_us_hr_payroll/models/state/ga_georgia.py index 38032409..188d3a34 100644 --- a/l10n_us_hr_payroll/models/state/ga_georgia.py +++ b/l10n_us_hr_payroll/models/state/ga_georgia.py @@ -1,12 +1,11 @@ # Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details. -from .general import _state_applies +from .general import _state_applies, sit_wage def ga_georgia_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) """ @@ -14,11 +13,14 @@ def ga_georgia_state_income_withholding(payslip, categories, worked_days, inputs if not _state_applies(payslip, state_code): return 0.0, 0.0 ga_filing_status = payslip.dict.contract_id.us_payroll_config_value('ga_g4_sit_filing_status') - if not ga_filing_status or ga_filing_status == 'exempt': + if not ga_filing_status: return 0.0, 0.0 # Determine Wage - wage = categories.GROSS + categories.DED_FIT_EXEMPT + wage = sit_wage(payslip, categories) + if not wage: + return 0.0, 0.0 + schedule_pay = payslip.dict.contract_id.schedule_pay additional = payslip.dict.contract_id.us_payroll_config_value('state_income_tax_additional_withholding') dependent_allowances = payslip.dict.contract_id.us_payroll_config_value('ga_g4_sit_dependent_allowances') @@ -27,10 +29,7 @@ def ga_georgia_state_income_withholding(payslip, categories, worked_days, inputs personal_allowance = payslip.dict.rule_parameter('us_ga_sit_personal_allowance').get(ga_filing_status, {}).get(schedule_pay) deduction = payslip.dict.rule_parameter('us_ga_sit_deduction').get(ga_filing_status, {}).get(schedule_pay) withholding_rate = payslip.dict.rule_parameter('us_ga_sit_rate').get(ga_filing_status, {}).get(schedule_pay) - if not all((dependent_allowance_rate, personal_allowance, deduction, withholding_rate)) or wage == 0.0: - return 0.0, 0.0 - - if wage == 0.0: + if not all((dependent_allowance_rate, personal_allowance, deduction, withholding_rate)): return 0.0, 0.0 after_standard_deduction = wage - deduction diff --git a/l10n_us_hr_payroll/models/state/general.py b/l10n_us_hr_payroll/models/state/general.py index f0dbc37f..8cac1bc6 100644 --- a/l10n_us_hr_payroll/models/state/general.py +++ b/l10n_us_hr_payroll/models/state/general.py @@ -1,9 +1,16 @@ # Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details. from odoo.exceptions import UserError +from ..federal.fed_940 import futa_wage, futa_wage_ytd +from ..federal.fed_941 import fit_wage, fit_wage_ytd # import logging # _logger = logging.getLogger(__name__) +suta_wage = futa_wage +suta_wage_ytd = futa_wage_ytd +sit_wage = fit_wage +sit_wage_ytd = fit_wage_ytd + def _state_applies(payslip, state_code): return state_code == payslip.dict.contract_id.us_payroll_config_value('state_code') @@ -89,12 +96,12 @@ def general_state_unemployment(payslip, categories, worked_days, inputs, wage_ba return 0.0, 0.0 # Determine Wage - year = payslip.dict.get_year() - ytd_wage = payslip.sum_category('GROSS', str(year) + '-01-01', str(year + 1) + '-01-01') - ytd_wage += payslip.sum_category('DED_FUTA_EXEMPT', str(year) + '-01-01', str(year + 1) + '-01-01') - ytd_wage += payslip.dict.contract_id.external_wages + wage = suta_wage(payslip, categories) + if not wage: + return 0.0, 0.0 + + ytd_wage = suta_wage_ytd(payslip, categories) - wage = categories.GROSS + categories.DED_FUTA_EXEMPT return _general_rate(payslip, wage, ytd_wage, wage_base=wage_base, wage_start=wage_start, rate=rate) @@ -112,12 +119,8 @@ def general_state_income_withholding(payslip, categories, worked_days, inputs, w return 0.0, 0.0 # Determine Wage - year = payslip.dict.get_year() - ytd_wage = payslip.sum_category('GROSS', str(year) + '-01-01', str(year + 1) + '-01-01') - ytd_wage += payslip.sum_category('DED_FIT_EXEMPT', str(year) + '-01-01', str(year + 1) + '-01-01') - ytd_wage += payslip.dict.contract_id.external_wages - - wage = categories.GROSS + categories.DED_FIT_EXEMPT + ytd_wage = sit_wage_ytd(payslip, categories) + wage = sit_wage(payslip, categories) result, result_rate = _general_rate(payslip, wage, ytd_wage, wage_base=wage_base, wage_start=wage_start, rate=rate) additional = payslip.dict.contract_id.us_payroll_config_value('state_income_tax_additional_withholding') if additional: diff --git a/l10n_us_hr_payroll/models/state/hi_hawaii.py b/l10n_us_hr_payroll/models/state/hi_hawaii.py new file mode 100644 index 00000000..b52a97bf --- /dev/null +++ b/l10n_us_hr_payroll/models/state/hi_hawaii.py @@ -0,0 +1,43 @@ +# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details. + +from .general import _state_applies, sit_wage + + +def hi_hawaii_state_income_withholding(payslip, categories, worked_days, inputs): + """ + Returns SIT eligible wage and rate. + + :return: result, result_rate (wage, percent) + """ + state_code = 'HI' + 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.dict.contract_id.us_payroll_config_value('hi_hw4_sit_filing_status') + if not filing_status: + return 0.0, 0.0 + + pay_periods = payslip.dict.get_pay_periods_in_year() + additional = payslip.dict.contract_id.us_payroll_config_value('state_income_tax_additional_withholding') + allowances = payslip.dict.contract_id.us_payroll_config_value('hi_hw4_sit_allowances') + tax_table = payslip.dict.rule_parameter('us_hi_sit_tax_rate')[filing_status] + personal_exemption = payslip.dict.rule_parameter('us_hi_sit_personal_exemption_rate') + + taxable_income = (wage * pay_periods) - (personal_exemption * allowances) + 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 = withholding / pay_periods + withholding += additional + return wage, -((withholding / wage) * 100.0) diff --git a/l10n_us_hr_payroll/models/state/ia_iowa.py b/l10n_us_hr_payroll/models/state/ia_iowa.py new file mode 100644 index 00000000..ca339a20 --- /dev/null +++ b/l10n_us_hr_payroll/models/state/ia_iowa.py @@ -0,0 +1,48 @@ +# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details. + +from .general import _state_applies, sit_wage + + +def ia_iowa_state_income_withholding(payslip, categories, worked_days, inputs): + """ + Returns SIT eligible wage and rate. + + :return: result, result_rate (wage, percent) + """ + state_code = 'IA' + if not _state_applies(payslip, state_code): + return 0.0, 0.0 + + if payslip.contract_id.us_payroll_config_value('state_income_tax_exempt'): + return 0.0, 0.0 + + # Determine Wage + wage = sit_wage(payslip, categories) + if not wage: + return 0.0, 0.0 + + schedule_pay = payslip.dict.contract_id.schedule_pay + fed_withholding = categories.EE_US_941_FIT + additional = payslip.dict.contract_id.us_payroll_config_value('state_income_tax_additional_withholding') + allowances = payslip.dict.contract_id.us_payroll_config_value('ia_w4_sit_allowances') + standard_deduction = payslip.dict.rule_parameter('us_ia_sit_standard_deduction_rate')[schedule_pay] + tax_table = payslip.dict.rule_parameter('us_ia_sit_tax_rate')[schedule_pay] + deduction_per_allowance = payslip.dict.rule_parameter('us_ia_sit_deduction_allowance_rate')[schedule_pay] + + t1 = wage + fed_withholding + standard_deduction_amt = standard_deduction[0] if allowances < 2 else standard_deduction[1] + t2 = t1 - standard_deduction_amt + t3 = 0.0 + last = 0.0 + for row in tax_table: + cap, rate, flat_fee = row + if float(cap) > float(t2): + taxed_amount = t2 - last + t3 = flat_fee + (rate * taxed_amount) + break + last = cap + withholding = t3 - (deduction_per_allowance * allowances) + + withholding = max(withholding, 0.0) + withholding += additional + return wage, -((withholding / wage) * 100.0) diff --git a/l10n_us_hr_payroll/models/state/id_idaho.py b/l10n_us_hr_payroll/models/state/id_idaho.py new file mode 100644 index 00000000..5eee7665 --- /dev/null +++ b/l10n_us_hr_payroll/models/state/id_idaho.py @@ -0,0 +1,41 @@ +# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details. + +from .general import _state_applies, sit_wage + + +def id_idaho_state_income_withholding(payslip, categories, worked_days, inputs): + """ + Returns SIT eligible wage and rate. + + :return: result, result_rate (wage, percent) + """ + state_code = 'ID' + 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.dict.contract_id.us_payroll_config_value('id_w4_sit_filing_status') + if not filing_status: + return 0.0, 0.0 + + schedule_pay = payslip.dict.contract_id.schedule_pay + allowances = payslip.dict.contract_id.us_payroll_config_value('id_w4_sit_allowances') + ictcat_table = payslip.dict.rule_parameter('us_id_sit_ictcat_rate')[schedule_pay] + tax_table = payslip.dict.rule_parameter('us_id_sit_tax_rate')[filing_status].get(schedule_pay) + + taxable_income = wage - (ictcat_table * allowances) + 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 = round(withholding) + return wage, -((withholding / wage) * 100.0) diff --git a/l10n_us_hr_payroll/models/state/il_illinois.py b/l10n_us_hr_payroll/models/state/il_illinois.py new file mode 100644 index 00000000..e0e920a3 --- /dev/null +++ b/l10n_us_hr_payroll/models/state/il_illinois.py @@ -0,0 +1,35 @@ +# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details. + +from .general import _state_applies, sit_wage + + +def il_illinois_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 = 'IL' + 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 + + pay_periods = payslip.dict.get_pay_periods_in_year() + additional = payslip.dict.contract_id.us_payroll_config_value('state_income_tax_additional_withholding') + basic_allowances_rate = payslip.dict.rule_parameter('us_il_sit_basic_allowances_rate') + additional_allowances_rate = payslip.dict.rule_parameter('us_il_sit_additional_allowances_rate') + basic_allowances = payslip.dict.contract_id.us_payroll_config_value('il_w4_sit_basic_allowances') + additional_allowances = payslip.dict.contract_id.us_payroll_config_value('il_w4_sit_additional_allowances') + + rate = 4.95 / 100.0 + withholding = rate * (wage - (((basic_allowances * basic_allowances_rate) + (additional_allowances * + additional_allowances_rate)) / pay_periods)) + if withholding < 0.0: + withholding = 0.0 + withholding += additional + return wage, -((withholding / wage) * 100.0) diff --git a/l10n_us_hr_payroll/models/state/in_indiana.py b/l10n_us_hr_payroll/models/state/in_indiana.py new file mode 100644 index 00000000..f210ae2d --- /dev/null +++ b/l10n_us_hr_payroll/models/state/in_indiana.py @@ -0,0 +1,34 @@ +# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details. + +from .general import _state_applies, sit_wage + + +def in_indiana_state_income_withholding(payslip, categories, worked_days, inputs): + """ + Returns SIT eligible wage and rate. + + :return: result, result_rate (wage, percent) + """ + state_code = 'IN' + 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 + + schedule_pay = payslip.dict.contract_id.schedule_pay + additional = payslip.dict.contract_id.us_payroll_config_value('state_income_tax_additional_withholding') + personal_exemption = payslip.dict.contract_id.us_payroll_config_value('in_w4_sit_personal_exemption') + personal_exemption_rate = payslip.dict.rule_parameter('us_in_sit_personal_exemption_rate')[schedule_pay][personal_exemption - 1] + dependent_exemption = payslip.dict.contract_id.us_payroll_config_value('in_w4_sit_dependent_exemption') + dependent_exemption_rate = payslip.dict.rule_parameter('us_in_sit_dependent_exemption_rate')[schedule_pay][dependent_exemption - 1] + income_tax_rate = payslip.dict.rule_parameter('us_in_suta_income_rate') + + taxable_income = wage - (personal_exemption_rate + dependent_exemption_rate) + withholding = taxable_income * (income_tax_rate / 100.0) + + withholding = max(withholding, 0.0) + withholding += additional + return wage, -((withholding / wage) * 100.0) diff --git a/l10n_us_hr_payroll/models/state/ks_kansas.py b/l10n_us_hr_payroll/models/state/ks_kansas.py new file mode 100644 index 00000000..cac3a05f --- /dev/null +++ b/l10n_us_hr_payroll/models/state/ks_kansas.py @@ -0,0 +1,44 @@ +# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details. + +from .general import _state_applies, sit_wage + + +def ks_kansas_state_income_withholding(payslip, categories, worked_days, inputs): + """ + Returns SIT eligible wage and rate. + + :return: result, result_rate (wage, percent) + """ + state_code = 'KS' + 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.dict.contract_id.us_payroll_config_value('ks_k4_sit_filing_status') + if not filing_status: + return 0.0, 0.0 + + schedule_pay = payslip.dict.contract_id.schedule_pay + additional = payslip.dict.contract_id.us_payroll_config_value('state_income_tax_additional_withholding') + allowances = payslip.dict.contract_id.us_payroll_config_value('ks_k4_sit_allowances') + allowances_amt = payslip.dict.rule_parameter('us_ks_sit_allowances_rate')[schedule_pay] + tax_table = payslip.dict.rule_parameter('us_ks_sit_tax_rate')[filing_status].get(schedule_pay) + + taxable_income = wage - (allowances * allowances_amt) + withholding = 0.0 + last = 0.0 + for row in tax_table: + amt, rate, flat_fee = row + if wage <= float(amt): + withholding = ((taxable_income - last) * (rate / 100)) + flat_fee + break + last = amt + + withholding = max(withholding, 0.0) + withholding += additional + withholding = round(withholding) + return wage, -((withholding / wage) * 100.0) diff --git a/l10n_us_hr_payroll/models/state/ky_kentucky.py b/l10n_us_hr_payroll/models/state/ky_kentucky.py new file mode 100644 index 00000000..75f53778 --- /dev/null +++ b/l10n_us_hr_payroll/models/state/ky_kentucky.py @@ -0,0 +1,32 @@ +# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details. + +from .general import _state_applies, sit_wage + + +def ky_kentucky_state_income_withholding(payslip, categories, worked_days, inputs): + """ + Returns SIT eligible wage and rate. + + :return: result, result_rate (wage, percent) + """ + state_code = 'KY' + 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 + + pay_periods = payslip.dict.get_pay_periods_in_year() + additional = payslip.dict.contract_id.us_payroll_config_value('state_income_tax_additional_withholding') + tax_rate = payslip.dict.rule_parameter('us_ky_sit_tax_rate') + standard_deduction = payslip.dict.rule_parameter('us_ky_sit_standard_deduction_rate') + + taxable_income = (wage * pay_periods) - standard_deduction + withholding = taxable_income * (tax_rate / 100) + + withholding = max(withholding, 0.0) + withholding /= pay_periods + withholding += additional + return wage, -((withholding / wage) * 100.0) diff --git a/l10n_us_hr_payroll/models/state/la_louisiana.py b/l10n_us_hr_payroll/models/state/la_louisiana.py new file mode 100644 index 00000000..db9c3bcf --- /dev/null +++ b/l10n_us_hr_payroll/models/state/la_louisiana.py @@ -0,0 +1,62 @@ +# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details. + +from .general import _state_applies, sit_wage + + +def la_louisiana_state_income_withholding(payslip, categories, worked_days, inputs): + """ + Returns SIT eligible wage and rate. + + :return: result, result_rate (wage, percent) + """ + state_code = 'LA' + 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.dict.contract_id.us_payroll_config_value('la_l4_sit_filing_status') + if not filing_status: + return 0.0, 0.0 + + pay_periods = payslip.dict.get_pay_periods_in_year() + personal_exemptions = payslip.dict.contract_id.us_payroll_config_value('la_l4_sit_exemptions') + additional = payslip.dict.contract_id.us_payroll_config_value('state_income_tax_additional_withholding') + dependent_exemptions = payslip.dict.contract_id.us_payroll_config_value('la_l4_sit_dependents') + tax_table = payslip.dict.rule_parameter('us_la_sit_tax_rate')[filing_status] + exemption_rate = payslip.dict.rule_parameter('us_la_sit_personal_exemption_rate') + dependent_rate = payslip.dict.rule_parameter('us_la_sit_dependent_rate') + + annual_wage = wage * pay_periods + + effect_cap = 0.0 + multiplier = 0.0 + if filing_status == 'single': + effect_cap = 12500.00 + multiplier = 1.60 + elif filing_status == 'married': + effect_cap = 25000.00 + multiplier = 1.65 + + after_credits_under = (2.100 / 100) * (((personal_exemptions * exemption_rate) + + (dependent_exemptions * dependent_rate)) / pay_periods) + after_credits_over = 0.00 + if after_credits_under > effect_cap: + after_credits_under = effect_cap + after_credits_over_check = ((personal_exemptions * exemption_rate) + (dependent_exemptions * dependent_rate)) - effect_cap + after_credits_over = (multiplier / 100.00) * (after_credits_over_check / pay_periods) if after_credits_over_check > 0 else 0.00 + withholding = 0.0 + last = 0.0 + for amt, rate in tax_table: + withholding = withholding + ((rate / 100.0) * (wage - (last / pay_periods))) + if annual_wage <= float(amt): + break + last = amt + + withholding = withholding - (after_credits_under + after_credits_over) + withholding = round(withholding, 2) + withholding += additional + return wage, -((withholding / wage) * 100.0) diff --git a/l10n_us_hr_payroll/models/state/me_maine.py b/l10n_us_hr_payroll/models/state/me_maine.py new file mode 100644 index 00000000..fa5bf874 --- /dev/null +++ b/l10n_us_hr_payroll/models/state/me_maine.py @@ -0,0 +1,62 @@ +# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details. + +from .general import _state_applies, sit_wage + + +def me_maine_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 = 'ME' + 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.dict.contract_id.us_payroll_config_value('me_w4me_sit_filing_status') + if not filing_status: + return 0.0, 0.0 + + exempt = payslip.dict.contract_id.us_payroll_config_value('state_income_tax_exempt') + if exempt: + return 0.0, 0.0 + + pay_periods = payslip.dict.get_pay_periods_in_year() + additional = payslip.dict.contract_id.us_payroll_config_value('state_income_tax_additional_withholding') + allowances = payslip.dict.contract_id.us_payroll_config_value('me_w4me_sit_allowances') + tax_rate = payslip.dict.rule_parameter('us_me_sit_tax_rate')[filing_status] + personal_exemption = payslip.dict.rule_parameter('us_me_sit_personal_exemption_rate') + standard_deduction = payslip.dict.rule_parameter('us_me_sit_standard_deduction_rate')[filing_status] + + taxable_income = wage * pay_periods + exemption_amt = allowances * personal_exemption + last = 0.0 + standard_deduction_amt = 0.0 + for row in standard_deduction: + amt, flat_amt = row + if taxable_income < 82900: + standard_deduction_amt = flat_amt + break + elif taxable_income < amt: + standard_deduction_amt = last * (amt - taxable_income) / flat_amt + break + last = flat_amt + annual_income = taxable_income - (exemption_amt + standard_deduction_amt) + withholding = 0.0 + for row in tax_rate: + amt, flat_fee, rate = row + if annual_income < float(amt): + withholding = ((annual_income - last) * (rate / 100)) + flat_fee + break + last = amt + + withholding = max(withholding, 0.0) + withholding = round(withholding / pay_periods) + withholding += additional + return wage, -((withholding / wage) * 100.0) diff --git a/l10n_us_hr_payroll/models/state/mi_michigan.py b/l10n_us_hr_payroll/models/state/mi_michigan.py new file mode 100644 index 00000000..1c5f1cf6 --- /dev/null +++ b/l10n_us_hr_payroll/models/state/mi_michigan.py @@ -0,0 +1,35 @@ +# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details. + +from .general import _state_applies, sit_wage + + +def mi_michigan_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 = 'MI' + if not _state_applies(payslip, state_code): + return 0.0, 0.0 + + if payslip.dict.contract_id.us_payroll_config_value('state_income_tax_exempt'): + return 0.0, 0.0 + + # Determine Wage + wage = sit_wage(payslip, categories) + if not wage: + return 0.0, 0.0 + + pay_periods = payslip.dict.get_pay_periods_in_year() + additional = payslip.dict.contract_id.us_payroll_config_value('state_income_tax_additional_withholding') + exemption_rate = payslip.dict.rule_parameter('us_mi_sit_exemption_rate') + exemption = payslip.dict.contract_id.us_payroll_config_value('mi_w4_sit_exemptions') + + annual_exemption = (exemption * exemption_rate) / pay_periods + withholding = ((wage - annual_exemption) * 0.0425) + if withholding < 0.0: + withholding = 0.0 + withholding += additional + return wage, -((withholding / wage) * 100.0) diff --git a/l10n_us_hr_payroll/models/state/mn_minnesota.py b/l10n_us_hr_payroll/models/state/mn_minnesota.py new file mode 100644 index 00000000..3aab572c --- /dev/null +++ b/l10n_us_hr_payroll/models/state/mn_minnesota.py @@ -0,0 +1,44 @@ +# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details. + +from .general import _state_applies, sit_wage + + +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 = sit_wage(payslip, categories) + if not wage: + return 0.0, 0.0 + + 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') + + 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) diff --git a/l10n_us_hr_payroll/models/state/mo_missouri.py b/l10n_us_hr_payroll/models/state/mo_missouri.py new file mode 100644 index 00000000..d917856c --- /dev/null +++ b/l10n_us_hr_payroll/models/state/mo_missouri.py @@ -0,0 +1,53 @@ +# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details. + +from .general import _state_applies, sit_wage + + +def mo_missouri_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 = 'MO' + if not _state_applies(payslip, state_code): + return 0.0, 0.0 + + filing_status = payslip.dict.contract_id.us_payroll_config_value('mo_mow4_sit_filing_status') + if not filing_status: + return 0.0, 0.0 + + # Determine Wage + wage = sit_wage(payslip, categories) + if not wage: + return 0.0, 0.0 + + reduced_withholding = payslip.contract_id.us_payroll_config_value('mo_mow4_sit_withholding') + if reduced_withholding: + return wage, -((reduced_withholding / wage) * 100.0) + + pay_periods = payslip.dict.get_pay_periods_in_year() + additional = payslip.dict.contract_id.us_payroll_config_value('state_income_tax_additional_withholding') + sit_table = payslip.dict.rule_parameter('us_mo_sit_rate') + deduction = payslip.dict.rule_parameter('us_mo_sit_deduction')[filing_status] + + gross_taxable_income = wage * pay_periods + gross_taxable_income -= deduction + + remaining_taxable_income = gross_taxable_income + withholding = 0.0 + for amt, rate in sit_table: + amt = float(amt) + rate = rate / 100.0 + if (remaining_taxable_income - amt) > 0.0 or (remaining_taxable_income - amt) == 0.0: + withholding += rate * amt + else: + withholding += rate * remaining_taxable_income + break + remaining_taxable_income = remaining_taxable_income - amt + + withholding /= pay_periods + withholding += additional + withholding = round(withholding) + return wage, -((withholding / wage) * 100.0) diff --git a/l10n_us_hr_payroll/models/state/ms_mississippi.py b/l10n_us_hr_payroll/models/state/ms_mississippi.py index 33162129..d5f0fa84 100644 --- a/l10n_us_hr_payroll/models/state/ms_mississippi.py +++ b/l10n_us_hr_payroll/models/state/ms_mississippi.py @@ -1,6 +1,6 @@ # Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details. -from .general import _state_applies +from .general import _state_applies, sit_wage def ms_mississippi_state_income_withholding(payslip, categories, worked_days, inputs): @@ -19,8 +19,8 @@ def ms_mississippi_state_income_withholding(payslip, categories, worked_days, in return 0.0, 0.0 # Determine Wage - wage = categories.GROSS + categories.DED_FIT_EXEMPT - if wage == 0.0: + wage = sit_wage(payslip, categories) + if not wage: return 0.0, 0.0 pay_periods = payslip.dict.get_pay_periods_in_year() diff --git a/l10n_us_hr_payroll/models/state/mt_montana.py b/l10n_us_hr_payroll/models/state/mt_montana.py index a531c0e0..92dc8b5c 100644 --- a/l10n_us_hr_payroll/models/state/mt_montana.py +++ b/l10n_us_hr_payroll/models/state/mt_montana.py @@ -1,6 +1,6 @@ # Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details. -from .general import _state_applies +from .general import _state_applies, sit_wage def mt_montana_state_income_withholding(payslip, categories, worked_days, inputs): @@ -18,13 +18,16 @@ def mt_montana_state_income_withholding(payslip, categories, worked_days, inputs return 0.0, 0.0 # Determine Wage - wage = categories.GROSS + categories.DED_FIT_EXEMPT + wage = sit_wage(payslip, categories) + if not wage: + return 0.0, 0.0 + schedule_pay = payslip.dict.contract_id.schedule_pay additional = payslip.dict.contract_id.us_payroll_config_value('state_income_tax_additional_withholding') exemptions = payslip.dict.contract_id.us_payroll_config_value('mt_mw4_sit_exemptions') exemption_rate = payslip.dict.rule_parameter('us_mt_sit_exemption_rate').get(schedule_pay) withholding_rate = payslip.dict.rule_parameter('us_mt_sit_rate').get(schedule_pay) - if not exemption_rate or not withholding_rate or wage == 0.0: + if not exemption_rate or not withholding_rate: return 0.0, 0.0 adjusted_wage = wage - (exemption_rate * (exemptions or 0)) diff --git a/l10n_us_hr_payroll/models/state/nc_northcarolina.py b/l10n_us_hr_payroll/models/state/nc_northcarolina.py new file mode 100644 index 00000000..1078a185 --- /dev/null +++ b/l10n_us_hr_payroll/models/state/nc_northcarolina.py @@ -0,0 +1,38 @@ +# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details. + +from .general import _state_applies, sit_wage + + +def nc_northcarolina_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 = 'NC' + if not _state_applies(payslip, state_code): + return 0.0, 0.0 + + filing_status = payslip.dict.contract_id.us_payroll_config_value('nc_nc4_sit_filing_status') + if not filing_status: + return 0.0, 0.0 + + # Determine Wage + wage = sit_wage(payslip, categories) + if not wage: + return 0.0, 0.0 + + schedule_pay = payslip.dict.contract_id.schedule_pay + additional = payslip.dict.contract_id.us_payroll_config_value('state_income_tax_additional_withholding') + allowances = payslip.dict.contract_id.us_payroll_config_value('nc_nc4_sit_allowances') + allowances_rate = payslip.dict.rule_parameter('us_nc_sit_allowance_rate').get(schedule_pay)['allowance'] + deduction = payslip.dict.rule_parameter('us_nc_sit_allowance_rate').get(schedule_pay)['standard_deduction'] if filing_status != 'head_household' else payslip.dict.rule_parameter('us_nc_sit_allowance_rate').get(schedule_pay)['standard_deduction_hh'] + + taxable_wage = round((wage - (deduction + (allowances * allowances_rate))) * 0.0535) + withholding = 0.0 + if taxable_wage < 0.0: + withholding -= taxable_wage + withholding = taxable_wage + withholding += additional + return wage, -((withholding / wage) * 100.0) diff --git a/l10n_us_hr_payroll/models/state/nd_north_dakota.py b/l10n_us_hr_payroll/models/state/nd_north_dakota.py new file mode 100644 index 00000000..f01fbb9d --- /dev/null +++ b/l10n_us_hr_payroll/models/state/nd_north_dakota.py @@ -0,0 +1,45 @@ +# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details. + +from .general import _state_applies, sit_wage + + +def nd_north_dakota_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 = 'ND' + 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.dict.contract_id.us_payroll_config_value('nd_w4_sit_filing_status') + if not filing_status: + return 0.0, 0.0 + + schedule_pay = payslip.dict.contract_id.schedule_pay + additional = payslip.dict.contract_id.us_payroll_config_value('state_income_tax_additional_withholding') + allowance = payslip.dict.contract_id.us_payroll_config_value('nd_w4_sit_allowances') + allowance_rate = payslip.dict.rule_parameter('us_nd_sit_allowances_rate')[schedule_pay] + tax_rate = payslip.dict.rule_parameter('us_nd_sit_tax_rate')[filing_status].get(schedule_pay) + + taxable_income = wage - (allowance * allowance_rate) + withholding = 0.0 + last = 0.0 + for row in tax_rate: + amt, flat_fee, rate = row + if taxable_income < float(amt): + withholding = ((taxable_income - last) * (rate / 100)) + flat_fee + break + last = amt + + withholding = round(withholding) + withholding = max(withholding, 0.0) + withholding += additional + return wage, -((withholding / wage) * 100.0) diff --git a/l10n_us_hr_payroll/models/state/ne_nebraska.py b/l10n_us_hr_payroll/models/state/ne_nebraska.py new file mode 100644 index 00000000..dfc67d6d --- /dev/null +++ b/l10n_us_hr_payroll/models/state/ne_nebraska.py @@ -0,0 +1,49 @@ +# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details. + +from .general import _state_applies, sit_wage + + +def ne_nebraska_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 = 'NE' + if not _state_applies(payslip, state_code): + return 0.0, 0.0 + + personal_exempt = payslip.dict.contract_id.us_payroll_config_value('state_income_tax_exempt') + if personal_exempt: + return 0.0, 0.0 + + # Determine Wage + wage = sit_wage(payslip, categories) + if not wage: + return 0.0, 0.0 + + filing_status = payslip.dict.contract_id.us_payroll_config_value('ne_w4n_sit_filing_status') + if not filing_status: + return 0.0, 0.0 + + schedule_pay = payslip.dict.contract_id.schedule_pay + additional = payslip.dict.contract_id.us_payroll_config_value('state_income_tax_additional_withholding') + allowances = payslip.dict.contract_id.us_payroll_config_value('ne_w4n_sit_allowances') + tax_rate = payslip.dict.rule_parameter('us_ne_sit_tax_rate')[filing_status].get(schedule_pay) + sit_allowance = payslip.dict.rule_parameter('us_ne_sit_allowances_rate')[schedule_pay] + + allowance_amt = allowances * sit_allowance + taxable_income = wage - allowance_amt + withholding = 0.0 + last = 0.0 + for row in tax_rate: + amt, flat_fee, rate = row + if taxable_income < float(amt): + withholding = ((taxable_income - last) * (rate / 100)) + flat_fee + break + last = amt + + withholding = max(withholding, 0.0) + withholding += additional + return wage, -((withholding / wage) * 100.0) diff --git a/l10n_us_hr_payroll/models/state/nj_newjersey.py b/l10n_us_hr_payroll/models/state/nj_newjersey.py new file mode 100644 index 00000000..4f9301fe --- /dev/null +++ b/l10n_us_hr_payroll/models/state/nj_newjersey.py @@ -0,0 +1,52 @@ +# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details. + +from .general import _state_applies, sit_wage + + +def nj_newjersey_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 = 'NJ' + if not _state_applies(payslip, state_code): + return 0.0, 0.0 + + filing_status = payslip.dict.contract_id.us_payroll_config_value('nj_njw4_sit_filing_status') + if not filing_status: + return 0.0, 0.0 + + # Determine Wage + wage = sit_wage(payslip, categories) + if not wage: + return 0.0, 0.0 + + allowances = payslip.dict.contract_id.us_payroll_config_value('nj_njw4_sit_allowances') + sit_rate_table_key = payslip.dict.contract_id.us_payroll_config_value('nj_njw4_sit_rate_table') + if not sit_rate_table_key and filing_status in ('single', 'married_joint'): + sit_rate_table_key = 'A' + elif not sit_rate_table_key: + sit_rate_table_key = 'B' + schedule_pay = payslip.dict.contract_id.schedule_pay + additional = payslip.dict.contract_id.us_payroll_config_value('state_income_tax_additional_withholding') + sit_table = payslip.dict.rule_parameter('us_nj_sit_rate')[sit_rate_table_key].get(schedule_pay) + allowance_value = payslip.dict.rule_parameter('us_nj_sit_allowance_rate')[schedule_pay] + if not allowances: + return 0.0, 0.0 + + gross_taxable_income = wage - (allowance_value * allowances) + withholding = 0.0 + prior_wage_base = 0.0 + for row in sit_table: + wage_base, base_amt, rate = row + wage_base = float(wage_base) + rate = rate / 100.0 + if gross_taxable_income <= wage_base: + withholding = base_amt + ((gross_taxable_income - prior_wage_base) * rate) + break + prior_wage_base = wage_base + + withholding += additional + return wage, -((withholding / wage) * 100.0) 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..4cf4e3b4 --- /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.dict.contract_id.us_payroll_config_value('fed_941_fit_w4_filing_status') + if not filing_status: + return 0.0, 0.0 + + schedule_pay = payslip.dict.contract_id.schedule_pay + additional = payslip.dict.contract_id.us_payroll_config_value('state_income_tax_additional_withholding') + tax_table = payslip.dict.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/models/state/ny_new_york.py b/l10n_us_hr_payroll/models/state/ny_new_york.py new file mode 100644 index 00000000..664507ef --- /dev/null +++ b/l10n_us_hr_payroll/models/state/ny_new_york.py @@ -0,0 +1,54 @@ +# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details. + +from .general import _state_applies, sit_wage + + +def ny_new_york_state_income_withholding(payslip, categories, worked_days, inputs): + """ + Returns SIT eligible wage and rate. + + :return: result, result_rate (wage, percent) + """ + state_code = 'NY' + 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('ny_it2104_sit_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.dict.rule_parameter('us_ny_sit_tax_rate')[filing_status].get(schedule_pay) + allowances = payslip.contract_id.us_payroll_config_value('ny_it2104_sit_allowances') + over_10_deduction = payslip.dict.rule_parameter('us_ny_sit_over_10_exemption_rate')[schedule_pay] + deduction_exemption = payslip.dict.rule_parameter('us_ny_sit_deduction_exemption_rate')[filing_status].get(schedule_pay) + + if allowances > 10: + if filing_status == 'single': + wage -= over_10_deduction[0] + over_10_deduction[2] * allowances + elif filing_status == 'married': + wage -= over_10_deduction[1] + over_10_deduction[2] * allowances + + else: + if filing_status == 'single': + wage -= deduction_exemption[allowances] + elif filing_status == 'married': + wage -= deduction_exemption[allowances] + last = 0.0 + withholding = 0.0 + for row in tax_table: + amt, rate, flat_fee = row + if wage <= float(amt): + withholding = ((wage - last) * rate) + flat_fee + break + last = amt + + withholding = max(withholding, 0.0) + withholding += additional + return wage, -((withholding / wage) * 100.0) diff --git a/l10n_us_hr_payroll/models/state/oh_ohio.py b/l10n_us_hr_payroll/models/state/oh_ohio.py index 4691600a..11ea9e9f 100644 --- a/l10n_us_hr_payroll/models/state/oh_ohio.py +++ b/l10n_us_hr_payroll/models/state/oh_ohio.py @@ -1,6 +1,6 @@ # Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details. -from .general import _state_applies +from .general import _state_applies, sit_wage def oh_ohio_state_income_withholding(payslip, categories, worked_days, inputs): @@ -18,15 +18,16 @@ def oh_ohio_state_income_withholding(payslip, categories, worked_days, inputs): return 0.0, 0.0 # Determine Wage - wage = categories.GROSS + categories.DED_FIT_EXEMPT + wage = sit_wage(payslip, categories) + if not wage: + return 0.0, 0.0 + pay_periods = payslip.dict.get_pay_periods_in_year() additional = payslip.dict.contract_id.us_payroll_config_value('state_income_tax_additional_withholding') exemptions = payslip.dict.contract_id.us_payroll_config_value('oh_it4_sit_exemptions') exemption_rate = payslip.dict.rule_parameter('us_oh_sit_exemption_rate') withholding_rate = payslip.dict.rule_parameter('us_oh_sit_rate') multiplier_rate = payslip.dict.rule_parameter('us_oh_sit_multiplier') - if wage == 0.0: - return 0.0, 0.0 taxable_wage = (wage * pay_periods) - (exemption_rate * (exemptions or 0)) withholding = 0.0 diff --git a/l10n_us_hr_payroll/models/state/ok_oklahoma.py b/l10n_us_hr_payroll/models/state/ok_oklahoma.py new file mode 100644 index 00000000..608421a5 --- /dev/null +++ b/l10n_us_hr_payroll/models/state/ok_oklahoma.py @@ -0,0 +1,47 @@ +# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details. + +from .general import _state_applies, sit_wage + + +def ok_oklahoma_state_income_withholding(payslip, categories, worked_days, inputs): + """ + Returns SIT eligible wage and rate. + + :return: result, result_rate (wage, percent) + """ + state_code = 'OK' + 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 + + if payslip.dict.contract_id.us_payroll_config_value('state_income_tax_exempt'): + return 0.0, 0.0 + + filing_status = payslip.dict.contract_id.us_payroll_config_value('ok_w4_sit_filing_status') + if not filing_status: + return 0.0, 0.0 + + schedule_pay = payslip.dict.contract_id.schedule_pay + additional = payslip.dict.contract_id.us_payroll_config_value('state_income_tax_additional_withholding') + allowances = payslip.dict.contract_id.us_payroll_config_value('ok_w4_sit_allowances') + allowances_amt = payslip.dict.rule_parameter('us_ok_sit_allowances_rate')[schedule_pay] + tax_table = payslip.dict.rule_parameter('us_ok_sit_tax_rate')[filing_status].get(schedule_pay) + + taxable_income = wage - (allowances * allowances_amt) + withholding = 0.0 + last = 0.0 + for row in tax_table: + amt, rate, flat_fee = row + if wage <= float(amt): + withholding = ((taxable_income - last) * (rate / 100)) + flat_fee + break + last = amt + + withholding = max(withholding, 0.0) + withholding += additional + withholding = round(withholding) + return wage, -((withholding / wage) * 100.0) diff --git a/l10n_us_hr_payroll/models/state/ri_rhode_island.py b/l10n_us_hr_payroll/models/state/ri_rhode_island.py new file mode 100644 index 00000000..20be0a0c --- /dev/null +++ b/l10n_us_hr_payroll/models/state/ri_rhode_island.py @@ -0,0 +1,48 @@ +# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details. + +from .general import _state_applies, sit_wage + + +def ri_rhode_island_state_income_withholding(payslip, categories, worked_days, inputs): + """ + Returns SIT eligible wage and rate. + + :return: result, result_rate (wage, percent) + """ + state_code = 'RI' + 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 + + if payslip.dict.contract_id.us_payroll_config_value('state_income_tax_exempt'): + return 0.0, 0.0 + + schedule_pay = payslip.dict.contract_id.schedule_pay + additional = payslip.dict.contract_id.us_payroll_config_value('state_income_tax_additional_withholding') + allowances = payslip.dict.contract_id.us_payroll_config_value('ri_w4_sit_allowances') + exemption_rate = payslip.dict.rule_parameter('us_ri_sit_exemption_rate')[schedule_pay] + tax_table = payslip.dict.rule_parameter('us_ri_sit_tax_rate')[schedule_pay] + + exemption_amt = 0.0 + for row in exemption_rate: + amt, flat_fee = row + if wage > amt: + exemption_amt = flat_fee + + taxable_income = wage - (allowances * exemption_amt) + withholding = 0.0 + last = 0.0 + for row in tax_table: + amt, flat_fee, rate = row + if wage <= float(amt): + withholding = ((taxable_income - last) * (rate / 100)) + flat_fee + break + last = amt + + withholding = max(withholding, 0.0) + withholding += additional + return wage, -((withholding / wage) * 100.0) diff --git a/l10n_us_hr_payroll/models/state/sc_south_carolina.py b/l10n_us_hr_payroll/models/state/sc_south_carolina.py new file mode 100644 index 00000000..e8d13934 --- /dev/null +++ b/l10n_us_hr_payroll/models/state/sc_south_carolina.py @@ -0,0 +1,50 @@ +# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details. + +from .general import _state_applies, sit_wage + + +def sc_south_carolina_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 = 'SC' + if not _state_applies(payslip, state_code): + return 0.0, 0.0 + + personal_exempt = payslip.dict.contract_id.us_payroll_config_value('state_income_tax_exempt') + if personal_exempt: + return 0.0, 0.0 + + # Determine Wage + wage = sit_wage(payslip, categories) + if not wage: + return 0.0, 0.0 + + pay_periods = payslip.dict.get_pay_periods_in_year() + additional = payslip.dict.contract_id.us_payroll_config_value('state_income_tax_additional_withholding') + allowances = payslip.dict.contract_id.us_payroll_config_value('sc_w4_sit_allowances') + tax_rate = payslip.dict.rule_parameter('us_sc_sit_tax_rate') + personal_exemption = payslip.dict.rule_parameter('us_sc_sit_personal_exemption_rate') + deduction = payslip.dict.rule_parameter('us_sc_sit_standard_deduction_rate') + + annual_wage = wage * pay_periods + personal_exemption_amt = allowances * personal_exemption + standard_deduction = 0.0 + if allowances > 0: + if (annual_wage * 0.1) > deduction: + standard_deduction = deduction + else: + standard_deduction = annual_wage * (10 / 100) + taxable_income = annual_wage - personal_exemption_amt - standard_deduction + withholding = 0.0 + last = 0.0 + for cap, rate, flat_amt in tax_rate: + if float(cap) > taxable_income: + withholding = (taxable_income * (rate / 100.0) - flat_amt) + break + withholding /= pay_periods + withholding += additional + return wage, -((withholding / wage) * 100.0) diff --git a/l10n_us_hr_payroll/models/state/ut_utah.py b/l10n_us_hr_payroll/models/state/ut_utah.py new file mode 100644 index 00000000..21bf2ba7 --- /dev/null +++ b/l10n_us_hr_payroll/models/state/ut_utah.py @@ -0,0 +1,39 @@ +# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details. + +from .general import _state_applies, sit_wage + + +def ut_utah_state_income_withholding(payslip, categories, worked_days, inputs): + """ + Returns SIT eligible wage and rate. + + :return: result, result_rate (wage, percent) + """ + state_code = 'UT' + 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.dict.contract_id.us_payroll_config_value('ut_w4_sit_filing_status') + if not filing_status: + return 0.0, 0.0 + + schedule_pay = payslip.dict.contract_id.schedule_pay + additional = payslip.dict.contract_id.us_payroll_config_value('state_income_tax_additional_withholding') + tax_rate = payslip.dict.rule_parameter('us_ut_tax_rate') + allowances = payslip.dict.rule_parameter('us_ut_sit_allowances_rate')[filing_status].get(schedule_pay) + tax_table = payslip.dict.rule_parameter('us_ut_sit_tax_rate')[filing_status].get(schedule_pay) + + taxable_income = wage * tax_rate + withholding = 0.0 + amt, rate = tax_table + withholding = taxable_income - (allowances - ((wage - amt) * (rate / 100))) + + withholding = max(withholding, 0.0) + withholding += additional + withholding = round(withholding) + return wage, -((withholding / wage) * 100.0) diff --git a/l10n_us_hr_payroll/models/state/va_virginia.py b/l10n_us_hr_payroll/models/state/va_virginia.py index e2cae3e2..a4929bca 100644 --- a/l10n_us_hr_payroll/models/state/va_virginia.py +++ b/l10n_us_hr_payroll/models/state/va_virginia.py @@ -1,6 +1,6 @@ # Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details. -from .general import _state_applies +from .general import _state_applies, sit_wage def va_virginia_state_income_withholding(payslip, categories, worked_days, inputs): @@ -18,7 +18,10 @@ def va_virginia_state_income_withholding(payslip, categories, worked_days, input return 0.0, 0.0 # Determine Wage - wage = categories.GROSS + categories.DED_FIT_EXEMPT + wage = sit_wage(payslip, categories) + if not wage: + return 0.0, 0.0 + pay_periods = payslip.dict.get_pay_periods_in_year() additional = payslip.dict.contract_id.us_payroll_config_value('state_income_tax_additional_withholding') personal_exemptions = payslip.dict.contract_id.us_payroll_config_value('va_va4_sit_exemptions') @@ -27,8 +30,6 @@ def va_virginia_state_income_withholding(payslip, categories, worked_days, input other_exemption_rate = payslip.dict.rule_parameter('us_va_sit_other_exemption_rate') deduction = payslip.dict.rule_parameter('us_va_sit_deduction') withholding_rate = payslip.dict.rule_parameter('us_va_sit_rate') - if wage == 0.0: - return 0.0, 0.0 taxable_wage = (wage * pay_periods) - (deduction + (personal_exemptions * personal_exemption_rate) + (other_exemptions * other_exemption_rate)) withholding = 0.0 diff --git a/l10n_us_hr_payroll/models/state/vt_vermont.py b/l10n_us_hr_payroll/models/state/vt_vermont.py new file mode 100644 index 00000000..5a63d314 --- /dev/null +++ b/l10n_us_hr_payroll/models/state/vt_vermont.py @@ -0,0 +1,46 @@ +# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details. + +from .general import _state_applies, sit_wage + + +def vt_vermont_state_income_withholding(payslip, categories, worked_days, inputs): + """ + Returns SIT eligible wage and rate. + + :return: result, result_rate (wage, percent) + """ + state_code = 'VT' + 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 + + if payslip.dict.contract_id.us_payroll_config_value('state_income_tax_exempt'): + return 0.0, 0.0 + + filing_status = payslip.dict.contract_id.us_payroll_config_value('vt_w4vt_sit_filing_status') + if not filing_status: + return 0.0, 0.0 + + schedule_pay = payslip.dict.contract_id.schedule_pay + additional = payslip.dict.contract_id.us_payroll_config_value('state_income_tax_additional_withholding') + allowances = payslip.dict.contract_id.us_payroll_config_value('vt_w4vt_sit_allowances') + allowance_amt = payslip.dict.rule_parameter('us_vt_sit_allowances_rate')[schedule_pay] + tax_table = payslip.dict.rule_parameter('us_vt_sit_tax_rate')[filing_status].get(schedule_pay) + + taxable_income = wage - (allowances * allowance_amt) + withholding = 0.0 + last = 0.0 + for row in tax_table: + amt, flat_fee, rate = row + if wage <= float(amt): + withholding = ((taxable_income - last) * (rate / 100)) + flat_fee + break + last = amt + + withholding = max(withholding, 0.0) + withholding += additional + return wage, -((withholding / wage) * 100.0) diff --git a/l10n_us_hr_payroll/models/state/wi_wisconsin.py b/l10n_us_hr_payroll/models/state/wi_wisconsin.py new file mode 100644 index 00000000..d522215d --- /dev/null +++ b/l10n_us_hr_payroll/models/state/wi_wisconsin.py @@ -0,0 +1,47 @@ +# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details. + +from .general import _state_applies, sit_wage + + +def wi_wisconsin_state_income_withholding(payslip, categories, worked_days, inputs): + """ + Returns SIT eligible wage and rate. + + :return: result, result_rate (wage, percent) + """ + state_code = 'WI' + 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 + + if payslip.dict.contract_id.us_payroll_config_value('state_income_tax_exempt'): + return 0.0, 0.0 + + filing_status = payslip.dict.contract_id.us_payroll_config_value('wi_wt4_sit_filing_status') + if not filing_status: + return 0.0, 0.0 + + pay_periods = payslip.dict.get_pay_periods_in_year() + additional = payslip.dict.contract_id.us_payroll_config_value('state_income_tax_additional_withholding') + exemptions = payslip.dict.contract_id.us_payroll_config_value('wi_wt4_sit_exemptions') + exemption_amt = payslip.dict.rule_parameter('us_wi_sit_exemption_rate') + tax_table = payslip.dict.rule_parameter('us_wi_sit_tax_rate')[filing_status] + + taxable_income = wage * pay_periods + withholding = 0.0 + last = 0.0 + for row in tax_table: + amt, rate, flat_fee = row + if taxable_income <= float(amt): + withholding = (((taxable_income - last) * (rate / 100)) + flat_fee) - (exemptions * exemption_amt) + break + last = amt + + withholding = max(withholding, 0.0) + withholding /= pay_periods + withholding += additional + return wage, -((withholding / wage) * 100.0) diff --git a/l10n_us_hr_payroll/models/state/wv_west_virginia.py b/l10n_us_hr_payroll/models/state/wv_west_virginia.py new file mode 100644 index 00000000..268d68ab --- /dev/null +++ b/l10n_us_hr_payroll/models/state/wv_west_virginia.py @@ -0,0 +1,44 @@ +# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details. + +from .general import _state_applies, sit_wage + + +def wv_west_virginia_state_income_withholding(payslip, categories, worked_days, inputs): + """ + Returns SIT eligible wage and rate. + + :return: result, result_rate (wage, percent) + """ + state_code = 'WV' + 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.dict.contract_id.us_payroll_config_value('wv_it104_sit_filing_status') + if not filing_status: + return 0.0, 0.0 + + schedule_pay = payslip.dict.contract_id.schedule_pay + additional = payslip.dict.contract_id.us_payroll_config_value('state_income_tax_additional_withholding') + exemptions = payslip.dict.contract_id.us_payroll_config_value('wv_it104_sit_exemptions') + exemption_amt = payslip.dict.rule_parameter('us_wv_sit_exemption_rate')[schedule_pay] + tax_table = payslip.dict.rule_parameter('us_wv_sit_tax_rate')[filing_status].get(schedule_pay) + + taxable_income = wage - (exemptions * exemption_amt) + withholding = 0.0 + last = 0.0 + for row in tax_table: + amt, flat_fee, rate = row + if taxable_income <= float(amt): + withholding = ((taxable_income - last) * (rate / 100)) + flat_fee + break + last = amt + + withholding = max(withholding, 0.0) + withholding += additional + withholding = round(withholding) + return wage, -((withholding / wage) * 100.0) diff --git a/l10n_us_hr_payroll/models/update.py b/l10n_us_hr_payroll/models/update.py new file mode 100644 index 00000000..2184abef --- /dev/null +++ b/l10n_us_hr_payroll/models/update.py @@ -0,0 +1,26 @@ +# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details. + +import datetime +from odoo import fields, models + + +class PublisherWarrantyContract(models.AbstractModel): + _inherit = 'publisher_warranty.contract' + + def _get_hibou_modules(self): + modules = super(PublisherWarrantyContract, self)._get_hibou_modules() + try: + today_date = fields.Date.today() + last_thirty_date = today_date - datetime.timedelta(days=30) + today = fields.Date.to_string(today_date + datetime.timedelta(days=1)) # Dates vs Datetimes, pad out a day + last_thirty = fields.Date.to_string(last_thirty_date) + self.env.cr.execute( + 'SELECT COUNT(DISTINCT(employee_id)) FROM hr_payslip WHERE create_date BETWEEN %s AND %s', + (last_thirty, today)) + employee_count = self.env.cr.fetchone()[0] or 0 + modules.update({ + 'l10n_us_hr_payroll': employee_count, + }) + except: + pass + return modules diff --git a/l10n_us_hr_payroll/models/us_payroll_config.py b/l10n_us_hr_payroll/models/us_payroll_config.py index 5ff26656..61481bae 100644 --- a/l10n_us_hr_payroll/models/us_payroll_config.py +++ b/l10n_us_hr_payroll/models/us_payroll_config.py @@ -51,8 +51,48 @@ class HRContractUSPayrollConfig(models.Model): fed_941_fit_w4_additional_withholding = fields.Float(string='Federal W4 Additional Withholding [4(c)]', help='Form W4 (2020+) 4(c)') + al_a4_sit_exemptions = fields.Selection([ + ('', '0'), + ('S', 'S'), + ('MS', 'MS'), + ('M', 'M'), + ('H', 'H'), + ], string='Alabama A4 Withholding Exemptions', help='A4 1. 2. 3.') + al_a4_sit_dependents = fields.Integer(string='Alabama A4 Dependents', help='A4 4.') + + ar_ar4ec_sit_allowances = fields.Integer(string='Arkansas AR4EC allowances', help='AR4EC 3.') + + az_a4_sit_withholding_percentage = fields.Float( + string='Arizona A-4 Withholding Percentage', + help='A-4 1. (0.8 or 1.3 or 1.8 or 2.7 or 3.6 or 4.2 or 5.1 or 0 for exempt.') + + ca_de4_sit_allowances = fields.Integer(string='California W-4 Allowances', + help='CA W-4 3.') + ca_de4_sit_additional_allowances = fields.Integer(string='California W-4 Additional Allowances', + help='CA W-4 4(c).') + ca_de4_sit_filing_status = fields.Selection([ + ('', 'Exempt'), + ('single', 'Single or Married filing separately'), + ('married', 'Married filing jointly'), + ('head_household', 'Head of Household') + ], string='California W-4 Filing Status', help='CA W-4 1(c).') + + ct_w4na_sit_code = fields.Selection([ + ('a', 'A'), + ('b', 'B'), + ('c', 'C'), + ('d', 'D'), + ('f', 'F'), + ], string='Connecticut CT-W4 Withholding Code', help='CT-W4 1.') + + de_w4_sit_filing_status = fields.Selection([ + ('single', 'Single or Married filing separately'), + ('married', 'Married filing jointly'), + ], string='Delaware W-4 Marital Status', help='DE W-4 3.') + de_w4_sit_dependent = fields.Integer(string='Delaware W-4 Dependents', help='DE W-4 4.') + ga_g4_sit_filing_status = fields.Selection([ - ('exempt', 'Exempt'), + ('', 'Exempt'), ('single', 'Single'), ('married filing joint, both spouses working', 'Married Filing Joint, both spouses working'), ('married filing joint, one spouse working', 'Married Filing Joint, one spouse working'), @@ -64,6 +104,66 @@ class HRContractUSPayrollConfig(models.Model): ga_g4_sit_additional_allowances = fields.Integer(string='Georgia G-4 Additional Allowances', help='G-4 5.') + hi_hw4_sit_filing_status = fields.Selection([ + ('', 'Exempt'), + ('single', 'Single'), + ('married', 'Married'), + ('head_of_household', 'Head of Household'), + ], string='Hawaii HW-4 Marital Status', help='HI HW-4 3.') + hi_hw4_sit_allowances = fields.Integer(string='Hawaii HW-4 Allowances', help='HI HW-4 4.') + + ia_w4_sit_allowances = fields.Integer(string='Iowa W-4 allowances', help='IA W-4 6.') + + id_w4_sit_filing_status = fields.Selection([ + ('single', 'Single'), + ('married', 'Married'), + ('head of household', 'Head of Household'), + ], string='Idaho ID W-4 Withholding Status', help='ID W-4 A.B.C.') + id_w4_sit_allowances = fields.Integer(string='Idaho ID W-4 Allowances', help='ID W-4 1.') + + il_w4_sit_basic_allowances = fields.Integer(string='Illinois IL-W-4 Number of Basic Allowances', help='IL-W-4 Step 1.') + il_w4_sit_additional_allowances = fields.Integer(string='Illinois IL-W-4 Number of Additional Allowances', help='IL-W-4 Step 2.') + + in_w4_sit_personal_exemption = fields.Integer(string='Indiana In-W-4 Number of Personal Exemption', help='IN-W-4 5.') + in_w4_sit_dependent_exemption = fields.Integer(string='Indiana In-W-4 Number of Dependent Exemption', help='IN-W-4 6.') + + ks_k4_sit_filing_status = fields.Selection([ + ('single', 'Single'), + ('married', 'Joint'), + ], string='Kansas K-4 Filing Status', help='KS K-4 3.') + ks_k4_sit_allowances = fields.Integer(string='Kansas KS K-4 Number of Allowances', help='KS K-4 Step 4.') + + la_l4_sit_filing_status = fields.Selection([ + ('single', 'Single'), + ('married', 'Married'), + ], string='Louisiana LA L-4 Filing Status', help='LA L-4 3.') + la_l4_sit_exemptions = fields.Integer(string='Louisiana LA L-4 Number of Exemptions', help='LA L-4 6.') + la_l4_sit_dependents = fields.Integer(string='Louisiana LA L-4 Number of Dependents', help='LA L-4 7.') + + me_w4me_sit_filing_status = fields.Selection([ + ('', 'Exempt'), + ('single', 'Single or Head of Household'), + ('married', 'Married'), + ], string='Maine W-4ME Filing Status', help='ME W-4ME 3.') + me_w4me_sit_allowances = fields.Integer(string='Maine Allowances', help='W-4ME 4.') + + 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'), + ('married', 'Married (Spouse does not work)'), + ('head_of_household', 'Head of Household'), + ], string='Missouri W-4 Filing Status', help='MO W-4 1.') + mo_mow4_sit_withholding = fields.Integer(string='Missouri MO W-4 Reduced Withholding', help='MO W-4 3.') + ms_89_350_sit_filing_status = fields.Selection([ ('', 'Exempt'), ('single', 'Single'), @@ -86,11 +186,93 @@ class HRContractUSPayrollConfig(models.Model): ('montana_for_marriage', 'Montana for Marriage'), ], string='Montana MW-4 Exempt from Withholding', help='MW-4 Section 2') + nc_nc4_sit_filing_status = fields.Selection([ + ('', 'Exempt'), + ('single', 'Single'), + ('married', 'Married'), + ('head_household', 'Head of Household') + ], string='North Carolina NC-4 Filing Status', help='NC-4') + nc_nc4_sit_allowances = fields.Integer(string='North Carolina NC-4 Allowances', help='NC-4 1.') + + nd_w4_sit_filing_status = fields.Selection([ + ('', 'Exempt'), + ('single', 'Single'), + ('married', 'Married'), + ('head_household', 'Head of Household') + ], string='North Dakota ND W-4 Filing Status', help='ND W-4') + nd_w4_sit_allowances = fields.Integer(string='North Dakota ND W-4') + + ne_w4n_sit_filing_status = fields.Selection([ + ('single', 'Single'), + ('married', 'Married'), + ], string='Nebraska NE W-4N Filing Status', help='NE W-4N') + ne_w4n_sit_allowances = fields.Integer(string='Nebraska NE W-4N Allowances', help='NE W-4N 1.') + + nj_njw4_sit_filing_status = fields.Selection([ + ('', 'Exempt'), + ('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='New Jersey NJ-W4 Filing Status', help='NJ-W4 2.') + nj_njw4_sit_allowances = fields.Integer(string='New Jersey NJ-W4 Allowances', help='NJ-W4 4.') + nj_njw4_sit_rate_table = fields.Selection([ + ('A', 'A'), + ('B', 'B'), + ('C', 'C'), + ('D', 'D'), + ('E', 'E') + ], string='New Jersey Wage Chart Letter', help='NJ-W4. 3.') + + ny_it2104_sit_filing_status = fields.Selection([ + ('', 'Exempt'), + ('single', 'Single'), + ('married', 'Married'), + ], string='New York NY IT-2104 Filing Status', help='NY IT-2104') + ny_it2104_sit_allowances = fields.Integer(string="New York IT-2104 Allowances", help="NY IT-2104 1. 2.") + # Ohio will use generic SIT exempt and additional fields oh_it4_sit_exemptions = fields.Integer(string='Ohio IT-4 Exemptions', help='Line 4') + ok_w4_sit_filing_status = fields.Selection([ + ('single', 'Single'), + ('married', 'Married'), + ('head_household', 'Married, but withhold at higher Single rate') + ], string='Oklahoma OK-W-4 Filing Status', help='OK-W-4') + ok_w4_sit_allowances = fields.Integer(string='Oklahoma OK-W-4 Allowances', help='OK-W-4 5.') + + ri_w4_sit_allowances = fields.Integer(string='Rhode Island RI W-4 Allowances', help='RI W-4 1.') + + sc_w4_sit_allowances = fields.Integer(string='South Carolina SC W-4 Allowances', help='SC W-4 5.') + + ut_w4_sit_filing_status = fields.Selection([ + ('single', 'Single'), + ('married', 'Married'), + ('head_household', 'Head of Household') + ], string='Utah UT W-4 Filing Status', help='UT W-4 C.') + + vt_w4vt_sit_filing_status = fields.Selection([ + ('single', 'Single'), + ('married', 'Married'), + ], string='Vermont VT W-4VT Filing Status', help='VT W-4VT') + vt_w4vt_sit_allowances = fields.Integer(string='Vermont VT W-4VT Allowances', help='VT W-4VT 5.') + va_va4_sit_exemptions = fields.Integer(string='Virginia VA-4(P) Personal Exemptions', help='VA-4(P) 1(a)') va_va4_sit_other_exemptions = fields.Integer(string='Virginia VA-4(P) Age & Blindness Exemptions', - help='VA-4(P) 1(b)') + help='VA-4(P) 1(b)') + + wi_wt4_sit_filing_status = fields.Selection([ + ('single', 'Single'), + ('married', 'Married'), + ], string='Wisconsin WT-4 Filing Status', help='WI WT-4') + wi_wt4_sit_exemptions = fields.Integer(string='Wisconsin Exemptions', help='WI WT-4 1.(d)') + + wv_it104_sit_filing_status = fields.Selection([ + ('single', 'Single'), + ('married', 'Married'), + ('head_household', 'Head of Household') + ], string='West Virginia WV/IT-104 Filing Status', help='WV WV/IT-104') + wv_it104_sit_exemptions = fields.Integer(string='West Virginia Exemptions', help='WV WV/IT-104 4.') diff --git a/l10n_us_hr_payroll/tests/__init__.py b/l10n_us_hr_payroll/tests/__init__.py index 3e4cb355..a7c95ebf 100755 --- a/l10n_us_hr_payroll/tests/__init__.py +++ b/l10n_us_hr_payroll/tests/__init__.py @@ -1,32 +1,130 @@ # Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details. from . import common + +from . import test_special + from . import test_us_payslip_2019 from . import test_us_payslip_2020 +from . import test_us_ak_alaska_payslip_2019 +from . import test_us_ak_alaska_payslip_2020 + +from . import test_us_al_alabama_payslip_2019 +from . import test_us_al_alabama_payslip_2020 + +from . import test_us_ar_arkansas_payslip_2019 +from . import test_us_ar_arkansas_payslip_2020 + +from . import test_us_az_arizona_payslip_2019 +from . import test_us_az_arizona_payslip_2020 + +from . import test_us_ca_california_payslip_2019 +from . import test_us_ca_california_payslip_2020 + +from . import test_us_co_colorado_payslip_2020 + +from . import test_us_ct_connecticut_payslip_2019 +from . import test_us_ct_connecticut_payslip_2020 + +from . import test_us_de_delaware_payslip_2020 + from . import test_us_fl_florida_payslip_2019 from . import test_us_fl_florida_payslip_2020 from . import test_us_ga_georgia_payslip_2019 from . import test_us_ga_georgia_payslip_2020 +from . import test_us_hi_hawaii_payslip_2019 +from . import test_us_hi_hawaii_payslip_2020 + +from . import test_us_ia_iowa_payslip_2019 +from . import test_us_ia_iowa_payslip_2020 + +from . import test_us_id_idaho_payslip_2019 +from . import test_us_id_idaho_payslip_2020 + +from . import test_us_il_illinois_payslip_2019 +from . import test_us_il_illinois_payslip_2020 + +from . import test_us_in_indiana_payslip_2020 + +from . import test_us_ky_kentucky_payslip_2020 + +from . import test_us_ks_kansas_payslip_2020 + +from . import test_us_la_louisiana_payslip_2019 +from . import test_us_la_louisiana_payslip_2020 + +from . import test_us_me_maine_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 + from . import test_us_ms_mississippi_payslip_2019 from . import test_us_ms_mississippi_payslip_2020 from . import test_us_mt_montana_payslip_2019 from . import test_us_mt_montana_payslip_2020 +from . import test_us_nc_northcarolina_payslip_2019 +from . import test_us_nc_northcarolina_payslip_2020 + +from . import test_us_nd_north_dakota_payslip_2020 + +from . import test_us_ne_nebraska_payslip_2020 + +from . import test_us_nh_new_hampshire_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_nv_nevada_payslip_2020 + +from . import test_us_ny_new_york_payslip_2019 +from . import test_us_ny_new_york_payslip_2020 + from . import test_us_oh_ohio_payslip_2019 from . import test_us_oh_ohio_payslip_2020 +from . import test_us_ok_oklahoma_payslip_2020 + from . import test_us_pa_pennsylvania_payslip_2019 from . import test_us_pa_pennsylvania_payslip_2020 +from . import test_us_ri_rhode_island_payslip_2020 + +from . import test_us_sc_south_carolina_payslip_2019 +from . import test_us_sc_south_carolina_payslip_2020 + +from . import test_us_sd_south_dakota_payslip_2020 + +from . import test_us_tn_tennessee_payslip_2020 + from . import test_us_tx_texas_payslip_2019 from . import test_us_tx_texas_payslip_2020 +from . import test_us_us_utah_payslip_2020 + +from . import test_us_vt_vermont_payslip_2020 + from . import test_us_va_virginia_payslip_2019 from . import test_us_va_virginia_payslip_2020 from . import test_us_wa_washington_payslip_2019 from . import test_us_wa_washington_payslip_2020 + +from . import test_us_wv_west_virginia_payslip_2020 + +from . import test_us_wi_wisconsin_payslip_2020 + +from . import test_us_wy_wyoming_payslip_2019 +from . import test_us_wy_wyoming_payslip_2020 diff --git a/l10n_us_hr_payroll/tests/common.py b/l10n_us_hr_payroll/tests/common.py index 338e1d44..a7c6aee5 100755 --- a/l10n_us_hr_payroll/tests/common.py +++ b/l10n_us_hr_payroll/tests/common.py @@ -22,6 +22,10 @@ class TestUsPayslip(common.TransactionCase): debug = False _logger = getLogger(__name__) + def setUp(self): + super(TestUsPayslip, self).setUp() + self.env['ir.config_parameter'].set_param('hr_payroll.payslip.sum_behavior', 'date_to') + float_info = sys_float_info def float_round(self, value, digits): @@ -154,15 +158,6 @@ class TestUsPayslip(common.TransactionCase): def assertPayrollAlmostEqual(self, first, second): self.assertAlmostEqual(first, second, self.payroll_digits-1) - def test_semi_monthly(self): - salary = 80000.0 - employee = self._createEmployee() - # so the schedule_pay is now on the Structure... - contract = self._createContract(employee, wage=salary, schedule_pay='semi-monthly') - payslip = self._createPayslip(employee, '2019-01-01', '2019-01-14') - - payslip.compute_sheet() - def get_us_state(self, code, cache={}): country_key = 'US_COUNTRY' if code in cache: @@ -177,7 +172,11 @@ class TestUsPayslip(common.TransactionCase): cache[code] = us_state return us_state - def _test_suta(self, category, state_code, rate, date, wage_base=None, **extra_contract): + def _test_suta(self, category, state_code, rate, date, wage_base=None, relaxed=False, **extra_contract): + if relaxed: + _assert = self.assertPayrollAlmostEqual + else: + _assert = self.assertPayrollEqual if wage_base: # Slightly larger than 1/2 the wage_base wage = round(wage_base / 2.0) + 100.0 @@ -200,18 +199,18 @@ class TestUsPayslip(common.TransactionCase): contract.us_payroll_config_id.fed_940_type = USHRContract.FUTA_TYPE_EXEMPT payslip.compute_sheet() cats = self._getCategories(payslip) - self.assertPayrollEqual(cats.get(category, 0.0), 0.0) + _assert(cats.get(category, 0.0), 0.0) contract.us_payroll_config_id.fed_940_type = USHRContract.FUTA_TYPE_BASIC payslip.compute_sheet() cats = self._getCategories(payslip) - self.assertPayrollEqual(cats.get(category, 0.0), 0.0) + _assert(cats.get(category, 0.0), 0.0) # Test Normal contract.us_payroll_config_id.fed_940_type = USHRContract.FUTA_TYPE_NORMAL payslip.compute_sheet() cats = self._getCategories(payslip) - self.assertPayrollEqual(cats.get(category, 0.0), wage * rate) + _assert(cats.get(category, 0.0), wage * rate) process_payslip(payslip) # Second Payslip @@ -222,7 +221,7 @@ class TestUsPayslip(common.TransactionCase): if wage_base: remaining_unemp_wages = wage_base - wage self.assertTrue((remaining_unemp_wages * rate) <= 0.01) # less than 0.01 because rate is negative - self.assertPayrollEqual(cats.get(category, 0.0), remaining_unemp_wages * rate) + _assert(cats.get(category, 0.0), remaining_unemp_wages * rate) # As if they were paid once already, so the first "two payslips" would remove all of the tax obligation # 1 wage - Payslip (confirmed) @@ -231,12 +230,12 @@ class TestUsPayslip(common.TransactionCase): contract.external_wages = wage payslip.compute_sheet() cats = self._getCategories(payslip) - self.assertPayrollEqual(cats.get(category, 0.0), 0.0) + _assert(cats.get(category, 0.0), 0.0) else: - self.assertPayrollEqual(cats.get(category, 0.0), wage * rate) + _assert(cats.get(category, 0.0), wage * rate) - def _test_er_suta(self, state_code, rate, date, wage_base=None, **extra_contract): - self._test_suta('ER_US_SUTA', state_code, rate, date, wage_base=wage_base, **extra_contract) + def _test_er_suta(self, state_code, rate, date, wage_base=None, relaxed=False, **extra_contract): + self._test_suta('ER_US_SUTA', state_code, rate, date, wage_base=wage_base, relaxed=relaxed, **extra_contract) - def _test_ee_suta(self, state_code, rate, date, wage_base=None, **extra_contract): - self._test_suta('EE_US_SUTA', state_code, rate, date, wage_base=wage_base, **extra_contract) + def _test_ee_suta(self, state_code, rate, date, wage_base=None, relaxed=False, **extra_contract): + self._test_suta('EE_US_SUTA', state_code, rate, date, wage_base=wage_base, relaxed=relaxed, **extra_contract) diff --git a/l10n_us_hr_payroll/tests/test_special.py b/l10n_us_hr_payroll/tests/test_special.py new file mode 100644 index 00000000..d68df65d --- /dev/null +++ b/l10n_us_hr_payroll/tests/test_special.py @@ -0,0 +1,119 @@ +from .common import TestUsPayslip, process_payslip + + +class TestSpecial(TestUsPayslip): + def test_semi_monthly(self): + salary = 80000.0 + employee = self._createEmployee() + # so the schedule_pay is now on the Structure... + contract = self._createContract(employee, wage=salary, schedule_pay='semi-monthly') + payslip = self._createPayslip(employee, '2019-01-01', '2019-01-14') + payslip.compute_sheet() + + def test_payslip_sum_behavior(self): + us_structure = self.env.ref('l10n_us_hr_payroll.structure_type_employee') + rule_category_comp = self.env.ref('hr_payroll.COMP') + test_rule_category = self.env['hr.salary.rule.category'].create({ + 'name': 'Test Sum Behavior', + 'code': 'test_sum_behavior', + 'parent_id': rule_category_comp.id, + }) + test_rule = self.env['hr.salary.rule'].create({ + 'sequence': 450, + 'category_id': test_rule_category.id, + 'name': 'Test Sum Behavior', + 'code': 'test_sum_behavior', + 'condition_select': 'python', + 'condition_python': 'result = 1', + 'amount_select': 'code', + 'amount_python_compute': ''' +ytd_category = payslip.sum_category('test_sum_behavior', '2020-01-01', '2021-01-01') +ytd_rule = payslip.sum('test_sum_behavior', '2020-01-01', '2021-01-01') +result = 0.0 +if ytd_category != ytd_rule: + # error + result = -1.0 +elif ytd_rule == 0.0: + # first payslip in period + result = 1.0 +''' + }) + us_structure.write({'rule_ids': [(4, test_rule.id, 0)]}) + + salary = 80000.0 + employee = self._createEmployee() + contract = self._createContract(employee, wage=salary, schedule_pay='bi-weekly') + payslip = self._createPayslip(employee, '2019-12-30', '2020-01-12') + payslip.compute_sheet() + cats = self._getCategories(payslip) + self.assertEqual(cats['test_sum_behavior'], 1.0) + process_payslip(payslip) + + # Basic date_from behavior. + self.env['ir.config_parameter'].set_param('hr_payroll.payslip.sum_behavior', 'date_from') + # The the date_from on the last payslip will not be found + payslip = self._createPayslip(employee, '2020-01-13', '2020-01-27') + payslip.compute_sheet() + cats = self._getCategories(payslip) + self.assertEqual(cats['test_sum_behavior'], 1.0) + + # date_to behavior. + self.env['ir.config_parameter'].set_param('hr_payroll.payslip.sum_behavior', 'date_to') + # The date_to on the last payslip is found + payslip = self._createPayslip(employee, '2020-01-13', '2020-01-27') + payslip.compute_sheet() + cats = self._getCategories(payslip) + self.assertEqual(cats['test_sum_behavior'], 0.0) + + def test_recursive_salary_rule_category(self): + self.debug = True + # In this scenario, you are in rule code that will check for the category + # and a subcategory will also + alw_category = self.env.ref('hr_payroll.ALW') + ded_category = self.env.ref('hr_payroll.DED') + test_category = self.env['hr.salary.rule.category'].create({ + 'name': 'Special ALW', + 'code': 'ALW_SPECIAL_RECURSIVE', + 'parent_id': alw_category.id, + }) + test_special_alw = self.env['hr.salary.rule'].create({ + 'name': 'Flat amount 200', + 'code': 'ALW_SPECIAL_RECURSIVE', + 'category_id': test_category.id, + 'condition_select': 'none', + 'amount_select': 'fix', + 'amount_fix': 200.0, + }) + test_recursion = self.env['hr.salary.rule'].create({ + 'name': 'Actual Test Behavior', + 'code': 'RECURSION_TEST', + 'category_id': ded_category.id, + 'condition_select': 'none', + 'amount_select': 'code', + 'amount_python_compute': """ +# this rule will always be the total of the ALW category and YTD ALW category +result = categories.ALW +year = payslip.dict.get_year() +result += payslip.sum_category('ALW', str(year) + '-01-01', str(year+1) + '-01-01') + """, + 'sequence': 101, + }) + struct = self.env.ref('l10n_us_hr_payroll.structure_type_employee') + struct.rule_ids = test_special_alw + test_recursion + + salary = 80000.0 + employee = self._createEmployee() + contract = self._createContract(employee, wage=salary, schedule_pay='bi-weekly') + payslip = self._createPayslip(employee, '2020-01-01', '2020-01-14') + payslip.compute_sheet() + cats = self._getCategories(payslip) + rules = self._getRules(payslip) + self.assertEqual(rules['RECURSION_TEST'], 200.0) + process_payslip(payslip) + + payslip = self._createPayslip(employee, '2020-01-15', '2020-01-27') + payslip.compute_sheet() + cats = self._getCategories(payslip) + rules = self._getRules(payslip) + # two hundred is in the YTD ALW + self.assertEqual(rules['RECURSION_TEST'], 200.0 + 200.0) diff --git a/l10n_us_hr_payroll/tests/test_us_ak_alaska_payslip_2019.py b/l10n_us_hr_payroll/tests/test_us_ak_alaska_payslip_2019.py new file mode 100644 index 00000000..3eb62184 --- /dev/null +++ b/l10n_us_hr_payroll/tests/test_us_ak_alaska_payslip_2019.py @@ -0,0 +1,61 @@ +# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details. + +from .common import TestUsPayslip, process_payslip + + +class TestUsAKPayslip(TestUsPayslip): + # TAXES AND RATES + AK_UNEMP_MAX_WAGE = 39900.00 + AK_UNEMP = -(1.780 / 100.0) + AK_UNEMP_EE = -(0.5 / 100.0) + + def test_taxes_monthly_over_max(self): + salary = 50000.00 + schedule_pay = 'monthly' + + employee = self._createEmployee() + contract = self._createContract(employee, + wage=salary, + state_id=self.get_us_state('AK'), + state_income_tax_additional_withholding=0.0, + schedule_pay=schedule_pay) + + self._log('2019 Alaska tax first payslip monthly:') + payslip = self._createPayslip(employee, '2019-01-01', '2019-01-31') + payslip.compute_sheet() + cats = self._getCategories(payslip) + + self.assertPayrollEqual(cats['ER_US_SUTA'], self.AK_UNEMP_MAX_WAGE * self.AK_UNEMP) + self.assertPayrollEqual(cats['EE_US_SUTA'], self.AK_UNEMP_MAX_WAGE * self.AK_UNEMP_EE) + + process_payslip(payslip) + + remaining_ak_unemp_wages = 0.00 # We already reached the maximum wage for unemployment insurance. + + self._log('2019 Alaska tax second payslip monthly:') + payslip = self._createPayslip(employee, '2019-02-01', '2019-02-28') + payslip.compute_sheet() + cats = self._getCategories(payslip) + + self.assertPayrollEqual(cats['ER_US_SUTA'], remaining_ak_unemp_wages * self.AK_UNEMP) # 0 + + def test_taxes_weekly_under_max(self): + salary = 5000.00 + schedule_pay = 'weekly' + + employee = self._createEmployee() + contract = self._createContract(employee, + wage=salary, + state_id=self.get_us_state('AK'), + state_income_tax_additional_withholding=0.0, + schedule_pay=schedule_pay) + + self._log('2019 Alaska 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.AK_UNEMP) + self.assertPayrollEqual(cats['EE_US_SUTA'], salary * self.AK_UNEMP_EE) + + process_payslip(payslip) diff --git a/l10n_us_hr_payroll/tests/test_us_ak_alaska_payslip_2020.py b/l10n_us_hr_payroll/tests/test_us_ak_alaska_payslip_2020.py new file mode 100644 index 00000000..868a8dff --- /dev/null +++ b/l10n_us_hr_payroll/tests/test_us_ak_alaska_payslip_2020.py @@ -0,0 +1,15 @@ +# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details. + +from datetime import date +from .common import TestUsPayslip + + +class TestUsAKPayslip(TestUsPayslip): + # TAXES AND RATES + AK_UNEMP_MAX_WAGE = 41500.00 + AK_UNEMP = 1.590 + AK_UNEMP_EE = 0.5 + + def test_2020_taxes(self): + self._test_er_suta('AK', self.AK_UNEMP, date(2020, 1, 1), wage_base=self.AK_UNEMP_MAX_WAGE) + self._test_ee_suta('AK', self.AK_UNEMP_EE, date(2020, 1, 1), wage_base=self.AK_UNEMP_MAX_WAGE) diff --git a/l10n_us_hr_payroll/tests/test_us_al_alabama_payslip_2019.py b/l10n_us_hr_payroll/tests/test_us_al_alabama_payslip_2019.py new file mode 100644 index 00000000..33ddb2f9 --- /dev/null +++ b/l10n_us_hr_payroll/tests/test_us_al_alabama_payslip_2019.py @@ -0,0 +1,264 @@ +# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details. + +from .common import TestUsPayslip, process_payslip + + +class TestUsALPayslip(TestUsPayslip): + # TAXES AND RATES + AL_UNEMP_MAX_WAGE = 8000.00 + AL_UNEMP = -2.70 / 100.0 + + def test_taxes_weekly(self): + salary = 10000.00 + schedule_pay = 'weekly' + dependents = 1 + filing_status = 'S' + # see https://revenue.alabama.gov/wp-content/uploads/2019/01/whbooklet_0119.pdf for reference + # Hand Calculated Amount to Test + # Step 1 -> 10000.00 for wages per period , 52.0 for weekly -> 10000 * 52 -> 520000.0 + # Step 2A -> standard deduction for highest wage bracket -> 2000. Subtract from yearly income + # 520000 - 2000 = 518000.0 + # Step 2B -> Subtract Federal Income Tax in yearly form -> Our Fed withholding is -2999.66 * 52 = -155982.32 + # -> 518000.0 - 155982.32 = 362017.68 + # Step 2C -> Subtract the personal exemption -> 1500 for single filing_status + # -> 362017.68 - 1500 = 360517.68 + # Step 2D -> Since income is so high, only 300$ per dependent -> 300$. Subtract + # -> 360517.68 - 300 = 360217.68 + # + # Step 5 (after adding previous lines) -> Compute marginal taxes. + # (500 * (2.00 / 100)) + (2500 * (4.00 / 100)) + ((360217.68 - 500 - 2500) * (5.00 / 100)) -> 17970.884000000002 + # Convert back to pay period + # wh = round(17970.884000000002, 2) -> 17970.88 / 52.0 -> 345.59 + wh = -345.59 + + employee = self._createEmployee() + contract = self._createContract(employee, + wage=salary, + state_id=self.get_us_state('AL'), + al_a4_sit_exemptions=filing_status, + state_income_tax_additional_withholding=0.0, + state_income_tax_exempt=False, + al_a4_sit_dependents=dependents, + schedule_pay=schedule_pay) + + self._log('2019 Alabama tax first payslip weekly:') + payslip = self._createPayslip(employee, '2019-01-01', '2019-01-31') + payslip.compute_sheet() + cats = self._getCategories(payslip) + + self.assertPayrollEqual(cats['EE_US_941_FIT'], -2999.66) # Hand Calculated. + self.assertPayrollEqual(cats['ER_US_SUTA'], self.AL_UNEMP_MAX_WAGE * self.AL_UNEMP) + self.assertPayrollEqual(cats['EE_US_SIT'], wh) + + process_payslip(payslip) + + remaining_AL_UNEMP_wages = 0.00 # We already reached the maximum wage for unemployment insurance. + + self._log('2019 Alabama 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_AL_UNEMP_wages * self.AL_UNEMP) # 0 + + def test_taxes_married_jointly(self): + salary = 10000.00 + schedule_pay = 'weekly' + dependents = 1 + filing_status = 'M' + + # see https://revenue.alabama.gov/wp-content/uploads/2019/01/whbooklet_0119.pdf for reference + # Hand Calculated Amount to Test + # Step 1 -> 10000.00 for wages per period , 52.0 for weekly -> 10000 * 52 -> 520000.0 + # Step 2A -> standard deduction for highest wage bracket -> 4000. Subtract from yearly income + # 520000 - 4000 = 516000.0 + # Step 2B -> Subtract Federal Income Tax in yearly form -> Our Fed withholding is -2999.66 * 52 = -155982.32 + # -> 516000.0 - 155982.32 = 360017.68 + # Step 2C -> Subtract the personal exemption -> 3000 for married filing jointly. + # -> 360017.68 - 3000 = 357017.68 + # Step 2D -> Since income is so high, only 300$ per dependent -> 300$. Subtract + # -> 357017.68 - 300 = 356717.68 + # + # Step 5 (after adding previous lines) -> Compute marginal taxes. + # (1000 * (2.00 / 100)) + (5000 * (4.00 / 100)) + ((356717.68 - 1000 - 50000) * (5.00 / 100)) + # -> 17755.884000000002 + # Convert back to pay period + # wh = round(17755.884000000002, 2) -> 15505.88 / 52.0 -> 341.45923076923077 + wh = -341.46 + + employee = self._createEmployee() + contract = self._createContract(employee, + wage=salary, + state_id=self.get_us_state('AL'), + al_a4_sit_exemptions=filing_status, + state_income_tax_additional_withholding=0.0, + state_income_tax_exempt=False, + al_a4_sit_dependents=dependents, + schedule_pay=schedule_pay) + + self._log('2019 Alabama tax first payslip weekly:') + payslip = self._createPayslip(employee, '2019-01-01', '2019-01-31') + payslip.compute_sheet() + cats = self._getCategories(payslip) + + self.assertPayrollEqual(cats['EE_US_941_FIT'], -2999.66) # Hand Calculated. + self.assertPayrollEqual(cats['ER_US_SUTA'], self.AL_UNEMP_MAX_WAGE * self.AL_UNEMP) + self.assertPayrollEqual(cats['EE_US_SIT'], wh) + + process_payslip(payslip) + + + def test_taxes_semimonthly_filing_seperate(self): + salary = 20000.00 + schedule_pay = 'monthly' + filing_status = 'MS' + dependents = 2 + + # see https://revenue.alabama.gov/wp-content/uploads/2019/01/whbooklet_0119.pdf for reference + # Hand Calculated Amount to Test + # Step 1 -> 10000.00 for wages per period , 12.0 for monthly -> 20000 * 12 -> 240000.00 + # Step 2A -> standard deduction for highest wage bracket -> 2000. Subtract from yearly income + # 240000.00 - 2000 = 238000.00 + # Step 2B -> Subtract Federal Income Tax in yearly form -> Our Fed withholding is -4821.99 * 12 = -57863.88 + # -> 238000.00 - 57863.88 = 180136.12 + # Step 2C -> Subtract the personal exemption -> 1500 for married filing separately + # -> 180136.12 - 1500 = 178636.12 + # Step 2D -> Since income is so high, only 300$ per dependent -> 600. Subtract + # -> 178636.12 - 600 = 178036.12 + # + # Step 5 (after adding previous lines) -> Compute marginal taxes. + # (500 * (2.00 / 100)) + (2500 * (4.00 / 100)) + ((178036.12 - 500 - 2500) * (5.00 / 100)) -> 8861.806 + # Convert back to pay period + # wh = 8861.806 / 12.0 rounded -> 738.48 + wh = -738.48 + + employee = self._createEmployee() + contract = self._createContract(employee, + wage=salary, + state_id=self.get_us_state('AL'), + al_a4_sit_exemptions=filing_status, + state_income_tax_additional_withholding=0.0, + state_income_tax_exempt=False, + al_a4_sit_dependents=dependents, + schedule_pay=schedule_pay) + + self._log('2019 Alabama tax first payslip monthly:') + payslip = self._createPayslip(employee, '2019-01-01', '2019-01-31') + payslip.compute_sheet() + cats = self._getCategories(payslip) + + self.assertPayrollEqual(cats['EE_US_941_FIT'], -4822.00) # Hand Calculated. + self.assertPayrollEqual(cats['ER_US_SUTA'], self.AL_UNEMP_MAX_WAGE * self.AL_UNEMP) + self.assertPayrollEqual(cats['EE_US_SIT'], wh) + + process_payslip(payslip) + + def test_tax_exempt(self): + salary = 5500.00 + wh = 0 + schedule_pay = 'weekly' + dependents = 2 + + employee = self._createEmployee() + contract = self._createContract(employee, + wage=salary, + state_id=self.get_us_state('AL'), + al_a4_sit_exemptions='', + state_income_tax_additional_withholding=0.0, + state_income_tax_exempt=True, + al_a4_sit_dependents=dependents, + schedule_pay=schedule_pay) + + self._log('2019 Alabama 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.AL_UNEMP) + self.assertPayrollEqual(cats.get('EE_US_SIT', 0.0), wh) + + def test_additional_withholding(self): + salary = 5500.0 + schedule_pay = 'weekly' + additional_wh = 40.0 + dependents = 2 + # filing status default is single + + # see https://revenue.alabama.gov/wp-content/uploads/2019/01/whbooklet_0119.pdf for reference + # Hand Calculated Amount to Test + # Step 1 -> 5500.00 for wages per period , 52.0 for monthly -> 5500 * 52.0 -> 286000.0 + # Step 2A -> standard deduction for highest wage bracket -> 2000. Subtract from yearly income + # 286000.0 - 2000 = 284000.0 + # Step 2B -> Subtract Federal Income Tax in yearly form -> Our Fed withholding is -1422.4 * 52.0 = -73964.8 + # -> 284000.0 - 73964.8 = 210035.2 + # Step 2C -> Subtract the personal exemption -> 1500 for single + # -> 210035.2 - 1500 = 208535.2 + # Step 2D -> Since income is so high, only 300$ per dependent -> 600. Subtract + # -> 208535.2 - 600 = 207935.2 + # + # Step 5 (after adding previous lines) -> Compute marginal taxes. + # (500 * (2.00 / 100)) + (2500 * (4.00 / 100)) + ((207935.2 - 500 - 2500) * (5.00 / 100)) -> 10356.76 + # Convert back to pay period + # wh = 10356.76 / 52.0 rounded -> 199.17 + wh = -199.17 + + employee = self._createEmployee() + contract = self._createContract(employee, + wage=salary, + state_id=self.get_us_state('AL'), + al_a4_sit_exemptions='S', + state_income_tax_additional_withholding=40.0, + state_income_tax_exempt=False, + al_a4_sit_dependents=dependents, + schedule_pay=schedule_pay) + + self._log('2019 Alabama 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['EE_US_941_FIT'], -1422.4) # Hand Calculated. + self.assertPayrollEqual(cats['ER_US_SUTA'], salary * self.AL_UNEMP) + self.assertPayrollEqual(cats['EE_US_SIT'], wh - additional_wh) + + def test_personal_exemption(self): + salary = 5500.0 + schedule_pay = 'weekly' + # filing status default is single + + # see https://revenue.alabama.gov/wp-content/uploads/2019/01/whbooklet_0119.pdf for reference + # Hand Calculated Amount to Test + # Step 1 -> 5500.00 for wages per period , 52.0 for monthly -> 5500 * 52.0 -> 286000.0 + # Step 2A -> standard deduction for highest wage bracket -> 2000. Subtract from yearly income + # 286000.0 - 2000 = 284000.0 + # Step 2B -> Subtract Federal Income Tax in yearly form -> Our Fed withholding is -1422.4 * 52.0 = -73964.8 + # -> 284000.0 - 73964.8 = 210035.2 + # Step 2C -> Subtract the personal exemption -> 0 for personal exemptioon + # -> 210035.2 - 0 = 210035.2 + # Step 2D -> Subtract per dependent. No dependents so 0 + # -> 210035.2 - 0 = 210035.2 + # + # Step 5 (after adding previous lines) -> Compute marginal taxes. + # (500 * (2.00 / 100)) + (2500 * (4.00 / 100)) + ((210035.2 - 500 - 2500) * (5.00 / 100)) -> 10461.76 + # Convert back to pay period + # wh = 10461.76 / 52.0 rounded -> 201.19 + wh = -199.74 + + employee = self._createEmployee() + contract = self._createContract(employee, + wage=salary, + state_id=self.get_us_state('AL'), + al_a4_sit_exemptions='S', + state_income_tax_additional_withholding=0.0, + state_income_tax_exempt=False, + al_a4_sit_dependents=0.0, + schedule_pay=schedule_pay) + + self._log('2019 Alabama 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['EE_US_941_FIT'], -1422.4) # Hand Calculated. + self.assertPayrollEqual(cats['ER_US_SUTA'], salary * self.AL_UNEMP) + self.assertPayrollEqual(cats['EE_US_SIT'], wh) diff --git a/l10n_us_hr_payroll/tests/test_us_al_alabama_payslip_2020.py b/l10n_us_hr_payroll/tests/test_us_al_alabama_payslip_2020.py new file mode 100644 index 00000000..23865fc7 --- /dev/null +++ b/l10n_us_hr_payroll/tests/test_us_al_alabama_payslip_2020.py @@ -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 TestUsALPayslip(TestUsPayslip): + # Taxes and Rates + AL_UNEMP_MAX_WAGE = 8000.00 + AL_UNEMP = 2.70 + + def _test_sit(self, wage, exempt, exemptions, additional_withholding, dependent, schedule_pay, date_start, expected_withholding): + + employee = self._createEmployee() + contract = self._createContract(employee, + wage=wage, + state_id=self.get_us_state('AL'), + al_a4_sit_exemptions=exempt, + state_income_tax_exempt=exemptions, + state_income_tax_additional_withholding=additional_withholding, + al_a4_sit_dependents=dependent, + 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('AL', self.AL_UNEMP, date(2020, 1, 1), wage_base=self.AL_UNEMP_MAX_WAGE) + self._test_sit(10000.0, 'S', False, 0.0, 1.0, 'weekly', date(2020, 1, 1), 349.08) + self._test_sit(850.0, 'M', False, 0.0, 2.0, 'weekly', date(2020, 1, 1), 29.98) + self._test_sit(5000.0, 'H', False, 0.0, 2.0, 'bi-weekly', date(2020, 1, 1), 191.15) + self._test_sit(20000.0, 'MS', False, 2.0, 0, 'monthly', date(2020, 1, 1), 757.6) + self._test_sit(5500.0, '', True, 2.0, 150, 'weekly', date(2020, 1, 1), 0.00) diff --git a/l10n_us_hr_payroll/tests/test_us_ar_arkansas_payslip_2019.py b/l10n_us_hr_payroll/tests/test_us_ar_arkansas_payslip_2019.py new file mode 100644 index 00000000..73b0f59c --- /dev/null +++ b/l10n_us_hr_payroll/tests/test_us_ar_arkansas_payslip_2019.py @@ -0,0 +1,72 @@ +# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details. + +from .common import TestUsPayslip, process_payslip + + +class TestUsARPayslip(TestUsPayslip): + # https://www.dfa.arkansas.gov/images/uploads/incomeTaxOffice/whformula.pdf Calculation based on this file. + AR_UNEMP_MAX_WAGE = 10000.00 + AR_UNEMP = -3.2 / 100.0 + AR_INC_TAX = -0.0535 + + def test_taxes_monthly(self): + salary = 2127.0 + schedule_pay = 'monthly' + + employee = self._createEmployee() + contract = self._createContract(employee, + wage=salary, + state_id=self.get_us_state('AR'), + state_income_tax_additional_withholding=0.0, + ar_ar4ec_sit_allowances=2.0, + state_income_tax_exempt=False, + schedule_pay='monthly') + + self._log('2019 Arkansas tax first payslip weekly:') + payslip = self._createPayslip(employee, '2019-01-01', '2019-01-31') + payslip.compute_sheet() + cats = self._getCategories(payslip) + + # Not exempt from rule 1 or rule 2 - unemployment wages., and actual unemployment. + self.assertPayrollEqual(cats['ER_US_SUTA'], salary * self.AR_UNEMP) + + process_payslip(payslip) + + # Make a new payslip, this one will have maximums + remaining_AR_UNEMP_wages = self.AR_UNEMP_MAX_WAGE - salary if (self.AR_UNEMP_MAX_WAGE - 2*salary < salary) else salary + # We reached the cap of 10000.0 in the first payslip. + self._log('2019 Arkansas 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_AR_UNEMP_wages * self.AR_UNEMP) + + def test_additional_withholding(self): + salary = 5000.0 + schedule_pay = 'monthly' + pay_periods = 12 + allowances = 2 + # TODO: comment on how it was calculated + test_ar_amt = 2598.60 + + employee = self._createEmployee() + contract = self._createContract(employee, + wage=salary, + state_id=self.get_us_state('AR'), + state_income_tax_additional_withholding=100.0, + ar_ar4ec_sit_allowances=2.0, + state_income_tax_exempt=False, + schedule_pay='monthly') + + + self._log('2019 Arkansas 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.AR_UNEMP) + # TODO: change to hand the test_ar_amt already be divided by pay periods + self.assertPayrollAlmostEqual(cats['EE_US_SIT'], -round(test_ar_amt / pay_periods) - 100) + + process_payslip(payslip) diff --git a/l10n_us_hr_payroll/tests/test_us_ar_arkansas_payslip_2020.py b/l10n_us_hr_payroll/tests/test_us_ar_arkansas_payslip_2020.py new file mode 100644 index 00000000..6afe3d4d --- /dev/null +++ b/l10n_us_hr_payroll/tests/test_us_ar_arkansas_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 TestUsARPayslip(TestUsPayslip): + # Taxes and Rates + AR_UNEMP_MAX_WAGE = 8000.0 + AR_UNEMP = 2.9 + + def _test_sit(self, wage, exemptions, allowances, additional_withholding, schedule_pay, date_start, expected_withholding): + + employee = self._createEmployee() + contract = self._createContract(employee, + wage=wage, + state_id=self.get_us_state('AR'), + state_income_tax_exempt=exemptions, + state_income_tax_additional_withholding=additional_withholding, + ar_ar4ec_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('AR', self.AR_UNEMP, date(2020, 1, 1), wage_base=self.AR_UNEMP_MAX_WAGE) + self._test_sit(5000.0, True, 0.0, 0, 'monthly', date(2020, 1, 1), 0.0) + self._test_sit(5000.0, False, 0.0, 0, 'monthly', date(2020, 1, 1), 221.0) + self._test_sit(700.0, False, 0.0, 150, 'weekly', date(2020, 1, 1), 175.0) + self._test_sit(7000.0, False, 2.0, 0, 'semi-monthly', date(2020, 1, 1), 420.0) + self._test_sit(3000.0, False, 1.0, 0, 'bi-weekly', date(2020, 1, 1), 142.0) diff --git a/l10n_us_hr_payroll/tests/test_us_az_arizona_payslip_2019.py b/l10n_us_hr_payroll/tests/test_us_az_arizona_payslip_2019.py new file mode 100644 index 00000000..b97063b6 --- /dev/null +++ b/l10n_us_hr_payroll/tests/test_us_az_arizona_payslip_2019.py @@ -0,0 +1,72 @@ +# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details. + +from .common import TestUsPayslip, process_payslip + + +class TestUsAZPayslip(TestUsPayslip): + + # TAXES AND RATES + AZ_UNEMP_MAX_WAGE = 7000.00 + AZ_UNEMP = -(2.00 / 100.0) + + def test_taxes_with_additional_wh(self): + salary = 15000.00 + schedule_pay = 'weekly' + withholding_percentage = 5.1 + percent_wh = (5.10 / 100) # 5.1% + additional_wh = 12.50 + + wh_to_test = -((percent_wh * salary) + additional_wh) + + employee = self._createEmployee() + contract = self._createContract(employee, + wage=salary, + state_id=self.get_us_state('AZ'), + state_income_tax_additional_withholding=12.50, + az_a4_sit_withholding_percentage=withholding_percentage, + schedule_pay=schedule_pay) + + self._log('2019 Arizona 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'], self.AZ_UNEMP_MAX_WAGE * self.AZ_UNEMP) + self.assertPayrollEqual(cats['EE_US_SIT'], wh_to_test) + + process_payslip(payslip) + + remaining_AZ_UNEMP_wages = 0.0 # We already reached max unemployment wages. + + self._log('2019 Arizona 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_AZ_UNEMP_wages * self.AZ_UNEMP) + + def test_taxes_monthly(self): + salary = 1000.00 + schedule_pay = 'monthly' + withholding_percentage = 2.7 + percent_wh = (2.70 / 100) # 2.7% + additional_wh = 0.0 + wh_to_test = -((percent_wh * salary) + additional_wh) + + employee = self._createEmployee() + contract = self._createContract(employee, + wage=salary, + state_id=self.get_us_state('AZ'), + state_income_tax_additional_withholding=0.0, + az_a4_sit_withholding_percentage=withholding_percentage, + schedule_pay=schedule_pay) + + self._log('2019 Arizona tax first payslip monthly:') + 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.AZ_UNEMP) + self.assertPayrollEqual(cats['EE_US_SIT'], wh_to_test) + + process_payslip(payslip) diff --git a/l10n_us_hr_payroll/tests/test_us_az_arizona_payslip_2020.py b/l10n_us_hr_payroll/tests/test_us_az_arizona_payslip_2020.py new file mode 100644 index 00000000..248648bc --- /dev/null +++ b/l10n_us_hr_payroll/tests/test_us_az_arizona_payslip_2020.py @@ -0,0 +1,34 @@ +# 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 TestUsAZPayslip(TestUsPayslip): + # Taxes and Rates + AZ_UNEMP_MAX_WAGE = 7000.0 + AZ_UNEMP = 2.0 + + def _test_sit(self, wage, additional_withholding, withholding_percent, schedule_pay, date_start, expected_withholding): + + employee = self._createEmployee() + contract = self._createContract(employee, + wage=wage, + state_id=self.get_us_state('AZ'), + state_income_tax_additional_withholding=additional_withholding, + az_a4_sit_withholding_percentage=withholding_percent, + 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('AZ', self.AZ_UNEMP, date(2020, 1, 1), wage_base=self.AZ_UNEMP_MAX_WAGE) + self._test_sit(1000.0, 0.0, 2.70, 'monthly', date(2020, 1, 1), 27.0) + self._test_sit(1000.0, 10.0, 2.70, 'monthly', date(2020, 1, 1), 37.0) + self._test_sit(15000.0, 0.0, 3.60, 'weekly', date(2020, 1, 1), 540.0) + self._test_sit(8000.0, 0.0, 4.20, 'semi-monthly', date(2020, 1, 1), 336.0) + self._test_sit(8000.0, 0.0, 0.00, 'semi-monthly', date(2020, 1, 1), 0.0) diff --git a/l10n_us_hr_payroll/tests/test_us_ca_california_payslip_2019.py b/l10n_us_hr_payroll/tests/test_us_ca_california_payslip_2019.py new file mode 100644 index 00000000..b9331fe3 --- /dev/null +++ b/l10n_us_hr_payroll/tests/test_us_ca_california_payslip_2019.py @@ -0,0 +1,245 @@ +# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details. + +from .common import TestUsPayslip, process_payslip + + +class TestUsCAPayslip(TestUsPayslip): + ### + # Taxes and Rates + ### + CA_MAX_WAGE = 7000 + CA_UIT = -3.5 / 100.0 + CA_ETT = -0.1 / 100.0 + CA_SDI = -1.0 / 100.0 + + # Examples from https://www.edd.ca.gov/pdf_pub_ctr/20methb.pdf + def test_example_a(self): + salary = 210 + schedule_pay = 'weekly' + allowances = 1 + additional_allowances = 0 + + wh = 0.00 + + employee = self._createEmployee() + + contract = self._createContract(employee, + wage=salary, + state_id=self.get_us_state('CA'), + ca_de4_sit_filing_status='single', + state_income_tax_additional_withholding=0.0, + ca_de4_sit_allowances=allowances, + ca_de4_sit_additional_allowances=additional_allowances, + schedule_pay=schedule_pay) + + self._log('2019 California tax first payslip:') + 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.CA_UIT + self.CA_ETT)) + self.assertPayrollEqual(cats['EE_US_SUTA'], salary * self.CA_SDI) + self.assertPayrollEqual(cats['EE_US_SIT'], wh) + + process_payslip(payslip) + + def test_example_b(self): + salary = 1250 + schedule_pay = 'bi-weekly' + allowances = 2 + additional_allowances = 1 + + # Example B + subject_to_withholding = salary - 38 + taxable_income = subject_to_withholding - 339 + computed_tax = (taxable_income - 632) * 0.022 + 6.95 # 6.95 Marginal Amount + wh = computed_tax - 9.65 # two exemption allowances + wh = -wh + + employee = self._createEmployee() + contract = self._createContract(employee, + wage=salary, + state_id=self.get_us_state('CA'), + ca_de4_sit_filing_status='married', + state_income_tax_additional_withholding=0.0, + ca_de4_sit_allowances=allowances, + ca_de4_sit_additional_allowances=additional_allowances, + schedule_pay=schedule_pay) + + self._log('2019 California tax first payslip:') + 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.CA_UIT + self.CA_ETT)) + self.assertPayrollEqual(cats['EE_US_SUTA'], salary * self.CA_SDI) + self.assertPayrollEqual(cats['EE_US_SIT'], wh) + + process_payslip(payslip) + + + def test_example_c(self): + salary = 4100 + schedule_pay = 'monthly' + allowances = 5 + additional_allowances = 0.0 + + wh = -9.3 + + employee = self._createEmployee() + contract = self._createContract(employee, + wage=salary, + state_id=self.get_us_state('CA'), + ca_de4_sit_filing_status='married', + state_income_tax_additional_withholding=0.0, + ca_de4_sit_allowances=allowances, + ca_de4_sit_additional_allowances=additional_allowances, + schedule_pay=schedule_pay) + + self._log('2019 California tax first payslip:') + 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.CA_UIT + self.CA_ETT)) + self.assertPayrollEqual(cats['EE_US_SUTA'], salary * self.CA_SDI) + self.assertPayrollEqual(cats['EE_US_SIT'], wh) + + process_payslip(payslip) + + # Make a new payslip, this one will have maximums + + remaining_ca_uit_wages = self.CA_MAX_WAGE - salary if (self.CA_MAX_WAGE - 2 * salary < salary) \ + else salary + + self._log('2019 California tax second payslip:') + payslip = self._createPayslip(employee, '2019-02-01', '2019-02-28') + + payslip.compute_sheet() + + cats = self._getCategories(payslip) + + self.assertPayrollEqual(cats['ER_US_SUTA'], round((remaining_ca_uit_wages * (self.CA_UIT + self.CA_ETT)), 2)) + + def test_example_d(self): + salary = 800 + schedule_pay = 'weekly' + allowances = 3 + additional_allowances = 0 + + wh = -3.18 + + employee = self._createEmployee() + contract = self._createContract(employee, + wage=salary, + state_id=self.get_us_state('CA'), + ca_de4_sit_filing_status='head_household', + state_income_tax_additional_withholding=0.0, + ca_de4_sit_allowances=allowances, + ca_de4_sit_additional_allowances=additional_allowances, + schedule_pay=schedule_pay) + + self._log('2019 California tax first payslip:') + 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.CA_UIT + self.CA_ETT)) + self.assertPayrollEqual(cats['EE_US_SUTA'], salary * self.CA_SDI) + self.assertPayrollEqual(cats['EE_US_SIT'], wh) + + process_payslip(payslip) + + # Make a new payslip, this one will have maximums + + remaining_ca_uit_wages = self.CA_MAX_WAGE - salary if (self.CA_MAX_WAGE - 2 * salary < salary) \ + else salary + + self._log('2019 California tax second payslip:') + payslip = self._createPayslip(employee, '2019-02-01', '2019-02-28') + + payslip.compute_sheet() + + cats = self._getCategories(payslip) + + self.assertPayrollEqual(cats['ER_US_SUTA'], round((remaining_ca_uit_wages * (self.CA_UIT + self.CA_ETT)), 2)) + + def test_example_e(self): + salary = 1800 + schedule_pay = 'semi-monthly' + allowances = 4 + additional_allowances = 0 + + wh = -3.08 + + employee = self._createEmployee() + contract = self._createContract(employee, + wage=salary, + state_id=self.get_us_state('CA'), + ca_de4_sit_filing_status='married', + state_income_tax_additional_withholding=0.0, + ca_de4_sit_allowances=allowances, + ca_de4_sit_additional_allowances=additional_allowances, + schedule_pay=schedule_pay) + + self._log('2019 California tax first payslip:') + 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.CA_UIT + self.CA_ETT)) + self.assertPayrollEqual(cats['EE_US_SUTA'], salary * self.CA_SDI) + self.assertPayrollEqual(cats['EE_US_SIT'], wh) + + process_payslip(payslip) + + # Make a new payslip, this one will have maximums + + remaining_ca_uit_wages = self.CA_MAX_WAGE - salary if (self.CA_MAX_WAGE - 2 * salary < salary) \ + else salary + + self._log('2019 California tax second payslip:') + payslip = self._createPayslip(employee, '2019-02-01', '2019-02-28') + + payslip.compute_sheet() + + cats = self._getCategories(payslip) + + self.assertPayrollEqual(cats['ER_US_SUTA'], round((remaining_ca_uit_wages * (self.CA_UIT + self.CA_ETT)), 2)) + + def test_example_f(self): + salary = 45000 + schedule_pay = 'annually' + allowances = 4 + additional_allowances = 0 + + wh = -113.85 + + employee = self._createEmployee() + contract = self._createContract(employee, + wage=salary, + state_id=self.get_us_state('CA'), + ca_de4_sit_filing_status='married', + state_income_tax_additional_withholding=0.0, + ca_de4_sit_allowances=allowances, + ca_de4_sit_additional_allowances=additional_allowances, + schedule_pay=schedule_pay) + + self._log('2019 California tax first payslip:') + payslip = self._createPayslip(employee, '2019-01-01', '2019-01-31') + + payslip.compute_sheet() + + cats = self._getCategories(payslip) + self.assertPayrollEqual(cats['ER_US_SUTA'], self.CA_MAX_WAGE * (self.CA_UIT + self.CA_ETT)) + self.assertPayrollEqual(cats['EE_US_SUTA'], self.CA_MAX_WAGE * self.CA_SDI) + self.assertPayrollEqual(cats['EE_US_SIT'], wh) + + process_payslip(payslip) \ No newline at end of file diff --git a/l10n_us_hr_payroll/tests/test_us_ca_california_payslip_2020.py b/l10n_us_hr_payroll/tests/test_us_ca_california_payslip_2020.py new file mode 100755 index 00000000..264b115e --- /dev/null +++ b/l10n_us_hr_payroll/tests/test_us_ca_california_payslip_2020.py @@ -0,0 +1,43 @@ +# 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 TestUsCAPayslip(TestUsPayslip): + ### + # 2020 Taxes and Rates + ### + CA_UNEMP_MAX_WAGE = 7000.0 # Note that this is used for SDI and FLI as well + CA_UIT = 3.4 + CA_ETT = 0.1 + CA_SDI = 1.0 + + def _test_sit(self, wage, filing_status, allowances, additional_allowances, additional_withholding, schedule_pay, date_start, expected_withholding): + employee = self._createEmployee() + contract = self._createContract(employee, + wage=wage, + state_id=self.get_us_state('CA'), + ca_de4_sit_filing_status=filing_status, + ca_de4_sit_allowances=allowances, + ca_de4_sit_additional_allowances=additional_allowances, + 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.assertPayrollAlmostEqual(cats.get('EE_US_SIT', 0.0), -expected_withholding if filing_status else 0.0) + + def test_2020_taxes_example1(self): + combined_er_rate = self.CA_UIT + self.CA_ETT + self._test_er_suta('CA', combined_er_rate, date(2020, 1, 1), wage_base=self.CA_UNEMP_MAX_WAGE) + self._test_ee_suta('CA', self.CA_SDI, date(2020, 1, 1), wage_base=self.CA_UNEMP_MAX_WAGE, relaxed=True) + # these expected values come from https://www.edd.ca.gov/pdf_pub_ctr/20methb.pdf + self._test_sit(210.0, 'single', 1, 0, 0, 'weekly', date(2020, 1, 1), 0.00) + self._test_sit(1250.0, 'married', 2, 1, 0, 'bi-weekly', date(2020, 1, 1), 1.23) + self._test_sit(4100.0, 'married', 5, 0, 0, 'monthly', date(2020, 1, 1), 1.5) + self._test_sit(800.0, 'head_household', 3, 0, 0, 'weekly', date(2020, 1, 1), 2.28) + self._test_sit(1800.0, 'married', 4, 0, 0, 'semi-monthly', date(2020, 1, 1), 0.84) + self._test_sit(45000.0, 'married', 4, 0, 0, 'annually', date(2020, 1, 1), 59.78) + self._test_sit(45000.0, 'married', 4, 0, 20.0, 'annually', date(2020, 1, 1), 79.78) + self._test_sit(6000.0, '', 4, 0, 20.0, 'annually', date(2020, 1, 1), 0.00) diff --git a/l10n_us_hr_payroll/tests/test_us_co_colorado_payslip_2020.py b/l10n_us_hr_payroll/tests/test_us_co_colorado_payslip_2020.py new file mode 100755 index 00000000..0fa45d9c --- /dev/null +++ b/l10n_us_hr_payroll/tests/test_us_co_colorado_payslip_2020.py @@ -0,0 +1,37 @@ +# 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 TestUsCOPayslip(TestUsPayslip): + ### + # 2020 Taxes and Rates + ### + CO_UNEMP_MAX_WAGE = 13600.0 + CO_UNEMP = 1.7 + + def _test_sit(self, wage, filing_status, additional_withholding, schedule_pay, date_start, expected_withholding, state_income_tax_exempt=False): + employee = self._createEmployee() + contract = self._createContract(employee, + wage=wage, + state_id=self.get_us_state('CO'), + fed_941_fit_w4_filing_status=filing_status, + state_income_tax_additional_withholding=additional_withholding, + state_income_tax_exempt=state_income_tax_exempt, + 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('CO', self.CO_UNEMP, date(2020, 1, 1), wage_base=self.CO_UNEMP_MAX_WAGE) + self._test_sit(5000.0, 'married', 0.0, 'semi-monthly', date(2020, 1, 1), 216.07) + self._test_sit(800.0, 'single', 0.0, 'weekly', date(2020, 1, 1), 33.48) + self._test_sit(20000.0, 'married', 0.0, 'quarterly', date(2020, 1, 1), 833.4) + self._test_sit(20000.0, 'married', 10.0, 'quarterly', date(2020, 1, 1), 843.4) + self._test_sit(20000.0, 'married', 0.0, 'quarterly', date(2020, 1, 1), 0.0, True) + self._test_sit(800.0, '', 0.0, 'weekly', date(2020, 1, 1), 0.00) diff --git a/l10n_us_hr_payroll/tests/test_us_ct_connecticut_payslip_2019.py b/l10n_us_hr_payroll/tests/test_us_ct_connecticut_payslip_2019.py new file mode 100644 index 00000000..ab423131 --- /dev/null +++ b/l10n_us_hr_payroll/tests/test_us_ct_connecticut_payslip_2019.py @@ -0,0 +1,121 @@ +# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details. + +from .common import TestUsPayslip, process_payslip + + +class TestUsCTPayslip(TestUsPayslip): + # TAXES AND RATES + CT_UNEMP_MAX_WAGE = 15000.00 + CT_UNEMP = -(3.40 / 100.0) + + def test_taxes_weekly_with_additional_wh(self): + + # Tax tables can be found here: + # https://portal.ct.gov/-/media/DRS/Publications/pubsip/2019/IP-2019(1).pdf?la=en + # Step 1 - Wages per period -> 10000.00 + salary = 10000.00 + # Step 2 and 3 - Annual wages -> 10000.00 * 52.0 -> 520000.0 + schedule_pay = 'weekly' + # Step 4 Employee Withholding Code -> A + wh_code = 'a' + # Step 5 - Use annual wages and withholding code with table for exemption amount. + # exemption_amt = 0 since highest bracket. + # Step 6 - Subtract 5 from 3 for taxable income. + # taxable income = 520000.00 since we do not have an exemption. + # Step 7 - Determine initial amount from table + # initial = 31550 + ((6.99 / 100) * (520000.00 - 500000.00)) + # 32948.0 + # Step 8 - Determine the tax rate phase out add back from table. + # phase_out = 200 + # Step 9 - Determine the recapture amount from table. + # Close to top, but not top. -> 2900 + # Step 10 - Add Step 7, 8, 9 + # 32948.0 + 200 + 2900.00 - > 36048.0 + # Step 11 - Determine decimal amount from personal tax credits. + # We get no tax credit. + # Step 12 - Multiple Step 10 by 1.00 - Step 11 + # 36048.0 * 1.00 = 36048.0 + # Step 13 - Divide by the number of pay periods. + # 36048.0 / 52.0 = 693.23 + # Step 14 & 15 & 16- Add / Subtract the additional or under withholding amount. Then Add this to the amount + # for withholding per period. + additional_wh = 12.50 + # 693.23 + 12.50 -> + wh = -705.73 + + employee = self._createEmployee() + contract = self._createContract(employee, + wage=salary, + state_id=self.get_us_state('CT'), + ct_w4na_sit_code=wh_code, + state_income_tax_additional_withholding=additional_wh, + schedule_pay=schedule_pay) + + self._log('2019 Connecticut 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.CT_UNEMP) + self.assertPayrollEqual(cats['EE_US_SIT'], wh) + + process_payslip(payslip) + + remaining_CT_UNEMP_wages = 5000.00 # We already reached the maximum wage for unemployment insurance. + self._log('2019 Connecticut 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_CT_UNEMP_wages * self.CT_UNEMP) + + def test_taxes_weekly_with_different_code(self): + + # Tax tables can be found here: + # https://portal.ct.gov/-/media/DRS/Publications/pubsip/2019/IP-2019(1).pdf?la=en + # Step 1 - Wages per period -> 15000.00 + salary = 15000.00 + # Step 2 and 3 - Annual wages -> 15000.00 * 12.0 -> 180000.0 + schedule_pay = 'monthly' + # Step 4 Employee Withholding Code -> B + wh_code = 'b' + # Step 5 - Use annual wages and withholding code with table for exemption amount. + # exemption_amt = 0 since highest bracket. + # Step 6 - Subtract 5 from 3 for taxable income. + # taxable income = 180000.0 since we do not have an exemption. + # Step 7 - Determine initial amount from table + # initial = 8080 + ((6.00 / 100) * (180000.0 - 160000)) + # 9280.0 + # Step 8 - Determine the tax rate phase out add back from table. + # phase_out = 320 + # Step 9 - Determine the recapture amount from table. + # Bottom -> 0 + # Step 10 - Add Step 7, 8, 9 + # 9280.0 + 320 + 0 - > 9600.0 + # Step 11 - Determine decimal amount from personal tax credits. + # We get no tax credit. + # Step 12 - Multiple Step 10 by 1.00 - Step 11 + # 9600.0 * 1.00 = 9600.0 + # Step 13 - Divide by the number of pay periods. + # 9600.0 / 12.0 = 800.0 + # Step 14 & 15 & 16- Add / Subtract the additional or under withholding amount. Then Add this to the amount + # for withholding per period. + additional_wh = 15.00 + # 800.0 + 15.00 -> + wh = -815.0 + + employee = self._createEmployee() + contract = self._createContract(employee, + wage=salary, + state_id=self.get_us_state('CT'), + ct_w4na_sit_code=wh_code, + state_income_tax_additional_withholding=additional_wh, + schedule_pay=schedule_pay) + + self._log('2019 Connecticut tax first payslip monthly:') + payslip = self._createPayslip(employee, '2019-01-01', '2019-01-31') + payslip.compute_sheet() + cats = self._getCategories(payslip) + + self.assertPayrollEqual(cats['ER_US_SUTA'], self.CT_UNEMP_MAX_WAGE * self.CT_UNEMP) + self.assertPayrollEqual(cats['EE_US_SIT'], wh) diff --git a/l10n_us_hr_payroll/tests/test_us_ct_connecticut_payslip_2020.py b/l10n_us_hr_payroll/tests/test_us_ct_connecticut_payslip_2020.py new file mode 100644 index 00000000..8ce41d06 --- /dev/null +++ b/l10n_us_hr_payroll/tests/test_us_ct_connecticut_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 TestUsCTPayslip(TestUsPayslip): + # Taxes and Rates + CT_UNEMP_MAX_WAGE = 15000.0 + CT_UNEMP = 3.2 + + def _test_sit(self, wage, withholding_code, additional_withholding, schedule_pay, date_start, expected_withholding): + + employee = self._createEmployee() + contract = self._createContract(employee, + wage=wage, + state_id=self.get_us_state('CT'), + ct_w4na_sit_code=withholding_code, + 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('CT', self.CT_UNEMP, date(2020, 1, 1), wage_base=self.CT_UNEMP_MAX_WAGE) + self._test_sit(10000.0, 'a', 0.0, 'weekly', date(2020, 1, 1), 693.23) + self._test_sit(12000.0, 'b', 15.0, 'bi-weekly', date(2020, 1, 1), 688.85) + self._test_sit(5000.0, 'f', 15.0, 'monthly', date(2020, 1, 1), 230.25) + self._test_sit(15000.0, 'c', 0.0, 'monthly', date(2020, 1, 1), 783.33) + self._test_sit(18000.0, 'b', 0.0, 'weekly', date(2020, 1, 1), 1254.35) + self._test_sit(500.0, 'd', 0.0, 'weekly', date(2020, 1, 1), 21.15) diff --git a/l10n_us_hr_payroll/tests/test_us_de_delaware_payslip_2020.py b/l10n_us_hr_payroll/tests/test_us_de_delaware_payslip_2020.py new file mode 100755 index 00000000..ed285368 --- /dev/null +++ b/l10n_us_hr_payroll/tests/test_us_de_delaware_payslip_2020.py @@ -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 TestUsDEPayslip(TestUsPayslip): + ### + # 2020 Taxes and Rates + ### + DE_UNEMP_MAX_WAGE = 16500.0 + DE_UNEMP = 1.50 + # Calculation based on section 17. https://revenue.delaware.gov/employers-guide-withholding-regulations-employers-duties/ + + def _test_sit(self, wage, filing_status, additional_withholding, dependents, schedule_pay, date_start, expected_withholding): + employee = self._createEmployee() + contract = self._createContract(employee, + wage=wage, + state_id=self.get_us_state('DE'), + de_w4_sit_filing_status=filing_status, + state_income_tax_additional_withholding=additional_withholding, + de_w4_sit_dependent=dependents, + 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('DE', self.DE_UNEMP, date(2020, 1, 1), wage_base=self.DE_UNEMP_MAX_WAGE) + self._test_sit(480.77, 'single', 0.0, 1.0, 'weekly', date(2020, 1, 1), 13.88) + self._test_sit(5000.0, 'single', 0.0, 2.0, 'monthly', date(2020, 1, 1), 211.93) + self._test_sit(5000.0, 'single', 10.0, 1.0, 'monthly', date(2020, 1, 1), 231.1) + self._test_sit(20000.0, 'married', 0.0, 3.0, 'quarterly', date(2020, 1, 1), 876.0) diff --git a/l10n_us_hr_payroll/tests/test_us_ga_georgia_payslip_2019.py b/l10n_us_hr_payroll/tests/test_us_ga_georgia_payslip_2019.py index b407a079..98206965 100755 --- a/l10n_us_hr_payroll/tests/test_us_ga_georgia_payslip_2019.py +++ b/l10n_us_hr_payroll/tests/test_us_ga_georgia_payslip_2019.py @@ -114,7 +114,7 @@ class TestUsGAPayslip(TestUsPayslip): salary = 25000.00 schedule_pay = 'monthly' allowances = 2 - filing_status = 'exempt' + filing_status = '' additional_wh = 15.00 employee = self._createEmployee() diff --git a/l10n_us_hr_payroll/tests/test_us_ga_georgia_payslip_2020.py b/l10n_us_hr_payroll/tests/test_us_ga_georgia_payslip_2020.py index 6debc2ca..21a0a810 100755 --- a/l10n_us_hr_payroll/tests/test_us_ga_georgia_payslip_2020.py +++ b/l10n_us_hr_payroll/tests/test_us_ga_georgia_payslip_2020.py @@ -1,7 +1,7 @@ # Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details. -from datetime import date -from .common import TestUsPayslip, process_payslip +from datetime import date, timedelta +from .common import TestUsPayslip class TestUsGAPayslip(TestUsPayslip): @@ -10,139 +10,30 @@ class TestUsGAPayslip(TestUsPayslip): GA_UNEMP_MAX_WAGE = 9500.00 GA_UNEMP = 2.70 - def _run_test_sit(self, - wage=0.0, - schedule_pay='monthly', - filing_status='single', - dependent_credit=0.0, - other_income=0.0, - deductions=0.0, - additional_withholding=0.0, - is_nonresident_alien=False, - state_income_tax_exempt=False, - state_income_tax_additional_withholding=0.0, - ga_g4_sit_dependent_allowances=0, - ga_g4_sit_additional_allowances=0, - ga_g4_sit_filing_status=None, - expected=0.0, - ): + # Example calculated based on https://dor.georgia.gov/employers-tax-guide 2020_employer tax gauide + + def _test_sit(self, wage, filing_status, additional_withholding, dependent_allowances, additional_allowances, + schedule_pay, date_start, expected_withholding): employee = self._createEmployee() contract = self._createContract(employee, wage=wage, - schedule_pay=schedule_pay, - fed_941_fit_w4_is_nonresident_alien=is_nonresident_alien, - fed_941_fit_w4_filing_status=filing_status, - fed_941_fit_w4_multiple_jobs_higher=False, - fed_941_fit_w4_dependent_credit=dependent_credit, - fed_941_fit_w4_other_income=other_income, - fed_941_fit_w4_deductions=deductions, - fed_941_fit_w4_additional_withholding=additional_withholding, - state_income_tax_exempt=state_income_tax_exempt, - state_income_tax_additional_withholding=state_income_tax_additional_withholding, - ga_g4_sit_dependent_allowances=ga_g4_sit_dependent_allowances, - ga_g4_sit_additional_allowances=ga_g4_sit_additional_allowances, - ga_g4_sit_filing_status=ga_g4_sit_filing_status, state_id=self.get_us_state('GA'), - ) - payslip = self._createPayslip(employee, '2020-01-01', '2020-01-31') + ga_g4_sit_filing_status=filing_status, + state_income_tax_additional_withholding=additional_withholding, + ga_g4_sit_dependent_allowances=dependent_allowances, + ga_g4_sit_additional_allowances=additional_allowances, + schedule_pay=schedule_pay) + payslip = self._createPayslip(employee, date_start, date_start + timedelta(days=7)) payslip.compute_sheet() cats = self._getCategories(payslip) - # Instead of PayrollEqual after initial first round of testing. - self.assertPayrollAlmostEqual(cats.get('EE_US_SIT', 0.0), -expected) - return payslip - def test_taxes_weekly_single_with_additional_wh(self): + self._log('Computed period tax: ' + str(expected_withholding)) + self.assertPayrollAlmostEqual(cats.get('EE_US_SIT', 0.0), -expected_withholding) + + def test_2020_taxes_example(self): self._test_er_suta('GA', self.GA_UNEMP, date(2020, 1, 1), wage_base=self.GA_UNEMP_MAX_WAGE) - salary = 15000.00 - schedule_pay = 'weekly' - allowances = 1 - filing_status = 'single' - additional_wh = 12.50 - # Hand Calculated Amount to Test - # Step 1 - Subtract standard deduction from wages. Std Deduct for single weekly is 88.50 - # step1 = 15000.00 - 88.50 = 14911.5 - # Step 2 - Subtract personal allowance from step1. Allowance for single weekly is 51.92 - # step2 = step1 - 51.92 = 14859.58 - # Step 3 - Subtract amount for dependents. Weekly dependent allowance is 57.50 - # step3 = 14859.58 - 57.50 = 14802.08 - # Step 4 -Determine wh amount from tables - # step4 = 4.42 + ((5.75 / 100.00) * (14802.08 - 135.00)) - # Add additional_wh - # wh = 847.7771 + 12.50 = 860.2771 - wh = 860.28 - - self._run_test_sit(wage=salary, - schedule_pay=schedule_pay, - state_income_tax_additional_withholding=additional_wh, - ga_g4_sit_dependent_allowances=allowances, - ga_g4_sit_additional_allowances=0, - ga_g4_sit_filing_status=filing_status, - expected=wh, - ) - - - def test_taxes_monthly_head_of_household(self): - salary = 25000.00 - schedule_pay = 'monthly' - allowances = 2 - filing_status = 'head of household' - additional_wh = 15.00 - # Hand Calculated Amount to Test - # Step 1 - Subtract standard deduction from wages. Std Deduct for head of household monthly is 383.50 - # step1 = 25000.00 - 383.50 = 24616.5 - # Step 2 - Subtract personal allowance from step1. Allowance for head of household monthly is 225.00 - # step2 = 24616.5 - 225.00 = 24391.5 - # Step 3 - Subtract amount for dependents. Weekly dependent allowance is 250.00 - # step3 = 24391.5 - (2 * 250.00) = 23891.5 - # Step 4 - Determine wh amount from tables - # step4 = 28.33 + ((5.75 / 100.00) * (23891.5 - 833.00)) = 1354.19375 - # Add additional_wh - # wh = 1354.19375 + 15.00 = 1369.19375 - wh = 1369.19 - - self._run_test_sit(wage=salary, - schedule_pay=schedule_pay, - state_income_tax_additional_withholding=additional_wh, - ga_g4_sit_dependent_allowances=allowances, - ga_g4_sit_additional_allowances=0, - ga_g4_sit_filing_status=filing_status, - expected=wh, - ) - - # additional from external calculator - self._run_test_sit(wage=425.0, - schedule_pay='weekly', - state_income_tax_additional_withholding=0.0, - ga_g4_sit_dependent_allowances=1, - ga_g4_sit_additional_allowances=0, - ga_g4_sit_filing_status='married filing separate', - expected=11.45, - ) - - self._run_test_sit(wage=3000.0, - schedule_pay='quarterly', - state_income_tax_additional_withholding=0.0, - ga_g4_sit_dependent_allowances=1, - ga_g4_sit_additional_allowances=1, - ga_g4_sit_filing_status='single', - expected=0.0, - ) - - # TODO 'married filing joint, both spouses working' returns lower than calculator - # TODO 'married filing joint, one spouse working' returns lower than calculator - - def test_taxes_exempt(self): - salary = 25000.00 - schedule_pay = 'monthly' - allowances = 2 - filing_status = 'exempt' - additional_wh = 15.00 - - self._run_test_sit(wage=salary, - schedule_pay=schedule_pay, - state_income_tax_additional_withholding=additional_wh, - ga_g4_sit_dependent_allowances=allowances, - ga_g4_sit_additional_allowances=0, - ga_g4_sit_filing_status=filing_status, - expected=0.0, - ) + self._test_sit(15000.0, 'single', 12.50, 1, 0, 'weekly', date(2020, 1, 1), 860.28) + self._test_sit(25000.0, 'head of household', 15.00, 2, 0, 'monthly', date(2020, 1, 1), 1369.19) + self._test_sit(425.0, 'married filing separate', 0.0, 1, 0, 'weekly', date(2020, 1, 1), 11.45) + self._test_sit(3000.0, 'single', 0.00, 1, 1, 'quarterly', date(2020, 1, 1), 0.0) + self._test_sit(2500.0, '', 0.00, 1, 1, 'quarterly', date(2020, 1, 1), 0.0) diff --git a/l10n_us_hr_payroll/tests/test_us_hi_hawaii_payslip_2019.py b/l10n_us_hr_payroll/tests/test_us_hi_hawaii_payslip_2019.py new file mode 100644 index 00000000..13f1f2b5 --- /dev/null +++ b/l10n_us_hr_payroll/tests/test_us_hi_hawaii_payslip_2019.py @@ -0,0 +1,93 @@ +# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details. + +from .common import TestUsPayslip, process_payslip + + +class TestUsHIPayslip(TestUsPayslip): + + # TAXES AND RATES + HI_UNEMP_MAX_WAGE = 46800.00 + HI_UNEMP = -(2.40 / 100.0) + + def test_taxes_single_weekly(self): + salary = 375.00 + schedule_pay = 'weekly' + filing_status = 'single' + allowances = 3 + wh_to_check = -15.3 + # Taxable income = (wage * payperiod ) - (allownaces * personal_exemption) + # taxable_income = (375 * 52) - (3 * 1144) = 16068 + # Last = row[0] = 692 + # withholding = row[1] + ((row[2] / 100.0) * (taxable_income - last)) + # withholding = 682 + ((6.80 / 100.0 ) * (16068 - 14400)) = 795.42 + # wh_to_check = 795.42/52 = 15.3 + employee = self._createEmployee() + contract = self._createContract(employee, + wage=salary, + state_id=self.get_us_state('HI'), + hi_hw4_sit_filing_status=filing_status, + state_income_tax_additional_withholding=0.0, + hi_hw4_sit_allowances=allowances, + schedule_pay=schedule_pay) + + self._log('2019 Hawaii tax first payslip single:') + 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.HI_UNEMP) + self.assertPayrollEqual(cats['EE_US_SIT'], wh_to_check) + + process_payslip(payslip) + + remaining_id_unemp_wages = self.HI_UNEMP_MAX_WAGE - salary if (self.HI_UNEMP_MAX_WAGE - 2*salary < salary) \ + else salary + + self._log('2019 Hawaii tax second payslip single:') + payslip = self._createPayslip(employee, '2019-02-01', '2019-02-28') + payslip.compute_sheet() + cats = self._getCategories(payslip) + + self.assertPayrollEqual(cats['ER_US_SUTA'], remaining_id_unemp_wages * self.HI_UNEMP) + + def test_taxes_married_monthly(self): + salary = 5000.00 + schedule_pay = 'monthly' + filing_status = 'married' + allowances = 2 + wh_to_check = -287.1 + # Taxable income = (wage * payperiod ) - (allownaces * personal_exemption) + # taxable_income = (5000 * 12) - (2 * 1144) = 57712 + # Last = row[0] = 48000 + # withholding = row[1] + ((row[2] / 100.0) * (taxable_income - last)) + # withholding = 2707 + ((7.70 / 100.0 ) * (57712 - 48000)) = 3445.112 + # wh_to_check = 3445.112/52 = 287.092 + employee = self._createEmployee() + contract = self._createContract(employee, + wage=salary, + state_id=self.get_us_state('HI'), + hi_hw4_sit_filing_status=filing_status, + state_income_tax_additional_withholding=0.0, + hi_hw4_sit_allowances=allowances, + schedule_pay=schedule_pay) + + self._log('2019 Hawaii tax first payslip monthly:') + 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.HI_UNEMP) + self.assertPayrollEqual(cats['EE_US_SIT'], wh_to_check) + + process_payslip(payslip) + + remaining_id_unemp_wages = self.HI_UNEMP_MAX_WAGE - salary if (self.HI_UNEMP_MAX_WAGE - 2*salary < salary) \ + else salary + + self._log('2019 Hawaii tax second payslip monthly:') + payslip = self._createPayslip(employee, '2019-02-01', '2019-02-28') + payslip.compute_sheet() + cats = self._getCategories(payslip) + + self.assertPayrollEqual(cats['ER_US_SUTA'], remaining_id_unemp_wages * self.HI_UNEMP) + diff --git a/l10n_us_hr_payroll/tests/test_us_hi_hawaii_payslip_2020.py b/l10n_us_hr_payroll/tests/test_us_hi_hawaii_payslip_2020.py new file mode 100755 index 00000000..9a746057 --- /dev/null +++ b/l10n_us_hr_payroll/tests/test_us_hi_hawaii_payslip_2020.py @@ -0,0 +1,37 @@ +# 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 TestUsHIPayslip(TestUsPayslip): + ### + # 2020 Taxes and Rates + ### + HI_UNEMP_MAX_WAGE = 48100.00 + HI_UNEMP = 2.4 + + def _test_sit(self, wage, filing_status, additional_withholding, allowances, schedule_pay, date_start, expected_withholding): + employee = self._createEmployee() + contract = self._createContract(employee, + wage=wage, + state_id=self.get_us_state('HI'), + hi_hw4_sit_filing_status=filing_status, + state_income_tax_additional_withholding=additional_withholding, + hi_hw4_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('HI', self.HI_UNEMP, date(2020, 1, 1), wage_base=self.HI_UNEMP_MAX_WAGE) + self._test_sit(375.0, 'single', 0.0, 3.0, 'weekly', date(2020, 1, 1), 15.3) + self._test_sit(5000.0, 'married', 0.0, 2.0, 'monthly', date(2020, 1, 1), 287.1) + self._test_sit(5000.0, 'married', 10.0, 2.0, 'monthly', date(2020, 1, 1), 297.1) + self._test_sit(50000.0, 'head_of_household', 0.0, 3.0, 'weekly', date(2020, 1, 1), 3933.65) + self._test_sit(750.0, 'single', 10.0, 3.0, 'bi-weekly', date(2020, 1, 1), 40.59) + self._test_sit(3000.0, '', 0.0, 3.0, 'weekly', date(2020, 1, 1), 0.00) diff --git a/l10n_us_hr_payroll/tests/test_us_ia_iowa_payslip_2019.py b/l10n_us_hr_payroll/tests/test_us_ia_iowa_payslip_2019.py new file mode 100644 index 00000000..cb3bccfd --- /dev/null +++ b/l10n_us_hr_payroll/tests/test_us_ia_iowa_payslip_2019.py @@ -0,0 +1,152 @@ +# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details. + +from .common import TestUsPayslip, process_payslip + + +class TestUsIAPayslip(TestUsPayslip): + IA_UNEMP_MAX_WAGE = 30600 + IA_UNEMP = -1.0 / 100.0 + IA_INC_TAX = -0.0535 + + def test_taxes_weekly(self): + wages = 30000.00 + schedule_pay = 'weekly' + allowances = 1 + additional_wh = 0.00 + employee = self._createEmployee() + contract = self._createContract(employee, + wage=wages, + state_id=self.get_us_state('IA'), + state_income_tax_additional_withholding=additional_wh, + ia_w4_sit_allowances=allowances, + schedule_pay=schedule_pay) + + self._log('2019 Iowa tax first payslip weekly:') + payslip = self._createPayslip(employee, '2019-01-01', '2019-01-31') + payslip.compute_sheet() + cats = self._getCategories(payslip) + + # T1 is the gross taxable wages for the pay period minus the Federal withholding amount. We add the federal + # withholding amount because it is calculated in the base US payroll module as a negative + # t1 = 30000 - (10399.66) = 19600.34 + t1_to_test = wages + cats['EE_US_941_FIT'] + self.assertPayrollAlmostEqual(t1_to_test, 19600.34) + + # T2 is T1 minus our standard deduction which is a table of flat rates dependent on the number of allowances. + # In our case, we have a weekly period which on the table has a std deduct. of $32.50 for 0 or 1 allowances, + # and 80.00 of 2 or more allowances. + standard_deduction = 32.50 # The allowance tells us what standard_deduction amount to use. + # t2 = 19600.34 - 32.50 = 19567.84 + t2_to_test = t1_to_test - standard_deduction + self.assertPayrollAlmostEqual(t2_to_test, 19567.84) + # T3 is T2 multiplied by the income rates in the large table plus a flat fee for that bracket. + # 1153.38 is the bracket floor. 8.53 is the rate, and 67.63 is the flat fee. + # t3 = 1638.38 + t3_to_test = ((t2_to_test - 1153.38) * (8.53 / 100)) + 67.63 + self.assertPayrollAlmostEqual(t3_to_test, 1638.38) + # T4 is T3 minus a flat amount determined by pay period * the number of deductions. For 2019, our weekly + # deduction amount per allowance is 0.77 + # t4 = 1638.38 - 0.77 = 155.03 + t4_to_test = t3_to_test - (0.77 * allowances) + self.assertPayrollAlmostEqual(t4_to_test, 1637.61) + # t5 is our T4 plus the additional withholding per period + # t5 = 1637.61 + 0.0 + # Convert to negative as well. + t5_to_test = -t4_to_test - additional_wh + self.assertPayrollAlmostEqual(t5_to_test, -1637.61) + + self.assertPayrollEqual(cats['ER_US_SUTA'], wages * self.IA_UNEMP) + self.assertPayrollEqual(cats['EE_US_SIT'], t5_to_test) + + + # Make a new payslip, this one will have maximums + + remaining_IA_UNEMP_wages = self.IA_UNEMP_MAX_WAGE - wages if (self.IA_UNEMP_MAX_WAGE - 2*wages < wages) \ + else wages + + self._log('2019 Iowa tax second payslip weekly:') + payslip = self._createPayslip(employee, '2019-02-01', '2019-02-28') + payslip.compute_sheet() + cats = self._getCategories(payslip) + + self.assertPayrollEqual(cats['ER_US_SUTA'], wages * self.IA_UNEMP) + + def test_taxes_biweekly(self): + wages = 3000.00 + schedule_pay = 'bi-weekly' + allowances = 1 + additional_wh = 0.00 + employee = self._createEmployee() + contract = self._createContract(employee, + wage=wages, + state_id=self.get_us_state('IA'), + state_income_tax_additional_withholding=additional_wh, + ia_w4_sit_allowances=allowances, + schedule_pay=schedule_pay) + + self._log('2019 Iowa tax first payslip bi-weekly:') + payslip = self._createPayslip(employee, '2019-01-01', '2019-01-31') + payslip.compute_sheet() + cats = self._getCategories(payslip) + + # T1 is the gross taxable wages for the pay period minus the Federal withholding amount. We add the federal + # withholding amount because it is calculated in the base US payroll module as a negative + t1_to_test = wages + cats['EE_US_941_FIT'] + # T2 is T1 minus our standard deduction which is a table of flat rates dependent on the number of allowances. + # In our case, we have a biweekly period which on the table has a std deduct. of $65.00 for 0 or 1 allowances, + # and $160.00 of 2 or more allowances. + standard_deduction = 65.00 # The allowance tells us what standard_deduction amount to use. + t2_to_test = t1_to_test - standard_deduction + # T3 is T2 multiplied by the income rates in the large table plus a flat fee for that bracket. + t3_to_test = ((t2_to_test - 2306.77) * (8.53 / 100)) + 135.28 + # T4 is T3 minus a flat amount determined by pay period * the number of deductions. For 2019, our weekly + # deduction amount per allowance is 0.77 + t4_to_test = t3_to_test - (1.54 * allowances) + # t5 is our T4 plus the additional withholding per period + t5_to_test = -t4_to_test - additional_wh + + self.assertPayrollEqual(cats['ER_US_SUTA'], wages * self.IA_UNEMP) + self.assertPayrollEqual(cats['EE_US_SIT'], t5_to_test - additional_wh) + + process_payslip(payslip) + + def test_taxes_with_external_weekly(self): + wages = 2500.00 + schedule_pay = 'weekly' + allowances = 1 + additional_wh = 0.00 + + employee = self._createEmployee() + contract = self._createContract(employee, + wage=wages, + state_id=self.get_us_state('IA'), + state_income_tax_additional_withholding=additional_wh, + ia_w4_sit_allowances=allowances, + schedule_pay=schedule_pay) + + self._log('2019 Iowa external tax first payslip external weekly:') + payslip = self._createPayslip(employee, '2019-01-01', '2019-01-31') + payslip.compute_sheet() + cats = self._getCategories(payslip) + + + # T1 is the gross taxable wages for the pay period minus the Federal withholding amount. We add the federal + # withholding amount because it is calculated in the base US payroll module as a negative + t1_to_test = wages + cats['EE_US_941_FIT'] + # T2 is T1 minus our standard deduction which is a table of flat rates dependent on the number of allowances. + # In our case, we have a weekly period which on the table has a std deduct. of $32.50 for 0 or 1 allowances, + # and 80.00 of 2 or more allowances. + standard_deduction = 32.50 # The allowance tells us what standard_deduction amount to use. + t2_to_test = t1_to_test - standard_deduction + # T3 is T2 multiplied by the income rates in the large table plus a flat fee for that bracket. + t3_to_test = ((t2_to_test - 1153.38) * (8.53 / 100)) + 67.63 + # T4 is T3 minus a flat amount determined by pay period * the number of deductions. For 2019, our weekly + # deduction amount per allowance is 0.77 + t4_to_test = t3_to_test - (0.77 * allowances) + # t5 is our T4 plus the additional withholding per period + t5_to_test = -t4_to_test - additional_wh + + self.assertPayrollEqual(cats['ER_US_SUTA'], wages * self.IA_UNEMP) + self.assertPayrollAlmostEqual(cats['EE_US_SIT'], t5_to_test) + + process_payslip(payslip) \ No newline at end of file diff --git a/l10n_us_hr_payroll/tests/test_us_ia_iowa_payslip_2020.py b/l10n_us_hr_payroll/tests/test_us_ia_iowa_payslip_2020.py new file mode 100755 index 00000000..eaca0e71 --- /dev/null +++ b/l10n_us_hr_payroll/tests/test_us_ia_iowa_payslip_2020.py @@ -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 TestUsIAPayslip(TestUsPayslip): + ### + # 2020 Taxes and Rates + ### + IA_UNEMP_MAX_WAGE = 31600.00 + IA_UNEMP = 1.0 + + def _test_sit(self, wage, exempt, additional_withholding, allowances, schedule_pay, date_start, expected_withholding): + employee = self._createEmployee() + contract = self._createContract(employee, + wage=wage, + state_id=self.get_us_state('IA'), + state_income_tax_exempt=exempt, + state_income_tax_additional_withholding=additional_withholding, + ia_w4_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.assertPayrollAlmostEqual(cats.get('EE_US_SIT', 0.0), -expected_withholding) + + def test_2020_taxes_example(self): + self._test_er_suta('IA', self.IA_UNEMP, date(2020, 1, 1), wage_base=self.IA_UNEMP_MAX_WAGE) + self._test_sit(2100.0, False, 0.0, 3.0, 'bi-weekly', date(2020, 1, 1), 83.5) + self._test_sit(3000.0, True, 10.0, 1.0, 'bi-weekly', date(2020, 1, 1), 0.00) + self._test_sit(300.0, False, 0.0, 1.0, 'weekly', date(2020, 1, 1), 6.77) + self._test_sit(5000.0, False, 0.0, 1.0, 'monthly', date(2020, 1, 1), 230.76) + self._test_sit(7500.0, False, 10.0, 2.0, 'semi-monthly', date(2020, 1, 1), 432.84) diff --git a/l10n_us_hr_payroll/tests/test_us_id_idaho_payslip_2019.py b/l10n_us_hr_payroll/tests/test_us_id_idaho_payslip_2019.py new file mode 100644 index 00000000..8e3576d6 --- /dev/null +++ b/l10n_us_hr_payroll/tests/test_us_id_idaho_payslip_2019.py @@ -0,0 +1,85 @@ +# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details. + +from .common import TestUsPayslip, process_payslip + + +class TestUsIDPayslip(TestUsPayslip): + + # TAXES AND RATES + ID_UNEMP_MAX_WAGE = 40000.00 + ID_UNEMP = -(1.00 / 100.0) + + def test_taxes_single_biweekly(self): + salary = 1212.00 + schedule_pay = 'bi-weekly' + filing_status = 'single' + allowances = 4 + # SEE https://tax.idaho.gov/i-1026.cfm?seg=compute for example calculations + wh_to_check = -10.00 + employee = self._createEmployee() + contract = self._createContract(employee, + wage=salary, + state_id=self.get_us_state('ID'), + id_w4_sit_filing_status=filing_status, + id_w4_sit_allowances=allowances, + schedule_pay=schedule_pay) + + self._log('2019 Idaho tax first payslip single:') + 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.ID_UNEMP) + self.assertPayrollEqual(cats['EE_US_SIT'], wh_to_check) + + process_payslip(payslip) + + remaining_id_unemp_wages = self.ID_UNEMP_MAX_WAGE - salary if (self.ID_UNEMP_MAX_WAGE - 2*salary < salary) \ + else salary + + self._log('2019 Idaho tax second payslip single:') + payslip = self._createPayslip(employee, '2019-02-01', '2019-02-28') + payslip.compute_sheet() + cats = self._getCategories(payslip) + + self.assertPayrollEqual(cats['ER_US_SUTA'], remaining_id_unemp_wages * self.ID_UNEMP) + + def test_taxes_married_monthly(self): + salary = 5000.00 + schedule_pay = 'monthly' + filing_status = 'married' + allowances = 2 + + # ICTCAT says monthly allowances are 246.67 + # we have 2 so 246.67 * 2 = 493.34 + # 5000.00 - 493.34 = 4506.66 + # Wh is 89$ plus 6.925% over 3959,00 + # 126.92545499999999 - > 127.0 + wh_to_check = -127.0 + employee = self._createEmployee() + contract = self._createContract(employee, + wage=salary, + state_id=self.get_us_state('ID'), + id_w4_sit_filing_status=filing_status, + id_w4_sit_allowances=allowances, + schedule_pay=schedule_pay) + + self._log('2019 Idaho tax first payslip monthly:') + 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.ID_UNEMP) + self.assertPayrollEqual(cats['EE_US_SIT'], wh_to_check) + + process_payslip(payslip) + + remaining_id_unemp_wages = self.ID_UNEMP_MAX_WAGE - salary if (self.ID_UNEMP_MAX_WAGE - 2*salary < salary) \ + else salary + + self._log('2019 Idaho tax second payslip monthly:') + payslip = self._createPayslip(employee, '2019-02-01', '2019-02-28') + payslip.compute_sheet() + cats = self._getCategories(payslip) + + self.assertPayrollEqual(cats['ER_US_SUTA'], remaining_id_unemp_wages * self.ID_UNEMP) diff --git a/l10n_us_hr_payroll/tests/test_us_id_idaho_payslip_2020.py b/l10n_us_hr_payroll/tests/test_us_id_idaho_payslip_2020.py new file mode 100755 index 00000000..eb0da9a7 --- /dev/null +++ b/l10n_us_hr_payroll/tests/test_us_id_idaho_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 TestUsIDPayslip(TestUsPayslip): + ### + # 2020 Taxes and Rates + ### + ID_UNEMP_MAX_WAGE = 41600.00 + ID_UNEMP = 1.0 + + def _test_sit(self, wage, filing_status, allowances, schedule_pay, date_start, expected_withholding): + employee = self._createEmployee() + contract = self._createContract(employee, + wage=wage, + state_id=self.get_us_state('ID'), + id_w4_sit_filing_status=filing_status, + id_w4_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('ID', self.ID_UNEMP, date(2020, 1, 1), wage_base=self.ID_UNEMP_MAX_WAGE) + self._test_sit(1212.0, 'single', 4.0, 'bi-weekly', date(2020, 1, 1), 10.0) + self._test_sit(10000.0, 'married', 1.0, 'annually', date(2020, 1, 1), 0.0) + self._test_sit(52000.0, 'married', 4.0, 'monthly', date(2020, 1, 1), 3345.0) + self._test_sit(5000.0, 'head of household', 0.0, 'semi-monthly', date(2020, 1, 1), 300.0) + self._test_sit(5900.0, 'single', 5.0, 'weekly', date(2020, 1, 1), 367.0) diff --git a/l10n_us_hr_payroll/tests/test_us_il_illinois_payslip_2019.py b/l10n_us_hr_payroll/tests/test_us_il_illinois_payslip_2019.py new file mode 100644 index 00000000..ba633607 --- /dev/null +++ b/l10n_us_hr_payroll/tests/test_us_il_illinois_payslip_2019.py @@ -0,0 +1,71 @@ +# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details. + +from .common import TestUsPayslip, process_payslip + + +class TestUsILPayslip(TestUsPayslip): + # TAXES AND RATES + IL_UNEMP_MAX_WAGE = 12960.00 + IL_UNEMP = -(3.175 / 100.0) + + def test_taxes_monthly(self): + salary = 15000.00 + schedule_pay = 'monthly' + basic_allowances = 1 + additional_allowances = 1 + flat_rate = (4.95 / 100) + wh_to_test = -(flat_rate * (salary - ((basic_allowances * 2275 + additional_allowances * 1000) / 12.0))) + + employee = self._createEmployee() + contract = self._createContract(employee, + wage=salary, + state_id=self.get_us_state('IL'), + state_income_tax_additional_withholding=0.0, + il_w4_sit_basic_allowances=1.0, + il_w4_sit_additional_allowances=1.0, + schedule_pay='monthly') + + self._log('2019 Illinois tax first payslip monthly:') + payslip = self._createPayslip(employee, '2019-01-01', '2019-01-31') + payslip.compute_sheet() + cats = self._getCategories(payslip) + + self.assertPayrollEqual(cats['ER_US_SUTA'], self.IL_UNEMP_MAX_WAGE * self.IL_UNEMP) + self.assertPayrollEqual(cats['EE_US_SIT'], wh_to_test) + + process_payslip(payslip) + + remaining_IL_UNEMP_wages = 0.0 # We already reached max unemployment wages. + + self._log('2019 Illinois tax second payslip monthly:') + payslip = self._createPayslip(employee, '2019-02-01', '2019-02-28') + payslip.compute_sheet() + cats = self._getCategories(payslip) + + self.assertPayrollEqual(cats['ER_US_SUTA'], remaining_IL_UNEMP_wages * self.IL_UNEMP) + + def test_taxes_with_additional_wh(self): + salary = 15000.00 + schedule_pay = 'monthly' + basic_allowances = 1 + additional_allowances = 1 + additional_wh = 15.0 + flat_rate = (4.95 / 100) + wh_to_test = -(flat_rate * (salary - ((basic_allowances * 2275 + additional_allowances * 1000) / 12.0)) + additional_wh) + + employee = self._createEmployee() + contract = self._createContract(employee, + wage=salary, + state_id=self.get_us_state('IL'), + state_income_tax_additional_withholding=15.0, + il_w4_sit_basic_allowances=1.0, + il_w4_sit_additional_allowances=1.0, + schedule_pay='monthly') + + self._log('2019 Illinois tax first payslip monthly:') + payslip = self._createPayslip(employee, '2019-01-01', '2019-01-31') + payslip.compute_sheet() + cats = self._getCategories(payslip) + + self.assertPayrollEqual(cats['ER_US_SUTA'], self.IL_UNEMP_MAX_WAGE * self.IL_UNEMP) + self.assertPayrollEqual(cats['EE_US_SIT'], wh_to_test) diff --git a/l10n_us_hr_payroll/tests/test_us_il_illinois_payslip_2020.py b/l10n_us_hr_payroll/tests/test_us_il_illinois_payslip_2020.py new file mode 100644 index 00000000..ead932e4 --- /dev/null +++ b/l10n_us_hr_payroll/tests/test_us_il_illinois_payslip_2020.py @@ -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 TestUsILPayslip(TestUsPayslip): + # Taxes and Rates + IL_UNEMP_MAX_WAGE = 12740.0 + IL_UNEMP = 3.125 + + def _test_sit(self, wage, additional_withholding, basic_allowances, additional_allowances, schedule_pay, date_start, expected_withholding): + + employee = self._createEmployee() + contract = self._createContract(employee, + wage=wage, + state_id=self.get_us_state('IL'), + state_income_tax_additional_withholding=additional_withholding, + il_w4_sit_basic_allowances=basic_allowances, + il_w4_sit_additional_allowances=additional_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('IL', self.IL_UNEMP, date(2020, 1, 1), wage_base=self.IL_UNEMP_MAX_WAGE) + self._test_sit(800.0, 0.0, 2, 2, 'weekly', date(2020, 1, 1), 33.27) + self._test_sit(800.0, 10.0, 2, 2, 'weekly', date(2020, 1, 1), 43.27) + self._test_sit(2500.0, 0.0, 1, 1, 'monthly', date(2020, 1, 1), 110.04) + self._test_sit(2500.0, 0.0, 0, 0, 'monthly', date(2020, 1, 1), 123.75) + self._test_sit(3000.0, 15.0, 0, 0, 'quarterly', date(2020, 1, 1), 163.50) + diff --git a/l10n_us_hr_payroll/tests/test_us_in_indiana_payslip_2020.py b/l10n_us_hr_payroll/tests/test_us_in_indiana_payslip_2020.py new file mode 100755 index 00000000..53b7ddf3 --- /dev/null +++ b/l10n_us_hr_payroll/tests/test_us_in_indiana_payslip_2020.py @@ -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 TestUsINPayslip(TestUsPayslip): + ### + # 2020 Taxes and Rates + ### + IN_UNEMP_MAX_WAGE = 9500.0 + IN_UNEMP = 2.5 + # Calculation based on https://www.in.gov/dor/files/dn01.pdf + + def _test_sit(self, wage, additional_withholding, personal_exemption, dependent_exemption, schedule_pay, date_start, expected_withholding): + employee = self._createEmployee() + contract = self._createContract(employee, + wage=wage, + state_id=self.get_us_state('IN'), + state_income_tax_additional_withholding=additional_withholding, + in_w4_sit_personal_exemption=personal_exemption, + in_w4_sit_dependent_exemption=dependent_exemption, + 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('IN', self.IN_UNEMP, date(2020, 1, 1), wage_base=self.IN_UNEMP_MAX_WAGE) + self._test_sit(800.0, 0.0, 5.0, 3.0, 'weekly', date(2020, 1, 1), 19.94) + self._test_sit(800.0, 10.0, 5.0, 3.0, 'weekly', date(2020, 1, 1), 29.94) + self._test_sit(9000.0, 0.0, 4.0, 3.0, 'monthly', date(2020, 1, 1), 267.82) + self._test_sit(10000.0, 0.0, 2.0, 2.0, 'bi-weekly', date(2020, 1, 1), 316.79) diff --git a/l10n_us_hr_payroll/tests/test_us_ks_kansas_payslip_2020.py b/l10n_us_hr_payroll/tests/test_us_ks_kansas_payslip_2020.py new file mode 100755 index 00000000..3ed586f8 --- /dev/null +++ b/l10n_us_hr_payroll/tests/test_us_ks_kansas_payslip_2020.py @@ -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 TestUsKSPayslip(TestUsPayslip): + ### + # 2020 Taxes and Rates + ### + KS_UNEMP_MAX_WAGE = 14000.0 + KS_UNEMP = 2.7 + # Calculation based on example https://revenue.ky.gov/Forms/42A003(T)%20(12-2019)%202020%20Tax%20Tables.pdf + + 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('KS'), + ks_k4_sit_filing_status=filing_status, + ks_k4_sit_allowances=allowances, + 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.assertPayrollAlmostEqual(cats.get('EE_US_SIT', 0.0), -expected_withholding) + + def test_2020_taxes_example(self): + self._test_er_suta('KS', self.KS_UNEMP, date(2020, 1, 1), wage_base=self.KS_UNEMP_MAX_WAGE) + self._test_sit(6250, 'married', 2, 0, 'semi-monthly', date(2020, 1, 1), 290.00) + self._test_sit(5000, 'single', 1, 0, 'monthly', date(2020, 1, 1), 222.00) + self._test_sit(1500, 'married', 0, 0, 'bi-weekly', date(2020, 1, 1), 39.00) + self._test_sit(750, 'single', 2, 10, 'weekly', date(2020, 1, 1), 36.00) diff --git a/l10n_us_hr_payroll/tests/test_us_ky_kentucky_payslip_2020.py b/l10n_us_hr_payroll/tests/test_us_ky_kentucky_payslip_2020.py new file mode 100755 index 00000000..aa067848 --- /dev/null +++ b/l10n_us_hr_payroll/tests/test_us_ky_kentucky_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 TestUsKYPayslip(TestUsPayslip): + ### + # 2020 Taxes and Rates + ### + KY_UNEMP_MAX_WAGE = 10800.0 + KY_UNEMP = 2.7 + # Calculation based on example https://revenue.ky.gov/Forms/42A003(T)%20(12-2019)%202020%20Tax%20Tables.pdf + + def _test_sit(self, wage, additional_withholding, schedule_pay, date_start, expected_withholding): + employee = self._createEmployee() + contract = self._createContract(employee, + wage=wage, + state_id=self.get_us_state('KY'), + 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('KY', self.KY_UNEMP, date(2020, 1, 1), wage_base=self.KY_UNEMP_MAX_WAGE) + self._test_sit(3020, 0.0, 'monthly', date(2020, 1, 1), 139.96) + self._test_sit(1500, 0.0, 'bi-weekly', date(2020, 1, 1), 69.90) + self._test_sit(1500, 10.0, 'bi-weekly', date(2020, 1, 1), 79.90) + self._test_sit(750, 00.0, 'weekly', date(2020, 1, 1), 34.95) + self._test_sit(7000, 0.0, 'semi-monthly', date(2020, 1, 1), 344.48) diff --git a/l10n_us_hr_payroll/tests/test_us_la_louisiana_payslip_2019.py b/l10n_us_hr_payroll/tests/test_us_la_louisiana_payslip_2019.py new file mode 100644 index 00000000..1d01c618 --- /dev/null +++ b/l10n_us_hr_payroll/tests/test_us_la_louisiana_payslip_2019.py @@ -0,0 +1,91 @@ +# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details. + +from .common import TestUsPayslip, process_payslip + + +class TestUsLAPayslip(TestUsPayslip): + + # TAXES AND RATES + LA_UNEMP_MAX_WAGE = 7700.00 + LA_UNEMP = -(1.14 / 100.0) + + def test_taxes_single_weekly(self): + salary = 700.00 + schedule_pay = 'weekly' + filing_status = 'single' + exemptions = 1 + dependents = 2 + additional_withholding = 0 + # SEE http://revenue.louisiana.gov/TaxForms/1306(1_12)TF.pdf for example calculations + # wh_to test is 19.42 + # Our algorithm correctly rounds whereas theirs does it prematurely. + wh_to_check = -19.43 + employee = self._createEmployee() + contract = self._createContract(employee, + wage=salary, + state_id=self.get_us_state('LA'), + la_l4_sit_filing_status=filing_status, + state_income_tax_additional_withholding=additional_withholding, + la_l4_sit_exemptions=exemptions, + la_l4_sit_dependents=dependents, + schedule_pay=schedule_pay) + + self._log('2019 Louisiana 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.LA_UNEMP) + self.assertPayrollEqual(cats['EE_US_SIT'], wh_to_check) + + process_payslip(payslip) + + remaining_la_unemp_wages = self.LA_UNEMP_MAX_WAGE - salary if (self.LA_UNEMP_MAX_WAGE - 2*salary < salary) \ + else salary + + self._log('2019 Louisiana 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_la_unemp_wages * self.LA_UNEMP) + + def test_taxes_married_biweekly(self): + salary = 4600.00 + schedule_pay = 'bi-weekly' + filing_status = 'married' + exemptions = 2 + dependents = 3 + additional_withholding = 0 + # SEE http://revenue.louisiana.gov/TaxForms/1306(1_12)TF.pdf for example calculations + # wh_to test is 157.12 + wh_to_check = -157.12 + employee = self._createEmployee() + contract = self._createContract(employee, + wage=salary, + state_id=self.get_us_state('LA'), + la_l4_sit_filing_status=filing_status, + state_income_tax_additional_withholding=additional_withholding, + la_l4_sit_exemptions=exemptions, + la_l4_sit_dependents=dependents, + schedule_pay=schedule_pay) + + self._log('2019 Louisiana tax first payslip bi-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.LA_UNEMP) + self.assertPayrollEqual(cats['EE_US_SIT'], wh_to_check) + + process_payslip(payslip) + + remaining_la_unemp_wages = self.LA_UNEMP_MAX_WAGE - salary if (self.LA_UNEMP_MAX_WAGE - 2*salary < salary) \ + else salary + + self._log('2019 Louisiana tax second payslip bi-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_la_unemp_wages * self.LA_UNEMP) diff --git a/l10n_us_hr_payroll/tests/test_us_la_louisiana_payslip_2020.py b/l10n_us_hr_payroll/tests/test_us_la_louisiana_payslip_2020.py new file mode 100755 index 00000000..d23c3ab3 --- /dev/null +++ b/l10n_us_hr_payroll/tests/test_us_la_louisiana_payslip_2020.py @@ -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 TestUsLAPayslip(TestUsPayslip): + ### + # 2020 Taxes and Rates + ### + LA_UNEMP_MAX_WAGE = 7700.0 + LA_UNEMP = 1.14 + # Calculation based on http://revenue.louisiana.gov/TaxForms/1306(1_12)TF.pdf + + def _test_sit(self, wage, filing_status, additional_withholding, exemptions, dependents, schedule_pay, date_start, expected_withholding): + employee = self._createEmployee() + contract = self._createContract(employee, + wage=wage, + state_id=self.get_us_state('LA'), + la_l4_sit_filing_status=filing_status, + state_income_tax_additional_withholding=additional_withholding, + la_l4_sit_exemptions=exemptions, + la_l4_sit_dependents=dependents, + 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.assertPayrollAlmostEqual(cats.get('EE_US_SIT', 0.0), -expected_withholding) + + def test_2020_taxes_example(self): + self._test_er_suta('LA', self.LA_UNEMP, date(2020, 1, 1), wage_base=self.LA_UNEMP_MAX_WAGE) + self._test_sit(700.0, 'single', 0.0, 1.0, 2.0, 'weekly', date(2020, 1, 1), 19.43) + self._test_sit(4600.0, 'married', 0.0, 2.0, 3.0, 'bi-weekly', date(2020, 1, 1), 157.12) + self._test_sit(6000.0, 'single', 10.0, 2.0, 3.0, 'monthly', date(2020, 1, 1), 219.08) diff --git a/l10n_us_hr_payroll/tests/test_us_me_maine_payslip_2020.py b/l10n_us_hr_payroll/tests/test_us_me_maine_payslip_2020.py new file mode 100644 index 00000000..165455ce --- /dev/null +++ b/l10n_us_hr_payroll/tests/test_us_me_maine_payslip_2020.py @@ -0,0 +1,39 @@ +# 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 TestUsMEPayslip(TestUsPayslip): + ### + # 2020 Taxes and Rates + ### + ME_UNEMP_MAX_WAGE = 12000.0 + ME_UNEMP = 1.92 + # Calculation based on this file page.6 and 7 https://www.maine.gov/revenue/forms/with/2020/20_WH_Tab&Instructions.pdf + + def _test_sit(self, wage, filing_status, additional_withholding, exempt, allowances, schedule_pay, date_start, expected_withholding): + employee = self._createEmployee() + contract = self._createContract(employee, + wage=wage, + state_id=self.get_us_state('ME'), + me_w4me_sit_filing_status=filing_status, + state_income_tax_additional_withholding=additional_withholding, + state_income_tax_exempt=exempt, + me_w4me_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.assertPayrollAlmostEqual(cats.get('EE_US_SIT', 0.0), -expected_withholding) + + def test_2020_taxes_example(self): + self._test_er_suta('ME', self.ME_UNEMP, date(2020, 1, 1), wage_base=self.ME_UNEMP_MAX_WAGE) + self._test_sit(300.0, 'single', 0.0, False, 2, 'weekly', date(2020, 1, 1), 0.0) + self._test_sit(800.0, 'single', 0.0, False, 2, 'bi-weekly', date(2020, 1, 1), 6.00) + self._test_sit(4500.0, 'married', 0.0, True, 0, 'weekly', date(2020, 1, 1), 0.00) + self._test_sit(4500.0, 'married', 0.0, False, 2, 'monthly', date(2020, 1, 1), 113.00) + self._test_sit(4500.0, 'married', 10.0, False, 2, 'weekly', date(2020, 1, 1), 287.00) + self._test_sit(7000.0, '', 10.0, False, 2, 'weekly', date(2020, 1, 1), 0.00) diff --git a/l10n_us_hr_payroll/tests/test_us_mi_michigan_payslip_2019.py b/l10n_us_hr_payroll/tests/test_us_mi_michigan_payslip_2019.py new file mode 100755 index 00000000..b12baed2 --- /dev/null +++ b/l10n_us_hr_payroll/tests/test_us_mi_michigan_payslip_2019.py @@ -0,0 +1,194 @@ +# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details. + +from .common import TestUsPayslip, process_payslip + + +class TestUsMIPayslip(TestUsPayslip): + # Taxes and Rates + MI_UNEMP_MAX_WAGE = 9500.0 + MI_UNEMP = - 2.7 / 100.0 + MI_INC_TAX = - 4.25 / 100.0 + ANNUAL_EXEMPTION_AMOUNT = 4400.00 + PAY_PERIOD_DIVISOR = { + 'weekly': 52.0, + 'bi-weekly': 26.0, + 'semi-monthly': 24.0, + 'monthly': 12.0 + } + + def test_2019_taxes_weekly(self): + salary = 5000.0 + schedule_pay = 'weekly' + exemptions = 1 + + employee = self._createEmployee() + contract = self._createContract(employee, + wage=salary, + state_id=self.get_us_state('MI'), + state_income_tax_additional_withholding=0.0, + mi_w4_sit_exemptions=1.0, + schedule_pay='weekly') + + allowance_amount = self.ANNUAL_EXEMPTION_AMOUNT / self.PAY_PERIOD_DIVISOR[schedule_pay] + wh = -((salary - (allowance_amount * exemptions)) * -self.MI_INC_TAX) + + self._log('2019 Michigan 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.MI_UNEMP) + self.assertPayrollAlmostEqual(cats['EE_US_SIT'], wh) + # + process_payslip(payslip) + + # Make a new payslip, this one will have maximums + remaining_MI_UNEMP_wages = self.MI_UNEMP_MAX_WAGE - salary if (self.MI_UNEMP_MAX_WAGE - 2*salary < salary) \ + else salary + + self._log('2019 Michigan 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_MI_UNEMP_wages * self.MI_UNEMP) + + def test_2019_taxes_biweekly(self): + salary = 5000.0 + schedule_pay = 'bi-weekly' + allowance_amount = self.ANNUAL_EXEMPTION_AMOUNT / self.PAY_PERIOD_DIVISOR[schedule_pay] + exemption = 2 + + wh = -((salary - (allowance_amount * exemption)) * -self.MI_INC_TAX) + + employee = self._createEmployee() + contract = self._createContract(employee, + wage=salary, + state_id=self.get_us_state('MI'), + state_income_tax_additional_withholding=0.0, + mi_w4_sit_exemptions=2.0, + schedule_pay='bi-weekly') + + self._log('2019 Michigan tax first payslip bi-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.MI_UNEMP) + self.assertPayrollEqual(cats['EE_US_SIT'], wh) + + process_payslip(payslip) + + # Make a new payslip, this one will have maximums + remaining_MI_UNEMP_wages = self.MI_UNEMP_MAX_WAGE - salary if (self.MI_UNEMP_MAX_WAGE - 2*salary < salary) \ + else salary + + self._log('2019 Michigan tax second payslip bi-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_MI_UNEMP_wages * self.MI_UNEMP) + + def test_2019_taxes_semimonthly(self): + salary = 5000.0 + schedule_pay = 'semi-monthly' + allowance_amount = self.ANNUAL_EXEMPTION_AMOUNT / self.PAY_PERIOD_DIVISOR[schedule_pay] + exemption = 1 + + wh = -((salary - (allowance_amount * exemption)) * -self.MI_INC_TAX) + + employee = self._createEmployee() + contract = self._createContract(employee, + wage=salary, + state_id=self.get_us_state('MI'), + state_income_tax_additional_withholding=0.0, + mi_w4_sit_exemptions=1.0, + schedule_pay='semi-monthly') + + self._log('2019 Michigan tax first payslip semi-monthly:') + 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.MI_UNEMP) + self.assertPayrollEqual(cats['EE_US_SIT'], wh) + + process_payslip(payslip) + + # Make a new payslip, this one will have maximums + remaining_MI_UNEMP_wages = self.MI_UNEMP_MAX_WAGE - salary if (self.MI_UNEMP_MAX_WAGE - 2 * salary < salary) \ + else salary + + self._log('2019 Michigan tax second payslip semi-monthly:') + payslip = self._createPayslip(employee, '2019-02-01', '2019-02-28') + payslip.compute_sheet() + cats = self._getCategories(payslip) + + self.assertPayrollEqual(cats['ER_US_SUTA'], remaining_MI_UNEMP_wages * self.MI_UNEMP) + + def test_2019_taxes_monthly(self): + salary = 5000.0 + schedule_pay = 'monthly' + allowance_amount = self.ANNUAL_EXEMPTION_AMOUNT / self.PAY_PERIOD_DIVISOR[schedule_pay] + exemption = 1 + + wh = -((salary - (allowance_amount * exemption)) * -self.MI_INC_TAX) + + employee = self._createEmployee() + contract = self._createContract(employee, + wage=salary, + state_id=self.get_us_state('MI'), + state_income_tax_additional_withholding=0.0, + mi_w4_sit_exemptions=1.0, + schedule_pay='monthly') + + self._log('2019 Michigan tax first payslip monthly:') + 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.MI_UNEMP) + self.assertPayrollEqual(cats['EE_US_SIT'], wh) + + process_payslip(payslip) + + # Make a new payslip, this one will have maximums + remaining_MI_UNEMP_wages = self.MI_UNEMP_MAX_WAGE - salary if ( + self.MI_UNEMP_MAX_WAGE - (2 * salary) < salary) \ + else salary + + self._log('2019 Michigan tax second payslip monthly:') + payslip = self._createPayslip(employee, '2019-02-01', '2019-02-28') + payslip.compute_sheet() + cats = self._getCategories(payslip) + + self.assertPayrollEqual(cats['ER_US_SUTA'], remaining_MI_UNEMP_wages * self.MI_UNEMP) + + def test_additional_withholding(self): + salary = 5000.0 + schedule_pay = 'weekly' + allowance_amount = 0.0 + allowance_amount = self.ANNUAL_EXEMPTION_AMOUNT / self.PAY_PERIOD_DIVISOR[schedule_pay] + additional_wh = 40.0 + exemption = 1 + + wh = -(((salary - (allowance_amount * exemption)) * -self.MI_INC_TAX) + additional_wh) + + employee = self._createEmployee() + contract = self._createContract(employee, + wage=salary, + state_id=self.get_us_state('MI'), + state_income_tax_additional_withholding=40.0, + mi_w4_sit_exemptions=1.0, + schedule_pay='weekly') + + self._log('2019 Michigan tax first payslip with 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.MI_UNEMP) + self.assertPayrollAlmostEqual(cats['EE_US_SIT'], wh) + + process_payslip(payslip) diff --git a/l10n_us_hr_payroll/tests/test_us_mi_michigan_payslip_2020.py b/l10n_us_hr_payroll/tests/test_us_mi_michigan_payslip_2020.py new file mode 100755 index 00000000..6de7b664 --- /dev/null +++ b/l10n_us_hr_payroll/tests/test_us_mi_michigan_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 TestUsMIPayslip(TestUsPayslip): + # Taxes and Rates + MI_UNEMP_MAX_WAGE = 9000.0 + MI_UNEMP = 2.7 + + def _test_sit(self, wage, exemptions, additional_withholding, schedule_pay, date_start, expected_withholding): + + employee = self._createEmployee() + contract = self._createContract(employee, + wage=wage, + state_id=self.get_us_state('MI'), + mi_w4_sit_exemptions=exemptions, + 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('MI', self.MI_UNEMP, date(2020, 1, 1), wage_base=self.MI_UNEMP_MAX_WAGE) + self._test_sit(750.0, 1, 100.0, 'weekly', date(2020, 1, 1), 127.99) + self._test_sit(1750.0, 1, 0.0, 'bi-weekly', date(2020, 1, 1), 66.61) + self._test_sit(5000.0, 1, 5.0, 'semi-monthly', date(2020, 1, 1), 209.09) + self._test_sit(8000.0, 1, 5.0, 'monthly', date(2020, 1, 1), 328.18) + self._test_sit(5000.0, 2, 0.0, 'monthly', date(2020, 1, 1), 178.86) + diff --git a/l10n_us_hr_payroll/tests/test_us_mn_minnesota_payslip_2019.py b/l10n_us_hr_payroll/tests/test_us_mn_minnesota_payslip_2019.py new file mode 100755 index 00000000..2a64b57d --- /dev/null +++ b/l10n_us_hr_payroll/tests/test_us_mn_minnesota_payslip_2019.py @@ -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) diff --git a/l10n_us_hr_payroll/tests/test_us_mn_minnesota_payslip_2020.py b/l10n_us_hr_payroll/tests/test_us_mn_minnesota_payslip_2020.py new file mode 100755 index 00000000..c91fa2a8 --- /dev/null +++ b/l10n_us_hr_payroll/tests/test_us_mn_minnesota_payslip_2020.py @@ -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) diff --git a/l10n_us_hr_payroll/tests/test_us_mo_missouri_payslip_2019.py b/l10n_us_hr_payroll/tests/test_us_mo_missouri_payslip_2019.py new file mode 100755 index 00000000..27a0ad93 --- /dev/null +++ b/l10n_us_hr_payroll/tests/test_us_mo_missouri_payslip_2019.py @@ -0,0 +1,188 @@ + +from datetime import date +from .common import TestUsPayslip + + +class TestUsMoPayslip(TestUsPayslip): + # Calculations from http://dor.mo.gov/forms/4282_2019.pdf + SALARY = 12000.0 + MO_UNEMP = -2.376 / 100.0 + + TAX = [ + (1053.0, 1.5), + (1053.0, 2.0), + (1053.0, 2.5), + (1053.0, 3.0), + (1053.0, 3.5), + (1053.0, 4.0), + (1053.0, 4.5), + (1053.0, 5.0), + (999999999.0, 5.4), + ] + + def test_2019_taxes_single(self): + # Payroll Period Monthly + salary = self.SALARY + pp = 12.0 + gross_salary = salary * pp + spouse_employed = False + + # Single + standard_deduction = 12400.0 + + employee = self._createEmployee() + contract = self._createContract(employee, + wage=salary, + state_id=self.get_us_state('MO'), + mo_mow4_sit_filing_status='single', + state_income_tax_additional_withholding=0.0, + schedule_pay='monthly') + + self._log('2019 Missouri tax single first payslip:') + 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.MO_UNEMP) + + mo_taxable_income = gross_salary - standard_deduction + self._log('%s = %s - %s -' % (mo_taxable_income, gross_salary, standard_deduction)) + + remaining_taxable_income = mo_taxable_income + tax = 0.0 + for amt, rate in self.TAX: + amt = float(amt) + rate = rate / 100.0 + self._log(str(amt) + ' : ' + str(rate) + ' : ' + str(remaining_taxable_income)) + if (remaining_taxable_income - amt) > 0.0 or (remaining_taxable_income - amt) == 0.0: + tax += rate * amt + else: + tax += rate * remaining_taxable_income + break + remaining_taxable_income = remaining_taxable_income - amt + + tax = -tax + self._log('Computed annual tax: ' + str(tax)) + + tax = tax / pp + tax = round(tax) + self._log('Computed period tax: ' + str(tax)) + self.assertPayrollEqual(cats['EE_US_SIT'], tax) + + def test_2019_spouse_not_employed(self): + # Payroll Period Semi-monthly + salary = self.SALARY + pp = 24.0 + gross_salary = salary * pp + + # Married + standard_deduction = 24800.0 + + employee = self._createEmployee() + + contract = self._createContract(employee, + wage=salary, + state_id=self.get_us_state('MO'), + mo_mow4_sit_filing_status='married', + state_income_tax_additional_withholding=0.0, + schedule_pay='semi-monthly') + + self._log('2019 Missouri tax first payslip:') + payslip = self._createPayslip(employee, '2019-01-01', '2019-01-31') + + payslip.compute_sheet() + + cats = self._getCategories(payslip) + + mo_taxable_income = gross_salary - standard_deduction + self._log(mo_taxable_income) + + remaining_taxable_income = mo_taxable_income + tax = 0.0 + for amt, rate in self.TAX: + amt = float(amt) + rate = rate / 100.0 + self._log(str(amt) + ' : ' + str(rate) + ' : ' + str(remaining_taxable_income)) + if (remaining_taxable_income - amt) > 0.0 or (remaining_taxable_income - amt) == 0.0: + tax += rate * amt + else: + tax += rate * remaining_taxable_income + break + remaining_taxable_income = remaining_taxable_income - amt + + tax = -tax + self._log('Computed annual tax: ' + str(tax)) + + tax = tax / pp + tax = round(tax) + self._log('Computed period tax: ' + str(tax)) + self.assertPayrollEqual(cats['EE_US_SIT'], tax) + + def test_2019_head_of_household(self): + # Payroll Period Weekly + salary = self.SALARY + + # Payroll Period Weekly + salary = self.SALARY + pp = 52.0 + gross_salary = salary * pp + + # Single HoH + standard_deduction = 18650.0 + + employee = self._createEmployee() + + contract = self._createContract(employee, + wage=salary, + state_id=self.get_us_state('MO'), + mo_mow4_sit_filing_status='head_of_household', + state_income_tax_additional_withholding=0.0, + schedule_pay='weekly') + + self._log('2019 Missouri tax first payslip:') + payslip = self._createPayslip(employee, '2019-01-01', '2019-01-31') + + payslip.compute_sheet() + + cats = self._getCategories(payslip) + + mo_taxable_income = gross_salary - standard_deduction + self._log(mo_taxable_income) + + remaining_taxable_income = mo_taxable_income + tax = 0.0 + for amt, rate in self.TAX: + amt = float(amt) + rate = rate / 100.0 + self._log(str(amt) + ' : ' + str(rate) + ' : ' + str(remaining_taxable_income)) + if (remaining_taxable_income - amt) > 0.0 or (remaining_taxable_income - amt) == 0.0: + tax += rate * amt + else: + tax += rate * remaining_taxable_income + break + remaining_taxable_income = remaining_taxable_income - amt + tax = -tax + self._log('Computed annual tax: ' + str(tax)) + + tax = tax / pp + tax = round(tax) + self._log('Computed period tax: ' + str(tax)) + self.assertPayrollEqual(cats['EE_US_SIT'], tax) + + def test_2019_underflow(self): + # Payroll Period Weekly + salary = 200.0 + + employee = self._createEmployee() + + contract = self._createContract(employee, + wage=salary, + state_id=self.get_us_state('MO')) + + payslip = self._createPayslip(employee, '2019-01-01', '2019-01-31') + payslip.compute_sheet() + cats = self._getCategories(payslip) + + self.assertPayrollEqual(cats['EE_US_SIT'], 0.0) diff --git a/l10n_us_hr_payroll/tests/test_us_mo_missouri_payslip_2020.py b/l10n_us_hr_payroll/tests/test_us_mo_missouri_payslip_2020.py new file mode 100755 index 00000000..ff6a0ca1 --- /dev/null +++ b/l10n_us_hr_payroll/tests/test_us_mo_missouri_payslip_2020.py @@ -0,0 +1,34 @@ +# 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 TestUsMoPayslip(TestUsPayslip): + # Calculations from http://dor.mo.gov/forms/4282_2020.pdf + MO_UNEMP_MAX_WAGE = 11500.0 + MO_UNEMP = 2.376 + + 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('MO'), + mo_mow4_sit_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.assertPayrollAlmostEqual(cats.get('EE_US_SIT', 0.0), -expected_withholding) + + def test_2020_taxes_example(self): + self._test_er_suta('MO', self.MO_UNEMP, date(2020, 1, 1), wage_base=self.MO_UNEMP_MAX_WAGE) + self._test_sit(750.0, 'single', 0.0, 'weekly', date(2020, 1, 1), 24.00) + self._test_sit(2500.0, 'single', 5.0, 'bi-weekly', date(2020, 1, 1), 107.00) + self._test_sit(7000.0, 'married', 0.0, 'monthly', date(2020, 1, 1), 251.00) + self._test_sit(5000.0, 'married', 10.0, 'semi-monthly', date(2020, 1, 1), 217.00) + self._test_sit(6000.0, '', 0.0, 'monthly', date(2020, 1, 1), 0.00) + diff --git a/l10n_us_hr_payroll/tests/test_us_ms_mississippi_payslip_2020.py b/l10n_us_hr_payroll/tests/test_us_ms_mississippi_payslip_2020.py index 5942d7ad..ea0081ca 100755 --- a/l10n_us_hr_payroll/tests/test_us_ms_mississippi_payslip_2020.py +++ b/l10n_us_hr_payroll/tests/test_us_ms_mississippi_payslip_2020.py @@ -1,120 +1,35 @@ # Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details. -from datetime import date +from datetime import date, timedelta from .common import TestUsPayslip class TestUsMsPayslip(TestUsPayslip): - # Calculations from https://www.dor.ms.gov/Documents/Computer%20Payroll%20Accounting%201-2-19.pdf + # Calculations from https://www.dor.ms.gov/Documents/Computer%20Payroll%20Flowchart.pdf MS_UNEMP = 1.2 MS_UNEMP_MAX_WAGE = 14000.0 - def test_2020_taxes_one(self): + def _test_sit(self, wage, filing_status, additional_withholding, exemption, schedule_pay, date_start, expected_withholding): + employee = self._createEmployee() + contract = self._createContract(employee, + wage=wage, + state_id=self.get_us_state('MS'), + ms_89_350_sit_filing_status=filing_status, + state_income_tax_additional_withholding=additional_withholding, + ms_89_350_sit_exemption_value=exemption, + 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.assertPayrollAlmostEqual(cats.get('EE_US_SIT', 0.0), -expected_withholding) + + def test_2020_taxes_example(self): self._test_er_suta('MS', self.MS_UNEMP, date(2020, 1, 1), wage_base=self.MS_UNEMP_MAX_WAGE) + self._test_sit(1250.0, 'head_of_household', 0.0, 11000, 'semi-monthly', date(2020, 1, 1), 22.00) + self._test_sit(500.0, '', 5.0, 0, 'bi-weekly', date(2020, 1, 1), 0.00) + self._test_sit(12000.0, 'single', 0.0, 11000, 'monthly', date(2020, 1, 1), 525.00) + self._test_sit(2500.0, 'married', 5.0, 500, 'bi-weekly', date(2020, 1, 1), 111.00) - salary = 1250.0 - ms_89_350_exemption = 11000.0 - employee = self._createEmployee() - contract = self._createContract(employee, - wage=salary, - state_id=self.get_us_state('MS'), - ms_89_350_sit_filing_status='head_of_household', - ms_89_350_sit_exemption_value=ms_89_350_exemption, - state_income_tax_additional_withholding=0.0, - schedule_pay='semi-monthly') - - self._log('2020 Mississippi tax single first payslip:') - payslip = self._createPayslip(employee, '2020-01-01', '2020-01-31') - - payslip.compute_sheet() - - cats = self._getCategories(payslip) - - STDED = 3400.0 # Head of Household - AGP = salary * 24 # Semi-Monthly - TI = AGP - (ms_89_350_exemption + STDED) - self.assertPayrollEqual(TI, 15600.0) - TAX = ((TI - 10000) * 0.05) + 260 # Over 10,000 - self.assertPayrollEqual(TAX, 540.0) - - ms_withhold = round(TAX / 24) # Semi-Monthly - self.assertPayrollEqual(cats['EE_US_SIT'], -ms_withhold) - - def test_2020_taxes_one_exempt(self): - salary = 1250.0 - ms_89_350_exemption = 11000.0 - - employee = self._createEmployee() - contract = self._createContract(employee, - wage=salary, - state_id=self.get_us_state('MS'), - ms_89_350_sit_filing_status='', - ms_89_350_sit_exemption_value=ms_89_350_exemption, - state_income_tax_additional_withholding=0.0, - schedule_pay='semi-monthly') - - self._log('2020 Mississippi tax single first payslip:') - payslip = self._createPayslip(employee, '2020-01-01', '2020-01-31') - - payslip.compute_sheet() - - cats = self._getCategories(payslip) - self.assertPayrollEqual(cats.get('EE_US_SIT', 0.0), 0.0) - - def test_2020_taxes_additional(self): - salary = 1250.0 - ms_89_350_exemption = 11000.0 - additional = 40.0 - - employee = self._createEmployee() - contract = self._createContract(employee, - wage=salary, - state_id=self.get_us_state('MS'), - ms_89_350_sit_filing_status='single', - ms_89_350_sit_exemption_value=ms_89_350_exemption, - state_income_tax_additional_withholding=additional, - schedule_pay='monthly') - - self._log('2020 Mississippi tax single first payslip:') - payslip = self._createPayslip(employee, '2020-01-01', '2020-01-31') - - payslip.compute_sheet() - - cats = self._getCategories(payslip) - - STDED = 2300.0 # Single - AGP = salary * 12 # Monthly - TI = AGP - (ms_89_350_exemption + STDED) - self.assertPayrollEqual(TI, 1700.0) - TAX = ((TI - 3000) * 0.03) - self.assertPayrollEqual(TAX, -39.0) - - ms_withhold = round(TAX / 12) # Monthly - self.assertTrue(ms_withhold <= 0.0) - self.assertPayrollEqual(cats['EE_US_SIT'], -40.0) # only additional - - # Test with higher wage - salary = 1700.0 - employee = self._createEmployee() - contract = self._createContract(employee, - wage=salary, - state_id=self.get_us_state('MS'), - ms_89_350_sit_filing_status='single', - ms_89_350_sit_exemption_value=ms_89_350_exemption, - state_income_tax_additional_withholding=additional, - schedule_pay='monthly') - payslip = self._createPayslip(employee, '2020-01-01', '2020-01-31') - payslip.compute_sheet() - cats = self._getCategories(payslip) - - STDED = 2300.0 # Single - AGP = salary * 12 # Monthly - TI = AGP - (ms_89_350_exemption + STDED) - self.assertPayrollEqual(TI, 7100.0) - TAX = ((TI - 5000) * 0.04) + 60.0 - self.assertPayrollEqual(TAX, 144.0) - - ms_withhold = round(TAX / 12) # Monthly - self.assertPayrollEqual(ms_withhold, 12.0) - self.assertPayrollEqual(cats['EE_US_SIT'], -(ms_withhold + additional)) diff --git a/l10n_us_hr_payroll/tests/test_us_mt_montana_payslip_2020.py b/l10n_us_hr_payroll/tests/test_us_mt_montana_payslip_2020.py index ec861a0d..13a7e69f 100755 --- a/l10n_us_hr_payroll/tests/test_us_mt_montana_payslip_2020.py +++ b/l10n_us_hr_payroll/tests/test_us_mt_montana_payslip_2020.py @@ -1,17 +1,37 @@ # Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details. -from datetime import date -from .common import TestUsPayslip, process_payslip +from datetime import date, timedelta +from .common import TestUsPayslip class TestUsMtPayslip(TestUsPayslip): - # Calculations from https://app.mt.gov/myrevenue/Endpoint/DownloadPdf?yearId=705 + ### + # 2020 Taxes and Rates + ### MT_UNEMP_WAGE_MAX = 34100.0 MT_UNEMP = 1.18 MT_UNEMP_AFT = 0.13 + # Calculations from https://app.mt.gov/myrevenue/Endpoint/DownloadPdf?yearId=705 + def _test_sit(self, wage, additional_withholding, exemptions, schedule_pay, date_start, expected_withholding): + employee = self._createEmployee() + contract = self._createContract(employee, + wage=wage, + state_id=self.get_us_state('MT'), + state_income_tax_additional_withholding=additional_withholding, + mt_mw4_sit_exemptions=exemptions, + 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_one(self): combined_rate = self.MT_UNEMP + self.MT_UNEMP_AFT # Combined for test as they both go to the same category and have the same cap self._test_er_suta('MT', combined_rate, date(2020, 1, 1), wage_base=self.MT_UNEMP_WAGE_MAX) - - # TODO Montana Incometax rates for 2020 when released + self._test_sit(550.0, 0.0, 5.0, 'semi-monthly', date(2020, 1, 1), 3.0) + self._test_sit(2950.0, 10.0, 2.0, 'bi-weekly', date(2020, 1, 1), 162.0) + self._test_sit(5000.0, 0.0, 1.0, 'monthly', date(2020, 1, 1), 256.0) + self._test_sit(750.0, 0.0, 1.0, 'weekly', date(2020, 1, 1), 34.0) diff --git a/l10n_us_hr_payroll/tests/test_us_nc_northcarolina_payslip_2019.py b/l10n_us_hr_payroll/tests/test_us_nc_northcarolina_payslip_2019.py new file mode 100755 index 00000000..14c1c5b2 --- /dev/null +++ b/l10n_us_hr_payroll/tests/test_us_nc_northcarolina_payslip_2019.py @@ -0,0 +1,270 @@ +# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details. + +from .common import TestUsPayslip, process_payslip + + +class TestUsNCPayslip(TestUsPayslip): + ### + # Taxes and Rates + ### + NC_UNEMP_MAX_WAGE = 24300.0 + NC_UNEMP = -1.0 / 100.0 + NC_INC_TAX = -0.0535 + + + def test_2019_taxes_weekly(self): + salary = 20000.0 + # allowance_multiplier and Portion of Standard Deduction for weekly + allowance_multiplier = 48.08 + PST = 192.31 + exemption = 1 + # Algorithm derived from percentage method in https://files.nc.gov/ncdor/documents/files/nc-30_book_web.pdf + wh = -round((salary - (PST + (allowance_multiplier * exemption))) * -self.NC_INC_TAX) + + employee = self._createEmployee() + contract = self._createContract(employee, + wage=salary, + state_id=self.get_us_state('NC'), + nc_nc4_sit_filing_status='married', + state_income_tax_additional_withholding=0.0, + nc_nc4_sit_allowances=1.0, + schedule_pay='weekly') + + self._log('2019 North Carolina tax first payslip weekly:') + payslip = self._createPayslip(employee, '2019-01-01', '2019-01-31') + + payslip.compute_sheet() + + cats = self._getCategories(payslip) + + self.assertPayrollEqual(cats['EE_US_SIT'], wh) + + process_payslip(payslip) + + # Make a new payslip, this one will have maximums + + remaining_NC_UNEMP_wages = self.NC_UNEMP_MAX_WAGE - salary if (self.NC_UNEMP_MAX_WAGE - 2*salary < salary) \ + else salary + self._log('2019 North Carolina 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_NC_UNEMP_wages * self.NC_UNEMP) + + def test_2019_taxes_with_external_weekly(self): + salary = 5000.0 + schedule_pay = 'weekly' + + employee = self._createEmployee() + + contract = self._createContract(employee, + wage=salary, + state_id=self.get_us_state('NC'), + nc_nc4_sit_filing_status='married', + state_income_tax_additional_withholding=0.0, + nc_nc4_sit_allowances=1.0, + schedule_pay='weekly') + + self._log('2019 NorthCarolina_external 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.NC_UNEMP) + + def test_2019_taxes_biweekly(self): + salary = 5000.0 + schedule_pay = 'bi-weekly' + # allowance_multiplier and Portion of Standard Deduction for weekly + allowance_multiplier = 96.15 + PST = 384.62 + + allowances = 2 + # Algorithm derived from percentage method in https://files.nc.gov/ncdor/documents/files/nc-30_book_web.pdf + + wh = -round((salary - (PST + (allowance_multiplier * allowances))) * -self.NC_INC_TAX) + + employee = self._createEmployee() + + contract = self._createContract(employee, + wage=salary, + state_id=self.get_us_state('NC'), + nc_nc4_sit_filing_status='married', + state_income_tax_additional_withholding=0.0, + nc_nc4_sit_allowances=2.0, + schedule_pay='bi-weekly') + + self._log('2019 North Carolina tax first payslip bi-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.NC_UNEMP) + self.assertPayrollEqual(cats['EE_US_SIT'], wh) + + process_payslip(payslip) + + # Make a new payslip, this one will have maximums + + remaining_NC_UNEMP_wages = self.NC_UNEMP_MAX_WAGE - salary if (self.NC_UNEMP_MAX_WAGE - 2*salary < salary) \ + else salary + + self._log('2019 North Carolina tax second payslip bi-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_NC_UNEMP_wages * self.NC_UNEMP) + + def test_2019_taxes_semimonthly(self): + salary = 4000.0 + # allowance_multiplier and Portion of Standard Deduction for weekly + allowance_multiplier = 104.17 + PST = 625.00 + + allowances = 1 + # Algorithm derived from percentage method in https://files.nc.gov/ncdor/documents/files/nc-30_book_web.pdf + + wh = -round((salary - (PST + (allowance_multiplier * allowances))) * -self.NC_INC_TAX) + + employee = self._createEmployee() + + contract = self._createContract(employee, + wage=salary, + state_id=self.get_us_state('NC'), + nc_nc4_sit_filing_status='head_household', + state_income_tax_additional_withholding=0.0, + nc_nc4_sit_allowances=1.0, + schedule_pay='semi-monthly') + + self._log('2019 North Carolina tax first payslip:') + 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.NC_UNEMP) + self.assertPayrollEqual(cats['EE_US_SIT'], wh) + + process_payslip(payslip) + + # Make a new payslip, this one will have maximums + + remaining_NC_UNEMP_wages = self.NC_UNEMP_MAX_WAGE - salary if (self.NC_UNEMP_MAX_WAGE - 2 * salary < salary) \ + else salary + + self._log('2019 North Carolina tax second payslip:') + payslip = self._createPayslip(employee, '2019-02-01', '2019-02-28') + + payslip.compute_sheet() + + cats = self._getCategories(payslip) + + self.assertPayrollEqual(cats['ER_US_SUTA'], remaining_NC_UNEMP_wages * self.NC_UNEMP) + + def test_2019_taxes_monthly(self): + salary = 4000.0 + schedule_pay = 'monthly' + # allowance_multiplier and Portion of Standard Deduction for weekly + allowance_multiplier = 208.33 + PST = 833.33 + + allowances = 1 + # Algorithm derived from percentage method in https://files.nc.gov/ncdor/documents/files/nc-30_book_web.pdf + + wh = -round((salary - (PST + (allowance_multiplier * allowances))) * -self.NC_INC_TAX) + + employee = self._createEmployee() + + contract = self._createContract(employee, + wage=salary, + state_id=self.get_us_state('NC'), + nc_nc4_sit_filing_status='single', + state_income_tax_additional_withholding=0.0, + nc_nc4_sit_allowances=1.0, + schedule_pay='monthly') + + self._log('2019 North Carolina tax first payslip:') + 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.NC_UNEMP) + self.assertPayrollEqual(cats['EE_US_SIT'], wh) + + process_payslip(payslip) + + # Make a new payslip, this one will have maximums + + remaining_NC_UNEMP_wages = self.NC_UNEMP_MAX_WAGE - salary if ( + self.NC_UNEMP_MAX_WAGE - 2 * salary < salary) \ + else salary + + self._log('2019 North Carolina tax second payslip:') + payslip = self._createPayslip(employee, '2019-02-01', '2019-02-28') + + payslip.compute_sheet() + + cats = self._getCategories(payslip) + + self.assertPayrollEqual(cats['ER_US_SUTA'], remaining_NC_UNEMP_wages * self.NC_UNEMP) + + def test_additional_withholding(self): + salary = 4000.0 + # allowance_multiplier and Portion of Standard Deduction for weekly + allowance_multiplier = 48.08 + PST = 192.31 + additional_wh = 40.0 + + #4000 - (168.27 + (48.08 * 1) + + allowances = 1 + # Algorithm derived from percentage method in https://files.nc.gov/ncdor/documents/files/nc-30_book_web.pdf + + wh = -round(((salary - (PST + (allowance_multiplier * allowances))) * -self.NC_INC_TAX) + additional_wh) + + employee = self._createEmployee() + + contract = self._createContract(employee, + wage=salary, + state_id=self.get_us_state('NC'), + nc_nc4_sit_filing_status='married', + state_income_tax_additional_withholding=40.0, + nc_nc4_sit_allowances=1.0, + schedule_pay='weekly') + + self._log('2019 North Carolina tax first payslip weekly:') + payslip = self._createPayslip(employee, '2019-01-01', '2019-01-31') + + payslip.compute_sheet() + + cats = self._getCategories(payslip) + self.assertPayrollEqual(cats['EE_US_SIT'], wh) + + process_payslip(payslip) + + # Make a new payslip, this one will have maximums + + remaining_NC_UNEMP_wages = self.NC_UNEMP_MAX_WAGE - salary if (self.NC_UNEMP_MAX_WAGE - 2 * salary < salary) \ + else salary + + self._log('2019 North Carolina 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_NC_UNEMP_wages * self.NC_UNEMP) diff --git a/l10n_us_hr_payroll/tests/test_us_nc_northcarolina_payslip_2020.py b/l10n_us_hr_payroll/tests/test_us_nc_northcarolina_payslip_2020.py new file mode 100755 index 00000000..8e2d69c1 --- /dev/null +++ b/l10n_us_hr_payroll/tests/test_us_nc_northcarolina_payslip_2020.py @@ -0,0 +1,37 @@ +# 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 TestUsNCPayslip(TestUsPayslip): + ### + # 2020 Taxes and Rates + ### + NC_UNEMP_MAX_WAGE = 25200.0 + NC_UNEMP = 1.0 + NC_INC_TAX = 0.0535 + # Example based on https://files.nc.gov/ncdor/documents/files/NC-30_book_Web_1-16-19_v4_Final.pdf + 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('NC'), + nc_nc4_sit_filing_status=filing_status, + nc_nc4_sit_allowances=allowances, + 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 if filing_status else 0.0) + + def test_2020_taxes_example(self): + self._test_er_suta('NC', self.NC_UNEMP, date(2020, 1, 1), wage_base=self.NC_UNEMP_MAX_WAGE) + self._test_sit(20000.0, 'single', 1, 100.0, 'weekly', date(2020, 1, 1), 1156.0) + self._test_sit(5000.0, 'married', 1, 0.0, 'weekly', date(2020, 1, 1), 254.0) + self._test_sit(4000.0, 'head_household', 1, 5.0, 'semi-monthly', date(2020, 1, 1), 177.0) + self._test_sit(7000.0, '', 1, 5.0, 'monthly', date(2020, 1, 1), 0.0) diff --git a/l10n_us_hr_payroll/tests/test_us_nd_north_dakota_payslip_2020.py b/l10n_us_hr_payroll/tests/test_us_nd_north_dakota_payslip_2020.py new file mode 100644 index 00000000..903cf816 --- /dev/null +++ b/l10n_us_hr_payroll/tests/test_us_nd_north_dakota_payslip_2020.py @@ -0,0 +1,37 @@ +# 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 TestUsNDPayslip(TestUsPayslip): + ### + # 2020 Taxes and Rates + ### + ND_UNEMP_MAX_WAGE = 37900.0 + ND_UNEMP = 1.02 + # Calculation based on this file page.47 https://www.nd.gov/tax/data/upfiles/media/rates-and-instructions.pdf?20200110115917 + + def _test_sit(self, wage, filing_status, additional_withholding, allowances, schedule_pay, date_start, expected_withholding): + employee = self._createEmployee() + contract = self._createContract(employee, + wage=wage, + state_id=self.get_us_state('ND'), + nd_w4_sit_filing_status=filing_status, + state_income_tax_additional_withholding=additional_withholding, + nd_w4_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.assertPayrollAlmostEqual(cats.get('EE_US_SIT', 0.0), -expected_withholding) + + def test_2020_taxes_example(self): + self._test_er_suta('ND', self.ND_UNEMP, date(2020, 1, 1), wage_base=self.ND_UNEMP_MAX_WAGE) + self._test_sit(700.0, 'single', 0.0, 0.0, 'weekly', date(2020, 1, 1), 6.0) + self._test_sit(5000.0, 'married', 0.0, 2.0, 'bi-weekly', date(2020, 1, 1), 76.0) + self._test_sit(25000.0, 'head_household', 0.0, 0.0, 'monthly', date(2020, 1, 1), 534.0) + self._test_sit(25000.0, 'head_household', 10.0, 2.0, 'monthly', date(2020, 1, 1), 525.0) + self._test_sit(3000.0, '', 10.0, 2.0, 'monthly', date(2020, 1, 1), 0.0) diff --git a/l10n_us_hr_payroll/tests/test_us_ne_nebraska_payslip_2020.py b/l10n_us_hr_payroll/tests/test_us_ne_nebraska_payslip_2020.py new file mode 100644 index 00000000..785e4417 --- /dev/null +++ b/l10n_us_hr_payroll/tests/test_us_ne_nebraska_payslip_2020.py @@ -0,0 +1,38 @@ +# 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 TestUsNEPayslip(TestUsPayslip): + ### + # 2020 Taxes and Rates + ### + NE_UNEMP_MAX_WAGE = 9000.0 + NE_UNEMP = 1.25 + + def _test_sit(self, wage, filing_status, exempt, additional_withholding, allowances, schedule_pay, date_start, expected_withholding): + employee = self._createEmployee() + contract = self._createContract(employee, + wage=wage, + state_id=self.get_us_state('NE'), + ne_w4n_sit_filing_status=filing_status, + state_income_tax_exempt=exempt, + state_income_tax_additional_withholding=additional_withholding, + ne_w4n_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.assertPayrollAlmostEqual(cats.get('EE_US_SIT', 0.0), -expected_withholding) + + def test_2020_taxes_example(self): + self._test_er_suta('NE', self.NE_UNEMP, date(2020, 1, 1), wage_base=self.NE_UNEMP_MAX_WAGE) + self._test_sit(750.0, 'single', False, 0.0, 2, 'weekly', date(2020, 1, 1), 27.53) + self._test_sit(9500.0, 'single', False, 0.0, 1, 'bi-weekly', date(2020, 1, 1), 612.63) + self._test_sit(10500.0, 'married', False, 0.0, 1, 'bi-weekly', date(2020, 1, 1), 659.85) + self._test_sit(9500.0, 'single', True, 0.0, 1, 'bi-weekly', date(2020, 1, 1), 0.0) + self._test_sit(10500.0, 'single', False, 10.0, 2, 'monthly', date(2020, 1, 1), 625.2) + self._test_sit(4000.0, 'single', False, 0.0, 1, 'monthly', date(2020, 1, 1), 179.44) diff --git a/l10n_us_hr_payroll/tests/test_us_nh_new_hampshire_payslip_2020.py b/l10n_us_hr_payroll/tests/test_us_nh_new_hampshire_payslip_2020.py new file mode 100644 index 00000000..1d85e700 --- /dev/null +++ b/l10n_us_hr_payroll/tests/test_us_nh_new_hampshire_payslip_2020.py @@ -0,0 +1,13 @@ +# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details. + +from datetime import date +from .common import TestUsPayslip + + +class TestUsNHPayslip(TestUsPayslip): + # TAXES AND RATES + NH_UNEMP_MAX_WAGE = 14000.00 + NH_UNEMP = 1.2 + + def test_2020_taxes(self): + self._test_er_suta('NH', self.NH_UNEMP, date(2020, 1, 1), wage_base=self.NH_UNEMP_MAX_WAGE) diff --git a/l10n_us_hr_payroll/tests/test_us_nj_newjersey_payslip_2019.py b/l10n_us_hr_payroll/tests/test_us_nj_newjersey_payslip_2019.py new file mode 100755 index 00000000..c28849b5 --- /dev/null +++ b/l10n_us_hr_payroll/tests/test_us_nj_newjersey_payslip_2019.py @@ -0,0 +1,128 @@ +# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details. + +from .common import TestUsPayslip, process_payslip + + +class TestUsNJPayslip(TestUsPayslip): + ### + # 2019 Taxes and Rates + ### + NJ_UNEMP_MAX_WAGE = 34400.0 # Note that this is used for SDI and FLI as well + + ER_NJ_UNEMP = -2.6825 / 100.0 + EE_NJ_UNEMP = -0.3825 / 100.0 + + ER_NJ_SDI = -0.5 / 100.0 + EE_NJ_SDI = -0.17 / 100.0 + + ER_NJ_WF = -0.1175 / 100.0 + EE_NJ_WF = -0.0425 / 100.0 + + ER_NJ_FLI = 0.0 + EE_NJ_FLI = -0.08 / 100.0 + + # Examples found on page 24 of http://www.state.nj.us/treasury/taxation/pdf/current/njwt.pdf + def test_2019_taxes_example1(self): + salary = 300 + + # Tax Percentage Method for Single, taxable under $385 + wh = -4.21 + + employee = self._createEmployee() + contract = self._createContract(employee, + wage=salary, + state_id=self.get_us_state('NJ'), + nj_njw4_sit_filing_status='single', + nj_njw4_sit_allowances=1, + state_income_tax_additional_withholding=0.0, + nj_njw4_sit_rate_table='A', + schedule_pay='weekly') + + self._log('2019 New Jersey tax first payslip:') + payslip = self._createPayslip(employee, '2019-01-01', '2019-01-31') + + payslip.compute_sheet() + + cats = self._getCategories(payslip) + + self.assertPayrollEqual(cats['EE_US_SUTA'], salary * (self.EE_NJ_UNEMP + self.EE_NJ_SDI + self.EE_NJ_WF + self.EE_NJ_FLI)) + self.assertPayrollEqual(cats['ER_US_SUTA'], salary * (self.ER_NJ_UNEMP + self.ER_NJ_SDI + self.ER_NJ_WF + self.ER_NJ_FLI)) + self.assertTrue(all((cats['EE_US_SUTA'], cats['ER_US_SUTA']))) + # self.assertPayrollEqual(cats['EE_US_NJ_SDI_SIT'], cats['EE_US_NJ_SDI_SIT'] * self.EE_NJ_SDI) + # self.assertPayrollEqual(cats['ER_US_NJ_SDI_SUTA'], cats['ER_US_NJ_SDI_SUTA'] * self.ER_NJ_SDI) + # self.assertPayrollEqual(cats['EE_US_NJ_FLI_SIT'], cats['EE_US_NJ_FLI_SIT'] * self.EE_NJ_FLI) + # self.assertPayrollEqual(cats['EE_US_NJ_WF_SIT'], cats['EE_US_NJ_WF_SIT'] * self.EE_NJ_WF) + self.assertPayrollEqual(cats['EE_US_SIT'], 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('2019 New Jersey tax second payslip:') + payslip = self._createPayslip(employee, '2019-02-01', '2019-02-28') + + payslip.compute_sheet() + + cats = self._getCategories(payslip) + + # self.assertPayrollEqual(cats['WAGE_US_NJ_UNEMP'], remaining_nj_unemp_wages) + self.assertPayrollEqual(cats['ER_US_SUTA'], remaining_nj_unemp_wages * (self.ER_NJ_UNEMP + self.ER_NJ_SDI + self.ER_NJ_WF + self.ER_NJ_FLI)) + self.assertPayrollEqual(cats['EE_US_SUTA'], remaining_nj_unemp_wages * (self.EE_NJ_UNEMP + self.EE_NJ_SDI + self.EE_NJ_WF + self.EE_NJ_FLI)) + + def test_2019_taxes_example2(self): + salary = 1400.00 + + # Tax Percentage Method for Single, taxable pay over $962, under $1346 + wh = -27.58 + + employee = self._createEmployee() + contract = self._createContract(employee, + wage=salary, + state_id=self.get_us_state('NJ'), + nj_njw4_sit_filing_status='married_separate', + nj_njw4_sit_allowances=3, + state_income_tax_additional_withholding=0.0, + #nj_njw4_sit_rate_table='B', + schedule_pay='weekly') + + self.assertEqual(contract.schedule_pay, 'weekly') + + self._log('2019 New Jersey tax first payslip:') + payslip = self._createPayslip(employee, '2019-01-01', '2019-01-31') + + payslip.compute_sheet() + + cats = self._getCategories(payslip) + + self.assertPayrollEqual(cats['EE_US_SIT'], wh) + + + def test_2019_taxes_to_the_limits(self): + salary = 30000.00 + + # Tax Percentage Method for Single, taxable pay over $18750, under 125000 + wh = -1467.51 + + employee = self._createEmployee() + contract = self._createContract(employee, + wage=salary, + state_id=self.get_us_state('NJ'), + nj_njw4_sit_filing_status='married_joint', + nj_njw4_sit_allowances=3, + state_income_tax_additional_withholding=0.0, + # nj_njw4_sit_rate_table='B', + schedule_pay='quarterly') + + self.assertEqual(contract.schedule_pay, 'quarterly') + + self._log('2019 New Jersey tax first payslip:') + payslip = self._createPayslip(employee, '2019-01-01', '2019-03-31') + + payslip.compute_sheet() + + cats = self._getCategories(payslip) + + self.assertPayrollEqual(cats['EE_US_SIT'], wh) diff --git a/l10n_us_hr_payroll/tests/test_us_nj_newjersey_payslip_2020.py b/l10n_us_hr_payroll/tests/test_us_nj_newjersey_payslip_2020.py new file mode 100755 index 00000000..1df4af6a --- /dev/null +++ b/l10n_us_hr_payroll/tests/test_us_nj_newjersey_payslip_2020.py @@ -0,0 +1,51 @@ +# 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 TestUsNJPayslip(TestUsPayslip): + ### + # 2020 Taxes and Rates + ### + NJ_UNEMP_MAX_WAGE = 35300.0 # Note that this is used for SDI and FLI as well + + ER_NJ_UNEMP = 2.6825 + EE_NJ_UNEMP = 0.3825 + + ER_NJ_SDI = 0.5 + EE_NJ_SDI = 0.26 + + ER_NJ_WF = 0.1175 + EE_NJ_WF = 0.0425 + + ER_NJ_FLI = 0.0 + EE_NJ_FLI = 0.16 + + def _test_sit(self, wage, filing_status, allowances, schedule_pay, date_start, expected_withholding, rate_table=False): + employee = self._createEmployee() + contract = self._createContract(employee, + wage=wage, + state_id=self.get_us_state('NJ'), + nj_njw4_sit_filing_status=filing_status, + nj_njw4_sit_allowances=allowances, + state_income_tax_additional_withholding=0.0, + nj_njw4_sit_rate_table=rate_table, + schedule_pay=schedule_pay) + payslip = self._createPayslip(employee, date_start, date_start + timedelta(days=7)) + payslip.compute_sheet() + cats = self._getCategories(payslip) + self.assertPayrollAlmostEqual(cats.get('EE_US_SIT', 0.0), -expected_withholding if filing_status else 0.0) + + def test_2020_taxes_example1(self): + combined_er_rate = self.ER_NJ_UNEMP + self.ER_NJ_FLI + self.ER_NJ_SDI + self.ER_NJ_WF + self._test_er_suta('NJ', combined_er_rate, date(2020, 1, 1), wage_base=self.NJ_UNEMP_MAX_WAGE) + combined_ee_rate = self.EE_NJ_UNEMP + self.EE_NJ_FLI + self.EE_NJ_SDI + self.EE_NJ_WF + self._test_ee_suta('NJ', combined_ee_rate, date(2020, 1, 1), wage_base=self.NJ_UNEMP_MAX_WAGE, relaxed=True) + # these expected values come from https://www.state.nj.us/treasury/taxation/pdf/current/njwt.pdf + self._test_sit(300.0, 'single', 1, 'weekly', date(2020, 1, 1), 4.21) + self._test_sit(375.0, 'married_separate', 3, 'weekly', date(2020, 1, 1), 4.76) + self._test_sit(1400.0, 'head_household', 3, 'weekly', date(2020, 1, 1), 27.60) + self._test_sit(1400.0, '', 3, 'weekly', date(2020, 1, 1), 0.00) + self._test_sit(2500.0, 'single', 3, 'bi-weekly', date(2020, 1, 1), 82.66) + self._test_sit(15000.0, 'married_joint', 2, 'monthly', date(2020, 1, 1), 844.85) 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..24f8c5a4 --- /dev/null +++ b/l10n_us_hr_payroll/tests/test_us_nm_new_mexico_payslip_2020.py @@ -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 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) + self._test_sit(4400.0, '', 0.0, 'monthly', date(2020, 1, 1), 0.00) diff --git a/l10n_us_hr_payroll/tests/test_us_nv_nevada_payslip_2020.py b/l10n_us_hr_payroll/tests/test_us_nv_nevada_payslip_2020.py new file mode 100755 index 00000000..52c2114b --- /dev/null +++ b/l10n_us_hr_payroll/tests/test_us_nv_nevada_payslip_2020.py @@ -0,0 +1,16 @@ +# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details. + +from datetime import date +from .common import TestUsPayslip + + +class TestUsNVPayslip(TestUsPayslip): + ### + # 2020 Taxes and Rates + ### + NV_UNEMP_MAX_WAGE = 32500.0 + NV_UNEMP = 2.95 + + def test_2020_taxes(self): + # Only has state unemployment + self._test_er_suta('NV', self.NV_UNEMP, date(2020, 1, 1), wage_base=self.NV_UNEMP_MAX_WAGE) diff --git a/l10n_us_hr_payroll/tests/test_us_ny_new_york_payslip_2019.py b/l10n_us_hr_payroll/tests/test_us_ny_new_york_payslip_2019.py new file mode 100644 index 00000000..eeb1f6dc --- /dev/null +++ b/l10n_us_hr_payroll/tests/test_us_ny_new_york_payslip_2019.py @@ -0,0 +1,160 @@ +# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details. + +from .common import TestUsPayslip, process_payslip + + +class TestUsNYPayslip(TestUsPayslip): + ### + # Taxes and Rates + ### + NY_UNEMP_MAX_WAGE = 11400.0 + NY_UNEMP = 2.5 + NY_RSF = 0.075 + NY_MCTMT = 0.0 + + def test_single_example1(self): + salary = 400 + schedule_pay = 'weekly' + allowances = 3 + additional_withholding = 0 + filing_status = 'single' + additional = 0.0 + wh = -8.20 + + employee = self._createEmployee() + + contract = self._createContract(employee, + wage=salary, + state_id=self.get_us_state('NY'), + ny_it2104_sit_filing_status=filing_status, + state_income_tax_additional_withholding=additional, + ny_it2104_sit_allowances=allowances, + schedule_pay=schedule_pay) + + self.assertEqual(contract.schedule_pay, 'weekly') + self._log('2018 New York tax first payslip:') + payslip = self._createPayslip(employee, '2019-01-01', '2019-01-31') + + payslip.compute_sheet() + + cats = self._getCategories(payslip) + + self.assertPayrollEqual(cats['NY_UNEMP'], cats['NY_UNEMP_WAGES'] * self.NY_UNEMP) + self.assertPayrollEqual(cats['NY_RSF'], cats['NY_UNEMP_WAGES'] * self.NY_RSF) + self.assertPayrollEqual(cats['NY_MCTMT'], cats['NY_UNEMP_WAGES'] * self.NY_MCTMT) + self.assertPayrollEqual(cats['EE_US_SIT'], wh) + + process_payslip(payslip) + + def test_married_example2(self): + salary = 5000 + schedule_pay = 'semi-monthly' + allowances = 3 + additional = 0 + filing_status = 'married' + wh = -284.19 + + employee = self._createEmployee() + contract = self._createContract(employee, + wage=salary, + state_id=self.get_us_state('NY'), + ny_it2104_sit_filing_status=filing_status, + state_income_tax_additional_withholding=additional, + ny_it2104_sit_allowances=allowances, + schedule_pay=schedule_pay) + + self._log('2019 New York tax first payslip:') + payslip = self._createPayslip(employee, '2019-01-01', '2019-01-31') + + payslip.compute_sheet() + + cats = self._getCategories(payslip) + + self.assertPayrollEqual(cats['NY_UNEMP'], cats['NY_UNEMP_WAGES'] * self.NY_UNEMP) + self.assertPayrollEqual(cats['NY_RSF'], cats['NY_UNEMP_WAGES'] * self.NY_RSF) + self.assertPayrollEqual(cats['NY_MCTMT'], cats['NY_UNEMP_WAGES'] * self.NY_MCTMT) + self.assertPayrollEqual(cats['EE_US_SIT'], wh) + + process_payslip(payslip) + + def test_single_example3(self): + salary = 50000 + schedule_pay = 'monthly' + allowances = 3 + additional = 0 + filing_status = 'single' + wh = -3575.63 + + employee = self._createEmployee() + + contract = self._createContract(employee, + wage=salary, + state_id=self.get_us_state('NY'), + ny_it2104_sit_filing_status=filing_status, + state_income_tax_additional_withholding=additional, + ny_it2104_sit_allowances=allowances, + schedule_pay=schedule_pay) + + self._log('2019 New York tax first payslip:') + payslip = self._createPayslip(employee, '2019-01-01', '2019-01-31') + + payslip.compute_sheet() + + cats = self._getCategories(payslip) + + self.assertPayrollEqual(cats['EE_US_SIT'], wh) + + def test_exempt_example3(self): + salary = 50000 + schedule_pay = 'monthly' + allowances = 3 + additional = 0 + filing_status = '' + wh = 0.0 + + employee = self._createEmployee() + + contract = self._createContract(employee, + wage=salary, + state_id=self.get_us_state('NY'), + ny_it2104_sit_filing_status=filing_status, + state_income_tax_additional_withholding=additional, + ny_it2104_sit_allowances=allowances, + schedule_pay=schedule_pay) + + self._log('2019 New York tax first payslip:') + payslip = self._createPayslip(employee, '2019-01-01', '2019-01-31') + + payslip.compute_sheet() + + cats = self._getCategories(payslip) + + self.assertPayrollEqual(cats['EE_US_SIT'], wh) + + def test_exempt_example3(self): + salary = 50000 + schedule_pay = 'monthly' + allowances = 3 + additional = 0 + filing_status = '' + wh = 0.0 + + employee = self._createEmployee() + + contract = self._createContract(employee, + wage=salary, + state_id=self.get_us_state('NY'), + ny_it2104_sit_filing_status=filing_status, + state_income_tax_additional_withholding=additional, + ny_it2104_sit_allowances=allowances, + schedule_pay=schedule_pay) + + self._log('2019 New York tax first payslip:') + payslip = self._createPayslip(employee, '2019-01-01', '2019-01-31') + + payslip.compute_sheet() + + cats = self._getCategories(payslip) + + self.assertPayrollEqual(cats['EE_US_SIT'], wh) + diff --git a/l10n_us_hr_payroll/tests/test_us_ny_new_york_payslip_2020.py b/l10n_us_hr_payroll/tests/test_us_ny_new_york_payslip_2020.py new file mode 100644 index 00000000..05e50792 --- /dev/null +++ b/l10n_us_hr_payroll/tests/test_us_ny_new_york_payslip_2020.py @@ -0,0 +1,39 @@ +# 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 TestUsNYPayslip(TestUsPayslip): + ### + # 2020 Taxes and Rates + ### + NY_UNEMP_MAX_WAGE = 11600.0 + NY_UNEMP = 2.5 + NY_RSF = 0.075 + NY_MCTMT = 0.0 + + def _test_sit(self, wage, filing_status, additional_withholding, allowances, schedule_pay, date_start, expected_withholding): + employee = self._createEmployee() + contract = self._createContract(employee, + wage=wage, + state_id=self.get_us_state('NY'), + ny_it2104_sit_filing_status=filing_status, + state_income_tax_additional_withholding=additional_withholding, + ny_it2104_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.assertPayrollAlmostEqual(cats.get('EE_US_SIT', 0.0), -expected_withholding) + + def test_2020_taxes_example(self): + combined_er_rate = self.NY_UNEMP + self.NY_RSF + self.NY_MCTMT + self._test_er_suta('NY', combined_er_rate, date(2020, 1, 1), wage_base=self.NY_UNEMP_MAX_WAGE, relaxed=True) + self._test_sit(400.0, 'single', 0.0, 3, 'weekly', date(2020, 1, 1), 8.20) + self._test_sit(10000.0, 'single', 0.0, 3, 'monthly', date(2020, 1, 1), 554.09) + self._test_sit(8000.0, 'married', 0.0, 5, 'monthly', date(2020, 1, 1), 400.32) + self._test_sit(4500.0, 'married', 10.0, 3, 'semi-monthly', date(2020, 1, 1), 247.69) + self._test_sit(50000.0, '', 0.0, 0, 'monthly', date(2020, 1, 1), 0.00) diff --git a/l10n_us_hr_payroll/tests/test_us_ok_oklahoma_payslip_2020.py b/l10n_us_hr_payroll/tests/test_us_ok_oklahoma_payslip_2020.py new file mode 100755 index 00000000..cacdcc16 --- /dev/null +++ b/l10n_us_hr_payroll/tests/test_us_ok_oklahoma_payslip_2020.py @@ -0,0 +1,38 @@ +# 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 TestUsOKPayslip(TestUsPayslip): + ### + # 2020 Taxes and Rates + ### + OK_UNEMP_MAX_WAGE = 18700.0 + OK_UNEMP = 1.5 + # Calculation based on example https://www.ok.gov/tax/documents/2020WHTables.pdf + + def _test_sit(self, wage, filing_status, allowances, additional_withholding, exempt, schedule_pay, date_start, expected_withholding): + employee = self._createEmployee() + contract = self._createContract(employee, + wage=wage, + state_id=self.get_us_state('OK'), + ok_w4_sit_filing_status=filing_status, + ok_w4_sit_allowances=allowances, + state_income_tax_additional_withholding=additional_withholding, + state_income_tax_exempt=exempt, + 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('OK', self.OK_UNEMP, date(2020, 1, 1), wage_base=self.OK_UNEMP_MAX_WAGE) + self._test_sit(1825, 'married', 2, 0, False, 'semi-monthly', date(2020, 1, 1), 46.00) + self._test_sit(1825, 'married', 2, 0, True, 'monthly', date(2020, 1, 1), 0.00) + self._test_sit(1000, 'single', 1, 0, False, 'weekly', date(2020, 1, 1), 39.00) + self._test_sit(1000, 'single', 1, 10, False, 'weekly', date(2020, 1, 1), 49.00) + self._test_sit(5000, 'head_household', 2, 10, False, 'monthly', date(2020, 1, 1), 210.00) diff --git a/l10n_us_hr_payroll/tests/test_us_ri_rhode_island_payslip_2020.py b/l10n_us_hr_payroll/tests/test_us_ri_rhode_island_payslip_2020.py new file mode 100755 index 00000000..9d92fec1 --- /dev/null +++ b/l10n_us_hr_payroll/tests/test_us_ri_rhode_island_payslip_2020.py @@ -0,0 +1,37 @@ +# 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 TestUsRIPayslip(TestUsPayslip): + ### + # 2020 Taxes and Rates + ### + RI_UNEMP_MAX_WAGE = 24000.0 + RI_UNEMP = 1.06 + # Calculation based on example http://www.tax.ri.gov/forms/2020/Withholding/2020%20Withhholding%20Tax%20Booklet.pdf + + def _test_sit(self, wage, allowances, additional_withholding, exempt, schedule_pay, date_start, expected_withholding): + employee = self._createEmployee() + contract = self._createContract(employee, + wage=wage, + state_id=self.get_us_state('RI'), + ri_w4_sit_allowances=allowances, + state_income_tax_additional_withholding=additional_withholding, + state_income_tax_exempt=exempt, + 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('RI', self.RI_UNEMP, date(2020, 1, 1), wage_base=self.RI_UNEMP_MAX_WAGE) + self._test_sit(2195, 1, 0, False, 'weekly', date(2020, 1, 1), 90.80) + self._test_sit(1800, 2, 10, True, 'weekly', date(2020, 1, 1), 0.00) + self._test_sit(10000, 1, 0, False, 'bi-weekly', date(2020, 1, 1), 503.15) + self._test_sit(18000, 2, 0, False, 'monthly', date(2020, 1, 1), 860.54) + self._test_sit(18000, 2, 10, False, 'monthly', date(2020, 1, 1), 870.55) diff --git a/l10n_us_hr_payroll/tests/test_us_sc_south_carolina_payslip_2019.py b/l10n_us_hr_payroll/tests/test_us_sc_south_carolina_payslip_2019.py new file mode 100644 index 00000000..793f84c4 --- /dev/null +++ b/l10n_us_hr_payroll/tests/test_us_sc_south_carolina_payslip_2019.py @@ -0,0 +1,97 @@ +# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details. + +from .common import TestUsPayslip, process_payslip + + +class TestUsSCPayslip(TestUsPayslip): + + # Taxes and Rates + SC_UNEMP_MAX_WAGE = 14000.0 + US_SC_UNEMP = -1.09 / 100 + US_SC_exemption_amount = 2510.00 + + def test_2019_taxes_weekly(self): + # We will hand calculate the amount to test for state withholding. + schedule_pay = 'weekly' + salary = 50000.00 # Employee is paid 50000 per week to be in top tax bracket + allowances = 2 + # Calculate annual wages + annual = 50000 * 52.0 + # From our annual we deduct personal exemption amounts. + # We deduct 2510.00 per exemption. Since we have two exemptions: + personal_exemption = self.US_SC_exemption_amount * allowances # 5020.0 + # From annual, we will also deduct a standard_deduction of 3470.00 or .1 of salary, which ever + # is small -> if 1 or more exemptions, else 0 + standard_deduction = 3470.00 + taxable_income = annual - personal_exemption - standard_deduction # 2591510.0 + # We then calculate the amounts off the SC tax pdf tables. + # 2591478.0 is in the highest bracket + test_amt = (taxable_income * (7.0 / 100.0)) - 467.95 + test_amt = 180935.51 + # Make it per period then negative + test_amt = (test_amt / 52.0) # Divided by 52 since it is weekly. + # test_amt = 3479.52 + test_amt = -test_amt + + employee = self._createEmployee() + contract = self._createContract(employee, + wage=salary, + state_id=self.get_us_state('SC'), + state_income_tax_exempt=False, + sc_w4_sit_allowances=allowances, + schedule_pay=schedule_pay) + + self._log('2019 South Carolina tax first payslip:') + payslip = self._createPayslip(employee, '2019-01-01', '2019-01-31') + payslip.compute_sheet() + cats = self._getCategories(payslip) + + self.assertPayrollAlmostEqual(cats['ER_US_SUTA'], self.SC_UNEMP_MAX_WAGE * self.US_SC_UNEMP) + self.assertPayrollAlmostEqual(cats['EE_US_SIT'], test_amt) + + process_payslip(payslip) + + remaining_SC_UNEMP_wages = self.SC_UNEMP_MAX_WAGE - annual if (annual < self.SC_UNEMP_MAX_WAGE) \ + else 0.00 + + self._log('2019 South Carolina tax second payslip:') + + payslip = self._createPayslip(employee, '2019-02-01', '2019-02-28') + payslip.compute_sheet() + cats = self._getCategories(payslip) + + self.assertEqual(0.0, remaining_SC_UNEMP_wages) + self.assertPayrollEqual(cats['ER_US_SUTA'], remaining_SC_UNEMP_wages * self.US_SC_UNEMP) + + def test_2019_taxes_filing_status(self): + salary = 20000.00 # Wages per pay period + schedule_pay = 'monthly' + annual = salary * 12 + allowances = 1 + # Hand Calculations + personal_exemption = 2510.00 + standard_deduction = min(3470.00, .1 * annual) # 3470.0 but min is shown for the process + taxable = annual - personal_exemption - standard_deduction + # taxable = 234020 + test_amt = ((taxable) * (7.0 / 100.0)) - 467.95 # 15991.850000000002 + test_amt = test_amt / 12.0 # Put it into monthly -> 1332.654166666667 + # Make it negative + test_amt = -test_amt + + employee = self._createEmployee() + contract = self._createContract(employee, + wage=salary, + state_id=self.get_us_state('SC'), + state_income_tax_exempt=False, + sc_w4_sit_allowances=allowances, + schedule_pay=schedule_pay) + + self._log('2019 South Carolina tax first payslip: ') + payslip = self._createPayslip(employee, '2019-01-01', '2019-01-31') + payslip.compute_sheet() + cats = self._getCategories(payslip) + + self.assertPayrollEqual(cats['ER_US_SUTA'], self.SC_UNEMP_MAX_WAGE * self.US_SC_UNEMP) + self.assertPayrollAlmostEqual(cats['EE_US_SIT'], test_amt) + + process_payslip(payslip) diff --git a/l10n_us_hr_payroll/tests/test_us_sc_south_carolina_payslip_2020.py b/l10n_us_hr_payroll/tests/test_us_sc_south_carolina_payslip_2020.py new file mode 100644 index 00000000..170c3bf5 --- /dev/null +++ b/l10n_us_hr_payroll/tests/test_us_sc_south_carolina_payslip_2020.py @@ -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 TestUsSCPayslip(TestUsPayslip): + ### + # 2020 Taxes and Rates + ### + SC_UNEMP_MAX_WAGE = 14000.0 + SC_UNEMP = 0.55 + # Calculation based on https://dor.sc.gov/forms-site/Forms/WH1603F_2020.pdf + + def _test_sit(self, wage, additional_withholding, exempt, allowances, schedule_pay, date_start, expected_withholding): + employee = self._createEmployee() + contract = self._createContract(employee, + wage=wage, + state_id=self.get_us_state('SC'), + state_income_tax_additional_withholding=additional_withholding, + state_income_tax_exempt=exempt, + sc_w4_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.assertPayrollAlmostEqual(cats.get('EE_US_SIT', 0.0), -expected_withholding) + + def test_2020_taxes_example(self): + self._test_er_suta('SC', self.SC_UNEMP, date(2020, 1, 1), wage_base=self.SC_UNEMP_MAX_WAGE) + self._test_sit(750.0, 0.0, False, 3.0, 'weekly', date(2020, 1, 1), 28.73) + self._test_sit(800.0, 0.0, True, 0.0, 'weekly', date(2020, 1, 1), 0.00) + self._test_sit(9000.0, 0.0, False, 0.0, 'monthly', date(2020, 1, 1), 594.61) + self._test_sit(5000.0, 10.0, False, 2.0, 'semi-monthly', date(2020, 1, 1), 316.06) diff --git a/l10n_us_hr_payroll/tests/test_us_sd_south_dakota_payslip_2020.py b/l10n_us_hr_payroll/tests/test_us_sd_south_dakota_payslip_2020.py new file mode 100644 index 00000000..bdbb7858 --- /dev/null +++ b/l10n_us_hr_payroll/tests/test_us_sd_south_dakota_payslip_2020.py @@ -0,0 +1,13 @@ +# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details. + +from datetime import date +from .common import TestUsPayslip + + +class TestUsSDPayslip(TestUsPayslip): + # TAXES AND RATES + SD_UNEMP_MAX_WAGE = 15000.00 + SD_UNEMP = 1.75 + + def test_2020_taxes(self): + self._test_er_suta('SD', self.SD_UNEMP, date(2020, 1, 1), wage_base=self.SD_UNEMP_MAX_WAGE) diff --git a/l10n_us_hr_payroll/tests/test_us_tn_tennessee_payslip_2020.py b/l10n_us_hr_payroll/tests/test_us_tn_tennessee_payslip_2020.py new file mode 100644 index 00000000..54acfa9a --- /dev/null +++ b/l10n_us_hr_payroll/tests/test_us_tn_tennessee_payslip_2020.py @@ -0,0 +1,13 @@ +# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details. + +from datetime import date +from .common import TestUsPayslip + + +class TestUsTNPayslip(TestUsPayslip): + # TAXES AND RATES + TN_UNEMP_MAX_WAGE = 7000.00 + TN_UNEMP = 2.7 + + def test_2020_taxes(self): + self._test_er_suta('TN', self.TN_UNEMP, date(2020, 1, 1), wage_base=self.TN_UNEMP_MAX_WAGE) diff --git a/l10n_us_hr_payroll/tests/test_us_us_utah_payslip_2020.py b/l10n_us_hr_payroll/tests/test_us_us_utah_payslip_2020.py new file mode 100755 index 00000000..a6881acb --- /dev/null +++ b/l10n_us_hr_payroll/tests/test_us_us_utah_payslip_2020.py @@ -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 TestUsUTPayslip(TestUsPayslip): + ### + # 2020 Taxes and Rates + ### + UT_UNEMP_MAX_WAGE = 36600.0 + UT_UNEMP = 0.1 + # Calculation based on example https://tax.utah.gov/forms/pubs/pub-14.pdf + + 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('UT'), + ut_w4_sit_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.assertPayrollAlmostEqual(cats.get('EE_US_SIT', 0.0), -expected_withholding) + + def test_2020_taxes_example(self): + self._test_er_suta('UT', self.UT_UNEMP, date(2020, 1, 1), wage_base=self.UT_UNEMP_MAX_WAGE) + self._test_sit(400, 'single', 0, 'weekly', date(2020, 1, 1), 16.00) + self._test_sit(1000, 'single', 0, 'bi-weekly', date(2020, 1, 1), 45.00) + self._test_sit(855, 'married', 0, 'semi-monthly', date(2020, 1, 1), 16.00) + self._test_sit(2500, 'married', 0, 'monthly', date(2020, 1, 1), 81.00) + self._test_sit(8000, 'head_household', 10, 'quarterly', date(2020, 1, 1), 397.00) diff --git a/l10n_us_hr_payroll/tests/test_us_vt_vermont_payslip_2020.py b/l10n_us_hr_payroll/tests/test_us_vt_vermont_payslip_2020.py new file mode 100755 index 00000000..7807bed7 --- /dev/null +++ b/l10n_us_hr_payroll/tests/test_us_vt_vermont_payslip_2020.py @@ -0,0 +1,37 @@ +# 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 TestUsVTPayslip(TestUsPayslip): + ### + # 2020 Taxes and Rates + ### + VT_UNEMP_MAX_WAGE = 16100.0 + VT_UNEMP = 1.0 + # Calculation based on example https://tax.vermont.gov/sites/tax/files/documents/WithholdingInstructions.pdf + + def _test_sit(self, wage, filing_status, allowances, additional_withholding, exempt, schedule_pay, date_start, expected_withholding): + employee = self._createEmployee() + contract = self._createContract(employee, + wage=wage, + state_id=self.get_us_state('VT'), + vt_w4vt_sit_filing_status=filing_status, + vt_w4vt_sit_allowances=allowances, + state_income_tax_additional_withholding=additional_withholding, + state_income_tax_exempt=exempt, + 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('VT', self.VT_UNEMP, date(2020, 1, 1), wage_base=self.VT_UNEMP_MAX_WAGE) + self._test_sit(1800, 'married', 2, 0, False, 'weekly', date(2020, 1, 1), 53.73) + self._test_sit(1800, 'married', 2, 10, False, 'weekly', date(2020, 1, 1), 63.73) + self._test_sit(1000, 'single', 1, 0, True, 'weekly', date(2020, 1, 1), 0.00) + self._test_sit(8000, 'single', 1, 10, False, 'bi-weekly', date(2020, 1, 1), 506.58) diff --git a/l10n_us_hr_payroll/tests/test_us_wi_wisconsin_payslip_2020.py b/l10n_us_hr_payroll/tests/test_us_wi_wisconsin_payslip_2020.py new file mode 100755 index 00000000..32bdfa30 --- /dev/null +++ b/l10n_us_hr_payroll/tests/test_us_wi_wisconsin_payslip_2020.py @@ -0,0 +1,39 @@ +# 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 TestUsWIPayslip(TestUsPayslip): + ### + # 2020 Taxes and Rates + ### + WI_UNEMP_MAX_WAGE = 14000.0 + WI_UNEMP = 3.05 + # Calculation based on example https://www.revenue.wi.gov/DOR%20Publications/pb166.pdf + + def _test_sit(self, wage, filing_status, exemption, additional_withholding, exempt, schedule_pay, date_start, expected_withholding): + employee = self._createEmployee() + contract = self._createContract(employee, + wage=wage, + state_id=self.get_us_state('WI'), + wi_wt4_sit_filing_status=filing_status, + wi_wt4_sit_exemptions=exemption, + state_income_tax_additional_withholding=additional_withholding, + state_income_tax_exempt=exempt, + 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.assertPayrollAlmostEqual(cats.get('EE_US_SIT', 0.0), -expected_withholding) + + def test_2020_taxes_example(self): + self._test_er_suta('WI', self.WI_UNEMP, date(2020, 1, 1), wage_base=self.WI_UNEMP_MAX_WAGE) + self._test_sit(300, 'single', 1, 0, False, 'weekly', date(2020, 1, 1), 7.21) + self._test_sit(700, 'married', 3, 0, False, 'bi-weekly', date(2020, 1, 1), 13.35) + self._test_sit(7000, 'single', 1, 10, True, 'bi-weekly', date(2020, 1, 1), 0.00) + self._test_sit(10000, 'married', 3, 10, False, 'bi-weekly', date(2020, 1, 1), 633.65) + # ((48000 - 26227) * (7.0224 /100) + 1073.55 - 44) / 12 + self._test_sit(4000, 'single', 2, 0, False, 'monthly', date(2020, 1, 1), 213.21) diff --git a/l10n_us_hr_payroll/tests/test_us_wv_west_virginia_payslip_2020.py b/l10n_us_hr_payroll/tests/test_us_wv_west_virginia_payslip_2020.py new file mode 100755 index 00000000..acef111e --- /dev/null +++ b/l10n_us_hr_payroll/tests/test_us_wv_west_virginia_payslip_2020.py @@ -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 TestUsWVPayslip(TestUsPayslip): + ### + # 2020 Taxes and Rates + ### + WV_UNEMP_MAX_WAGE = 12000.0 + WV_UNEMP = 2.7 + # Calculation based on example https://tax.wv.gov/Documents/TaxForms/it100.1a.pdf + + def _test_sit(self, wage, filing_status, exemption, additional_withholding, schedule_pay, date_start, expected_withholding): + employee = self._createEmployee() + contract = self._createContract(employee, + wage=wage, + state_id=self.get_us_state('WV'), + wv_it104_sit_filing_status=filing_status, + wv_it104_sit_exemptions=exemption, + 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('WV', self.WV_UNEMP, date(2020, 1, 1), wage_base=self.WV_UNEMP_MAX_WAGE) + self._test_sit(1250, 'married', 2, 0, 'semi-monthly', date(2020, 1, 1), 44.00) + self._test_sit(1300, 'single', 1, 0, 'bi-weekly', date(2020, 1, 1), 46.00) + self._test_sit(1300, 'single', 1, 10, 'bi-weekly', date(2020, 1, 1), 56.00) + self._test_sit(15000, 'single', 2, 0, 'monthly', date(2020, 1, 1), 860.00) diff --git a/l10n_us_hr_payroll/tests/test_us_wy_wyoming_payslip_2019.py b/l10n_us_hr_payroll/tests/test_us_wy_wyoming_payslip_2019.py new file mode 100644 index 00000000..a8fa3df8 --- /dev/null +++ b/l10n_us_hr_payroll/tests/test_us_wy_wyoming_payslip_2019.py @@ -0,0 +1,58 @@ +# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details. + +from datetime import date +from .common import TestUsPayslip, process_payslip + + +class TestUsWYPayslip(TestUsPayslip): + + # TAXES AND RATES + WY_UNEMP_MAX_WAGE = 25400 + WY_UNEMP = -2.10 / 100.0 + + def test_2019_taxes(self): + salary = 15000.00 + + employee = self._createEmployee() + contract = self._createContract(employee, + wage=salary, + state_id=self.get_us_state('WY')) + + self._log('2019 Wyoming tax first payslip:') + 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.WY_UNEMP) + + process_payslip(payslip) + + # Make a new payslip, this one will have maximums + + remaining_wy_unemp_wages = self.WY_UNEMP_MAX_WAGE - salary if (self.WY_UNEMP_MAX_WAGE - 2*salary < salary) \ + else salary + + self._log('2019 Wyoming tax second payslip:') + payslip = self._createPayslip(employee, '2019-02-01', '2019-02-28') + payslip.compute_sheet() + cats = self._getCategories(payslip) + + self.assertPayrollEqual(cats['ER_US_SUTA'], remaining_wy_unemp_wages * self.WY_UNEMP) + + def test_2019_taxes_with_external(self): + # Wage is the cap itself, 25400 + # so salary is equal to self.WY_UNEMP + salary = 25400 + + employee = self._createEmployee() + contract = self._createContract(employee, + wage=salary, + state_id=self.get_us_state('WY')) + + self._log('2019 Wyoming External tax first payslip:') + 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.WY_UNEMP) diff --git a/l10n_us_hr_payroll/tests/test_us_wy_wyoming_payslip_2020.py b/l10n_us_hr_payroll/tests/test_us_wy_wyoming_payslip_2020.py new file mode 100644 index 00000000..b6ca4482 --- /dev/null +++ b/l10n_us_hr_payroll/tests/test_us_wy_wyoming_payslip_2020.py @@ -0,0 +1,13 @@ +# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details. + +from datetime import date +from .common import TestUsPayslip + + +class TestUsWYPayslip(TestUsPayslip): + # TAXES AND RATES + WY_UNEMP_MAX_WAGE = 26400.00 + WY_UNEMP = 8.5 + + def test_2020_taxes(self): + self._test_er_suta('WY', self.WY_UNEMP, date(2020, 1, 1), wage_base=self.WY_UNEMP_MAX_WAGE) diff --git a/l10n_us_hr_payroll/views/res_config_settings_views.xml b/l10n_us_hr_payroll/views/res_config_settings_views.xml new file mode 100644 index 00000000..3c69b42f --- /dev/null +++ b/l10n_us_hr_payroll/views/res_config_settings_views.xml @@ -0,0 +1,32 @@ + + + + + res.config.settings.view.form.inherit + res.config.settings + + + +
+
+
+ Payslip Sum Behavior +
+ Customize the behavior of what payslips are eligible when summing over date ranges in rules. + Generally, "Date To" or "Accounting Date" would be preferred in the United States and anywhere + else where the ending date on the payslip is used to calculate wage bases. +
+
+
+
+
+
+
+
+
+
+
+ +
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 247309b5..94d316bf 100644 --- a/l10n_us_hr_payroll/views/us_payroll_config_views.xml +++ b/l10n_us_hr_payroll/views/us_payroll_config_views.xml @@ -44,6 +44,47 @@ + +

Form A4 - State Income Tax

+ + + + +
+ +

Form AR4EC - State Income Tax

+ + + +
+ +

Form A-4 - State Income Tax

+ + +
+ +

Form W-4 - State Income Tax

+ + + + +
+ +

Form W-4 - State Income Tax

+ + +
+ +

Form DE W-4 - State Income Tax

+ + + +
+ +

Form CT-W4 - State Income Tax

+ + +

No additional fields.

@@ -55,6 +96,79 @@ + +

Form HI HW-4 - State Income Tax

+ + + +
+ +

Form IA W-4 - State Income Tax

+ + + +
+ +

Form ID W-4 - State Income Tax

+ + +
+ +

Form IL-W-4 - State Income Tax

+ + + +
+ +

Form IN WH-4 - State Income Tax

+ + + +
+ +

Form KS K-4 - State Income Tax

+ + + + +
+ +

No additional fields.

+ + +
+ +

Form LA L-4 - State Income Tax

+ + + + +
+ +

Form W-4ME - State Income Tax

+ + + + +
+ +

Form MI-W4 - State Income Tax

+ + + +
+ +

Form W-4MN - State Income Tax

+ + + +
+ +

Form MO W-4 - State Income Tax

+ + + +

Form 89-350 - State Income Tax

@@ -67,19 +181,97 @@
+ +

Form NC-4 - State Income Tax

+ + + +
+ +

Form ND W-4 - State Income Tax

+ + +
+ +

Form NC-4 - State Income Tax

+ + + + +
+ +

No additional fields.

+
+ +

Form NJ-W4 - State Income Tax

+ + + + +
+ +

Form NM W-4 - State Income Tax

+ +
+ +

No additional fields.

+
+ +

Form NY IT-2104 - State Income Tax

+ + + +

Form IT-4 - State Income Tax

+ +

Form OK-W-4 - State Income Tax

+ + + + +
+ +

Form RI W-4 - State Income Tax

+ + + +
+ +

Form SC W-4 - State Income Tax

+ + + +
+ +

No additional fields.

+
+ +

No additional fields.

+

No additional fields.

+ +

Form UT W-4 - State Income Tax

+ + +
+ +

Form VT W-4VT - State Income Tax

+ + + + +

Form VA-4/VA-4P - State Income Tax

@@ -91,6 +283,22 @@

No additional fields.

Ensure that your Employee and Employer workers' comp code fields are filled in for WA LNI withholding.

+ +

Form WV/IT-104 - State Income Tax

+ + + +
+ +

Form WT-4 - State Income Tax

+ + + + +
+ +

No additional fields.

+