diff --git a/l10n_us_hr_payroll/__manifest__.py b/l10n_us_hr_payroll/__manifest__.py index ae62eff5..683b8752 100644 --- a/l10n_us_hr_payroll/__manifest__.py +++ b/l10n_us_hr_payroll/__manifest__.py @@ -26,6 +26,7 @@ United States of America - Payroll Rules. 'data/federal/fed_941_fit_parameters.xml', 'data/federal/fed_941_fit_rules.xml', 'data/state/fl_florida.xml', + 'data/state/ga_georgia.xml', 'data/state/mt_montana.xml', 'data/state/oh_ohio.xml', 'data/state/pa_pennsylvania.xml', diff --git a/l10n_us_hr_payroll/data/state/ga_georgia.xml b/l10n_us_hr_payroll/data/state/ga_georgia.xml new file mode 100644 index 00000000..72844e5e --- /dev/null +++ b/l10n_us_hr_payroll/data/state/ga_georgia.xml @@ -0,0 +1,279 @@ + + + + + US GA Georgia SUTA Wage Base + us_ga_suta_wage_base + + + + + 9500.00 + + + + + 9500.00 + + + + + + + + US GA Georgia SUTA Rate + us_ga_suta_rate + + + + + 2.7 + + + + + 2.7 + + + + + + + US GA Georgia SIT Rate Table + us_ga_sit_rate + + + + + { + 'married filing joint, both spouses working': { + 'weekly': ((9.50, 0.00, 1.00), (29.00, .10, 2.00), (48.00, .48, 3.00), (67.50, 1.06, 4.00), (96.00, 1.83, 5.00), ('inf', 3.27, 5.75)), + 'bi-weekly': ((19.00, 0.00, 1.00), (57.50, .19, 2.00), (96.00, .96, 3.00), (135.00, 2.12, 4.00), (192.00, 3.65, 5.00), ('inf', 6.54, 5.75)), + 'semi-monthly': ((21.00, 0.00, 1.00), (62.50, .21, 2.00), (104.00, 1.04, 3.00), (146.00, 2.29, 4.00), (208.00, 3.96, 5.00), ('inf', 7.08, 5.75)), + 'monthly': ((41.50, 0.00, 1.00), (125.50, .42, 2.00), (208.00, 2.08, 3.00), (292.00, 4.58, 4.00), (417.00, 7.92, 5.00), ('inf', 14.17, 5.75)), + 'quarterly': ((125.00, 0.00, 1.00), (375.00, 1.25, 2.00), (625.00, 6.25, 3.00), (875.00, 13.75, 4.00), (1250.00, 23.75, 5.00), ('inf', 42.50, 5.75)), + 'semi-annual': ((250.00, 0.00, 1.00), (750.00, 2.50, 2.00), (1250.00, 12.50, 3.00), (1750.00, 27.50, 4.00), (2500.00, 47.50, 5.00), ('inf', 85.00, 5.75)), + 'annual': ((500.00, 0.00, 1.00), (1500.00, 5.00, 2.00), (2500.00, 25.00, 3.00), (3500.00, 55.00, 4.00), (5000.00, 95.00, 5.00), ('inf', 170.00, 5.75)), + }, + 'married filing joint, one spouse working': { + 'weekly': ((19.00, 0.00, 1.00), (57.50, .19, 2.00), (96.00, .96, 3.00), (135.00, 2.12, 4.00), (192.50, 3.65, 5.00), ('inf', 6.54, 5.75)), + 'bi-weekly': ((38.50, 0.00, 1.00), (115.00, .38, 2.00), (192.00, 1.92, 3.00), (269.00, 4.23, 4.00), (385.00, 7.31, 5.00), ('inf', 13.08, 5.75)), + 'semi-monthly': ((41.50, 0.00, 1.00), (125.00, .42, 2.00), (208.00, 2.08, 3.00), (292.00, 4.58, 4.00), (417.00, 7.92, 5.00), ('inf', 14.17, 5.75)), + 'monthly': ((83.00, 0.00, 1.00), (250.00, .83, 2.00), (417.00, 4.17, 3.00), (583.00, 9.17, 4.00), (833.00, 15.83, 5.00), ('inf', 28.33, 5.75)), + 'quarterly': ((250.00, 0.00, 1.00), (750.00, 2.50, 2.00), (1250.00, 12.50, 3.00), (1750.00, 27.50, 4.00), (2500.00, 47.50, 5.00), ('inf', 85.00, 5.75)), + 'semi-annual': ((500.00, 0.00, 1.00), (1500.00, 5.00, 2.00), (2500.00, 25.00, 3.00), (3500.00, 55.00, 4.00), (5000.00, 95.00, 5.00), ('inf', 170.00, 5.75)), + 'annual': ((1000.00, 0.00, 1.00), (3000.00, 10.00, 2.00), (5000.00, 50.00, 3.00), (7000.00, 110.00, 4.00), (10000.00, 190.00, 5.00), ('inf', 340.00, 5.75)), + }, + 'single': { + 'weekly': ((14.50, 0.00, 1.00), (43.50, .14, 2.00), (72.00, .72, 3.00), (101.00, 1.59, 4.00), (135.00, 2.74, 5.00), ('inf', 4.42, 5.75)), + 'bi-weekly': ((29.00, 0.00, 1.00), (86.50, .29, 2.00), (144.00, 1.44, 3.00), (202.00, 3.17, 4.00), (269.00, 5.48, 5.00), ('inf', 8.85, 5.75)), + 'semi-monthly': ((31.00, 0.00, 1.00), (93.50, .31, 2.00), (156.00, 1.56, 3.00), (219.00, 3.34, 4.00), (292.00, 5.94, 5.00), ('inf', 9.58, 5.75)), + 'monthly': ((62.50, 0.00, 1.00), (187.00, .62, 2.00), (312.00, 3.12, 3.00), (437.00, 6.87, 4.00), (583.00, 11.87, 5.00), ('inf', 19.17, 5.75)), + 'quarterly': ((187.50, 0.00, 1.00), (562.50, 1.88, 2.00), (937.50, 9.38, 3.00), (1312.00, 20.63, 4.00), (1750.00, 35.63, 5.00), ('inf', 57.50, 5.75)), + 'semi-annual': ((375.00, 0.00, 1.00), (1125.00, 3.75, 2.00), (1875.00, 18.75, 3.00), (2625.00, 41.25, 4.00), (3500.00, 71.25, 5.00), ('inf', 115.00, 5.75)), + 'annual': ((750.00, 0.00, 1.00), (2250.00, 7.50, 2.00), (3750.00, 37.50, 3.00), (5250.00, 82.50, 4.00), (7000.00, 142.50, 5.00), ('inf', 230.00, 5.75)), + }, + 'head of household': { + 'weekly': ((19.00, 0.00, 1.00), (57.50, .19, 2.00), (96.00, .96, 3.00), (135.00, 2.12, 4.00), (192.50, 3.65, 5.00), ('inf', 6.54, 5.75)), + 'bi-weekly': ((38.50, 0.00, 1.00), (115.00, .38, 2.00), (192.00, 1.92, 3.00), (269.00, 4.23, 4.00), (385.00, 7.31, 5.00), ('inf', 13.08, 5.75)), + 'semi-monthly': ((41.50, 0.00, 1.00), (125.00, .42, 2.00), (208.00, 2.08, 3.00), (292.00, 4.58, 4.00), (417.00, 7.92, 5.00), ('inf', 14.17, 5.75)), + 'monthly': ((83.00, 0.00, 1.00), (250.00, .83, 2.00), (417.00, 4.17, 3.00), (583.00, 9.17, 4.00), (833.00, 15.83, 5.00), ('inf', 28.33, 5.75)), + 'quarterly': ((250.00, 0.00, 1.00), (750.00, 2.50, 2.00), (1250.00, 12.50, 3.00), (1750.00, 27.50, 4.00), (2500.00, 47.50, 5.00), ('inf', 85.00, 5.75)), + 'semi-annual': ((500.00, 0.00, 1.00), (1500.00, 5.00, 2.00), (2500.00, 25.00, 3.00), (3500.00, 55.00, 4.00), (5000.00, 95.00, 5.00), ('inf', 170.00, 5.75)), + 'annual': ((1000.00, 0.00, 1.00), (3000.00, 10.00, 2.00), (5000.00, 50.00, 3.00), (7000.00, 110.00, 4.00), (10000.00, 190.00, 5.00), ('inf', 340.00, 5.75)), + }, + 'married filing separate': { + 'weekly': ((9.50, 0.00, 1.00), (29.00, .10, 2.00), (48.00, .48, 3.00), (67.50, 1.06, 4.00), (96.00, 1.83, 5.00), ('inf', 3.27, 5.75)), + 'bi-weekly': ((19.00, 0.00, 1.00), (57.50, .19, 2.00), (96.00, .96, 3.00), (135.00, 2.12, 4.00), (192.00, 3.65, 5.00), ('inf', 6.54, 5.75)), + 'semi-monthly': ((21.00, 0.00, 1.00), (62.50, .21, 2.00), (104.00, 1.04, 3.00), (146.00, 2.29, 4.00), (208.00, 3.96, 5.00), ('inf', 7.08, 5.75)), + 'monthly': ((41.50, 0.00, 1.00), (125.50, .42, 2.00), (208.00, 2.08, 3.00), (292.00, 4.58, 4.00), (417.00, 7.92, 5.00), ('inf', 14.17, 5.75)), + 'quarterly': ((125.00, 0.00, 1.00), (375.00, 1.25, 2.00), (625.00, 6.25, 3.00), (875.00, 13.75, 4.00), (1250.00, 23.75, 5.00), ('inf', 42.50, 5.75)), + 'semi-annual': ((250.00, 0.00, 1.00), (750.00, 2.50, 2.00), (1250.00, 12.50, 3.00), (1750.00, 27.50, 4.00), (2500.00, 47.50, 5.00), ('inf', 85.00, 5.75)), + 'annual': ((500.00, 0.00, 1.00), (1500.00, 5.00, 2.00), (2500.00, 25.00, 3.00), (3500.00, 55.00, 4.00), (5000.00, 95.00, 5.00), ('inf', 170.00, 5.75)), + }, + } + + + + + + + US GA Georgia SIT Personal Allowance + us_ga_sit_personal_allowance + + + + + { + 'married filing joint, both spouses working': { + 'weekly': 142.30, + 'bi-weekly': 284.62, + 'semi-monthly': 308.33, + 'monthly': 616.67, + 'quarterly': 1850.00, + 'semi-annual': 3700.00, + 'annual': 7400.00, + }, + 'married filing joint, one spouse working': { + 'weekly': 142.30, + 'bi-weekly': 284.62, + 'semi-monthly': 308.33, + 'monthly': 616.67, + 'quarterly': 1850.00, + 'semi-annual': 3700.00, + 'annual': 7400.00, + }, + 'single': { + 'weekly': 51.92, + 'bi-weekly': 103.85, + 'semi-monthly': 112.50, + 'monthly': 225.00, + 'quarterly': 675.00, + 'semi-annual': 1350.00, + 'annual': 2700.00, + }, + 'head of household': { + 'weekly': 51.92, + 'bi-weekly': 103.85, + 'semi-monthly': 112.50, + 'monthly': 225.00, + 'quarterly': 675.00, + 'semi-annual': 1350.00, + 'annual': 2700.00, + }, + 'married filing separate': { + 'weekly': 71.15, + 'bi-weekly': 142.30, + 'semi-monthly': 154.16, + 'monthly': 308.33, + 'quarterly': 925.00, + 'semi-annual': 1850.00, + 'annual': 3700.00, + }, + } + + + + + + + US GA Georgia SIT Dependent Allowance Rate + us_ga_sit_dependent_allowance_rate + + + + + { + 'weekly': 57.50, + 'bi-weekly': 115.00, + 'semi-monthly': 125.00, + 'monthly': 250.00, + 'quarterly': 750.00, + 'semi-annual': 1500.00, + 'annual': 3000.00, + } + + + + + + + US GA Georgia SIT Deduction + us_ga_sit_deduction + + + + + { + 'married filing joint, both spouses working': { + 'weekly': 115.50, + 'bi-weekly': 230.75, + 'semi-monthly': 250.00, + 'monthly': 500.00, + 'quarterly': 1500.00, + 'semi-annual': 3000.00, + 'annual': 6000.00, + }, + 'married filing joint, one spouse working': { + 'weekly': 115.50, + 'bi-weekly': 230.75, + 'semi-monthly': 250.00, + 'monthly': 500.00, + 'quarterly': 1500.00, + 'semi-annual': 3000.00, + 'annual': 6000.00, + }, + 'single': { + 'weekly': 88.50, + 'bi-weekly': 177.00, + 'semi-monthly': 191.75, + 'monthly': 383.50, + 'quarterly': 1150.00, + 'semi-annual': 2300.00, + 'annual': 4600.00, + }, + 'head of household': { + 'weekly': 88.50, + 'bi-weekly': 177.00, + 'semi-monthly': 191.75, + 'monthly': 383.50, + 'quarterly': 1150.00, + 'semi-annual': 2300.00, + 'annual': 4600.00, + }, + 'married filing separate': { + 'weekly': 57.75, + 'bi-weekly': 115.50, + 'semi-monthly': 125.00, + 'monthly': 250.00, + 'quarterly': 750.00, + 'semi-annual': 1500.00, + 'annual': 3000.00, + }, + } + + + + + + + + US Georgia - Department of Taxation - Unemployment Tax + + + + US Georgia - Department of Taxation - Income Tax + + + + + + + + + + ER: US GA Georgia State Unemployment + ER_US_GA_SUTA + python + result, _ = general_state_unemployment(payslip, categories, worked_days, inputs, wage_base='us_ga_suta_wage_base', rate='us_ga_suta_rate', state_code='GA') + code + result, result_rate = general_state_unemployment(payslip, categories, worked_days, inputs, wage_base='us_ga_suta_wage_base', rate='us_ga_suta_rate', state_code='GA') + + + + + + + + + EE: US GA Georgia State Income Tax Withholding + EE_US_GA_SIT + python + result, _ = ga_georgia_state_income_withholding(payslip, categories, worked_days, inputs) + code + result, result_rate = ga_georgia_state_income_withholding(payslip, categories, worked_days, inputs) + + + + + \ No newline at end of file diff --git a/l10n_us_hr_payroll/models/hr_payslip.py b/l10n_us_hr_payroll/models/hr_payslip.py index d42d60c7..7b00f540 100644 --- a/l10n_us_hr_payroll/models/hr_payslip.py +++ b/l10n_us_hr_payroll/models/hr_payslip.py @@ -12,6 +12,7 @@ from .federal.fed_941 import ee_us_941_fica_ss, \ from .state.general import general_state_unemployment, \ general_state_income_withholding, \ is_us_state +from .state.ga_georgia import ga_georgia_state_income_withholding from .state.mt_montana import mt_montana_state_income_withholding from .state.oh_ohio import oh_ohio_state_income_withholding from .state.va_virginia import va_virginia_state_income_withholding @@ -48,6 +49,7 @@ class HRPayslip(models.Model): 'general_state_unemployment': general_state_unemployment, 'general_state_income_withholding': general_state_income_withholding, 'is_us_state': is_us_state, + 'ga_georgia_state_income_withholding': ga_georgia_state_income_withholding, 'mt_montana_state_income_withholding': mt_montana_state_income_withholding, 'oh_ohio_state_income_withholding': oh_ohio_state_income_withholding, 'va_virginia_state_income_withholding': va_virginia_state_income_withholding, diff --git a/l10n_us_hr_payroll/models/state/ga_georgia.py b/l10n_us_hr_payroll/models/state/ga_georgia.py new file mode 100644 index 00000000..42c24cd4 --- /dev/null +++ b/l10n_us_hr_payroll/models/state/ga_georgia.py @@ -0,0 +1,52 @@ +# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details. + +from .general import _state_applies + + +def ga_georgia_state_income_withholding(payslip, categories, worked_days, inputs): + """ + Returns SIT eligible wage and rate. + WAGE = GROSS - WAGE_US_941_FIT_EXEMPT + + :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 or ga_filing_status == 'exempt': + return 0.0, 0.0 + + # Determine Wage + wage = categories.GROSS - categories.WAGE_US_941_FIT_EXEMPT + 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)) or wage == 0.0: + return 0.0, 0.0 + + if wage == 0.0: + 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) diff --git a/l10n_us_hr_payroll/models/us_payroll_config.py b/l10n_us_hr_payroll/models/us_payroll_config.py index 4d86a1b7..885846e2 100644 --- a/l10n_us_hr_payroll/models/us_payroll_config.py +++ b/l10n_us_hr_payroll/models/us_payroll_config.py @@ -51,6 +51,19 @@ class HRContractUSPayrollConfig(models.Model): fed_941_fit_w4_additional_withholding = fields.Float(string='Federal W4 Additional Withholding [4(c)]', help='Form W4 (2020+) 4(c)') + ga_g4_sit_filing_status = fields.Selection([ + ('exempt', 'Exempt'), + ('single', 'Single'), + ('married filing joint, both spouses working', 'Married Filing Joint, both spouses working'), + ('married filing joint, one spouse working', 'Married Filing Joint, one spouse working'), + ('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.') + 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 diff --git a/l10n_us_hr_payroll/tests/__init__.py b/l10n_us_hr_payroll/tests/__init__.py index ef846086..43613969 100755 --- a/l10n_us_hr_payroll/tests/__init__.py +++ b/l10n_us_hr_payroll/tests/__init__.py @@ -7,6 +7,9 @@ from . import test_us_payslip_2020 from . import test_us_fl_florida_payslip_2019 from . import test_us_fl_florida_payslip_2020 +from . import test_us_ga_georgia_payslip_2019 +from . import test_us_ga_georgia_payslip_2020 + from . import test_us_mt_montana_payslip_2019 from . import test_us_mt_montana_payslip_2020 diff --git a/l10n_us_hr_payroll/tests/test_us_ga_georgia_payslip_2019.py b/l10n_us_hr_payroll/tests/test_us_ga_georgia_payslip_2019.py new file mode 100755 index 00000000..b407a079 --- /dev/null +++ b/l10n_us_hr_payroll/tests/test_us_ga_georgia_payslip_2019.py @@ -0,0 +1,135 @@ +# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details. + +from .common import TestUsPayslip, process_payslip + + +class TestUsGAPayslip(TestUsPayslip): + + # TAXES AND RATES + GA_UNEMP_MAX_WAGE = 9500.00 + GA_UNEMP = -(2.70 / 100.0) + + def test_taxes_weekly_single_with_additional_wh(self): + salary = 15000.00 + schedule_pay = 'weekly' + allowances = 1 + filing_status = 'single' + additional_wh = 12.50 + # Hand Calculated Amount to Test + # Step 1 - Subtract standard deduction from wages. Std Deduct for single weekly is 88.50 + # step1 = 15000.00 - 88.50 = 14911.5 + # Step 2 - Subtract personal allowance from step1. Allowance for single weekly is 51.92 + # step2 = step1 - 51.92 = 14859.58 + # Step 3 - Subtract amount for dependents. Weekly dependent allowance is 57.50 + # step3 = 14859.58 - 57.50 = 14802.08 + # Step 4 -Determine wh amount from tables + # step4 = 4.42 + ((5.75 / 100.00) * (14802.08 - 135.00)) + # Add additional_wh + # wh = 847.7771 + 12.50 = 860.2771 + wh = -860.28 + + employee = self._createEmployee() + contract = self._createContract(employee, + wage=salary, + state_id=self.get_us_state('GA'), + ga_g4_sit_dependent_allowances=allowances, + ga_g4_sit_additional_allowances=0, + ga_g4_sit_filing_status=filing_status, + state_income_tax_additional_withholding=additional_wh, + schedule_pay=schedule_pay) + + self.assertEqual(contract.schedule_pay, 'weekly') + + self._log('2019 Georgia tax first payslip weekly:') + payslip = self._createPayslip(employee, '2019-01-01', '2019-01-31') + payslip.compute_sheet() + cats = self._getCategories(payslip) + + self.assertPayrollEqual(cats['ER_US_SUTA'], self.GA_UNEMP_MAX_WAGE * self.GA_UNEMP) + self.assertPayrollEqual(cats['EE_US_SIT'], wh) + + process_payslip(payslip) + + remaining_GA_UNEMP_wages = 0.0 # We already reached max unemployment wages. + + self._log('2019 Georgia 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_GA_UNEMP_wages * self.GA_UNEMP) + + + def test_taxes_monthly_head_of_household(self): + salary = 25000.00 + schedule_pay = 'monthly' + allowances = 2 + filing_status = 'head of household' + additional_wh = 15.00 + # Hand Calculated Amount to Test + # Step 1 - Subtract standard deduction from wages. Std Deduct for head of household monthly is 383.50 + # step1 = 25000.00 - 383.50 = 24616.5 + # Step 2 - Subtract personal allowance from step1. Allowance for head of household monthly is 225.00 + # step2 = 24616.5 - 225.00 = 24391.5 + # Step 3 - Subtract amount for dependents. Weekly dependent allowance is 250.00 + # step3 = 24391.5 - (2 * 250.00) = 23891.5 + # Step 4 - Determine wh amount from tables + # step4 = 28.33 + ((5.75 / 100.00) * (23891.5 - 833.00)) = 1354.19375 + # Add additional_wh + # wh = 1354.19375 + 15.00 = 1369.19375 + wh = -1369.19 + + employee = self._createEmployee() + contract = self._createContract(employee, + wage=salary, + state_id=self.get_us_state('GA'), + ga_g4_sit_dependent_allowances=allowances, + ga_g4_sit_additional_allowances=0, + ga_g4_sit_filing_status=filing_status, + state_income_tax_additional_withholding=additional_wh, + schedule_pay=schedule_pay) + + self.assertEqual(contract.schedule_pay, 'monthly') + + self._log('2019 Georgia 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.GA_UNEMP_MAX_WAGE * self.GA_UNEMP) + self.assertPayrollAlmostEqual(cats['EE_US_SIT'], wh) + + process_payslip(payslip) + + remaining_GA_UNEMP_wages = 0.0 # We already reached max unemployment wages. + + self._log('2019 Georgia 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_GA_UNEMP_wages * self.GA_UNEMP) + + def test_taxes_exempt(self): + salary = 25000.00 + schedule_pay = 'monthly' + allowances = 2 + filing_status = 'exempt' + additional_wh = 15.00 + + employee = self._createEmployee() + contract = self._createContract(employee, + wage=salary, + state_id=self.get_us_state('GA'), + ga_g4_sit_dependent_allowances=allowances, + ga_g4_sit_additional_allowances=0, + ga_g4_sit_filing_status=filing_status, + state_income_tax_additional_withholding=additional_wh, + schedule_pay=schedule_pay) + + self._log('2019 Georgia tax first payslip exempt:') + payslip = self._createPayslip(employee, '2019-01-01', '2019-01-31') + payslip.compute_sheet() + cats = self._getCategories(payslip) + + self.assertPayrollEqual(cats.get('EE_US_SIT', 0), 0) diff --git a/l10n_us_hr_payroll/tests/test_us_ga_georgia_payslip_2020.py b/l10n_us_hr_payroll/tests/test_us_ga_georgia_payslip_2020.py new file mode 100755 index 00000000..6debc2ca --- /dev/null +++ b/l10n_us_hr_payroll/tests/test_us_ga_georgia_payslip_2020.py @@ -0,0 +1,148 @@ +# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details. + +from datetime import date +from .common import TestUsPayslip, process_payslip + + +class TestUsGAPayslip(TestUsPayslip): + + # TAXES AND RATES + GA_UNEMP_MAX_WAGE = 9500.00 + GA_UNEMP = 2.70 + + def _run_test_sit(self, + wage=0.0, + schedule_pay='monthly', + filing_status='single', + dependent_credit=0.0, + other_income=0.0, + deductions=0.0, + additional_withholding=0.0, + is_nonresident_alien=False, + state_income_tax_exempt=False, + state_income_tax_additional_withholding=0.0, + ga_g4_sit_dependent_allowances=0, + ga_g4_sit_additional_allowances=0, + ga_g4_sit_filing_status=None, + expected=0.0, + ): + employee = self._createEmployee() + contract = self._createContract(employee, + wage=wage, + schedule_pay=schedule_pay, + fed_941_fit_w4_is_nonresident_alien=is_nonresident_alien, + fed_941_fit_w4_filing_status=filing_status, + fed_941_fit_w4_multiple_jobs_higher=False, + fed_941_fit_w4_dependent_credit=dependent_credit, + fed_941_fit_w4_other_income=other_income, + fed_941_fit_w4_deductions=deductions, + fed_941_fit_w4_additional_withholding=additional_withholding, + state_income_tax_exempt=state_income_tax_exempt, + state_income_tax_additional_withholding=state_income_tax_additional_withholding, + ga_g4_sit_dependent_allowances=ga_g4_sit_dependent_allowances, + ga_g4_sit_additional_allowances=ga_g4_sit_additional_allowances, + ga_g4_sit_filing_status=ga_g4_sit_filing_status, + state_id=self.get_us_state('GA'), + ) + payslip = self._createPayslip(employee, '2020-01-01', '2020-01-31') + payslip.compute_sheet() + cats = self._getCategories(payslip) + # Instead of PayrollEqual after initial first round of testing. + self.assertPayrollAlmostEqual(cats.get('EE_US_SIT', 0.0), -expected) + return payslip + + def test_taxes_weekly_single_with_additional_wh(self): + self._test_er_suta('GA', self.GA_UNEMP, date(2020, 1, 1), wage_base=self.GA_UNEMP_MAX_WAGE) + salary = 15000.00 + schedule_pay = 'weekly' + allowances = 1 + filing_status = 'single' + additional_wh = 12.50 + # Hand Calculated Amount to Test + # Step 1 - Subtract standard deduction from wages. Std Deduct for single weekly is 88.50 + # step1 = 15000.00 - 88.50 = 14911.5 + # Step 2 - Subtract personal allowance from step1. Allowance for single weekly is 51.92 + # step2 = step1 - 51.92 = 14859.58 + # Step 3 - Subtract amount for dependents. Weekly dependent allowance is 57.50 + # step3 = 14859.58 - 57.50 = 14802.08 + # Step 4 -Determine wh amount from tables + # step4 = 4.42 + ((5.75 / 100.00) * (14802.08 - 135.00)) + # Add additional_wh + # wh = 847.7771 + 12.50 = 860.2771 + wh = 860.28 + + self._run_test_sit(wage=salary, + schedule_pay=schedule_pay, + state_income_tax_additional_withholding=additional_wh, + ga_g4_sit_dependent_allowances=allowances, + ga_g4_sit_additional_allowances=0, + ga_g4_sit_filing_status=filing_status, + expected=wh, + ) + + + def test_taxes_monthly_head_of_household(self): + salary = 25000.00 + schedule_pay = 'monthly' + allowances = 2 + filing_status = 'head of household' + additional_wh = 15.00 + # Hand Calculated Amount to Test + # Step 1 - Subtract standard deduction from wages. Std Deduct for head of household monthly is 383.50 + # step1 = 25000.00 - 383.50 = 24616.5 + # Step 2 - Subtract personal allowance from step1. Allowance for head of household monthly is 225.00 + # step2 = 24616.5 - 225.00 = 24391.5 + # Step 3 - Subtract amount for dependents. Weekly dependent allowance is 250.00 + # step3 = 24391.5 - (2 * 250.00) = 23891.5 + # Step 4 - Determine wh amount from tables + # step4 = 28.33 + ((5.75 / 100.00) * (23891.5 - 833.00)) = 1354.19375 + # Add additional_wh + # wh = 1354.19375 + 15.00 = 1369.19375 + wh = 1369.19 + + self._run_test_sit(wage=salary, + schedule_pay=schedule_pay, + state_income_tax_additional_withholding=additional_wh, + ga_g4_sit_dependent_allowances=allowances, + ga_g4_sit_additional_allowances=0, + ga_g4_sit_filing_status=filing_status, + expected=wh, + ) + + # additional from external calculator + self._run_test_sit(wage=425.0, + schedule_pay='weekly', + state_income_tax_additional_withholding=0.0, + ga_g4_sit_dependent_allowances=1, + ga_g4_sit_additional_allowances=0, + ga_g4_sit_filing_status='married filing separate', + expected=11.45, + ) + + self._run_test_sit(wage=3000.0, + schedule_pay='quarterly', + state_income_tax_additional_withholding=0.0, + ga_g4_sit_dependent_allowances=1, + ga_g4_sit_additional_allowances=1, + ga_g4_sit_filing_status='single', + expected=0.0, + ) + + # TODO 'married filing joint, both spouses working' returns lower than calculator + # TODO 'married filing joint, one spouse working' returns lower than calculator + + def test_taxes_exempt(self): + salary = 25000.00 + schedule_pay = 'monthly' + allowances = 2 + filing_status = 'exempt' + additional_wh = 15.00 + + self._run_test_sit(wage=salary, + schedule_pay=schedule_pay, + state_income_tax_additional_withholding=additional_wh, + ga_g4_sit_dependent_allowances=allowances, + ga_g4_sit_additional_allowances=0, + ga_g4_sit_filing_status=filing_status, + expected=0.0, + ) diff --git a/l10n_us_hr_payroll/views/us_payroll_config_views.xml b/l10n_us_hr_payroll/views/us_payroll_config_views.xml index 987c6958..395b008b 100644 --- a/l10n_us_hr_payroll/views/us_payroll_config_views.xml +++ b/l10n_us_hr_payroll/views/us_payroll_config_views.xml @@ -47,6 +47,14 @@

No additional fields.

+ +

Form G-4 - State Income Tax

+ + + + + +

Form MT-4 - State Income Tax