IMP l10n_us_hr_payroll Port l10n_us_ct_hr_payroll CT Connecticut including migration

This commit is contained in:
Bhoomi Vaishnani
2020-02-21 18:41:45 -05:00
parent 89d9dcb867
commit 90b86e46f3
10 changed files with 1475 additions and 0 deletions

View File

@@ -32,6 +32,7 @@ USA Payroll Rules.
'data/state/al_alabama.xml',
'data/state/ar_arkansas.xml',
'data/state/az_arizona.xml',
'data/state/ct_connecticut.xml',
'data/state/fl_florida.xml',
'data/state/ga_georgia.xml',
'data/state/il_illinois.xml',

View File

@@ -28,6 +28,9 @@
ref('hr_payroll_rule_er_us_az_suta'),
ref('hr_payroll_rule_ee_us_az_sit'),
ref('hr_payroll_rule_er_us_ct_suta'),
ref('hr_payroll_rule_ee_us_ct_sit'),
ref('hr_payroll_rule_er_us_fl_suta'),
ref('hr_payroll_rule_er_us_ga_suta'),

File diff suppressed because it is too large Load Diff

View File

@@ -21,6 +21,9 @@ FIELDS_CONTRACT_TO_US_PAYROLL_FORMS_2020 = {
'az_a4_withholding_percentage': 'az_a4_sit_withholding_percentage',
'az_a4_additional_withholding': 'state_income_tax_additional_withholding',
'ct_w4na_code': 'ct_w4na_sit_code',
'ct_w4na_wh_amount': 'state_income_tax_additional_withholding',
'ga_g4_filing_status': 'ga_g4_sit_filing_status',
'ga_g4_dependent_allowances': 'ga_g4_sit_dependent_allowances',
'ga_g4_additional_allowances': 'ga_g4_sit_additional_allowances',
@@ -104,6 +107,11 @@ XMLIDS_TO_REMOVE_2020 = [
'l10n_us_az_hr_payroll.hr_payroll_az_income_withhold',
'l10n_us_az_hr_payroll.hr_payroll_rules_az_unemp_wages',
'l10n_us_ct_hr_payroll.hr_payroll_ct_unemp_wages',
'l10n_us_ct_hr_payroll.hr_payroll_ct_unemp',
'l10n_us_ct_hr_payroll.hr_payroll_ct_income_withhold',
'l10n_us_ct_hr_payroll.hr_payroll_rules_ct_unemp_wages',
'l10n_us_fl_hr_payroll.hr_payroll_fl_unemp_wages',
'l10n_us_fl_hr_payroll.hr_payroll_fl_unemp',
'l10n_us_fl_hr_payroll.hr_payroll_rules_fl_unemp_wages_2018',
@@ -249,6 +257,13 @@ XMLIDS_TO_RENAME_2020 = {
'l10n_us_az_hr_payroll.hr_payroll_az_unemp': 'l10n_us_hr_payroll.hr_payroll_rule_er_us_az_suta',
'l10n_us_az_hr_payroll.hr_payroll_az_income_withhold': 'l10n_us_hr_payroll.hr_payroll_rule_ee_us_az_sit',
'l10n_us_ct_hr_payroll.res_partner_ct_dol_unemp': 'l10n_us_hr_payroll.res_partner_us_ct_dor',
'l10n_us_ct_hr_payroll.res_partner_ct_drs_withhold': 'l10n_us_hr_payroll.res_partner_us_ct_dor_sit',
'l10n_us_ct_hr_payroll.contrib_register_ct_dol_unemp': 'l10n_us_hr_payroll.contrib_register_us_ct_dor',
'l10n_us_ct_hr_payroll.contrib_register_ct_drs_withhold': 'l10n_us_hr_payroll.contrib_register_us_ct_dor_sit',
'l10n_us_ct_hr_payroll.hr_payroll_rules_ct_unemp': 'l10n_us_hr_payroll.hr_payroll_rule_er_us_ct_suta',
'l10n_us_ct_hr_payroll.hr_payroll_rules_ct_inc_withhold': 'l10n_us_hr_payroll.hr_payroll_rule_ee_us_ct_sit',
'l10n_us_fl_hr_payroll.hr_payroll_rules_fl_unemp_2018': 'l10n_us_hr_payroll.hr_payroll_rule_er_us_fl_suta',
'l10n_us_fl_hr_payroll.res_partner_fldor': 'l10n_us_hr_payroll.res_partner_us_fl_dor',
'l10n_us_fl_hr_payroll.contrib_register_fldor': 'l10n_us_hr_payroll.contrib_register_us_fl_dor',

View File

@@ -17,6 +17,7 @@ from .state.general import general_state_unemployment, \
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.ct_connecticut import ct_connecticut_state_income_withholding
from .state.ga_georgia import ga_georgia_state_income_withholding
from .state.il_illinois import il_illinois_state_income_withholding
from .state.mi_michigan import mi_michigan_state_income_withholding
@@ -65,6 +66,7 @@ class HRPayslip(models.Model):
'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,
'ct_connecticut_state_income_withholding': ct_connecticut_state_income_withholding,
'ga_georgia_state_income_withholding': ga_georgia_state_income_withholding,
'il_illinois_state_income_withholding': il_illinois_state_income_withholding,
'mi_michigan_state_income_withholding': mi_michigan_state_income_withholding,

View 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.dict.contract_id.us_payroll_config_value('state_income_tax_additional_withholding')
withholding_code = payslip.dict.contract_id.us_payroll_config_value('ct_w4na_sit_code')
exemption_table = payslip.dict.rule_parameter('us_ct_sit_personal_exemption_rate').get(withholding_code, [('inf', 0.0)])
initial_tax_tbl = payslip.dict.rule_parameter('us_ct_sit_initial_tax_rate').get(withholding_code, [('inf', 0.0, 0.0)])
tax_table = payslip.dict.rule_parameter('us_ct_sit_tax_rate').get(withholding_code, [('inf', 0.0)])
recapture_table = payslip.dict.rule_parameter('us_ct_sit_recapture_rate').get(withholding_code, [('inf', 0.0)])
decimal_table = payslip.dict.rule_parameter('us_ct_sit_decimal_rate').get(withholding_code, [('inf', 0.0)])
annual_wages = wage * pay_periods
personal_exemption = 0.0
for bracket in exemption_table:
if annual_wages <= float(bracket[0]):
personal_exemption = bracket[1]
break
withholding = 0.0
taxable_income = annual_wages - personal_exemption
if taxable_income < 0.0:
taxable_income = 0.0
if taxable_income:
initial_tax = 0.0
last = 0.0
for bracket in initial_tax_tbl:
if taxable_income <= float(bracket[0]):
initial_tax = bracket[1] + ((bracket[2] / 100.0) * (taxable_income - last))
break
last = bracket[0]
tax_add_back = 0.0
for bracket in tax_table:
if annual_wages <= float(bracket[0]):
tax_add_back = bracket[1]
break
recapture_amount = 0.0
for bracket in recapture_table:
if annual_wages <= float(bracket[0]):
recapture_amount = bracket[1]
break
withholding = initial_tax + tax_add_back + recapture_amount
decimal_amount = 1.0
for bracket in decimal_table:
if annual_wages <= float(bracket[0]):
decimal_amount= bracket[1]
break
withholding = withholding * (1.00 - decimal_amount)
if withholding < 0.0:
withholding = 0.0
withholding /= pay_periods
withholding += additional
return wage, -((withholding / wage) * 100.0)

View File

@@ -66,6 +66,14 @@ class HRContractUSPayrollConfig(models.Model):
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.')
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.')
ga_g4_sit_filing_status = fields.Selection([
('exempt', 'Exempt'),
('single', 'Single'),

View File

@@ -16,6 +16,9 @@ from . import test_us_ar_arkansas_payslip_2020
from . import test_us_az_arizona_payslip_2019
from . import test_us_az_arizona_payslip_2020
from . import test_us_ct_connecticut_payslip_2019
from . import test_us_ct_connecticut_payslip_2020
from . import test_us_fl_florida_payslip_2019
from . import test_us_fl_florida_payslip_2020

View File

@@ -0,0 +1,121 @@
# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details.
from .common import TestUsPayslip, process_payslip
class TestUsCTPayslip(TestUsPayslip):
# TAXES AND RATES
CT_UNEMP_MAX_WAGE = 15000.00
CT_UNEMP = -(3.40 / 100.0)
def test_taxes_weekly_with_additional_wh(self):
# Tax tables can be found here:
# https://portal.ct.gov/-/media/DRS/Publications/pubsip/2019/IP-2019(1).pdf?la=en
# Step 1 - Wages per period -> 10000.00
salary = 10000.00
# Step 2 and 3 - Annual wages -> 10000.00 * 52.0 -> 520000.0
schedule_pay = 'weekly'
# Step 4 Employee Withholding Code -> A
wh_code = 'a'
# Step 5 - Use annual wages and withholding code with table for exemption amount.
# exemption_amt = 0 since highest bracket.
# Step 6 - Subtract 5 from 3 for taxable income.
# taxable income = 520000.00 since we do not have an exemption.
# Step 7 - Determine initial amount from table
# initial = 31550 + ((6.99 / 100) * (520000.00 - 500000.00))
# 32948.0
# Step 8 - Determine the tax rate phase out add back from table.
# phase_out = 200
# Step 9 - Determine the recapture amount from table.
# Close to top, but not top. -> 2900
# Step 10 - Add Step 7, 8, 9
# 32948.0 + 200 + 2900.00 - > 36048.0
# Step 11 - Determine decimal amount from personal tax credits.
# We get no tax credit.
# Step 12 - Multiple Step 10 by 1.00 - Step 11
# 36048.0 * 1.00 = 36048.0
# Step 13 - Divide by the number of pay periods.
# 36048.0 / 52.0 = 693.23
# Step 14 & 15 & 16- Add / Subtract the additional or under withholding amount. Then Add this to the amount
# for withholding per period.
additional_wh = 12.50
# 693.23 + 12.50 ->
wh = -705.73
employee = self._createEmployee()
contract = self._createContract(employee,
wage=salary,
state_id=self.get_us_state('CT'),
ct_w4na_sit_code=wh_code,
state_income_tax_additional_withholding=additional_wh,
schedule_pay=schedule_pay)
self._log('2019 Connecticut tax first payslip weekly:')
payslip = self._createPayslip(employee, '2019-01-01', '2019-01-31')
payslip.compute_sheet()
cats = self._getCategories(payslip)
self.assertPayrollEqual(cats['ER_US_SUTA'], salary * self.CT_UNEMP)
self.assertPayrollEqual(cats['EE_US_SIT'], wh)
process_payslip(payslip)
remaining_CT_UNEMP_wages = 5000.00 # We already reached the maximum wage for unemployment insurance.
self._log('2019 Connecticut tax second payslip weekly:')
payslip = self._createPayslip(employee, '2019-02-01', '2019-02-28')
payslip.compute_sheet()
cats = self._getCategories(payslip)
self.assertPayrollEqual(cats['ER_US_SUTA'], remaining_CT_UNEMP_wages * self.CT_UNEMP)
def test_taxes_weekly_with_different_code(self):
# Tax tables can be found here:
# https://portal.ct.gov/-/media/DRS/Publications/pubsip/2019/IP-2019(1).pdf?la=en
# Step 1 - Wages per period -> 15000.00
salary = 15000.00
# Step 2 and 3 - Annual wages -> 15000.00 * 12.0 -> 180000.0
schedule_pay = 'monthly'
# Step 4 Employee Withholding Code -> B
wh_code = 'b'
# Step 5 - Use annual wages and withholding code with table for exemption amount.
# exemption_amt = 0 since highest bracket.
# Step 6 - Subtract 5 from 3 for taxable income.
# taxable income = 180000.0 since we do not have an exemption.
# Step 7 - Determine initial amount from table
# initial = 8080 + ((6.00 / 100) * (180000.0 - 160000))
# 9280.0
# Step 8 - Determine the tax rate phase out add back from table.
# phase_out = 320
# Step 9 - Determine the recapture amount from table.
# Bottom -> 0
# Step 10 - Add Step 7, 8, 9
# 9280.0 + 320 + 0 - > 9600.0
# Step 11 - Determine decimal amount from personal tax credits.
# We get no tax credit.
# Step 12 - Multiple Step 10 by 1.00 - Step 11
# 9600.0 * 1.00 = 9600.0
# Step 13 - Divide by the number of pay periods.
# 9600.0 / 12.0 = 800.0
# Step 14 & 15 & 16- Add / Subtract the additional or under withholding amount. Then Add this to the amount
# for withholding per period.
additional_wh = 15.00
# 800.0 + 15.00 ->
wh = -815.0
employee = self._createEmployee()
contract = self._createContract(employee,
wage=salary,
state_id=self.get_us_state('CT'),
ct_w4na_sit_code=wh_code,
state_income_tax_additional_withholding=additional_wh,
schedule_pay=schedule_pay)
self._log('2019 Connecticut tax first payslip monthly:')
payslip = self._createPayslip(employee, '2019-01-01', '2019-01-31')
payslip.compute_sheet()
cats = self._getCategories(payslip)
self.assertPayrollEqual(cats['ER_US_SUTA'], self.CT_UNEMP_MAX_WAGE * self.CT_UNEMP)
self.assertPayrollEqual(cats['EE_US_SIT'], wh)

View File

@@ -0,0 +1,34 @@
# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details.
from datetime import date, timedelta
from .common import TestUsPayslip
class TestUsCTPayslip(TestUsPayslip):
# Taxes and Rates
CT_UNEMP_MAX_WAGE = 15000.0
CT_UNEMP = 3.2
def _test_sit(self, wage, withholding_code, additional_withholding, schedule_pay, date_start, expected_withholding):
employee = self._createEmployee()
contract = self._createContract(employee,
wage=wage,
state_id=self.get_us_state('CT'),
ct_w4na_sit_code=withholding_code,
state_income_tax_additional_withholding=additional_withholding,
schedule_pay=schedule_pay)
payslip = self._createPayslip(employee, date_start, date_start + timedelta(days=7))
payslip.compute_sheet()
cats = self._getCategories(payslip)
self._log('Computed period tax: ' + str(expected_withholding))
self.assertPayrollEqual(cats.get('EE_US_SIT', 0.0), -expected_withholding)
def test_2020_taxes_example(self):
self._test_er_suta('CT', self.CT_UNEMP, date(2020, 1, 1), wage_base=self.CT_UNEMP_MAX_WAGE)
self._test_sit(10000.0, 'a', 0.0, 'weekly', date(2020, 1, 1), 693.23)
self._test_sit(12000.0, 'b', 15.0, 'bi-weekly', date(2020, 1, 1), 688.85)
self._test_sit(5000.0, 'f', 15.0, 'monthly', date(2020, 1, 1), 230.25)
self._test_sit(15000.0, 'c', 0.0, 'monthly', date(2020, 1, 1), 783.33)
self._test_sit(18000.0, 'b', 0.0, 'weekly', date(2020, 1, 1), 1254.35)