mirror of
https://gitlab.com/hibou-io/hibou-odoo/suite.git
synced 2025-01-20 12:37:31 +02:00
[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)
This commit is contained in:
@@ -1,5 +1,8 @@
|
||||
# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details.
|
||||
|
||||
from . import browsable_object
|
||||
from . import hr_contract
|
||||
from . import hr_payslip
|
||||
from . import res_config_settings
|
||||
from . import update
|
||||
from . import us_payroll_config
|
||||
|
||||
148
l10n_us_hr_payroll/models/browsable_object.py
Normal file
148
l10n_us_hr_payroll/models/browsable_object.py
Normal file
@@ -0,0 +1,148 @@
|
||||
# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details.
|
||||
|
||||
from odoo import fields
|
||||
from odoo.addons.hr_payroll.models import browsable_object
|
||||
|
||||
|
||||
class BrowsableObject(object):
|
||||
def __init__(self, employee_id, dict, env):
|
||||
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 _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.{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 _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.{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):
|
||||
res = self._sum(code, from_date, to_date)
|
||||
return res and res[0] or 0.0
|
||||
|
||||
def sum_hours(self, code, from_date, to_date=None):
|
||||
res = self._sum(code, from_date, to_date)
|
||||
return res and res[1] or 0.0
|
||||
|
||||
|
||||
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(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):
|
||||
if to_date is None:
|
||||
to_date = fields.Date.today()
|
||||
|
||||
self.env['hr.payslip'].flush(['credit_note', 'employee_id', 'state', 'date_from', 'date_to'])
|
||||
self.env['hr.payslip.line'].flush(['total', 'slip_id', 'category_id'])
|
||||
self.env['hr.salary.rule.category'].flush(['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
|
||||
|
||||
@property
|
||||
def paid_amount(self):
|
||||
return self.dict._get_paid_amount()
|
||||
|
||||
|
||||
# Patch over Core
|
||||
browsable_object.BrowsableObject.__init__ = BrowsableObject.__init__
|
||||
browsable_object.BrowsableObject._compile_browsable_query = BrowsableObject._compile_browsable_query
|
||||
browsable_object.InputLine._compile_browsable_query = InputLine._compile_browsable_query
|
||||
browsable_object.InputLine.sum = InputLine.sum
|
||||
browsable_object.WorkedDays._compile_browsable_query = WorkedDays._compile_browsable_query
|
||||
browsable_object.WorkedDays.sum = WorkedDays.sum
|
||||
browsable_object.Payslips._compile_browsable_query = Payslips._compile_browsable_query
|
||||
browsable_object.Payslips.sum = Payslips.sum
|
||||
browsable_object.Payslips.sum_category = Payslips.sum_category
|
||||
@@ -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.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 - WAGE_US_940_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.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('WAGE_US_940_FUTA_EXEMPT', str(year) + '-01-01', str(year+1) + '-01-01')
|
||||
ytd_wage += payslip.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.rule_parameter('fed_940_futa_wage_base')
|
||||
remaining = wage_base - ytd_wage
|
||||
|
||||
wage = categories.GROSS - categories.WAGE_US_940_FUTA_EXEMPT
|
||||
|
||||
if remaining < 0.0:
|
||||
result = 0.0
|
||||
elif remaining < wage:
|
||||
|
||||
@@ -4,10 +4,54 @@
|
||||
# _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 - WAGE_US_941_FICA_EXEMPT
|
||||
:return: result, result_rate (wage, percent)
|
||||
"""
|
||||
exempt = payslip.contract_id.us_payroll_config_value('fed_941_fica_exempt')
|
||||
@@ -18,16 +62,14 @@ def ee_us_941_fica_ss(payslip, categories, worked_days, inputs):
|
||||
result_rate = -payslip.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('WAGE_US_941_FICA_EXEMPT', str(year) + '-01-01', str(year+1) + '-01-01')
|
||||
ytd_wage += payslip.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.rule_parameter('fed_941_fica_ss_wage_base')
|
||||
remaining = wage_base - ytd_wage
|
||||
|
||||
wage = categories.GROSS - categories.WAGE_US_941_FICA_EXEMPT
|
||||
|
||||
if remaining < 0.0:
|
||||
result = 0.0
|
||||
elif remaining < wage:
|
||||
@@ -44,7 +86,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 - WAGE_US_941_FICA_EXEMPT
|
||||
:return: result, result_rate (wage, percent)
|
||||
"""
|
||||
exempt = payslip.contract_id.us_payroll_config_value('fed_941_fica_exempt')
|
||||
@@ -55,16 +96,14 @@ def ee_us_941_fica_m(payslip, categories, worked_days, inputs):
|
||||
result_rate = -payslip.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('WAGE_US_941_FICA_EXEMPT', str(year) + '-01-01', str(year+1) + '-01-01')
|
||||
ytd_wage += payslip.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.rule_parameter('fed_941_fica_m_wage_base')) # inf
|
||||
remaining = wage_base - ytd_wage
|
||||
|
||||
wage = categories.GROSS - categories.WAGE_US_941_FICA_EXEMPT
|
||||
|
||||
if remaining < 0.0:
|
||||
result = 0.0
|
||||
elif remaining < wage:
|
||||
@@ -81,8 +120,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.contract_id.us_payroll_config_value('fed_941_fica_exempt')
|
||||
@@ -93,16 +130,14 @@ def ee_us_941_fica_m_add(payslip, categories, worked_days, inputs):
|
||||
result_rate = -payslip.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('WAGE_US_941_FICA_EXEMPT', str(year) + '-01-01', str(year+1) + '-01-01')
|
||||
ytd_wage += payslip.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.rule_parameter('fed_941_fica_m_add_wage_start')
|
||||
existing_wage = ytd_wage - wage_start
|
||||
|
||||
wage = categories.GROSS - categories.WAGE_US_941_FICA_EXEMPT
|
||||
|
||||
if existing_wage >= 0.0:
|
||||
result = wage
|
||||
elif wage + existing_wage > 0.0:
|
||||
@@ -113,11 +148,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.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 - WAGE_US_941_FIT_EXEMPT
|
||||
:return: result, result_rate (wage, percent)
|
||||
"""
|
||||
filing_status = payslip.contract_id.us_payroll_config_value('fed_941_fit_w4_filing_status')
|
||||
@@ -125,7 +203,10 @@ def ee_us_941_fit(payslip, categories, worked_days, inputs):
|
||||
return 0.0, 0.0
|
||||
|
||||
schedule_pay = payslip.contract_id.schedule_pay
|
||||
wage = categories.GROSS - categories.WAGE_US_941_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:
|
||||
|
||||
@@ -6,6 +6,11 @@ from .us_payroll_config import FUTA_TYPE_NORMAL, \
|
||||
FUTA_TYPE_EXEMPT
|
||||
|
||||
|
||||
class HrPayrollStructureType(models.Model):
|
||||
_inherit = 'hr.payroll.structure.type'
|
||||
default_schedule_pay = fields.Selection(selection_add=[('semi-monthly', 'Semi-monthly')])
|
||||
|
||||
|
||||
class HrPayrollStructure(models.Model):
|
||||
_inherit = 'hr.payroll.structure'
|
||||
schedule_pay = fields.Selection(selection_add=[('semi-monthly', 'Semi-monthly')])
|
||||
|
||||
@@ -9,6 +9,48 @@ from .federal.fed_941 import ee_us_941_fica_ss, \
|
||||
er_us_941_fica_ss, \
|
||||
er_us_941_fica_m, \
|
||||
ee_us_941_fit
|
||||
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):
|
||||
@@ -37,6 +79,48 @@ class HRPayslip(models.Model):
|
||||
'er_us_941_fica_ss': er_us_941_fica_ss,
|
||||
'er_us_941_fica_m': er_us_941_fica_m,
|
||||
'ee_us_941_fit': ee_us_941_fit,
|
||||
'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,
|
||||
})
|
||||
return res
|
||||
|
||||
|
||||
24
l10n_us_hr_payroll/models/res_config_settings.py
Normal file
24
l10n_us_hr_payroll/models/res_config_settings.py
Normal file
@@ -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')
|
||||
1
l10n_us_hr_payroll/models/state/__init__.py
Normal file
1
l10n_us_hr_payroll/models/state/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details.
|
||||
80
l10n_us_hr_payroll/models/state/al_alabama.py
Normal file
80
l10n_us_hr_payroll/models/state/al_alabama.py
Normal file
@@ -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.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.contract_id.us_payroll_config_value('state_income_tax_additional_withholding')
|
||||
tax_table = payslip.rule_parameter('us_al_sit_tax_rate')
|
||||
dependent_rate = payslip.rule_parameter('us_al_sit_dependent_rate')
|
||||
standard_deduction = payslip.rule_parameter('us_al_sit_standard_deduction_rate').get(exemptions, 0.0)
|
||||
personal_exemption = payslip.rule_parameter('us_al_sit_personal_exemption_rate').get(exemptions, 0.0)
|
||||
dependent = payslip.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)
|
||||
47
l10n_us_hr_payroll/models/state/ar_arkansas.py
Normal file
47
l10n_us_hr_payroll/models/state/ar_arkansas.py
Normal file
@@ -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.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.contract_id.us_payroll_config_value('state_income_tax_additional_withholding')
|
||||
sit_tax_rate = payslip.rule_parameter('us_ar_sit_tax_rate')
|
||||
standard_deduction = payslip.rule_parameter('us_ar_sit_standard_deduction_rate')
|
||||
allowances = payslip.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)
|
||||
35
l10n_us_hr_payroll/models/state/az_arizona.py
Normal file
35
l10n_us_hr_payroll/models/state/az_arizona.py
Normal file
@@ -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.contract_id.schedule_pay
|
||||
additional = payslip.contract_id.us_payroll_config_value('state_income_tax_additional_withholding')
|
||||
withholding_percent = payslip.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)
|
||||
98
l10n_us_hr_payroll/models/state/ca_california.py
Normal file
98
l10n_us_hr_payroll/models/state/ca_california.py
Normal file
@@ -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.contract_id.us_payroll_config_value('ca_de4_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')
|
||||
sit_allowances = payslip.contract_id.us_payroll_config_value('ca_de4_sit_allowances')
|
||||
additional_allowances = payslip.contract_id.us_payroll_config_value('ca_de4_sit_additional_allowances')
|
||||
low_income_exemption = payslip.rule_parameter('us_ca_sit_income_exemption_rate')[schedule_pay]
|
||||
estimated_deduction = payslip.rule_parameter('us_ca_sit_estimated_deduction_rate')[schedule_pay]
|
||||
tax_table = payslip.rule_parameter('us_ca_sit_tax_rate')[filing_status].get(schedule_pay)
|
||||
standard_deduction = payslip.rule_parameter('us_ca_sit_standard_deduction_rate')[schedule_pay]
|
||||
exemption_allowances = payslip.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)
|
||||
45
l10n_us_hr_payroll/models/state/co_colorado.py
Normal file
45
l10n_us_hr_payroll/models/state/co_colorado.py
Normal file
@@ -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.contract_id.us_payroll_config_value('fed_941_fit_w4_filing_status')
|
||||
if not filing_status:
|
||||
return 0.0, 0.0
|
||||
|
||||
state_exempt = payslip.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.contract_id.us_payroll_config_value('state_income_tax_additional_withholding')
|
||||
exemption_rate = payslip.rule_parameter('us_co_sit_exemption_rate')
|
||||
tax_rate = payslip.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)
|
||||
76
l10n_us_hr_payroll/models/state/ct_connecticut.py
Normal file
76
l10n_us_hr_payroll/models/state/ct_connecticut.py
Normal file
@@ -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.contract_id.us_payroll_config_value('state_income_tax_additional_withholding')
|
||||
withholding_code = payslip.contract_id.us_payroll_config_value('ct_w4na_sit_code')
|
||||
exemption_table = payslip.rule_parameter('us_ct_sit_personal_exemption_rate').get(withholding_code, [('inf', 0.0)])
|
||||
initial_tax_tbl = payslip.rule_parameter('us_ct_sit_initial_tax_rate').get(withholding_code, [('inf', 0.0, 0.0)])
|
||||
tax_table = payslip.rule_parameter('us_ct_sit_tax_rate').get(withholding_code, [('inf', 0.0)])
|
||||
recapture_table = payslip.rule_parameter('us_ct_sit_recapture_rate').get(withholding_code, [('inf', 0.0)])
|
||||
decimal_table = payslip.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)
|
||||
49
l10n_us_hr_payroll/models/state/de_delaware.py
Normal file
49
l10n_us_hr_payroll/models/state/de_delaware.py
Normal file
@@ -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.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.contract_id.us_payroll_config_value('state_income_tax_additional_withholding')
|
||||
tax_table = payslip.rule_parameter('us_de_sit_tax_rate')
|
||||
personal_exemption = payslip.rule_parameter('us_de_sit_personal_exemption_rate')
|
||||
allowances = payslip.contract_id.us_payroll_config_value('de_w4_sit_dependent')
|
||||
standard_deduction = payslip.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)
|
||||
51
l10n_us_hr_payroll/models/state/ga_georgia.py
Normal file
51
l10n_us_hr_payroll/models/state/ga_georgia.py
Normal file
@@ -0,0 +1,51 @@
|
||||
# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details.
|
||||
|
||||
from .general import _state_applies, sit_wage
|
||||
|
||||
|
||||
def ga_georgia_state_income_withholding(payslip, categories, worked_days, inputs):
|
||||
"""
|
||||
Returns SIT eligible wage and rate.
|
||||
|
||||
:return: result, result_rate (wage, percent)
|
||||
"""
|
||||
state_code = 'GA'
|
||||
if not _state_applies(payslip, state_code):
|
||||
return 0.0, 0.0
|
||||
ga_filing_status = payslip.contract_id.us_payroll_config_value('ga_g4_sit_filing_status')
|
||||
if not ga_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.contract_id.schedule_pay
|
||||
additional = payslip.contract_id.us_payroll_config_value('state_income_tax_additional_withholding')
|
||||
dependent_allowances = payslip.contract_id.us_payroll_config_value('ga_g4_sit_dependent_allowances')
|
||||
additional_allowances = payslip.contract_id.us_payroll_config_value('ga_g4_sit_additional_allowances')
|
||||
dependent_allowance_rate = payslip.rule_parameter('us_ga_sit_dependent_allowance_rate').get(schedule_pay)
|
||||
personal_allowance = payslip.rule_parameter('us_ga_sit_personal_allowance').get(ga_filing_status, {}).get(schedule_pay)
|
||||
deduction = payslip.rule_parameter('us_ga_sit_deduction').get(ga_filing_status, {}).get(schedule_pay)
|
||||
withholding_rate = payslip.rule_parameter('us_ga_sit_rate').get(ga_filing_status, {}).get(schedule_pay)
|
||||
if not all((dependent_allowance_rate, personal_allowance, deduction, withholding_rate)):
|
||||
return 0.0, 0.0
|
||||
|
||||
after_standard_deduction = wage - deduction
|
||||
allowances = dependent_allowances + additional_allowances
|
||||
working_wages = after_standard_deduction - (personal_allowance + (allowances * dependent_allowance_rate))
|
||||
|
||||
withholding = 0.0
|
||||
if working_wages > 0.0:
|
||||
prior_row_base = 0.0
|
||||
for row in withholding_rate:
|
||||
wage_base, base, rate = row
|
||||
wage_base = float(wage_base)
|
||||
if working_wages < wage_base:
|
||||
withholding = base + ((working_wages - prior_row_base) * rate / 100.0)
|
||||
break
|
||||
prior_row_base = wage_base
|
||||
|
||||
withholding += additional
|
||||
return wage, -((withholding / wage) * 100.0)
|
||||
131
l10n_us_hr_payroll/models/state/general.py
Normal file
131
l10n_us_hr_payroll/models/state/general.py
Normal file
@@ -0,0 +1,131 @@
|
||||
# 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.contract_id.us_payroll_config_value('state_code')
|
||||
|
||||
|
||||
# Export for eval context
|
||||
is_us_state = _state_applies
|
||||
|
||||
|
||||
def _general_rate(payslip, wage, ytd_wage, wage_base=None, wage_start=None, rate=None):
|
||||
"""
|
||||
Function parameters:
|
||||
wage_base, wage_start, rate can either be strings (rule_parameters) or floats
|
||||
:return: result, result_rate(wage, percent)
|
||||
"""
|
||||
|
||||
# Resolve parameters. On exception, return (probably missing a year, would rather not have exception)
|
||||
if wage_base and isinstance(wage_base, str):
|
||||
try:
|
||||
wage_base = payslip.rule_parameter(wage_base)
|
||||
except (KeyError, UserError):
|
||||
return 0.0, 0.0
|
||||
|
||||
if wage_start and isinstance(wage_start, str):
|
||||
try:
|
||||
wage_start = payslip.rule_parameter(wage_start)
|
||||
except (KeyError, UserError):
|
||||
return 0.0, 0.0
|
||||
|
||||
if rate and isinstance(rate, str):
|
||||
try:
|
||||
rate = payslip.rule_parameter(rate)
|
||||
except (KeyError, UserError):
|
||||
return 0.0, 0.0
|
||||
|
||||
if not rate:
|
||||
return 0.0, 0.0
|
||||
else:
|
||||
# Rate assumed positive percentage!
|
||||
rate = -rate
|
||||
|
||||
if wage_base:
|
||||
remaining = wage_base - ytd_wage
|
||||
if remaining < 0.0:
|
||||
result = 0.0
|
||||
elif remaining < wage:
|
||||
result = remaining
|
||||
else:
|
||||
result = wage
|
||||
|
||||
# _logger.warn(' wage_base method result: ' + str(result) + ' rate: ' + str(rate))
|
||||
return result, rate
|
||||
if wage_start:
|
||||
if ytd_wage >= wage_start:
|
||||
# _logger.warn(' wage_start 1 method result: ' + str(wage) + ' rate: ' + str(rate))
|
||||
return wage, rate
|
||||
if ytd_wage + wage <= wage_start:
|
||||
# _logger.warn(' wage_start 2 method result: ' + str(0.0) + ' rate: ' + str(0.0))
|
||||
return 0.0, 0.0
|
||||
# _logger.warn(' wage_start 3 method result: ' + str((wage - (wage_start - ytd_wage))) + ' rate: ' + str(rate))
|
||||
return (wage - (wage_start - ytd_wage)), rate
|
||||
|
||||
# If the wage doesn't have a start or a base
|
||||
# _logger.warn(' basic result: ' + str(wage) + ' rate: ' + str(rate))
|
||||
return wage, rate
|
||||
|
||||
|
||||
def general_state_unemployment(payslip, categories, worked_days, inputs, wage_base=None, wage_start=None, rate=None, state_code=None):
|
||||
"""
|
||||
Returns SUTA eligible wage and rate.
|
||||
WAGE = GROSS + DED_FUTA_EXEMPT
|
||||
|
||||
The contract's `futa_type` determines if SUTA should be collected.
|
||||
|
||||
:return: result, result_rate(wage, percent)
|
||||
"""
|
||||
|
||||
if not _state_applies(payslip, state_code):
|
||||
return 0.0, 0.0
|
||||
|
||||
# Determine Eligible.
|
||||
if payslip.contract_id.futa_type in (payslip.contract_id.FUTA_TYPE_EXEMPT, payslip.contract_id.FUTA_TYPE_BASIC):
|
||||
return 0.0, 0.0
|
||||
|
||||
# Determine Wage
|
||||
wage = suta_wage(payslip, categories)
|
||||
if not wage:
|
||||
return 0.0, 0.0
|
||||
|
||||
ytd_wage = suta_wage_ytd(payslip, categories)
|
||||
|
||||
return _general_rate(payslip, wage, ytd_wage, wage_base=wage_base, wage_start=wage_start, rate=rate)
|
||||
|
||||
|
||||
def general_state_income_withholding(payslip, categories, worked_days, inputs, wage_base=None, wage_start=None, rate=None, state_code=None):
|
||||
"""
|
||||
Returns SIT eligible wage and rate.
|
||||
WAGE = GROSS + DED_FIT_EXEMPT
|
||||
|
||||
:return: result, result_rate (wage, percent)
|
||||
"""
|
||||
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
|
||||
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.contract_id.us_payroll_config_value('state_income_tax_additional_withholding')
|
||||
if additional:
|
||||
tax = result * (result_rate / 100.0)
|
||||
tax -= additional # assumed result_rate is negative and that the 'additional' should increase it.
|
||||
return result, ((tax / result) * 100.0)
|
||||
return result, result_rate
|
||||
43
l10n_us_hr_payroll/models/state/hi_hawaii.py
Normal file
43
l10n_us_hr_payroll/models/state/hi_hawaii.py
Normal file
@@ -0,0 +1,43 @@
|
||||
# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details.
|
||||
|
||||
from .general import _state_applies, 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.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.contract_id.us_payroll_config_value('state_income_tax_additional_withholding')
|
||||
allowances = payslip.contract_id.us_payroll_config_value('hi_hw4_sit_allowances')
|
||||
tax_table = payslip.rule_parameter('us_hi_sit_tax_rate')[filing_status]
|
||||
personal_exemption = payslip.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)
|
||||
48
l10n_us_hr_payroll/models/state/ia_iowa.py
Normal file
48
l10n_us_hr_payroll/models/state/ia_iowa.py
Normal file
@@ -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.contract_id.schedule_pay
|
||||
fed_withholding = categories.EE_US_941_FIT
|
||||
additional = payslip.contract_id.us_payroll_config_value('state_income_tax_additional_withholding')
|
||||
allowances = payslip.contract_id.us_payroll_config_value('ia_w4_sit_allowances')
|
||||
standard_deduction = payslip.rule_parameter('us_ia_sit_standard_deduction_rate')[schedule_pay]
|
||||
tax_table = payslip.rule_parameter('us_ia_sit_tax_rate')[schedule_pay]
|
||||
deduction_per_allowance = payslip.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)
|
||||
41
l10n_us_hr_payroll/models/state/id_idaho.py
Normal file
41
l10n_us_hr_payroll/models/state/id_idaho.py
Normal file
@@ -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.contract_id.us_payroll_config_value('id_w4_sit_filing_status')
|
||||
if not filing_status:
|
||||
return 0.0, 0.0
|
||||
|
||||
schedule_pay = payslip.contract_id.schedule_pay
|
||||
allowances = payslip.contract_id.us_payroll_config_value('id_w4_sit_allowances')
|
||||
ictcat_table = payslip.rule_parameter('us_id_sit_ictcat_rate')[schedule_pay]
|
||||
tax_table = payslip.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)
|
||||
35
l10n_us_hr_payroll/models/state/il_illinois.py
Normal file
35
l10n_us_hr_payroll/models/state/il_illinois.py
Normal file
@@ -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.contract_id.us_payroll_config_value('state_income_tax_additional_withholding')
|
||||
basic_allowances_rate = payslip.rule_parameter('us_il_sit_basic_allowances_rate')
|
||||
additional_allowances_rate = payslip.rule_parameter('us_il_sit_additional_allowances_rate')
|
||||
basic_allowances = payslip.contract_id.us_payroll_config_value('il_w4_sit_basic_allowances')
|
||||
additional_allowances = payslip.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)
|
||||
34
l10n_us_hr_payroll/models/state/in_indiana.py
Normal file
34
l10n_us_hr_payroll/models/state/in_indiana.py
Normal file
@@ -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.contract_id.schedule_pay
|
||||
additional = payslip.contract_id.us_payroll_config_value('state_income_tax_additional_withholding')
|
||||
personal_exemption = payslip.contract_id.us_payroll_config_value('in_w4_sit_personal_exemption')
|
||||
personal_exemption_rate = payslip.rule_parameter('us_in_sit_personal_exemption_rate')[schedule_pay][personal_exemption - 1]
|
||||
dependent_exemption = payslip.contract_id.us_payroll_config_value('in_w4_sit_dependent_exemption')
|
||||
dependent_exemption_rate = payslip.rule_parameter('us_in_sit_dependent_exemption_rate')[schedule_pay][dependent_exemption - 1]
|
||||
income_tax_rate = payslip.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)
|
||||
44
l10n_us_hr_payroll/models/state/ks_kansas.py
Normal file
44
l10n_us_hr_payroll/models/state/ks_kansas.py
Normal file
@@ -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.contract_id.us_payroll_config_value('ks_k4_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')
|
||||
allowances = payslip.contract_id.us_payroll_config_value('ks_k4_sit_allowances')
|
||||
allowances_amt = payslip.rule_parameter('us_ks_sit_allowances_rate')[schedule_pay]
|
||||
tax_table = payslip.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)
|
||||
32
l10n_us_hr_payroll/models/state/ky_kentucky.py
Normal file
32
l10n_us_hr_payroll/models/state/ky_kentucky.py
Normal file
@@ -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.contract_id.us_payroll_config_value('state_income_tax_additional_withholding')
|
||||
tax_rate = payslip.rule_parameter('us_ky_sit_tax_rate')
|
||||
standard_deduction = payslip.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)
|
||||
62
l10n_us_hr_payroll/models/state/la_louisiana.py
Normal file
62
l10n_us_hr_payroll/models/state/la_louisiana.py
Normal file
@@ -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.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.contract_id.us_payroll_config_value('la_l4_sit_exemptions')
|
||||
additional = payslip.contract_id.us_payroll_config_value('state_income_tax_additional_withholding')
|
||||
dependent_exemptions = payslip.contract_id.us_payroll_config_value('la_l4_sit_dependents')
|
||||
tax_table = payslip.rule_parameter('us_la_sit_tax_rate')[filing_status]
|
||||
exemption_rate = payslip.rule_parameter('us_la_sit_personal_exemption_rate')
|
||||
dependent_rate = payslip.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)
|
||||
62
l10n_us_hr_payroll/models/state/me_maine.py
Normal file
62
l10n_us_hr_payroll/models/state/me_maine.py
Normal file
@@ -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.contract_id.us_payroll_config_value('me_w4me_sit_filing_status')
|
||||
if not filing_status:
|
||||
return 0.0, 0.0
|
||||
|
||||
exempt = payslip.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.contract_id.us_payroll_config_value('state_income_tax_additional_withholding')
|
||||
allowances = payslip.contract_id.us_payroll_config_value('me_w4me_sit_allowances')
|
||||
tax_rate = payslip.rule_parameter('us_me_sit_tax_rate')[filing_status]
|
||||
personal_exemption = payslip.rule_parameter('us_me_sit_personal_exemption_rate')
|
||||
standard_deduction = payslip.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)
|
||||
35
l10n_us_hr_payroll/models/state/mi_michigan.py
Normal file
35
l10n_us_hr_payroll/models/state/mi_michigan.py
Normal file
@@ -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.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.contract_id.us_payroll_config_value('state_income_tax_additional_withholding')
|
||||
exemption_rate = payslip.rule_parameter('us_mi_sit_exemption_rate')
|
||||
exemption = payslip.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)
|
||||
44
l10n_us_hr_payroll/models/state/mn_minnesota.py
Normal file
44
l10n_us_hr_payroll/models/state/mn_minnesota.py
Normal file
@@ -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.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.contract_id.us_payroll_config_value('state_income_tax_additional_withholding')
|
||||
sit_tax_rate = payslip.rule_parameter('us_mn_sit_tax_rate')[filing_status]
|
||||
allowances_rate = payslip.rule_parameter('us_mn_sit_allowances_rate')
|
||||
allowances = payslip.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)
|
||||
53
l10n_us_hr_payroll/models/state/mo_missouri.py
Normal file
53
l10n_us_hr_payroll/models/state/mo_missouri.py
Normal file
@@ -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.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.contract_id.us_payroll_config_value('state_income_tax_additional_withholding')
|
||||
sit_table = payslip.rule_parameter('us_mo_sit_rate')
|
||||
deduction = payslip.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)
|
||||
46
l10n_us_hr_payroll/models/state/ms_mississippi.py
Normal file
46
l10n_us_hr_payroll/models/state/ms_mississippi.py
Normal file
@@ -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 ms_mississippi_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 = 'MS'
|
||||
if not _state_applies(payslip, state_code):
|
||||
return 0.0, 0.0
|
||||
|
||||
filing_status = payslip.contract_id.us_payroll_config_value('ms_89_350_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.contract_id.us_payroll_config_value('state_income_tax_additional_withholding')
|
||||
exemptions = payslip.contract_id.us_payroll_config_value('ms_89_350_sit_exemption_value')
|
||||
standard_deduction = payslip.rule_parameter('us_ms_sit_deduction').get(filing_status)
|
||||
withholding_rate = payslip.rule_parameter('us_ms_sit_rate')
|
||||
|
||||
wage_annual = wage * pay_periods
|
||||
taxable_income = wage_annual - (exemptions + standard_deduction)
|
||||
if taxable_income <= 0.01:
|
||||
return wage, 0.0
|
||||
|
||||
withholding = 0.0
|
||||
for row in withholding_rate:
|
||||
wage_base, base, rate = row
|
||||
if taxable_income >= wage_base:
|
||||
withholding = base + ((taxable_income - wage_base) * rate)
|
||||
break
|
||||
withholding /= pay_periods
|
||||
withholding = round(withholding)
|
||||
withholding += round(additional)
|
||||
return wage, -((withholding / wage) * 100.0)
|
||||
45
l10n_us_hr_payroll/models/state/mt_montana.py
Normal file
45
l10n_us_hr_payroll/models/state/mt_montana.py
Normal file
@@ -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 mt_montana_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 = 'MT'
|
||||
if not _state_applies(payslip, state_code):
|
||||
return 0.0, 0.0
|
||||
|
||||
if payslip.contract_id.us_payroll_config_value('mt_mw4_sit_exempt'):
|
||||
return 0.0, 0.0
|
||||
|
||||
# Determine Wage
|
||||
wage = sit_wage(payslip, categories)
|
||||
if not wage:
|
||||
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')
|
||||
exemptions = payslip.contract_id.us_payroll_config_value('mt_mw4_sit_exemptions')
|
||||
exemption_rate = payslip.rule_parameter('us_mt_sit_exemption_rate').get(schedule_pay)
|
||||
withholding_rate = payslip.rule_parameter('us_mt_sit_rate').get(schedule_pay)
|
||||
if not exemption_rate or not withholding_rate:
|
||||
return 0.0, 0.0
|
||||
|
||||
adjusted_wage = wage - (exemption_rate * (exemptions or 0))
|
||||
withholding = 0.0
|
||||
if adjusted_wage > 0.0:
|
||||
prior_wage_cap = 0.0
|
||||
for row in withholding_rate:
|
||||
wage_cap, base, rate = row
|
||||
wage_cap = float(wage_cap) # e.g. 'inf'
|
||||
if adjusted_wage < wage_cap:
|
||||
withholding = round(base + ((rate / 100.0) * (adjusted_wage - prior_wage_cap)))
|
||||
break
|
||||
prior_wage_cap = wage_cap
|
||||
withholding += additional
|
||||
return wage, -((withholding / wage) * 100.0)
|
||||
38
l10n_us_hr_payroll/models/state/nc_northcarolina.py
Normal file
38
l10n_us_hr_payroll/models/state/nc_northcarolina.py
Normal file
@@ -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.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.contract_id.schedule_pay
|
||||
additional = payslip.contract_id.us_payroll_config_value('state_income_tax_additional_withholding')
|
||||
allowances = payslip.contract_id.us_payroll_config_value('nc_nc4_sit_allowances')
|
||||
allowances_rate = payslip.rule_parameter('us_nc_sit_allowance_rate').get(schedule_pay)['allowance']
|
||||
deduction = payslip.rule_parameter('us_nc_sit_allowance_rate').get(schedule_pay)['standard_deduction'] if filing_status != 'head_household' else payslip.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)
|
||||
45
l10n_us_hr_payroll/models/state/nd_north_dakota.py
Normal file
45
l10n_us_hr_payroll/models/state/nd_north_dakota.py
Normal file
@@ -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.contract_id.us_payroll_config_value('nd_w4_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')
|
||||
allowance = payslip.contract_id.us_payroll_config_value('nd_w4_sit_allowances')
|
||||
allowance_rate = payslip.rule_parameter('us_nd_sit_allowances_rate')[schedule_pay]
|
||||
tax_rate = payslip.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)
|
||||
49
l10n_us_hr_payroll/models/state/ne_nebraska.py
Normal file
49
l10n_us_hr_payroll/models/state/ne_nebraska.py
Normal file
@@ -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.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.contract_id.us_payroll_config_value('ne_w4n_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')
|
||||
allowances = payslip.contract_id.us_payroll_config_value('ne_w4n_sit_allowances')
|
||||
tax_rate = payslip.rule_parameter('us_ne_sit_tax_rate')[filing_status].get(schedule_pay)
|
||||
sit_allowance = payslip.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)
|
||||
52
l10n_us_hr_payroll/models/state/nj_newjersey.py
Normal file
52
l10n_us_hr_payroll/models/state/nj_newjersey.py
Normal file
@@ -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.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.contract_id.us_payroll_config_value('nj_njw4_sit_allowances')
|
||||
sit_rate_table_key = payslip.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.contract_id.schedule_pay
|
||||
additional = payslip.contract_id.us_payroll_config_value('state_income_tax_additional_withholding')
|
||||
sit_table = payslip.rule_parameter('us_nj_sit_rate')[sit_rate_table_key].get(schedule_pay)
|
||||
allowance_value = payslip.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)
|
||||
40
l10n_us_hr_payroll/models/state/nm_new_mexico.py
Normal file
40
l10n_us_hr_payroll/models/state/nm_new_mexico.py
Normal file
@@ -0,0 +1,40 @@
|
||||
# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details.
|
||||
|
||||
from .general import _state_applies, sit_wage
|
||||
|
||||
|
||||
def nm_new_mexico_state_income_withholding(payslip, categories, worked_days, inputs):
|
||||
"""
|
||||
Returns SIT eligible wage and rate.
|
||||
|
||||
:return: result, result_rate (wage, percent)
|
||||
"""
|
||||
state_code = 'NM'
|
||||
if not _state_applies(payslip, state_code):
|
||||
return 0.0, 0.0
|
||||
|
||||
# Determine Wage
|
||||
wage = sit_wage(payslip, categories)
|
||||
if not wage:
|
||||
return 0.0, 0.0
|
||||
|
||||
filing_status = payslip.contract_id.us_payroll_config_value('fed_941_fit_w4_filing_status')
|
||||
if not filing_status:
|
||||
return 0.0, 0.0
|
||||
|
||||
schedule_pay = payslip.contract_id.schedule_pay
|
||||
additional = payslip.contract_id.us_payroll_config_value('state_income_tax_additional_withholding')
|
||||
tax_table = payslip.rule_parameter('us_nm_sit_tax_rate')[filing_status].get(schedule_pay)
|
||||
|
||||
taxable_income = wage
|
||||
withholding = 0.0
|
||||
last = 0.0
|
||||
for row in tax_table:
|
||||
if taxable_income <= float(row[0]):
|
||||
withholding = row[1] + ((row[2] / 100.0) * (taxable_income - last))
|
||||
break
|
||||
last = row[0]
|
||||
|
||||
withholding = max(withholding, 0.0)
|
||||
withholding += additional
|
||||
return wage, -((withholding / wage) * 100.0)
|
||||
54
l10n_us_hr_payroll/models/state/ny_new_york.py
Normal file
54
l10n_us_hr_payroll/models/state/ny_new_york.py
Normal file
@@ -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.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.rule_parameter('us_ny_sit_over_10_exemption_rate')[schedule_pay]
|
||||
deduction_exemption = payslip.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)
|
||||
47
l10n_us_hr_payroll/models/state/oh_ohio.py
Normal file
47
l10n_us_hr_payroll/models/state/oh_ohio.py
Normal file
@@ -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 oh_ohio_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 = 'OH'
|
||||
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
|
||||
|
||||
pay_periods = payslip.dict.get_pay_periods_in_year()
|
||||
additional = payslip.contract_id.us_payroll_config_value('state_income_tax_additional_withholding')
|
||||
exemptions = payslip.contract_id.us_payroll_config_value('oh_it4_sit_exemptions')
|
||||
exemption_rate = payslip.rule_parameter('us_oh_sit_exemption_rate')
|
||||
withholding_rate = payslip.rule_parameter('us_oh_sit_rate')
|
||||
multiplier_rate = payslip.rule_parameter('us_oh_sit_multiplier')
|
||||
|
||||
taxable_wage = (wage * pay_periods) - (exemption_rate * (exemptions or 0))
|
||||
withholding = 0.0
|
||||
if taxable_wage > 0.0:
|
||||
prior_wage_cap = 0.0
|
||||
for row in withholding_rate:
|
||||
wage_cap, base, rate = row
|
||||
wage_cap = float(wage_cap) # e.g. 'inf'
|
||||
if taxable_wage < wage_cap:
|
||||
withholding = base + (rate * (taxable_wage - prior_wage_cap))
|
||||
break
|
||||
prior_wage_cap = wage_cap
|
||||
# Normalize to pay periods
|
||||
withholding /= pay_periods
|
||||
withholding *= multiplier_rate
|
||||
withholding += additional
|
||||
return wage, -((withholding / wage) * 100.0)
|
||||
47
l10n_us_hr_payroll/models/state/ok_oklahoma.py
Normal file
47
l10n_us_hr_payroll/models/state/ok_oklahoma.py
Normal file
@@ -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.contract_id.us_payroll_config_value('state_income_tax_exempt'):
|
||||
return 0.0, 0.0
|
||||
|
||||
filing_status = payslip.contract_id.us_payroll_config_value('ok_w4_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')
|
||||
allowances = payslip.contract_id.us_payroll_config_value('ok_w4_sit_allowances')
|
||||
allowances_amt = payslip.rule_parameter('us_ok_sit_allowances_rate')[schedule_pay]
|
||||
tax_table = payslip.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)
|
||||
48
l10n_us_hr_payroll/models/state/ri_rhode_island.py
Normal file
48
l10n_us_hr_payroll/models/state/ri_rhode_island.py
Normal file
@@ -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.contract_id.us_payroll_config_value('state_income_tax_exempt'):
|
||||
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')
|
||||
allowances = payslip.contract_id.us_payroll_config_value('ri_w4_sit_allowances')
|
||||
exemption_rate = payslip.rule_parameter('us_ri_sit_exemption_rate')[schedule_pay]
|
||||
tax_table = payslip.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)
|
||||
50
l10n_us_hr_payroll/models/state/sc_south_carolina.py
Normal file
50
l10n_us_hr_payroll/models/state/sc_south_carolina.py
Normal file
@@ -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.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.contract_id.us_payroll_config_value('state_income_tax_additional_withholding')
|
||||
allowances = payslip.contract_id.us_payroll_config_value('sc_w4_sit_allowances')
|
||||
tax_rate = payslip.rule_parameter('us_sc_sit_tax_rate')
|
||||
personal_exemption = payslip.rule_parameter('us_sc_sit_personal_exemption_rate')
|
||||
deduction = payslip.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)
|
||||
39
l10n_us_hr_payroll/models/state/ut_utah.py
Normal file
39
l10n_us_hr_payroll/models/state/ut_utah.py
Normal file
@@ -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.contract_id.us_payroll_config_value('ut_w4_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_rate = payslip.rule_parameter('us_ut_tax_rate')
|
||||
allowances = payslip.rule_parameter('us_ut_sit_allowances_rate')[filing_status].get(schedule_pay)
|
||||
tax_table = payslip.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)
|
||||
44
l10n_us_hr_payroll/models/state/va_virginia.py
Normal file
44
l10n_us_hr_payroll/models/state/va_virginia.py
Normal file
@@ -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 va_virginia_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 = 'VA'
|
||||
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
|
||||
|
||||
pay_periods = payslip.dict.get_pay_periods_in_year()
|
||||
additional = payslip.contract_id.us_payroll_config_value('state_income_tax_additional_withholding')
|
||||
personal_exemptions = payslip.contract_id.us_payroll_config_value('va_va4_sit_exemptions')
|
||||
other_exemptions = payslip.contract_id.us_payroll_config_value('va_va4_sit_other_exemptions')
|
||||
personal_exemption_rate = payslip.rule_parameter('us_va_sit_exemption_rate')
|
||||
other_exemption_rate = payslip.rule_parameter('us_va_sit_other_exemption_rate')
|
||||
deduction = payslip.rule_parameter('us_va_sit_deduction')
|
||||
withholding_rate = payslip.rule_parameter('us_va_sit_rate')
|
||||
|
||||
taxable_wage = (wage * pay_periods) - (deduction + (personal_exemptions * personal_exemption_rate) + (other_exemptions * other_exemption_rate))
|
||||
withholding = 0.0
|
||||
if taxable_wage > 0.0:
|
||||
for row in withholding_rate:
|
||||
if taxable_wage > row[0]:
|
||||
selected_row = row
|
||||
wage_min, base, rate = selected_row
|
||||
withholding = base + ((taxable_wage - wage_min) * rate / 100.0)
|
||||
withholding /= pay_periods
|
||||
withholding += additional
|
||||
return wage, -((withholding / wage) * 100.0)
|
||||
46
l10n_us_hr_payroll/models/state/vt_vermont.py
Normal file
46
l10n_us_hr_payroll/models/state/vt_vermont.py
Normal file
@@ -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.contract_id.us_payroll_config_value('state_income_tax_exempt'):
|
||||
return 0.0, 0.0
|
||||
|
||||
filing_status = payslip.contract_id.us_payroll_config_value('vt_w4vt_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')
|
||||
allowances = payslip.contract_id.us_payroll_config_value('vt_w4vt_sit_allowances')
|
||||
allowance_amt = payslip.rule_parameter('us_vt_sit_allowances_rate')[schedule_pay]
|
||||
tax_table = payslip.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)
|
||||
27
l10n_us_hr_payroll/models/state/wa_washington.py
Normal file
27
l10n_us_hr_payroll/models/state/wa_washington.py
Normal file
@@ -0,0 +1,27 @@
|
||||
# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details.
|
||||
|
||||
from .general import _state_applies, _general_rate
|
||||
|
||||
|
||||
def _wa_washington_fml(payslip, categories, worked_days, inputs, inner_rate=None):
|
||||
if not inner_rate:
|
||||
return 0.0, 0.0
|
||||
|
||||
if not _state_applies(payslip, 'WA'):
|
||||
return 0.0, 0.0
|
||||
|
||||
wage = categories.GROSS
|
||||
year = payslip.dict.get_year()
|
||||
ytd_wage = payslip.sum_category('GROSS', str(year) + '-01-01', str(year + 1) + '-01-01')
|
||||
ytd_wage += payslip.contract_id.external_wages
|
||||
rate = payslip.rule_parameter('us_wa_fml_rate')
|
||||
rate *= payslip.rule_parameter(inner_rate) / 100.0
|
||||
return _general_rate(payslip, wage, ytd_wage, wage_base='us_wa_fml_wage_base', rate=rate)
|
||||
|
||||
|
||||
def wa_washington_fml_er(payslip, categories, worked_days, inputs):
|
||||
return _wa_washington_fml(payslip, categories, worked_days, inputs, inner_rate='us_wa_fml_rate_er')
|
||||
|
||||
|
||||
def wa_washington_fml_ee(payslip, categories, worked_days, inputs):
|
||||
return _wa_washington_fml(payslip, categories, worked_days, inputs, inner_rate='us_wa_fml_rate_ee')
|
||||
47
l10n_us_hr_payroll/models/state/wi_wisconsin.py
Normal file
47
l10n_us_hr_payroll/models/state/wi_wisconsin.py
Normal file
@@ -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.contract_id.us_payroll_config_value('state_income_tax_exempt'):
|
||||
return 0.0, 0.0
|
||||
|
||||
filing_status = payslip.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.contract_id.us_payroll_config_value('state_income_tax_additional_withholding')
|
||||
exemptions = payslip.contract_id.us_payroll_config_value('wi_wt4_sit_exemptions')
|
||||
exemption_amt = payslip.rule_parameter('us_wi_sit_exemption_rate')
|
||||
tax_table = payslip.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)
|
||||
44
l10n_us_hr_payroll/models/state/wv_west_virginia.py
Normal file
44
l10n_us_hr_payroll/models/state/wv_west_virginia.py
Normal file
@@ -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.contract_id.us_payroll_config_value('wv_it104_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')
|
||||
exemptions = payslip.contract_id.us_payroll_config_value('wv_it104_sit_exemptions')
|
||||
exemption_amt = payslip.rule_parameter('us_wv_sit_exemption_rate')[schedule_pay]
|
||||
tax_table = payslip.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)
|
||||
26
l10n_us_hr_payroll/models/update.py
Normal file
26
l10n_us_hr_payroll/models/update.py
Normal file
@@ -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
|
||||
@@ -14,6 +14,13 @@ class HRContractUSPayrollConfig(models.Model):
|
||||
name = fields.Char(string="Description")
|
||||
employee_id = fields.Many2one('hr.employee', string="Employee", required=True)
|
||||
state_id = fields.Many2one('res.country.state', string="Applied State")
|
||||
state_code = fields.Char(related='state_id.code')
|
||||
state_income_tax_exempt = fields.Boolean(string='State Income Tax Exempt')
|
||||
state_income_tax_additional_withholding = fields.Float(string='State Income Tax Additional Withholding')
|
||||
workers_comp_ee_code = fields.Char(string='Workers\' Comp Code (Employee Withholding)',
|
||||
help='Code for a Rule Parameter, used by some states or your own rules.')
|
||||
workers_comp_er_code = fields.Char(string='Workers\' Comp Code (Employer Withholding)',
|
||||
help='Code for a Rule Parameter, used by some states or your own rules.')
|
||||
|
||||
fed_940_type = fields.Selection([
|
||||
(FUTA_TYPE_EXEMPT, 'Exempt (0%)'),
|
||||
@@ -43,3 +50,229 @@ class HRContractUSPayrollConfig(models.Model):
|
||||
help='Form W4 (2020+) 4(b)')
|
||||
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'),
|
||||
('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'),
|
||||
('married filing separate', 'Married Filing Separate'),
|
||||
('head of household', 'Head of Household'),
|
||||
], string='Georgia G-4 Filing Status', help='G-4 3.')
|
||||
ga_g4_sit_dependent_allowances = fields.Integer(string='Georgia G-4 Dependent Allowances',
|
||||
help='G-4 4.')
|
||||
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'),
|
||||
('married', 'Married (spouse NOT employed)'),
|
||||
('married_dual', 'Married (spouse IS employed)'),
|
||||
('head_of_household', 'Head of Household'),
|
||||
], string='Mississippi 89-350 Filing Status', help='89-350 1. 2. 3. 8.')
|
||||
ms_89_350_sit_exemption_value = fields.Float(string='Mississippi 89-350 Exemption Total',
|
||||
help='89-350 Box 6 (including filing status amounts)')
|
||||
|
||||
mt_mw4_sit_exemptions = fields.Integer(string='Montana MW-4 Exemptions',
|
||||
help='MW-4 Box G')
|
||||
# Don't use the main state_income_tax_exempt because of special meaning and reporting
|
||||
# Use additional withholding but name it on the form 'MW-4 Box H'
|
||||
mt_mw4_sit_exempt = fields.Selection([
|
||||
('', 'Not Exempt'),
|
||||
('tribe', 'Registered Tribe'),
|
||||
('reserve', 'Reserve or National Guard'),
|
||||
('north_dakota', 'North Dakota'),
|
||||
('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)')
|
||||
|
||||
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.')
|
||||
|
||||
Reference in New Issue
Block a user