From fe05ac55c4bbbdb584ced60be3984f0eba9d3705 Mon Sep 17 00:00:00 2001
From: Jared Kipe
Date: Thu, 9 Jan 2020 11:04:38 -0800
Subject: [PATCH] IMP `l10n_us_hr_payroll` Add GA Georgia (unemployment, income
tax)
---
l10n_us_hr_payroll/__manifest__.py | 1 +
l10n_us_hr_payroll/data/state/ga_georgia.xml | 279 ++++++++++++++++++
l10n_us_hr_payroll/models/hr_payslip.py | 2 +
l10n_us_hr_payroll/models/state/ga_georgia.py | 52 ++++
.../models/us_payroll_config.py | 13 +
l10n_us_hr_payroll/tests/__init__.py | 3 +
.../tests/test_us_ga_georgia_payslip_2019.py | 135 +++++++++
.../tests/test_us_ga_georgia_payslip_2020.py | 148 ++++++++++
.../views/us_payroll_config_views.xml | 8 +
9 files changed, 641 insertions(+)
create mode 100644 l10n_us_hr_payroll/data/state/ga_georgia.xml
create mode 100644 l10n_us_hr_payroll/models/state/ga_georgia.py
create mode 100755 l10n_us_hr_payroll/tests/test_us_ga_georgia_payslip_2019.py
create mode 100755 l10n_us_hr_payroll/tests/test_us_ga_georgia_payslip_2020.py
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