Files
suite/l10n_us_hr_payroll/models/federal/fed_941.py
Jared Kipe be1fd5c8d2 [IMP] l10n_us_hr_payroll: Rules and improvements. (+104 squashed commits)
Squashed commits:
[9ca3d040] [FIX] l10n_us_hr_payroll: payslip category sum over date range now includes child categories
[7a92b96e] [FIX] l10n_us_hr_payroll: remove overwrite to correct wage calculation above
[45d130ce] [IMP] l10n_us_hr_payroll: Add migration code to handle known issues from Odoo S.A. migrations.
[54bffced] [FIX] l10n_us_hr_payroll: add missing `semi-monthly` as a default schedule pay
[d7206395] [IMP] l10n_us_hr_payroll: common test call paramaterize defaults for Structure Type and Resource Calendar
[a1174740] [FIX] l10n_us_hr_payroll : Fixed exempt test case for 2019.
[2d8ec31b] [IMP] l10n_us_hr_payroll: Improved Tax table and improved Test case for NJ New Jersey 2020
[51f61ab5] [IMP] l10n_us_hr_payroll: Added comment and improved Test case for MS Mississippi 2020
[5bfe38f3] [IMP] l10n_us_hr_payroll: Improved Test case for MI Michigan 2020
[c21aa7a7] [IMP] l10n_us_hr_payroll: Added comment for MN Minnesota 2020
[ed67319a] [IMP] l10n_us_hr_payroll: Added comment and improved Test case for MO Missouri 2020
[cc68ea2e] [IMP] l10n_us_hr_payroll: Added Tax table and improved Test case for MT Montana 2020
[9450418c] [IMP] l10n_us_hr_payroll: Added Tax table and improved Test case for ID Idaho 2020
[c389748c] [IMP] l10n_us_hr_payroll: Added Tax table and improved Test case for KY Kentucky 2020
[6d4171fc] [IMP] l10n_us_hr_payroll: Reformat tax table, improved comments and test case for IA Iowa 2020
[77588bc6] [IMP] l10n_us_hr_payroll: Improved Tax table and Test case for HI Hawaii 2020
[585f8cbf] [IMP] l10n_us_hr_payroll: Added Tax table for 2020 and improved Test case for GA Georgia 2020
[92a89e59] [IMP] l10n_us_hr_payroll: Reformat tax table, improved comments and test case for CA California 2020
[785b33e3] [IMP] l10n_us_hr_payroll: Improved comments and test case for CT Connecticut 2020
[13198a9e] [IMP] l10n_us_hr_payroll: Improved test case for CO Colorado 2020
[c65b62a7] [IMP] l10n_us_hr_payroll: Improved comments and test case for AR Arkansas 2020
[e01eeb65] [IMP] l10n_us_hr_payroll: Improved test case for AZ Arizona 2020
[5cf0b69e] [IMP] l10n_us_hr_payroll: Improved comments, Tax table, filing status and test case for AL Alabama 2020
[64436b6e] [IMP] l10n_us_hr_payroll: Improved comments and test case for NM New Mexico 2020
[c395c8a9] [IMP] l10n_us_hr_payroll: Added Comment, removed one filing status which was not used in calculation and improve test case for exempt for NC North Carolina 2020
[ff4adfe8] [IMP] l10n_us_hr_payroll: Comment add for table for VA Virginia 2020
[9fc9b3b6] [IMP] l10n_us_hr_payroll: Reformat Tax table and changed wage for VT Vermont 2020
[5c96026b] [IMP] l10n_us_hr_payroll: Reformat Tax table and changed SUTA rate for RI Rhode Island 2020
[2a2abb62] [IMP] l10n_us_hr_payroll: Reformat Tax table, changed SUTA rate and improved test case for UT Utah 2020.
[42edfc06] [IMP] l10n_us_hr_payroll: Refactored Tax table, changed filing status string and Improved test case for KS Kansas 2020.
[733e721a] [IMP] l10n_us_hr_payroll: Reformat Tax table, changed field string and improved test case for OK Oklahoma 2020
[7c2d9a20] [IMP] l10n_us_hr_payroll: Reformat Tax table for WV West Virginia 2020.
[91630c86] [IMP] l10n_us_hr_payroll: Refactored Tax table, changed tax rate and added additional withholding field. Improved test case for ME Maine 2020.
[9c62ebaf] [IMP] l10n_us_hr_payroll: Refactored Tax table and Improved test case for NE Nebraska 2020.
[88118297] [IMP] l10n_us_hr_payroll: Refactored  Tax table and Improved test case for ME Maine 2020.
[641bb815] [IMP] l10n_us_hr_payroll: Refactored sit rate tax table and added allowance field and apply on calculation. Also Improved test case for for ND North Dakota 2020.
[f6f81615] [IMP] l10n_us_hr_payroll: Changed Form name and additional withholding field string for IN Indiana 2020.
[e4c9774f] [IMP] l10n_us_hr_payroll: Added additional withholding, changed suta rate for 2020 and Improved test for SC South Carolina 2020.
[91887067] [IMP] l10n_us_hr_payroll: Improved test and restructured table for WI Wisconsin 2020.
[9110d174] [FIX] l10n_us_hr_payroll: Updated NY New York 2020 rates and tests.
[1a7c26d8] [FIX]  l10n_us_hr_payroll: Added exempt on filing status for NY.
[8f447aaa] [IMP] l10n_us_hr_payroll: Changed wage base and suta rate for NY New York 2019/2020.
[e9a53918] [IMP] l10n_us_hr_payroll: Changed suta rate for WY Wyoming 2020.

H2914
[eddc6431] [IMP] l10n_us_hr_payroll: Changed suta rate and added exempt.

H2816
[dff4a2ca] [IMP] l10n_us_hr_payroll: For Rhode Island 13.0
[baea9412] [IMP] l10n_us_hr_payroll: For West Virginia 13.0
[8fed8e7b] [IMP] l10n_us_hr_payroll: For Wisconsin 13.0
[57182a87] [IMP] l10n_us_hr_payroll: For South Dakota 13.0
[1011c62e] [IMP] l10n_us_hr_payroll: For Tennessee 13.0
[688a3cc1] [IMP] l10n_us_hr_payroll: For Utah 13.0
[ded656db] [IMP] l10n_us_hr_payroll: For Vermont 13.0
[a0da1841] [IMP] l10n_us_hr_payroll: Port `l10n_us_wy_hr_payroll` WY Wyoming including migration.
[977cc3af] [IMP] l10n_us_hr_payroll: For Oklahoma 13.0
[68a0697c] [FIX]l10n_us_hr_payroll: Spell mistake on Kansas state payroll.
[addd5f03] [IMP] l10n_us_hr_payroll: For Kentucky 13.0
[4fb48854] [IMP] l10n_us_hr_payroll: For Kansas 13.0
[60d40449] [IMP] l10n_us_hr_payroll: For Nevada 13.0
[2475250f] [IMP] l10n_us_hr_payroll: For Maine 13.0
[1234467d] [IMP] l10n_us_hr_payroll: For North Dakota 13.0
[d1642bbe] IMP `l10n_us_hr_payroll` Allow configurable changes to payslip summing behavior.

In stock Odoo, summing anything in payroll rules (but most importantly rule amounts and category amounts by code), the considered payslips are referenced from their `date_from` field.  However in the USA, it is in fact the `date_to` that is more important (or accounting date). A Payslip made for 2019-12-20 to 2020-01-04 should in fact be considered a '2020' payslip, and thus the summation on other '2020' payslips must find it by considering payslips `date_to`.
[0af81085] IMP `l10n_us_hr_payroll` Port `l10n_us_ny_hr_payroll` NY New York including migration
[bc5c0b47] IMP `l10n_us_hr_payroll` for Nebraska 13.0
[6f3120f8] IMP `l10n_us_hr_payroll` Port `l10n_us_sc_hr_payroll` SC South Carolina including migration
[9bee1ce7] IMP `l10n_us_hr_payroll` Port `l10n_us_la_hr_payroll` LA Louisiana including migration
[368a7e59] IMP `l10n_us_hr_payroll` for Indiana 13.0
[c7647d08] IMP `l10n_us_hr_payroll` for New Hampshire 13.0
[a738a0af] IMP `l10n_us_hr_payroll` for New Mexico 13.0
[d2898035] IMP `l10n_us_hr_payroll` Port `l10n_us_ia_hr_payroll` IA Iowa including migration
[acdd3d43] IMP `l10n_us_hr_payroll` for Colorado 13.0
[e1eccfc2] IMP `l10n_us_hr_payroll` Port `l10n_us_de_hr_payroll` DE Delaware including migration
[7b4adef4] IMP `l10n_us_hr_payroll` Port `l10n_us_hi_hr_payroll` HI Hawaii including migration
[28eb5b9d] FIX `l10n_us_hr_payroll` Don't give error on Zero wage in FIT
[498137cb] FIX `l10n_us_hr_payroll` Port `l10n_us_id_hr_payroll` Remove supplier from the Partners..
[8895e59f] FIX `l10n_us_hr_payroll` Port `l10n_us_ca_hr_payroll` Added test case on file.
[0082fce8] IMP `l10n_us_hr_payroll` Port `l10n_us_id_hr_payroll` ID Idaho including migration
[92f6d30c] IMP `l10n_us_hr_payroll` Port `l10n_us_ca_hr_payroll` CA California including migration
[2059172b] IMP `l10n_us_hr_payroll` Port `l10n_us_ct_hr_payroll` CT Connecticut including migration
[dd8f7369] IMP `l10n_us_hr_payroll` Port `l10n_us_al_hr_payroll` AL Alabama including migration
[d5c3e427] IMP `l10n_us_hr_payroll` Port `l10n_us_ak_hr_payroll` AK Alaska including migration
[fbba5b2b] FIX `l10n_us_hr_payroll` Changed SUTA Rate for Illinois 2020.
[18421d01] IMP `l10n_us_hr_payroll` Port `l10n_us_az_hr_payroll` AZ Arizona including migration
[f960d135] IMP `l10n_us_hr_payroll` Port `l10n_us_il_hr_payroll` IL Illinois including migration
[b85e7483] IMP `l10n_us_hr_payroll` Port `l10n_us_ar_hr_payroll` AR Arkansas including migration
[61e9530f] IMP `l10n_us_hr_payroll` Create tax exempt categories for table coverage from IRS Pub. 15-B
[38decf71] IMP `l10n_us_hr_payroll` Port `l10n_us_mn_hr_payroll` MN Minnesota including migration
[2c9dca19] IMP `l10n_us_hr_payroll` Port `l10n_us_mi_hr_payroll` MI Michigan including migration
[e175ecbb] IMP `l10n_us_hr_payroll` Port `l10n_us_nc_hr_payroll` NC North Carolina including migration
[db689da4] IMP `l10n_us_hr_payroll` Port `l10n_us_nj_hr_payroll` NJ New Jersey including migration
[130ce65c] IMP `l10n_us_hr_payroll` Add MO Missouri (unemployment, income tax)
[4d4fcd45] IMP `l10n_us_hr_payroll` Use the raw ER rate for Washington LNI (instead of the combined rate and removing EE portion)
[45fb9682] FIX `l10n_us_hr_payroll` Missing Parent Category and Code not matching pattern.
[3ae7b859] IMP `l10n_us_hr_payroll` Refactor to simply tax exempt deductions.
[30eafd14] IMP `l10n_us_hr_payroll` Add MS Mississippi (unemployment, income tax)
[2f7e7b96] IMP `l10n_us_hr_payroll` Add GA Georgia (unemployment, income tax)
[3d79ed81] IMP `l10n_us_hr_payroll` Add form name in Virginia's state box.
[2e6c7050] IMP `l10n_us_hr_payroll` Add VA Virginia (unemployment, income tax)
[8ae58731] IMP `l10n_us_hr_payroll` Add TX Texas (unemployment, OA, ETIA)
[f83bf47c] IMP `l10n_us_hr_payroll` Add WA Washington (unemployment, lni, fml)
[1d661f8d] IMP `l10n_us_hr_payroll` Add OH Ohio (unemployment, income tax)
[edbc8c59] IMP `l10n_us_hr_payroll` Add MT Montana (unemployment (with AFT), income tax)
[dfe38521] IMP `l10n_us_hr_payroll` Implement generic state income tax exempt and additional fields.  Include in PA Tests and State Form section.
[900bc138] IMP `l10n_us_hr_payroll` Add Generic SIT Category and method, add PA Pennsylvania (unemployment (ER, EE), income tax)
[dcafce90] IMP `l10n_us_hr_payroll` Refactor SUTA tests into generic test. (Reworked Florida 2020) (+1 squashed commit)
Squashed commits:
[667cc8c4] IMP `l10n_us_hr_payroll` Add Generic SUTA Category and method, add FL Florida (unemployment, no income tax)
2021-10-07 13:09:15 +00:00

321 lines
13 KiB
Python

# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details.
# import logging
# _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.
:return: result, result_rate (wage, percent)
"""
exempt = payslip.contract_id.us_payroll_config_value('fed_941_fica_exempt')
if exempt:
return 0.0, 0.0
# Determine Rate.
result_rate = -payslip.rule_parameter('fed_941_fica_ss_rate')
# Determine Wage
wage = fica_wage(payslip, categories)
if not wage:
return 0.0, 0.0
ytd_wage = fica_wage_ytd(payslip, categories)
wage_base = payslip.rule_parameter('fed_941_fica_ss_wage_base')
remaining = wage_base - ytd_wage
if remaining < 0.0:
result = 0.0
elif remaining < wage:
result = remaining
else:
result = wage
return result, result_rate
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.
:return: result, result_rate (wage, percent)
"""
exempt = payslip.contract_id.us_payroll_config_value('fed_941_fica_exempt')
if exempt:
return 0.0, 0.0
# Determine Rate.
result_rate = -payslip.rule_parameter('fed_941_fica_m_rate')
# Determine Wage
wage = fica_wage(payslip, categories)
if not wage:
return 0.0, 0.0
ytd_wage = fica_wage_ytd(payslip, categories)
wage_base = float(payslip.rule_parameter('fed_941_fica_m_wage_base')) # inf
remaining = wage_base - ytd_wage
if remaining < 0.0:
result = 0.0
elif remaining < wage:
result = remaining
else:
result = wage
return result, result_rate
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.
:return: result, result_rate (wage, percent)
"""
exempt = payslip.contract_id.us_payroll_config_value('fed_941_fica_exempt')
if exempt:
return 0.0, 0.0
# Determine Rate.
result_rate = -payslip.rule_parameter('fed_941_fica_m_add_rate')
# Determine Wage
wage = fica_wage(payslip, categories)
if not wage:
return 0.0, 0.0
ytd_wage = fica_wage_ytd(payslip, categories)
wage_start = payslip.rule_parameter('fed_941_fica_m_add_wage_start')
existing_wage = ytd_wage - wage_start
if existing_wage >= 0.0:
result = wage
elif wage + existing_wage > 0.0:
result = wage + existing_wage
else:
result = 0.0
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.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.
:return: result, result_rate (wage, percent)
"""
filing_status = payslip.contract_id.us_payroll_config_value('fed_941_fit_w4_filing_status')
if not filing_status:
return 0.0, 0.0
schedule_pay = payslip.contract_id.schedule_pay
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:
# Large changes in Federal Income Tax in 2020 and the W4
# We will assume that your W4 is the 2020 version
# Steps are from IRS Publication 15-T
#
# Step 1
working_wage = wage
is_nra = payslip.contract_id.us_payroll_config_value('fed_941_fit_w4_is_nonresident_alien')
if is_nra:
nra_table = payslip.rule_parameter('fed_941_fit_nra_additional')
working_wage += nra_table.get(schedule_pay, 0.0)
#_logger.warn(' is_nrm after wage: ' + str(working_wage))
pay_periods = payslip.dict.get_pay_periods_in_year()
wage_annual = pay_periods * working_wage
#_logger.warn('annual wage: ' + str(wage_annual))
wage_annual += payslip.contract_id.us_payroll_config_value('fed_941_fit_w4_other_income')
#_logger.warn(' after other income: ' + str(wage_annual))
deductions = payslip.contract_id.us_payroll_config_value('fed_941_fit_w4_deductions')
#_logger.warn('deductions from W4: ' + str(deductions))
higher_rate_type = payslip.contract_id.us_payroll_config_value('fed_941_fit_w4_multiple_jobs_higher')
if not higher_rate_type:
deductions += 12900.0 if filing_status == 'married' else 8600.0
#_logger.warn(' deductions after standard deduction: ' + str(deductions))
adjusted_wage_annual = wage_annual - deductions
if adjusted_wage_annual < 0.0:
adjusted_wage_annual = 0.0
#_logger.warn('adusted annual wage: ' + str(adjusted_wage_annual))
# Step 2
if filing_status == 'single':
tax_tables = payslip.rule_parameter('fed_941_fit_table_single')
elif filing_status == 'married':
tax_tables = payslip.rule_parameter('fed_941_fit_table_married')
else:
# married_as_single for historic reasons
tax_tables = payslip.rule_parameter('fed_941_fit_table_hh')
if higher_rate_type:
tax_table = tax_tables['higher']
else:
tax_table = tax_tables['standard']
selected_row = None
for row in tax_table:
if row[0] <= adjusted_wage_annual:
selected_row = row
else:
# First row where wage is higher than adjusted_wage_annual
break
wage_threshold, base_withholding_amount, marginal_rate = selected_row
#_logger.warn(' selected row: ' + str(selected_row))
working_wage = adjusted_wage_annual - wage_threshold
tentative_withholding_amount = (working_wage * marginal_rate) + base_withholding_amount
tentative_withholding_amount = tentative_withholding_amount / pay_periods
#_logger.warn('tenative withholding amount: ' + str(tentative_withholding_amount))
# Step 3
dependent_credit = payslip.contract_id.us_payroll_config_value('fed_941_fit_w4_dependent_credit')
dependent_credit = dependent_credit / pay_periods
#_logger.warn('dependent credit (per period): ' + str(dependent_credit))
tentative_withholding_amount -= dependent_credit
if tentative_withholding_amount < 0.0:
tentative_withholding_amount = 0.0
# Step 4
withholding_amount = tentative_withholding_amount + payslip.contract_id.us_payroll_config_value('fed_941_fit_w4_additional_withholding')
#_logger.warn('final withholding amount: ' + str(withholding_amount))
# Ideally we would set the 'taxable wage' as the result and compute the percentage tax.
# This is off by 1 penny across our tests, but I feel like it is worth it for the added reporting.
# - Jared Kipe 2019 during Odoo 13.0 rewrite.
#
# return -withholding_amount, 100.0
return wage, -(withholding_amount / wage * 100.0)
else:
working_wage = wage
is_nra = payslip.contract_id.us_payroll_config_value('fed_941_fit_w4_is_nonresident_alien')
if is_nra:
nra_table = payslip.rule_parameter('fed_941_fit_nra_additional')
working_wage += nra_table[schedule_pay]
allowance_table = payslip.rule_parameter('fed_941_fit_allowance')
allowances = payslip.contract_id.us_payroll_config_value('fed_941_fit_w4_allowances')
working_wage -= allowance_table[schedule_pay] * allowances
tax = 0.0
last_limit = 0.0
if filing_status == 'married':
tax_table = payslip.rule_parameter('fed_941_fit_table_married')
else:
tax_table = payslip.rule_parameter('fed_941_fit_table_single')
for row in tax_table[schedule_pay]:
limit, base, percent = row
limit = float(limit) # 'inf'
if working_wage <= limit:
tax = base + ((working_wage - last_limit) * (percent / 100.0))
break
last_limit = limit
tax += payslip.contract_id.us_payroll_config_value('fed_941_fit_w4_additional_withholding')
# Ideally we would set the 'taxable wage' as the result and compute the percentage tax.
# This is off by 1 penny across our tests, but I feel like it is worth it for the added reporting.
# - Jared Kipe 2019 during Odoo 13.0 rewrite.
#
# return -tax, 100.0
return wage, -(tax / wage * 100.0)