diff --git a/l10n_us_ca_hr_payroll/__init__.py b/l10n_us_ca_hr_payroll/__init__.py
index 1027e233..0650744f 100755
--- a/l10n_us_ca_hr_payroll/__init__.py
+++ b/l10n_us_ca_hr_payroll/__init__.py
@@ -1 +1 @@
-from . import hr_payroll
\ No newline at end of file
+from . import models
diff --git a/l10n_us_ca_hr_payroll/__manifest__.py b/l10n_us_ca_hr_payroll/__manifest__.py
index b712cbae..7486370d 100755
--- a/l10n_us_ca_hr_payroll/__manifest__.py
+++ b/l10n_us_ca_hr_payroll/__manifest__.py
@@ -4,7 +4,7 @@
'license': 'AGPL-3',
'category': 'Localization',
'depends': ['l10n_us_hr_payroll'],
- 'version': '11.0.2018.1.0',
+ 'version': '11.0.2019.0.0',
'description': """
USA::California Payroll Rules.
==============================
@@ -22,9 +22,10 @@ USA::California Payroll Rules.
'auto_install': False,
'website': 'https://hibou.io/',
'data': [
- 'hr_payroll_view.xml',
+ 'views/hr_payroll_views.xml',
'data/base.xml',
- 'data/rules_2018.xml',
+ 'data/rates.xml',
+ 'data/rules.xml',
'data/final.xml',
],
'installable': True
diff --git a/l10n_us_ca_hr_payroll/data/base.xml b/l10n_us_ca_hr_payroll/data/base.xml
index 6ec2431a..ea585d66 100755
--- a/l10n_us_ca_hr_payroll/data/base.xml
+++ b/l10n_us_ca_hr_payroll/data/base.xml
@@ -32,62 +32,43 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- California Unemployment Insurance Tax - Wages
- CA_UIT_WAGES
+ Wage: US-CA Unemployment Insurance
+ WAGE_US_CA_UNEMP
- California Unemployment Insurance Tax
- CA_UIT
+ ER: US-CA Unemployment Insurance
+ ER_US_CA_UNEMP
- California Employee Training Tax - Wages
- CA_ETT_WAGES
+ Wage: US-CA Employee Training Tax
+ WAGE_US_CA_ETT
- California Employee Training Tax
- CA_ETT
+ ER: US-CA Employee Training Tax
+ ER_US_CA_ETT
- California State Disability Insurance - Wages
- CA_SDI_WAGES
+ Wage: US-CA State Disability Insurance
+ WAGE_US_CA_SDI
- California State Disability Insurance
- CA_SDI
+ EE: US-CA State Disability Insurance
+ EE_US_CA_SDI
- California Income Withholding
- CA_WITHHOLD
+ EE: US-CA Income Withholding
+ EE_US_CA_INC_WITHHOLD
diff --git a/l10n_us_ca_hr_payroll/data/rates.xml b/l10n_us_ca_hr_payroll/data/rates.xml
new file mode 100755
index 00000000..86dd0f2c
--- /dev/null
+++ b/l10n_us_ca_hr_payroll/data/rates.xml
@@ -0,0 +1,46 @@
+
+
+
+ US California Unemployment
+ US_CA_UNEMP
+ 2.6
+ 2018-01-01
+
+
+
+ US California Employment Training Tax
+ US_CA_ETT
+ 0.1
+ 2018-01-01
+
+
+
+ US California State Disability Insurance
+ US_CA_SDI
+ 1.0
+ 2018-01-01
+
+
+
+
+ US California Unemployment
+ US_CA_UNEMP
+ 3.4
+ 2019-01-01
+
+
+
+ US California Employment Training Tax
+ US_CA_ETT
+ 0.1
+ 2019-01-01
+
+
+
+ US California State Disability Insurance
+ US_CA_SDI
+ 1.0
+ 2019-01-01
+
+
+
diff --git a/l10n_us_ca_hr_payroll/data/rules.xml b/l10n_us_ca_hr_payroll/data/rules.xml
new file mode 100755
index 00000000..9a31434f
--- /dev/null
+++ b/l10n_us_ca_hr_payroll/data/rules.xml
@@ -0,0 +1,1005 @@
+
+
+
+
+
+
+
+
+
+ Wage: US-CA Unemployment Insurance
+ WAGE_US_CA_UNEMP
+ python
+ result = (contract.futa_type != contract.FUTA_TYPE_BASIC)
+ code
+
+###
+rate = payslip.dict.get_rate('US_CA_UNEMP')
+year = int(payslip.dict.date_from[:4])
+ytd = payslip.sum('WAGE_US_CA_UNEMP', str(year) + '-01-01', str(year+1) + '-01-01')
+ytd += contract.external_wages
+remaining = rate.wage_limit_year - ytd
+if remaining <= 0.0:
+ result = 0
+elif remaining < categories.BASIC:
+ result = remaining
+else:
+ result = categories.BASIC
+
+
+
+
+
+
+
+ ER: US-CA Unemployment Insurance Tax
+ ER_US_CA_UNEMP
+ python
+ result = (contract.futa_type != contract.FUTA_TYPE_BASIC)
+ code
+
+rate = payslip.dict.get_rate('US_CA_UNEMP')
+result_rate = -rate.rate
+result = categories.WAGE_US_CA_UNEMP
+
+# result_rate of 0 implies 100% due to bug
+if result_rate == 0.0:
+ result = 0.0
+
+
+
+
+
+
+
+
+
+ Wage: US-CA Employment Training Tax
+ WAGE_US_CA_ETT
+ python
+ result = (contract.futa_type != contract.FUTA_TYPE_BASIC)
+ code
+
+###
+rate = payslip.dict.get_rate('US_CA_ETT')
+year = int(payslip.dict.date_from[:4])
+ytd = payslip.sum('WAGE_US_CA_ETT', str(year) + '-01-01', str(year+1) + '-01-01')
+ytd += contract.external_wages
+remaining = rate.wage_limit_year - ytd
+if remaining <= 0.0:
+ result = 0
+elif remaining < categories.BASIC:
+ result = remaining
+else:
+ result = categories.BASIC
+
+
+
+
+
+
+
+ ER: US-CA Employee Training Tax
+ ER_US_CA_ETT
+ python
+ result = (contract.futa_type != contract.FUTA_TYPE_BASIC)
+ code
+
+rate = payslip.dict.get_rate('US_CA_ETT')
+result_rate = -rate.rate
+result = categories.WAGE_US_CA_ETT
+
+# result_rate of 0 implies 100% due to bug
+if result_rate == 0.0:
+ result = 0.0
+
+
+
+
+
+
+
+
+
+ Wage: US-CA State Disability Insurance
+ WAGE_US_CA_SDI
+ python
+ result = (contract.futa_type != contract.FUTA_TYPE_BASIC)
+ code
+
+###
+rate = payslip.dict.get_rate('US_CA_SDI')
+year = int(payslip.dict.date_from[:4])
+ytd = payslip.sum('WAGE_US_CA_SDI', str(year) + '-01-01', str(year+1) + '-01-01')
+ytd += contract.external_wages
+remaining = rate.wage_limit_year - ytd
+if remaining <= 0.0:
+ result = 0
+elif remaining < categories.BASIC:
+ result = remaining
+else:
+ result = categories.BASIC
+
+
+
+
+
+
+
+ EE: US-CA State Disability Insurance
+ EE_US_CA_SDI
+ python
+ result = (contract.futa_type != contract.FUTA_TYPE_BASIC)
+ code
+
+rate = payslip.dict.get_rate('US_CA_SDI')
+result_rate = -rate.rate
+result = categories.WAGE_US_CA_SDI
+
+# result_rate of 0 implies 100% due to bug
+if result_rate == 0.0:
+ result = 0.0
+
+
+
+
+
+
+
+
+
+ EE: US-CA Income Withholding
+ EE_US_CA_INC_WITHHOLD
+ python
+ result = True
+ code
+
+year = int(payslip.dict.date_from[:4])
+wages = categories.GROSS
+allowances = contract.ca_de4_allowances
+additional_allowances = contract.ca_additional_allowances
+schedule_pay = contract.schedule_pay
+filing_status = contract.ca_de4_filing_status
+low_income = False
+
+if year == 2018:
+ # Tables are found in http://www.edd.ca.gov/pdf_pub_ctr/18methb.pdf
+ # First check low income exemption table (Step 1)
+ low_income_exemption_table = {
+ 'weekly': (270, 270, 540, 540),
+ 'bi-weekly': (540, 540, 1081, 1081),
+ 'semi-monthly': (585, 585, 1171, 1171),
+ 'monthly': (1171, 1171, 2341, 2341),
+ 'quarterly': (3512, 3512, 7024, 7024),
+ 'semi-annual': (7024, 7024, 14048, 14048),
+ 'annually': (14048, 14048, 28095, 28095),
+ }
+
+ if filing_status == 'head_household':
+ _, _, _, income = low_income_exemption_table[schedule_pay]
+ if wages <= income:
+ result = 0
+ low_income = True
+ elif filing_status == 'married':
+ if allowances >= 2:
+ _, _, income, _ = low_income_exemption_table[schedule_pay]
+ if wages <= income:
+ result = 0
+ low_income = True
+ else:
+ _, income, _, _ = low_income_exemption_table[schedule_pay]
+ if wages <= income:
+ result = 0
+ low_income = True
+ else:
+ income, _, _, _ = low_income_exemption_table[schedule_pay]
+ if wages <= income:
+ result = 0
+ low_income = True
+
+ if not low_income:
+ # Estimated deduction table (Step 2)
+ estimated_deduction_table = {
+ 'weekly': (19, 38, 58, 77, 96, 115, 135, 154, 173, 192),
+ 'bi-weekly': (38, 77, 115, 154, 192, 231, 269, 308, 346, 385),
+ 'semi-monthly': (42, 83, 125, 167, 208, 250, 292, 333, 375, 417),
+ 'monthly': (83, 167, 250, 333, 417, 500, 583, 667, 750, 833),
+ 'quarterly': (250, 500, 750, 1000, 1250, 1500, 1750, 2000, 2250, 2500),
+ 'semi-annual': (500, 1000, 1500, 2000, 2500, 3000, 3500, 4000, 4500, 5000),
+ 'annually': (1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000, 10000),
+ }
+
+ allowance_index = additional_allowances - 1
+ if additional_allowances > 10:
+ deduction = (estimated_deduction_table[schedule_pay][0]) * additional_allowances
+ wages -= deduction
+ elif additional_allowances > 0:
+ deduction = estimated_deduction_table[schedule_pay][allowance_index]
+ wages -= deduction
+
+ # Standard deduction table (Step 3)
+ standard_deduction_table = {
+ 'weekly': (81, 81, 163, 163),
+ 'bi-weekly': (163, 163, 326, 326),
+ 'semi-monthly': (177, 177, 353, 353),
+ 'monthly': (353, 353, 706, 706),
+ 'quarterly': (1059, 1059, 2118, 2118),
+ 'semi-annual': (2118, 2118, 4236, 4236),
+ 'annually': (4236, 4236, 8472, 8472),
+ }
+
+ if filing_status == 'head_household':
+ _, _, _, deduction = standard_deduction_table[schedule_pay]
+ wages -= deduction
+ elif filing_status == 'married':
+ if allowances >= 2:
+ _, _, deduction, _ = standard_deduction_table[schedule_pay]
+ wages -= deduction
+ else:
+ _, deduction, _, _ = standard_deduction_table[schedule_pay]
+ wages -= deduction
+ else:
+ deduction, _, _, _ = standard_deduction_table[schedule_pay]
+ wages -= deduction
+
+ # Tax Rate Tables (Step 4)
+ #### WEEKLY ####
+ if schedule_pay == 'weekly':
+ if filing_status == 'head_household' and wages > 0:
+ tax_rate_table = [
+ (316, 0.011, 0.0),
+ (750, 0.022, 3.48),
+ (967, 0.044, 13.03),
+ (1196, 0.066, 22.58),
+ (1413, 0.088, 37.69),
+ (7212, 0.1023, 56.79),
+ (8654, 0.1133, 650.03),
+ (14423, 0.1243, 813.41),
+ (19231, 0.1353, 1530.50),
+ (float('inf'), 0.1463, 2181.02),
+ ]
+
+ elif filing_status == 'married':
+ tax_rate_table = [
+ (316, 0.011, 0.0),
+ (750, 0.022, 3.48),
+ (1184, 0.044, 13.03),
+ (1642, 0.066, 32.13),
+ (2076, 0.088, 62.36),
+ (10606, 0.1023, 100.55),
+ (12726, 0.1133, 973.17),
+ (19231, 0.1243, 1213.37),
+ (21210, 0.1353, 2021.94),
+ (float('inf'), 0.1463, 2289.70),
+ ]
+
+ else:
+ tax_rate_table = [
+ (158, 0.011, 0.0),
+ (375, 0.022, 1.74),
+ (592, 0.044, 6.51),
+ (821, 0.066, 16.06),
+ (1038, 0.088, 31.17),
+ (5303, 0.1023, 50.27),
+ (6363, 0.1133, 486.58),
+ (10605, 0.1243, 606.68),
+ (19231, 0.1353, 1133.96),
+ (float('inf'), 0.1463, 2301.06),
+ ]
+
+ #### BI-WEEKLY ####
+ elif schedule_pay == 'bi-weekly':
+ if filing_status == 'head_household':
+ tax_rate_table = [
+ (632, 0.011, 0.0),
+ (1500, 0.022, 6.95),
+ (1934, 0.044, 26.05),
+ (2392, 0.066, 45.15),
+ (2826, 0.088, 75.38),
+ (14424, 0.1023, 113.57),
+ (17308, 0.1133, 1300.05),
+ (28846, 0.1243, 1626.81),
+ (38462, 0.1353, 3060.98),
+ (float('inf'), 0.1463, 4362.02),
+ ]
+
+ elif filing_status == 'married':
+ tax_rate_table = [
+ (632, 0.011, 0.0),
+ (1500, 0.022, 6.95),
+ (2368, 0.044, 26.05),
+ (3284, 0.066, 64.24),
+ (4152, 0.088, 124.70),
+ (21212, 0.1023, 201.08),
+ (25452, 0.1133, 1946.32),
+ (38462, 0.1243, 2426.71),
+ (42420, 0.1353, 4043.85),
+ (float('inf'), 0.1463, 4579.37),
+ ]
+
+ else:
+ tax_rate_table = [
+ (316, 0.011, 0.0),
+ (750, 0.022, 3.48),
+ (1184, 0.044, 13.03),
+ (1642, 0.066, 32.13),
+ (2076, 0.088, 62.36),
+ (10606, 0.1023, 100.55),
+ (12726, 0.1133, 973.17),
+ (21210, 0.1243, 1213.37),
+ (38462, 0.1353, 2267.93),
+ (float('inf'), 0.1463, 4602.13),
+ ]
+
+ #### SEMI-MONTHLY ####
+ elif schedule_pay == 'semi-monthly':
+ if filing_status == 'head_household':
+ tax_rate_table = [
+ (686, 0.011, 0.0),
+ (1625, 0.022, 7.55),
+ (2094, 0.044, 28.21),
+ (2592, 0.066, 48.85),
+ (3062, 0.088, 81.72),
+ (15625, 0.1023, 123.08),
+ (18750, 0.1133, 1408.27),
+ (31250, 0.1243, 1762.33),
+ (41667, 0.1353, 3316.08),
+ (float('inf'), 0.1463, 4725.50),
+ ]
+
+ elif filing_status == 'married':
+ tax_rate_table = [
+ (686, 0.011, 0.0),
+ (1624, 0.022, 7.55),
+ (2564, 0.044, 28.19),
+ (3560, 0.066, 69.55),
+ (4498, 0.088, 135.29),
+ (22978, 0.1023, 217.83),
+ (27574, 0.1133, 2108.33),
+ (41667, 0.1243, 2629.06),
+ (45956, 0.1353, 4380.82),
+ (float('inf'), 0.1463, 4961.12),
+ ]
+
+ else:
+ tax_rate_table = [
+ (343, 0.011, 0.0),
+ (812, 0.022, 3.77),
+ (1282, 0.044, 14.09),
+ (1780, 0.066, 34.77),
+ (2249, 0.088, 67.64),
+ (11489, 0.1023, 108.91),
+ (13787, 0.1133, 1054.16),
+ (22978, 0.1243, 1314.52),
+ (41667, 0.1353, 2456.96),
+ (float('inf'), 0.1463, 4985.58),
+ ]
+
+ #### MONTHLY ####
+ elif schedule_pay == 'monthly':
+ if filing_status == 'head_household':
+ tax_rate_table = [
+ (1372, 0.011, 0.0),
+ (3250, 0.022, 15.09),
+ (4188, 0.044, 56.41),
+ (5184, 0.066, 97.68),
+ (6124, 0.088, 163.42),
+ (31250, 0.1023, 246.148),
+ (37500, 0.1133, 2816.53),
+ (62500, 0.1243, 3524.66),
+ (83334, 0.1353, 6632.16),
+ (float('inf'), 0.1463, 9451.00),
+ ]
+
+ elif filing_status == 'married':
+ tax_rate_table = [
+ (1372, 0.011, 0.0),
+ (3248, 0.022, 15.09),
+ (5128, 0.044, 56.36),
+ (7120, 0.066, 139.08),
+ (8996, 0.088, 270.55),
+ (45956, 0.1023, 435.64),
+ (55148, 0.1133, 4216.65),
+ (83334, 0.1243, 5258.10),
+ (91912, 0.1353, 8761.62),
+ (float('inf'), 0.1463, 9922.22),
+ ]
+
+ else:
+ tax_rate_table = [
+ (686, 0.011, 0.0),
+ (1624, 0.022, 7.55),
+ (2564, 0.044, 28.19),
+ (3560, 0.066, 69.55),
+ (4498, 0.088, 135.29),
+ (22978, 0.1023, 217.83),
+ (27574, 0.1133, 2108.33),
+ (45956, 0.1243, 2629.06),
+ (83334, 0.1353, 4913.94),
+ (float('inf'), 0.1463, 9971.18),
+ ]
+
+ #### QUARTERLY ####
+ elif schedule_pay == 'quarterly':
+ if filing_status == 'head_household':
+ tax_rate_table = [
+ (4114, 0.011, 0.0),
+ (9748, 0.022, 45.25),
+ (12566, 0.044, 169.20),
+ (15552, 0.066, 293.19),
+ (18369, 0.088, 490.27),
+ (93751, 0.1023, 738.17),
+ (112501, 0.1133, 8449.75),
+ (187501, 0.1243, 10574.13),
+ (250000, 0.1353, 19896.63),
+ (float('inf'), 0.1463, 28352.74),
+ ]
+
+ elif filing_status == 'married':
+ tax_rate_table = [
+ (4112, 0.011, 0.0),
+ (9748, 0.022, 45.23),
+ (15384, 0.044, 169.22),
+ (21356, 0.066, 417.20),
+ (26990, 0.088, 811.35),
+ (137870, 0.1023, 1307.14),
+ (165442, 0.1133, 12650.16),
+ (250000, 0.1243, 15774.07),
+ (275736, 0.1353, 26284.63),
+ (float('inf'), 0.1463, 29766.71),
+ ]
+
+ else:
+ tax_rate_table = [
+ (2056, 0.011, 0.0),
+ (4874, 0.022, 22.62),
+ (7692, 0.044, 84.62),
+ (10678, 0.066, 208.61),
+ (13495, 0.088, 405.69),
+ (68935, 0.1023, 653.59),
+ (82721, 0.1133, 6325.10),
+ (137868, 0.1243, 7887.05),
+ (250000, 0.1353, 14741.82),
+ (float('inf'), 0.1463, 29913.28),
+ ]
+
+ #### SEMI-ANNUAL ####
+ elif schedule_pay == 'semi-annual':
+ if filing_status == 'head_household':
+ tax_rate_table = [
+ (8228, 0.011, 0.0),
+ (19496, 0.022, 90.51),
+ (25132, 0.044, 338.41),
+ (31104, 0.066, 586.39),
+ (36738, 0.088, 980.54),
+ (187502, 0.1023, 1476.33),
+ (225002, 0.1133, 16899.49),
+ (375002, 0.1243, 21148.24),
+ (500000, 0.1353, 39793.24),
+ (float('inf'), 0.1463, 56705.47),
+ ]
+
+ elif filing_status == 'married':
+ tax_rate_table = [
+ (8224, 0.011, 0.0),
+ (19496, 0.022, 90.46),
+ (30768, 0.044, 338.44),
+ (42712, 0.066, 834.41),
+ (53980, 0.088, 1622.71),
+ (275740, 0.1023, 2614.29),
+ (330884, 0.1133, 25300.34),
+ (500000, 0.1243, 31548.16),
+ (551472, 0.1353, 52569.28),
+ (float('inf'), 0.1463, 59533.44),
+ ]
+
+ else:
+ tax_rate_table = [
+ (4112, 0.011, 0.0),
+ (9748, 0.022, 45.23),
+ (15384, 0.044, 169.22),
+ (21356, 0.066, 417.20),
+ (26990, 0.088, 811.35),
+ (137870, 0.1023, 1307.14),
+ (165442, 0.1133, 12650.16),
+ (275736, 0.1243, 15774.07),
+ (500000, 0.1353, 29483.61),
+ (float('inf'), 0.1463, 59826.53),
+ ]
+
+ #### ANNUAL ####
+ elif schedule_pay == 'annually':
+ if filing_status == 'head_household':
+ tax_rate_table = [
+ (16457, 0.011, 0.0),
+ (38991, 0.022, 181.03),
+ (50264, 0.044, 676.78),
+ (62206, 0.066, 1172.79),
+ (73477, 0.088, 1960.96),
+ (375002, 0.1023, 2952.81),
+ (450003, 0.1133, 33798.82),
+ (750003, 0.1243, 42296.43),
+ (1000000, 0.1353, 79586.43),
+ (float('inf'), 0.1463, 113411.02),
+ ]
+
+ elif filing_status == 'married':
+ tax_rate_table = [
+ (16446, 0.011, 0.0),
+ (38990, 0.022, 180.91),
+ (61538, 0.044, 676.88),
+ (85422, 0.066, 1668.99),
+ (107960, 0.088, 3245.33),
+ (551476, 0.1023, 5228.67),
+ (661768, 0.1133, 50600.36),
+ (1000000, 0.1243, 63096.44),
+ (1102946, 0.1353, 105138.68),
+ (float('inf'), 0.1463, 119067.26),
+ ]
+
+ else:
+ tax_rate_table = [
+ (8223, 0.011, 0.0),
+ (19495, 0.022, 90.45),
+ (30769, 0.044, 338.43),
+ (42711, 0.066, 834.49),
+ (53980, 0.088, 1622.66),
+ (275738, 0.1023, 2614.33),
+ (330884, 0.1133, 25300.17),
+ (551473, 0.1243, 31548.21),
+ (1000000, 0.1353, 58967.42),
+ (float('inf'), 0.1463, 119653.12),
+ ]
+
+ over = 0.0
+ tax = 0.0
+ for row in tax_rate_table:
+ if wages <= row[0]:
+ tax = ((wages - over) * row[1]) + row[2]
+ break
+ over = row[0]
+
+ # Exemption allowance table (Step 5)
+ exemption_allowance_table = {
+ 'weekly': (2.41, 4.82, 7.23, 9.65, 12.06, 14.47, 16.88, 19.29, 21.70, 24.12),
+ 'bi-weekly': (4.82, 9.65, 14.47, 19.29, 24.12, 28.94, 33.76, 38.58, 43.41, 48.23),
+ 'semi-monthly': (5.23, 10.45, 15.68, 20.90, 26.13, 31.35, 36.58, 41.80, 47.03, 52.25),
+ 'monthly': (10.45, 20.90, 31.35, 41.80, 52.25, 62.70, 73.15, 83.60, 94.05, 104.50),
+ 'quarterly': (31.35, 62.70, 94.05, 125.40, 156.75, 188.10, 219.45, 250.80, 282.15, 313.50),
+ 'semi-annual': (62.70, 125.40, 188.10, 250.80, 313.50, 376.20, 438.90, 501.60, 564.30, 627.00),
+ 'annually': (125.40, 250.80, 376.20, 501.60, 627.00, 752.40, 877.80, 1003.20, 1128.60, 1254.00),
+ }
+
+ allowance_index = allowances - 1
+ if allowances > 10:
+ deduction = (exemption_allowance_table[schedule_pay][0]) * allowances
+ tax -= deduction
+ elif allowances > 0:
+ deduction = exemption_allowance_table[schedule_pay][allowance_index]
+ tax -= deduction
+
+ result = -tax
+else:
+ # 2019
+ # Tables are found in http://www.edd.ca.gov/pdf_pub_ctr/18methb.pdf
+ # First check low income exemption table (Step 1)
+ low_income_exemption_table = {
+ 'weekly': (280, 280, 561, 561),
+ 'bi-weekly': (561, 561, 1121, 1121),
+ 'semi-monthly': (607, 607, 1214, 1214),
+ 'monthly': (1214, 1214, 2429, 2429),
+ 'quarterly': (3643, 3643, 7287, 7287),
+ 'semi-annual': (7287, 7287, 14573, 14573),
+ 'annually': (14573, 14573, 29146, 29146),
+ }
+
+ if filing_status == 'head_household':
+ _, _, _, income = low_income_exemption_table[schedule_pay]
+ if wages <= income:
+ result = 0
+ low_income = True
+ elif filing_status == 'married':
+ if allowances >= 2:
+ _, _, income, _ = low_income_exemption_table[schedule_pay]
+ if wages <= income:
+ result = 0
+ low_income = True
+ else:
+ _, income, _, _ = low_income_exemption_table[schedule_pay]
+ if wages <= income:
+ result = 0
+ low_income = True
+ else:
+ income, _, _, _ = low_income_exemption_table[schedule_pay]
+ if wages <= income:
+ result = 0
+ low_income = True
+
+ if not low_income:
+ # Estimated deduction table (Step 2)
+ estimated_deduction_table = {
+ 'weekly': (19, 38, 58, 77, 96, 115, 135, 154, 173, 192),
+ 'bi-weekly': (38, 77, 115, 154, 192, 231, 269, 308, 346, 385),
+ 'semi-monthly': (42, 83, 125, 167, 208, 250, 292, 333, 375, 417),
+ 'monthly': (83, 167, 250, 333, 417, 500, 583, 667, 750, 833),
+ 'quarterly': (250, 500, 750, 1000, 1250, 1500, 1750, 2000, 2250, 2500),
+ 'semi-annual': (500, 1000, 1500, 2000, 2500, 3000, 3500, 4000, 4500, 5000),
+ 'annually': (1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000, 10000),
+ }
+
+ allowance_index = additional_allowances - 1
+ if additional_allowances > 10:
+ deduction = (estimated_deduction_table[schedule_pay][0]) * additional_allowances
+ wages -= deduction
+ elif additional_allowances > 0:
+ deduction = estimated_deduction_table[schedule_pay][allowance_index]
+ wages -= deduction
+
+ # Standard deduction table (Step 3)
+ standard_deduction_table = {
+ 'weekly': (85, 85, 169, 169),
+ 'bi-weekly': (169, 169, 339, 339),
+ 'semi-monthly': (183, 183, 367, 367),
+ 'monthly': (367, 367, 734, 734),
+ 'quarterly': (1100, 1100, 2201, 2201),
+ 'semi-annual': (2201, 2201, 4401, 4401),
+ 'annually': (4401, 4401, 8802, 8802),
+ }
+
+ if filing_status == 'head_household':
+ _, _, _, deduction = standard_deduction_table[schedule_pay]
+ wages -= deduction
+ elif filing_status == 'married':
+ if allowances >= 2:
+ _, _, deduction, _ = standard_deduction_table[schedule_pay]
+ wages -= deduction
+ else:
+ _, deduction, _, _ = standard_deduction_table[schedule_pay]
+ wages -= deduction
+ else:
+ deduction, _, _, _ = standard_deduction_table[schedule_pay]
+ wages -= deduction
+
+ # Tax Rate Tables (Step 4)
+ #### WEEKLY ####
+ if schedule_pay == 'weekly':
+ if filing_status == 'head_household' and wages > 0:
+ tax_rate_table = [
+ (316, 0.011, 0.0),
+ (750, 0.022, 3.48),
+ (967, 0.044, 13.03),
+ (1196, 0.066, 22.58),
+ (1413, 0.088, 37.69),
+ (7212, 0.1023, 56.79),
+ (8654, 0.1133, 650.03),
+ (14423, 0.1243, 813.41),
+ (19231, 0.1353, 1530.50),
+ (float('inf'), 0.1463, 2181.02),
+ ]
+
+ elif filing_status == 'married':
+ tax_rate_table = [
+ (316, 0.011, 0.0),
+ (750, 0.022, 3.48),
+ (1184, 0.044, 13.03),
+ (1642, 0.066, 32.13),
+ (2076, 0.088, 62.36),
+ (10606, 0.1023, 100.55),
+ (12726, 0.1133, 973.17),
+ (19231, 0.1243, 1213.37),
+ (21210, 0.1353, 2021.94),
+ (float('inf'), 0.1463, 2289.70),
+ ]
+
+ else:
+ tax_rate_table = [
+ (158, 0.011, 0.0),
+ (375, 0.022, 1.74),
+ (592, 0.044, 6.51),
+ (821, 0.066, 16.06),
+ (1038, 0.088, 31.17),
+ (5303, 0.1023, 50.27),
+ (6363, 0.1133, 486.58),
+ (10605, 0.1243, 606.68),
+ (19231, 0.1353, 1133.96),
+ (float('inf'), 0.1463, 2301.06),
+ ]
+
+ #### BI-WEEKLY ####
+ elif schedule_pay == 'bi-weekly':
+ if filing_status == 'head_household':
+ tax_rate_table = [
+ (632, 0.011, 0.0),
+ (1500, 0.022, 6.95),
+ (1934, 0.044, 26.05),
+ (2392, 0.066, 45.15),
+ (2826, 0.088, 75.38),
+ (14424, 0.1023, 113.57),
+ (17308, 0.1133, 1300.05),
+ (28846, 0.1243, 1626.81),
+ (38462, 0.1353, 3060.98),
+ (float('inf'), 0.1463, 4362.02),
+ ]
+
+ elif filing_status == 'married':
+ tax_rate_table = [
+ (632, 0.011, 0.0),
+ (1500, 0.022, 6.95),
+ (2368, 0.044, 26.05),
+ (3284, 0.066, 64.24),
+ (4152, 0.088, 124.70),
+ (21212, 0.1023, 201.08),
+ (25452, 0.1133, 1946.32),
+ (38462, 0.1243, 2426.71),
+ (42420, 0.1353, 4043.85),
+ (float('inf'), 0.1463, 4579.37),
+ ]
+
+ else:
+ tax_rate_table = [
+ (316, 0.011, 0.0),
+ (750, 0.022, 3.48),
+ (1184, 0.044, 13.03),
+ (1642, 0.066, 32.13),
+ (2076, 0.088, 62.36),
+ (10606, 0.1023, 100.55),
+ (12726, 0.1133, 973.17),
+ (21210, 0.1243, 1213.37),
+ (38462, 0.1353, 2267.93),
+ (float('inf'), 0.1463, 4602.13),
+ ]
+
+ #### SEMI-MONTHLY ####
+ elif schedule_pay == 'semi-monthly':
+ if filing_status == 'head_household':
+ tax_rate_table = [
+ (686, 0.011, 0.0),
+ (1625, 0.022, 7.55),
+ (2094, 0.044, 28.21),
+ (2592, 0.066, 48.85),
+ (3062, 0.088, 81.72),
+ (15625, 0.1023, 123.08),
+ (18750, 0.1133, 1408.27),
+ (31250, 0.1243, 1762.33),
+ (41667, 0.1353, 3316.08),
+ (float('inf'), 0.1463, 4725.50),
+ ]
+
+ elif filing_status == 'married':
+ tax_rate_table = [
+ (686, 0.011, 0.0),
+ (1624, 0.022, 7.55),
+ (2564, 0.044, 28.19),
+ (3560, 0.066, 69.55),
+ (4498, 0.088, 135.29),
+ (22978, 0.1023, 217.83),
+ (27574, 0.1133, 2108.33),
+ (41667, 0.1243, 2629.06),
+ (45956, 0.1353, 4380.82),
+ (float('inf'), 0.1463, 4961.12),
+ ]
+
+ else:
+ tax_rate_table = [
+ (343, 0.011, 0.0),
+ (812, 0.022, 3.77),
+ (1282, 0.044, 14.09),
+ (1780, 0.066, 34.77),
+ (2249, 0.088, 67.64),
+ (11489, 0.1023, 108.91),
+ (13787, 0.1133, 1054.16),
+ (22978, 0.1243, 1314.52),
+ (41667, 0.1353, 2456.96),
+ (float('inf'), 0.1463, 4985.58),
+ ]
+
+ #### MONTHLY ####
+ elif schedule_pay == 'monthly':
+ if filing_status == 'head_household':
+ tax_rate_table = [
+ (1372, 0.011, 0.0),
+ (3250, 0.022, 15.09),
+ (4188, 0.044, 56.41),
+ (5184, 0.066, 97.68),
+ (6124, 0.088, 163.42),
+ (31250, 0.1023, 246.148),
+ (37500, 0.1133, 2816.53),
+ (62500, 0.1243, 3524.66),
+ (83334, 0.1353, 6632.16),
+ (float('inf'), 0.1463, 9451.00),
+ ]
+
+ elif filing_status == 'married':
+ tax_rate_table = [
+ (1372, 0.011, 0.0),
+ (3248, 0.022, 15.09),
+ (5128, 0.044, 56.36),
+ (7120, 0.066, 139.08),
+ (8996, 0.088, 270.55),
+ (45956, 0.1023, 435.64),
+ (55148, 0.1133, 4216.65),
+ (83334, 0.1243, 5258.10),
+ (91912, 0.1353, 8761.62),
+ (float('inf'), 0.1463, 9922.22),
+ ]
+
+ else:
+ tax_rate_table = [
+ (686, 0.011, 0.0),
+ (1624, 0.022, 7.55),
+ (2564, 0.044, 28.19),
+ (3560, 0.066, 69.55),
+ (4498, 0.088, 135.29),
+ (22978, 0.1023, 217.83),
+ (27574, 0.1133, 2108.33),
+ (45956, 0.1243, 2629.06),
+ (83334, 0.1353, 4913.94),
+ (float('inf'), 0.1463, 9971.18),
+ ]
+
+ #### QUARTERLY ####
+ elif schedule_pay == 'quarterly':
+ if filing_status == 'head_household':
+ tax_rate_table = [
+ (4114, 0.011, 0.0),
+ (9748, 0.022, 45.25),
+ (12566, 0.044, 169.20),
+ (15552, 0.066, 293.19),
+ (18369, 0.088, 490.27),
+ (93751, 0.1023, 738.17),
+ (112501, 0.1133, 8449.75),
+ (187501, 0.1243, 10574.13),
+ (250000, 0.1353, 19896.63),
+ (float('inf'), 0.1463, 28352.74),
+ ]
+
+ elif filing_status == 'married':
+ tax_rate_table = [
+ (4112, 0.011, 0.0),
+ (9748, 0.022, 45.23),
+ (15384, 0.044, 169.22),
+ (21356, 0.066, 417.20),
+ (26990, 0.088, 811.35),
+ (137870, 0.1023, 1307.14),
+ (165442, 0.1133, 12650.16),
+ (250000, 0.1243, 15774.07),
+ (275736, 0.1353, 26284.63),
+ (float('inf'), 0.1463, 29766.71),
+ ]
+
+ else:
+ tax_rate_table = [
+ (2056, 0.011, 0.0),
+ (4874, 0.022, 22.62),
+ (7692, 0.044, 84.62),
+ (10678, 0.066, 208.61),
+ (13495, 0.088, 405.69),
+ (68935, 0.1023, 653.59),
+ (82721, 0.1133, 6325.10),
+ (137868, 0.1243, 7887.05),
+ (250000, 0.1353, 14741.82),
+ (float('inf'), 0.1463, 29913.28),
+ ]
+
+ #### SEMI-ANNUAL ####
+ elif schedule_pay == 'semi-annual':
+ if filing_status == 'head_household':
+ tax_rate_table = [
+ (8228, 0.011, 0.0),
+ (19496, 0.022, 90.51),
+ (25132, 0.044, 338.41),
+ (31104, 0.066, 586.39),
+ (36738, 0.088, 980.54),
+ (187502, 0.1023, 1476.33),
+ (225002, 0.1133, 16899.49),
+ (375002, 0.1243, 21148.24),
+ (500000, 0.1353, 39793.24),
+ (float('inf'), 0.1463, 56705.47),
+ ]
+
+ elif filing_status == 'married':
+ tax_rate_table = [
+ (8224, 0.011, 0.0),
+ (19496, 0.022, 90.46),
+ (30768, 0.044, 338.44),
+ (42712, 0.066, 834.41),
+ (53980, 0.088, 1622.71),
+ (275740, 0.1023, 2614.29),
+ (330884, 0.1133, 25300.34),
+ (500000, 0.1243, 31548.16),
+ (551472, 0.1353, 52569.28),
+ (float('inf'), 0.1463, 59533.44),
+ ]
+
+ else:
+ tax_rate_table = [
+ (4112, 0.011, 0.0),
+ (9748, 0.022, 45.23),
+ (15384, 0.044, 169.22),
+ (21356, 0.066, 417.20),
+ (26990, 0.088, 811.35),
+ (137870, 0.1023, 1307.14),
+ (165442, 0.1133, 12650.16),
+ (275736, 0.1243, 15774.07),
+ (500000, 0.1353, 29483.61),
+ (float('inf'), 0.1463, 59826.53),
+ ]
+
+ #### ANNUAL ####
+ elif schedule_pay == 'annually':
+ if filing_status == 'head_household':
+ tax_rate_table = [
+ (16457, 0.011, 0.0),
+ (38991, 0.022, 181.03),
+ (50264, 0.044, 676.78),
+ (62206, 0.066, 1172.79),
+ (73477, 0.088, 1960.96),
+ (375002, 0.1023, 2952.81),
+ (450003, 0.1133, 33798.82),
+ (750003, 0.1243, 42296.43),
+ (1000000, 0.1353, 79586.43),
+ (float('inf'), 0.1463, 113411.02),
+ ]
+
+ elif filing_status == 'married':
+ tax_rate_table = [
+ (16446, 0.011, 0.0),
+ (38990, 0.022, 180.91),
+ (61538, 0.044, 676.88),
+ (85422, 0.066, 1668.99),
+ (107960, 0.088, 3245.33),
+ (551476, 0.1023, 5228.67),
+ (661768, 0.1133, 50600.36),
+ (1000000, 0.1243, 63096.44),
+ (1102946, 0.1353, 105138.68),
+ (float('inf'), 0.1463, 119067.26),
+ ]
+
+ else:
+ tax_rate_table = [
+ (8223, 0.011, 0.0),
+ (19495, 0.022, 90.45),
+ (30769, 0.044, 338.43),
+ (42711, 0.066, 834.49),
+ (53980, 0.088, 1622.66),
+ (275738, 0.1023, 2614.33),
+ (330884, 0.1133, 25300.17),
+ (551473, 0.1243, 31548.21),
+ (1000000, 0.1353, 58967.42),
+ (float('inf'), 0.1463, 119653.12),
+ ]
+
+ over = 0.0
+ tax = 0.0
+ for row in tax_rate_table:
+ if wages <= row[0]:
+ tax = ((wages - over) * row[1]) + row[2]
+ break
+ over = row[0]
+
+ # Exemption allowance table (Step 5) (Table 4)
+ exemption_allowance_table = {
+ 'weekly': (2.41, 4.82, 7.23, 9.65, 12.06, 14.47, 16.88, 19.29, 21.70, 24.12),
+ 'bi-weekly': (4.82, 9.65, 14.47, 19.29, 24.12, 28.94, 33.76, 38.58, 43.41, 48.23),
+ 'semi-monthly': (5.23, 10.45, 15.68, 20.90, 26.13, 31.35, 36.58, 41.80, 47.03, 52.25),
+ 'monthly': (10.45, 20.90, 31.35, 41.80, 52.25, 62.70, 73.15, 83.60, 94.05, 104.50),
+ 'quarterly': (31.35, 62.70, 94.05, 125.40, 156.75, 188.10, 219.45, 250.80, 282.15, 313.50),
+ 'semi-annual': (62.70, 125.40, 188.10, 250.80, 313.50, 376.20, 438.90, 501.60, 564.30, 627.00),
+ 'annually': (125.40, 250.80, 376.20, 501.60, 627.00, 752.40, 877.80, 1003.20, 1128.60, 1254.00),
+ }
+
+ allowance_index = allowances - 1
+ if allowances > 10:
+ deduction = (exemption_allowance_table[schedule_pay][0]) * allowances
+ tax -= deduction
+ elif allowances > 0:
+ deduction = exemption_allowance_table[schedule_pay][allowance_index]
+ tax -= deduction
+
+ result = -tax
+
+
+
+
+
+
diff --git a/l10n_us_ca_hr_payroll/data/rules_2018.xml b/l10n_us_ca_hr_payroll/data/rules_2018.xml
deleted file mode 100755
index 0cd42d36..00000000
--- a/l10n_us_ca_hr_payroll/data/rules_2018.xml
+++ /dev/null
@@ -1,576 +0,0 @@
-
-
-
-
-
-
-
-
-
- California Unemployment Insurance Tax - Wages (2018)
- CA_UIT_WAGES_2018
- python
- result = (payslip.date_to[:4] == '2018')
- code
-
-###
-ytd = payslip.sum('CA_UIT_WAGES_2018', '2018-01-01', '2019-01-01')
-ytd += contract.external_wages
-remaining = 7000.0 - ytd
-if remaining <= 0.0:
- result = 0
-elif remaining < categories.BASIC:
- result = remaining
-else:
- result = categories.BASIC
-
-
-
-
-
-
-
- California Unemployment Insurance Tax(2018)
- CA_UIT_2018
- python
- result = (payslip.date_to[:4] == '2018')
- code
-
-result_rate = -contract.ca_uit_rate(2018)
-result = categories.CA_UIT_WAGES
-
-# result_rate of 0 implies 100% due to bug
-if result_rate == 0.0:
- result = 0.0
-
-
-
-
-
-
-
-
-
- California Employment Training Tax - Wages (2018)
- CA_ETT_WAGES_2018
- python
- result = (payslip.date_to[:4] == '2018')
- code
-
-###
-ytd = payslip.sum('CA_ETT_WAGES_2018', '2018-01-01', '2019-01-01')
-ytd += contract.external_wages
-remaining = 7000.0 - ytd
-if remaining <= 0.0:
- result = 0
-elif remaining < categories.BASIC:
- result = remaining
-else:
- result = categories.BASIC
-
-
-
-
-
-
-
- California Employee Training Tax(2018)
- CA_ETT_2018
- python
- result = (payslip.date_to[:4] == '2018')
- code
-
-result_rate = -contract.ca_ett_rate(2018)
-result = categories.CA_ETT_WAGES
-
-# result_rate of 0 implies 100% due to bug
-if result_rate == 0.0:
- result = 0.0
-
-
-
-
-
-
-
-
-
- California State Disability Insurance Tax - Wages (2018)
- CA_SDI_WAGES_2018
- python
- result = (payslip.date_to[:4] == '2018')
- code
-
-###
-ytd = payslip.sum('CA_SDI_WAGES_2018', '2018-01-01', '2019-01-01')
-ytd += contract.external_wages
-remaining = 114967.0 - ytd
-if remaining <= 0.0:
- result = 0
-elif remaining < categories.BASIC:
- result = remaining
-else:
- result = categories.BASIC
-
-
-
-
-
-
-
- California State Disability Insurance(2018)
- CA_SDI_2018
- python
- result = (payslip.date_to[:4] == '2018')
- code
-
-result_rate = -contract.ca_sdi_rate(2018)
-result = categories.CA_SDI_WAGES
-
-# result_rate of 0 implies 100% due to bug
-if result_rate == 0.0:
- result = 0.0
-
-
-
-
-
-
-
-
-
- California Income Withholding
- CA_INC_WITHHOLD_2018
- python
- result = (payslip.date_to[:4] == '2018')
- code
-
-wages = categories.GROSS
-allowances = contract.ca_de4_allowances
-additional_allowances = contract.ca_additional_allowances
-schedule_pay = contract.schedule_pay
-filing_status = contract.ca_de4_filing_status
-low_income = False
-
-# Tables are found in http://www.edd.ca.gov/pdf_pub_ctr/18methb.pdf
-# First check low income exemption table (Step 1)
-low_income_exemption_table = {
-'weekly': (270, 270, 540, 540),
-'bi-weekly': (540, 540, 1081, 1081),
-'semi-monthly': (585, 585, 1171, 1171),
-'monthly': (1171, 1171, 2341, 2341),
-'quarterly': (3512, 3512, 7024, 7024),
-'semi-annual': (7024, 7024, 14048, 14048),
-'annually': (14048, 14048, 28095, 28095),
-}
-
-if filing_status == 'head_household':
- _, _, _, income = low_income_exemption_table[schedule_pay]
- if wages <= income:
- result = 0
- low_income = True
-elif filing_status == 'married':
- if allowances >= 2:
- _, _, income, _ = low_income_exemption_table[schedule_pay]
- if wages <= income:
- result = 0
- low_income = True
- else:
- _, income, _, _ = low_income_exemption_table[schedule_pay]
- if wages <= income:
- result = 0
- low_income = True
-else:
- income, _, _, _ = low_income_exemption_table[schedule_pay]
- if wages <= income:
- result = 0
- low_income = True
-
-if not low_income:
- # Estimated deduction table (Step 2)
- estimated_deduction_table = {
- 'weekly': (19, 38, 58, 77, 96, 115, 135, 154, 173, 192),
- 'bi-weekly': (38, 77, 115, 154, 192, 231, 269, 308, 346, 385),
- 'semi-monthly': (42, 83, 125, 167, 208, 250, 292, 333, 375, 417),
- 'monthly': (83, 167, 250, 333, 417, 500, 583, 667, 750, 833),
- 'quarterly': (250, 500, 750, 1000, 1250, 1500, 1750, 2000, 2250, 2500),
- 'semi-annual': (500, 1000, 1500, 2000, 2500, 3000, 3500, 4000, 4500, 5000),
- 'annually': (1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000, 10000),
- }
-
- allowance_index = additional_allowances - 1
- if additional_allowances > 10:
- deduction = (estimated_deduction_table[schedule_pay][0]) * additional_allowances
- wages -= deduction
- elif additional_allowances > 0:
- deduction = estimated_deduction_table[schedule_pay][allowance_index]
- wages -= deduction
-
- # Standard deduction table (Step 3)
- standard_deduction_table = {
- 'weekly': (81, 81, 163, 163),
- 'bi-weekly': (163, 163, 326, 326),
- 'semi-monthly': (177, 177, 353, 353),
- 'monthly': (353, 353, 706, 706),
- 'quarterly': (1059, 1059, 2118, 2118),
- 'semi-annual': (2118, 2118, 4236, 4236),
- 'annually': (4236, 4236, 8472, 8472),
- }
-
- if filing_status == 'head_household':
- _, _, _, deduction = standard_deduction_table[schedule_pay]
- wages -= deduction
- elif filing_status == 'married':
- if allowances >= 2:
- _, _, deduction, _ = standard_deduction_table[schedule_pay]
- wages -= deduction
- else:
- _, deduction, _, _ = standard_deduction_table[schedule_pay]
- wages -= deduction
- else:
- deduction, _, _, _ = standard_deduction_table[schedule_pay]
- wages -= deduction
-
- # Tax Rate Tables (Step 4)
- #### WEEKLY ####
- if schedule_pay == 'weekly':
- if filing_status == 'head_household' and wages > 0:
- tax_rate_table = [
- (316, 0.011, 0.0),
- (750, 0.022, 3.48),
- (967, 0.044, 13.03),
- (1196, 0.066, 22.58),
- (1413, 0.088, 37.69),
- (7212, 0.1023, 56.79),
- (8654, 0.1133, 650.03),
- (14423, 0.1243, 813.41),
- (19231, 0.1353, 1530.50),
- (float('inf'), 0.1463, 2181.02),
- ]
-
- elif filing_status == 'married':
- tax_rate_table = [
- (316, 0.011, 0.0),
- (750, 0.022, 3.48),
- (1184, 0.044, 13.03),
- (1642, 0.066, 32.13),
- (2076, 0.088, 62.36),
- (10606, 0.1023, 100.55),
- (12726, 0.1133, 973.17),
- (19231, 0.1243, 1213.37),
- (21210, 0.1353, 2021.94),
- (float('inf'), 0.1463, 2289.70),
- ]
-
- else:
- tax_rate_table = [
- (158, 0.011, 0.0),
- (375, 0.022, 1.74),
- (592, 0.044, 6.51),
- (821, 0.066, 16.06),
- (1038, 0.088, 31.17),
- (5303, 0.1023, 50.27),
- (6363, 0.1133, 486.58),
- (10605, 0.1243, 606.68),
- (19231, 0.1353, 1133.96),
- (float('inf'), 0.1463, 2301.06),
- ]
-
- #### BI-WEEKLY ####
- elif schedule_pay == 'bi-weekly':
- if filing_status == 'head_household':
- tax_rate_table = [
- (632, 0.011, 0.0),
- (1500, 0.022, 6.95),
- (1934, 0.044, 26.05),
- (2392, 0.066, 45.15),
- (2826, 0.088, 75.38),
- (14424, 0.1023, 113.57),
- (17308, 0.1133, 1300.05),
- (28846, 0.1243, 1626.81),
- (38462, 0.1353, 3060.98),
- (float('inf'), 0.1463, 4362.02),
- ]
-
- elif filing_status == 'married':
- tax_rate_table = [
- (632, 0.011, 0.0),
- (1500, 0.022, 6.95),
- (2368, 0.044, 26.05),
- (3284, 0.066, 64.24),
- (4152, 0.088, 124.70),
- (21212, 0.1023, 201.08),
- (25452, 0.1133, 1946.32),
- (38462, 0.1243, 2426.71),
- (42420, 0.1353, 4043.85),
- (float('inf'), 0.1463, 4579.37),
- ]
-
- else:
- tax_rate_table = [
- (316, 0.011, 0.0),
- (750, 0.022, 3.48),
- (1184, 0.044, 13.03),
- (1642, 0.066, 32.13),
- (2076, 0.088, 62.36),
- (10606, 0.1023, 100.55),
- (12726, 0.1133, 973.17),
- (21210, 0.1243, 1213.37),
- (38462, 0.1353, 2267.93),
- (float('inf'), 0.1463, 4602.13),
- ]
-
- #### SEMI-MONTHLY ####
- elif schedule_pay == 'semi-monthly':
- if filing_status == 'head_household':
- tax_rate_table = [
- (686, 0.011, 0.0),
- (1625, 0.022, 7.55),
- (2094, 0.044, 28.21),
- (2592, 0.066, 48.85),
- (3062, 0.088, 81.72),
- (15625, 0.1023, 123.08),
- (18750, 0.1133, 1408.27),
- (31250, 0.1243, 1762.33),
- (41667, 0.1353, 3316.08),
- (float('inf'), 0.1463, 4725.50),
- ]
-
- elif filing_status == 'married':
- tax_rate_table = [
- (686, 0.011, 0.0),
- (1624, 0.022, 7.55),
- (2564, 0.044, 28.19),
- (3560, 0.066, 69.55),
- (4498, 0.088, 135.29),
- (22978, 0.1023, 217.83),
- (27574, 0.1133, 2108.33),
- (41667, 0.1243, 2629.06),
- (45956, 0.1353, 4380.82),
- (float('inf'), 0.1463, 4961.12),
- ]
-
- else:
- tax_rate_table = [
- (343, 0.011, 0.0),
- (812, 0.022, 3.77),
- (1282, 0.044, 14.09),
- (1780, 0.066, 34.77),
- (2249, 0.088, 67.64),
- (11489, 0.1023, 108.91),
- (13787, 0.1133, 1054.16),
- (22978, 0.1243, 1314.52),
- (41667, 0.1353, 2456.96),
- (float('inf'), 0.1463, 4985.58),
- ]
-
- #### MONTHLY ####
- elif schedule_pay == 'monthly':
- if filing_status == 'head_household':
- tax_rate_table = [
- (1372, 0.011, 0.0),
- (3250, 0.022, 15.09),
- (4188, 0.044, 56.41),
- (5184, 0.066, 97.68),
- (6124, 0.088, 163.42),
- (31250, 0.1023, 246.148),
- (37500, 0.1133, 2816.53),
- (62500, 0.1243, 3524.66),
- (83334, 0.1353, 6632.16),
- (float('inf'), 0.1463, 9451.00),
- ]
-
- elif filing_status == 'married':
- tax_rate_table = [
- (1372, 0.011, 0.0),
- (3248, 0.022, 15.09),
- (5128, 0.044, 56.36),
- (7120, 0.066, 139.08),
- (8996, 0.088, 270.55),
- (45956, 0.1023, 435.64),
- (55148, 0.1133, 4216.65),
- (83334, 0.1243, 5258.10),
- (91912, 0.1353, 8761.62),
- (float('inf'), 0.1463, 9922.22),
- ]
-
- else:
- tax_rate_table = [
- (686, 0.011, 0.0),
- (1624, 0.022, 7.55),
- (2564, 0.044, 28.19),
- (3560, 0.066, 69.55),
- (4498, 0.088, 135.29),
- (22978, 0.1023, 217.83),
- (27574, 0.1133, 2108.33),
- (45956, 0.1243, 2629.06),
- (83334, 0.1353, 4913.94),
- (float('inf'), 0.1463, 9971.18),
- ]
-
- #### QUARTERLY ####
- elif schedule_pay == 'quarterly':
- if filing_status == 'head_household':
- tax_rate_table = [
- (4114, 0.011, 0.0),
- (9748, 0.022, 45.25),
- (12566, 0.044, 169.20),
- (15552, 0.066, 293.19),
- (18369, 0.088, 490.27),
- (93751, 0.1023, 738.17),
- (112501, 0.1133, 8449.75),
- (187501, 0.1243, 10574.13),
- (250000, 0.1353, 19896.63),
- (float('inf'), 0.1463, 28352.74),
- ]
-
- elif filing_status == 'married':
- tax_rate_table = [
- (4112, 0.011, 0.0),
- (9748, 0.022, 45.23),
- (15384, 0.044, 169.22),
- (21356, 0.066, 417.20),
- (26990, 0.088, 811.35),
- (137870, 0.1023, 1307.14),
- (165442, 0.1133, 12650.16),
- (250000, 0.1243, 15774.07),
- (275736, 0.1353, 26284.63),
- (float('inf'), 0.1463, 29766.71),
- ]
-
- else:
- tax_rate_table = [
- (2056, 0.011, 0.0),
- (4874, 0.022, 22.62),
- (7692, 0.044, 84.62),
- (10678, 0.066, 208.61),
- (13495, 0.088, 405.69),
- (68935, 0.1023, 653.59),
- (82721, 0.1133, 6325.10),
- (137868, 0.1243, 7887.05),
- (250000, 0.1353, 14741.82),
- (float('inf'), 0.1463, 29913.28),
- ]
-
- #### SEMI-ANNUAL ####
- elif schedule_pay == 'semi-annual':
- if filing_status == 'head_household':
- tax_rate_table = [
- (8228, 0.011, 0.0),
- (19496, 0.022, 90.51),
- (25132, 0.044, 338.41),
- (31104, 0.066, 586.39),
- (36738, 0.088, 980.54),
- (187502, 0.1023, 1476.33),
- (225002, 0.1133, 16899.49),
- (375002, 0.1243, 21148.24),
- (500000, 0.1353, 39793.24),
- (float('inf'), 0.1463, 56705.47),
- ]
-
- elif filing_status == 'married':
- tax_rate_table = [
- (8224, 0.011, 0.0),
- (19496, 0.022, 90.46),
- (30768, 0.044, 338.44),
- (42712, 0.066, 834.41),
- (53980, 0.088, 1622.71),
- (275740, 0.1023, 2614.29),
- (330884, 0.1133, 25300.34),
- (500000, 0.1243, 31548.16),
- (551472, 0.1353, 52569.28),
- (float('inf'), 0.1463, 59533.44),
- ]
-
- else:
- tax_rate_table = [
- (4112, 0.011, 0.0),
- (9748, 0.022, 45.23),
- (15384, 0.044, 169.22),
- (21356, 0.066, 417.20),
- (26990, 0.088, 811.35),
- (137870, 0.1023, 1307.14),
- (165442, 0.1133, 12650.16),
- (275736, 0.1243, 15774.07),
- (500000, 0.1353, 29483.61),
- (float('inf'), 0.1463, 59826.53),
- ]
-
- #### ANNUAL ####
- elif schedule_pay == 'annually':
- if filing_status == 'head_household':
- tax_rate_table = [
- (16457, 0.011, 0.0),
- (38991, 0.022, 181.03),
- (50264, 0.044, 676.78),
- (62206, 0.066, 1172.79),
- (73477, 0.088, 1960.96),
- (375002, 0.1023, 2952.81),
- (450003, 0.1133, 33798.82),
- (750003, 0.1243, 42296.43),
- (1000000, 0.1353, 79586.43),
- (float('inf'), 0.1463, 113411.02),
- ]
-
- elif filing_status == 'married':
- tax_rate_table = [
- (16446, 0.011, 0.0),
- (38990, 0.022, 180.91),
- (61538, 0.044, 676.88),
- (85422, 0.066, 1668.99),
- (107960, 0.088, 3245.33),
- (551476, 0.1023, 5228.67),
- (661768, 0.1133, 50600.36),
- (1000000, 0.1243, 63096.44),
- (1102946, 0.1353, 105138.68),
- (float('inf'), 0.1463, 119067.26),
- ]
-
- else:
- tax_rate_table = [
- (8223, 0.011, 0.0),
- (19495, 0.022, 90.45),
- (30769, 0.044, 338.43),
- (42711, 0.066, 834.49),
- (53980, 0.088, 1622.66),
- (275738, 0.1023, 2614.33),
- (330884, 0.1133, 25300.17),
- (551473, 0.1243, 31548.21),
- (1000000, 0.1353, 58967.42),
- (float('inf'), 0.1463, 119653.12),
- ]
-
- over = 0.0
- tax = 0.0
- for row in tax_rate_table:
- if wages <= row[0]:
- tax = ((wages - over) * row[1]) + row[2]
- break
- over = row[0]
-
- # Exemption allowance table (Step 5)
- exemption_allowance_table = {
- 'weekly': (2.41, 4.82, 7.23, 9.65, 12.06, 14.47, 16.88, 19.29, 21.70, 24.12),
- 'bi-weekly': (4.82, 9.65, 14.47, 19.29, 24.12, 28.94, 33.76, 38.58, 43.41, 48.23),
- 'semi-monthly': (5.23, 10.45, 15.68, 20.90, 26.13, 31.35, 36.58, 41.80, 47.03, 52.25),
- 'monthly': (10.45, 20.90, 31.35, 41.80, 52.25, 62.70, 73.15, 83.60, 94.05, 104.50),
- 'quarterly': (31.35, 62.70, 94.05, 125.40, 156.75, 188.10, 219.45, 250.80, 282.15, 313.50),
- 'semi-annual': (62.70, 125.40, 188.10, 250.80, 313.50, 376.20, 438.90, 501.60, 564.30, 627.00),
- 'annually': (125.40, 250.80, 376.20, 501.60, 627.00, 752.40, 877.80, 1003.20, 1128.60, 1254.00),
- }
-
- allowance_index = allowances - 1
- if allowances > 10:
- deduction = (exemption_allowance_table[schedule_pay][0]) * allowances
- tax -= deduction
- elif allowances > 0:
- deduction = exemption_allowance_table[schedule_pay][allowance_index]
- tax -= deduction
-
- result = -tax
-
-
-
-
-
-
diff --git a/l10n_us_ca_hr_payroll/hr_payroll.py b/l10n_us_ca_hr_payroll/hr_payroll.py
deleted file mode 100755
index b1a3eebf..00000000
--- a/l10n_us_ca_hr_payroll/hr_payroll.py
+++ /dev/null
@@ -1,56 +0,0 @@
-from odoo import models, fields, api
-
-
-class USCAHrContract(models.Model):
- _inherit = 'hr.contract'
-
- ca_de4_allowances = fields.Integer(string="California CA-4 Allowances",
- default=0,
- help="Estimated Deductions claimed on DE-4")
- ca_additional_allowances = fields.Integer(string="Additional Allowances", default=0)
- ca_de4_filing_status = fields.Selection([
- ('exempt', 'Exempt'),
- ('single', 'Single'),
- ('married', 'Married'),
- ('head_household', 'Head of Household')
- ], string='CA Filing Status', default='single')
-
- @api.multi
- def ca_uit_rate(self, year):
- self.ensure_one()
- if self.futa_type == self.FUTA_TYPE_BASIC:
- return 0.0
-
- if hasattr(self.employee_id.company_id, 'ca_uit_rate_' + str(year)):
- return self.employee_id.company_id['ca_uit_rate_' + str(year)]
-
- raise NotImplemented('Year (' + str(year) + ') Not implemented for US California.')
-
- def ca_ett_rate(self, year):
- self.ensure_one()
- if self.futa_type == self.FUTA_TYPE_BASIC:
- return 0.0
-
- if hasattr(self.employee_id.company_id, 'ca_ett_rate_' + str(year)):
- return self.employee_id.company_id['ca_ett_rate_' + str(year)]
-
- raise NotImplemented('Year (' + str(year) + ') Not implemented for US California.')
-
- def ca_sdi_rate(self, year):
- self.ensure_one()
- if self.futa_type == self.FUTA_TYPE_BASIC:
- return 0.0
-
- if hasattr(self.employee_id.company_id, 'ca_sdi_rate_' + str(year)):
- return self.employee_id.company_id['ca_sdi_rate_' + str(year)]
-
- raise NotImplemented('Year (' + str(year) + ') Not implemented for US California.')
-
-
-class CACompany(models.Model):
- _inherit = 'res.company'
-
- # UIT can be calculated using http://www.edd.ca.gov/pdf_pub_ctr/de44.pdf ETT is default.
- ca_uit_rate_2018 = fields.Float(string="California Unemployment Insurance Tax Rate 2018", default=2.6)
- ca_ett_rate_2018 = fields.Float(string="California Employment Training Tax Rate 2018", default=0.1)
- ca_sdi_rate_2018 = fields.Float(string="California State Disability Insurance Rate 2018", default=1.0)
diff --git a/l10n_us_ca_hr_payroll/models/__init__.py b/l10n_us_ca_hr_payroll/models/__init__.py
new file mode 100644
index 00000000..e99aa24a
--- /dev/null
+++ b/l10n_us_ca_hr_payroll/models/__init__.py
@@ -0,0 +1 @@
+from . import hr_payroll
diff --git a/l10n_us_ca_hr_payroll/models/hr_payroll.py b/l10n_us_ca_hr_payroll/models/hr_payroll.py
new file mode 100755
index 00000000..28590d82
--- /dev/null
+++ b/l10n_us_ca_hr_payroll/models/hr_payroll.py
@@ -0,0 +1,16 @@
+from odoo import models, fields, api
+
+
+class USCAHrContract(models.Model):
+ _inherit = 'hr.contract'
+
+ ca_de4_allowances = fields.Integer(string="California CA-4 Allowances",
+ default=0,
+ help="Estimated Deductions claimed on DE-4")
+ ca_additional_allowances = fields.Integer(string="Additional Allowances", default=0)
+ ca_de4_filing_status = fields.Selection([
+ ('exempt', 'Exempt'),
+ ('single', 'Single'),
+ ('married', 'Married'),
+ ('head_household', 'Head of Household')
+ ], string='CA Filing Status', default='single')
diff --git a/l10n_us_ca_hr_payroll/tests/__init__.py b/l10n_us_ca_hr_payroll/tests/__init__.py
index 8011621b..545b0768 100755
--- a/l10n_us_ca_hr_payroll/tests/__init__.py
+++ b/l10n_us_ca_hr_payroll/tests/__init__.py
@@ -1 +1,2 @@
-from . import test_us_ca_payslip_2018
\ No newline at end of file
+from . import test_us_ca_payslip_2018
+from . import test_us_ca_payslip_2019
diff --git a/l10n_us_ca_hr_payroll/tests/test_us_ca_payslip_2018.py b/l10n_us_ca_hr_payroll/tests/test_us_ca_payslip_2018.py
index d0835917..b8f13bf9 100755
--- a/l10n_us_ca_hr_payroll/tests/test_us_ca_payslip_2018.py
+++ b/l10n_us_ca_hr_payroll/tests/test_us_ca_payslip_2018.py
@@ -1,5 +1,4 @@
from odoo.addons.l10n_us_hr_payroll.tests.test_us_payslip import TestUsPayslip, process_payslip
-from odoo.addons.l10n_us_hr_payroll.models.l10n_us_hr_payroll import USHrContract
class TestUsCAPayslip(TestUsPayslip):
@@ -10,6 +9,10 @@ class TestUsCAPayslip(TestUsPayslip):
CA_UIT_MAX_WAGE = 7000
CA_SDI_MAX_WAGE = 114967
+ CA_UIT = -2.6 / 100.0
+ CA_ETT = -0.1 / 100.0
+ CA_SDI = -1.0 / 100.0
+
# Examples from http://www.edd.ca.gov/pdf_pub_ctr/18methb.pdf
def test_example_a(self):
salary = 210
@@ -32,11 +35,6 @@ class TestUsCAPayslip(TestUsPayslip):
self.assertEqual(contract.schedule_pay, 'weekly')
- # tax rates
- ca_uit = contract.ca_uit_rate(2018) / -100.0
- ca_ett = contract.ca_ett_rate(2018) / -100.0
- ca_sdi = contract.ca_sdi_rate(2018) / -100.0
-
self._log('2017 California tax last payslip:')
payslip = self._createPayslip(employee, '2017-12-01', '2017-12-31')
payslip.compute_sheet()
@@ -49,13 +47,13 @@ class TestUsCAPayslip(TestUsPayslip):
cats = self._getCategories(payslip)
- self.assertPayrollEqual(cats['CA_UIT_WAGES'], salary)
- self.assertPayrollEqual(cats['CA_UIT'], cats['CA_UIT_WAGES'] * ca_uit)
- self.assertPayrollEqual(cats['CA_ETT_WAGES'], salary)
- self.assertPayrollEqual(cats['CA_ETT'], cats['CA_ETT_WAGES'] * ca_ett)
- self.assertPayrollEqual(cats['CA_SDI_WAGES'], salary)
- self.assertPayrollEqual(cats['CA_SDI'], cats['CA_SDI_WAGES'] * ca_sdi)
- self.assertPayrollEqual(cats['CA_WITHHOLD'], wh)
+ self.assertPayrollEqual(cats['WAGE_US_CA_UNEMP'], salary)
+ self.assertPayrollEqual(cats['ER_US_CA_UNEMP'], cats['WAGE_US_CA_UNEMP'] * self.CA_UIT)
+ self.assertPayrollEqual(cats['WAGE_US_CA_ETT'], salary)
+ self.assertPayrollEqual(cats['ER_US_CA_ETT'], cats['WAGE_US_CA_ETT'] * self.CA_ETT)
+ self.assertPayrollEqual(cats['WAGE_US_CA_SDI'], salary)
+ self.assertPayrollEqual(cats['EE_US_CA_SDI'], cats['WAGE_US_CA_SDI'] * self.CA_SDI)
+ self.assertPayrollEqual(cats['EE_US_CA_INC_WITHHOLD'], wh)
process_payslip(payslip)
@@ -71,8 +69,8 @@ class TestUsCAPayslip(TestUsPayslip):
cats = self._getCategories(payslip)
- self.assertPayrollEqual(cats['CA_UIT_WAGES'], remaining_ca_uit_wages)
- self.assertPayrollEqual(cats['CA_UIT'], remaining_ca_uit_wages * ca_uit)
+ self.assertPayrollEqual(cats['WAGE_US_CA_UNEMP'], remaining_ca_uit_wages)
+ self.assertPayrollEqual(cats['ER_US_CA_UNEMP'], remaining_ca_uit_wages * self.CA_UIT)
def test_example_b(self):
salary = 1250
@@ -81,16 +79,8 @@ class TestUsCAPayslip(TestUsPayslip):
additional_allowances = 1
wh = -2.89
- # tax rates
- ca_uit = 2.6
- ca_ett = 0.1
- ca_sdi = 1.0
employee = self._createEmployee()
- employee.company_id.ca_uit_rate_2018 = ca_uit
- employee.company_id.ca_ett_rate_2018 = ca_ett
- employee.company_id.ca_sdi_rate_2018 = ca_sdi
-
contract = self._createContract(employee,
salary,
struct_id=self.ref(
@@ -117,13 +107,13 @@ class TestUsCAPayslip(TestUsPayslip):
cats = self._getCategories(payslip)
- self.assertPayrollEqual(cats['CA_UIT_WAGES'], salary)
- self.assertPayrollEqual(cats['CA_UIT'], round((cats['CA_UIT_WAGES'] * ca_uit)/-100, 2))
- self.assertPayrollEqual(cats['CA_ETT_WAGES'], salary)
- self.assertPayrollEqual(cats['CA_ETT'], round((cats['CA_ETT_WAGES'] * ca_ett)/-100, 2))
- self.assertPayrollEqual(cats['CA_SDI_WAGES'], salary)
- self.assertPayrollEqual(cats['CA_SDI'], round((cats['CA_SDI_WAGES'] * ca_sdi)/-100, 2))
- self.assertPayrollEqual(cats['CA_WITHHOLD'], wh)
+ self.assertPayrollEqual(cats['WAGE_US_CA_UNEMP'], salary)
+ self.assertPayrollEqual(cats['ER_US_CA_UNEMP'], round((cats['WAGE_US_CA_UNEMP'] * self.CA_UIT), 2))
+ self.assertPayrollEqual(cats['WAGE_US_CA_ETT'], salary)
+ self.assertPayrollEqual(cats['ER_US_CA_ETT'], round((cats['WAGE_US_CA_ETT'] * self.CA_ETT), 2))
+ self.assertPayrollEqual(cats['WAGE_US_CA_SDI'], salary)
+ self.assertPayrollEqual(cats['EE_US_CA_SDI'], round((cats['WAGE_US_CA_SDI'] * self.CA_SDI), 2))
+ self.assertPayrollEqual(cats['EE_US_CA_INC_WITHHOLD'], wh)
process_payslip(payslip)
@@ -139,8 +129,8 @@ class TestUsCAPayslip(TestUsPayslip):
cats = self._getCategories(payslip)
- self.assertPayrollEqual(cats['CA_UIT_WAGES'], remaining_ca_uit_wages)
- self.assertPayrollEqual(cats['CA_UIT'], round((remaining_ca_uit_wages * ca_uit)/-100, 2))
+ self.assertPayrollEqual(cats['WAGE_US_CA_UNEMP'], remaining_ca_uit_wages)
+ self.assertPayrollEqual(cats['ER_US_CA_UNEMP'], round((remaining_ca_uit_wages * self.CA_UIT), 2))
def test_example_c(self):
salary = 3800
@@ -149,16 +139,8 @@ class TestUsCAPayslip(TestUsPayslip):
additional_allowances = 0.72
wh = -0.72
- # tax rates
- ca_uit = 2.6
- ca_ett = 0.1
- ca_sdi = 1.0
employee = self._createEmployee()
- employee.company_id.ca_uit_rate_2018 = ca_uit
- employee.company_id.ca_ett_rate_2018 = ca_ett
- employee.company_id.ca_sdi_rate_2018 = ca_sdi
-
contract = self._createContract(employee,
salary,
struct_id=self.ref(
@@ -185,13 +167,13 @@ class TestUsCAPayslip(TestUsPayslip):
cats = self._getCategories(payslip)
- self.assertPayrollEqual(cats['CA_UIT_WAGES'], salary)
- self.assertPayrollEqual(cats['CA_UIT'], round((cats['CA_UIT_WAGES'] * ca_uit)/-100, 2))
- self.assertPayrollEqual(cats['CA_ETT_WAGES'], salary)
- self.assertPayrollEqual(cats['CA_ETT'], round((cats['CA_ETT_WAGES'] * ca_ett)/-100, 2))
- self.assertPayrollEqual(cats['CA_SDI_WAGES'], salary)
- self.assertPayrollEqual(cats['CA_SDI'], round((cats['CA_SDI_WAGES'] * ca_sdi)/-100, 2))
- self.assertPayrollEqual(cats['CA_WITHHOLD'], wh)
+ self.assertPayrollEqual(cats['WAGE_US_CA_UNEMP'], salary)
+ self.assertPayrollEqual(cats['ER_US_CA_UNEMP'], round((cats['WAGE_US_CA_UNEMP'] * self.CA_UIT), 2))
+ self.assertPayrollEqual(cats['WAGE_US_CA_ETT'], salary)
+ self.assertPayrollEqual(cats['ER_US_CA_ETT'], round((cats['WAGE_US_CA_ETT'] * self.CA_ETT), 2))
+ self.assertPayrollEqual(cats['WAGE_US_CA_SDI'], salary)
+ self.assertPayrollEqual(cats['EE_US_CA_SDI'], round((cats['WAGE_US_CA_SDI'] * self.CA_SDI), 2))
+ self.assertPayrollEqual(cats['EE_US_CA_INC_WITHHOLD'], wh)
process_payslip(payslip)
@@ -207,8 +189,8 @@ class TestUsCAPayslip(TestUsPayslip):
cats = self._getCategories(payslip)
- self.assertPayrollEqual(cats['CA_UIT_WAGES'], remaining_ca_uit_wages)
- self.assertPayrollEqual(cats['CA_UIT'], round((remaining_ca_uit_wages * ca_uit)/-100, 2))
+ self.assertPayrollEqual(cats['WAGE_US_CA_UNEMP'], remaining_ca_uit_wages)
+ self.assertPayrollEqual(cats['ER_US_CA_UNEMP'], round((remaining_ca_uit_wages * self.CA_UIT), 2))
def test_example_d(self):
salary = 800
@@ -217,16 +199,8 @@ class TestUsCAPayslip(TestUsPayslip):
additional_allowances = 0
wh = -3.31
- # tax rates
- ca_uit = 2.6
- ca_ett = 0.1
- ca_sdi = 1.0
employee = self._createEmployee()
- employee.company_id.ca_uit_rate_2018 = ca_uit
- employee.company_id.ca_ett_rate_2018 = ca_ett
- employee.company_id.ca_sdi_rate_2018 = ca_sdi
-
contract = self._createContract(employee,
salary,
struct_id=self.ref(
@@ -253,13 +227,13 @@ class TestUsCAPayslip(TestUsPayslip):
cats = self._getCategories(payslip)
- self.assertPayrollEqual(cats['CA_UIT_WAGES'], salary)
- self.assertPayrollEqual(cats['CA_UIT'], round((cats['CA_UIT_WAGES'] * ca_uit)/-100, 2))
- self.assertPayrollEqual(cats['CA_ETT_WAGES'], salary)
- self.assertPayrollEqual(cats['CA_ETT'], round((cats['CA_ETT_WAGES'] * ca_ett)/-100, 2))
- self.assertPayrollEqual(cats['CA_SDI_WAGES'], salary)
- self.assertPayrollEqual(cats['CA_SDI'], round((cats['CA_SDI_WAGES'] * ca_sdi)/-100, 2))
- self.assertPayrollEqual(cats['CA_WITHHOLD'], wh)
+ self.assertPayrollEqual(cats['WAGE_US_CA_UNEMP'], salary)
+ self.assertPayrollEqual(cats['ER_US_CA_UNEMP'], round((cats['WAGE_US_CA_UNEMP'] * self.CA_UIT), 2))
+ self.assertPayrollEqual(cats['WAGE_US_CA_ETT'], salary)
+ self.assertPayrollEqual(cats['ER_US_CA_ETT'], round((cats['WAGE_US_CA_ETT'] * self.CA_ETT), 2))
+ self.assertPayrollEqual(cats['WAGE_US_CA_SDI'], salary)
+ self.assertPayrollEqual(cats['EE_US_CA_SDI'], round((cats['WAGE_US_CA_SDI'] * self.CA_SDI), 2))
+ self.assertPayrollEqual(cats['EE_US_CA_INC_WITHHOLD'], wh)
process_payslip(payslip)
@@ -275,8 +249,8 @@ class TestUsCAPayslip(TestUsPayslip):
cats = self._getCategories(payslip)
- self.assertPayrollEqual(cats['CA_UIT_WAGES'], remaining_ca_uit_wages)
- self.assertPayrollEqual(cats['CA_UIT'], round((remaining_ca_uit_wages * ca_uit)/-100, 2))
+ self.assertPayrollEqual(cats['WAGE_US_CA_UNEMP'], remaining_ca_uit_wages)
+ self.assertPayrollEqual(cats['ER_US_CA_UNEMP'], round((remaining_ca_uit_wages * self.CA_UIT), 2))
def test_example_e(self):
salary = 1800
@@ -285,16 +259,8 @@ class TestUsCAPayslip(TestUsPayslip):
additional_allowances = 0
wh = -3.39
- # tax rates
- ca_uit = 2.6
- ca_ett = 0.1
- ca_sdi = 1.0
employee = self._createEmployee()
- employee.company_id.ca_uit_rate_2018 = ca_uit
- employee.company_id.ca_ett_rate_2018 = ca_ett
- employee.company_id.ca_sdi_rate_2018 = ca_sdi
-
contract = self._createContract(employee,
salary,
struct_id=self.ref(
@@ -321,13 +287,13 @@ class TestUsCAPayslip(TestUsPayslip):
cats = self._getCategories(payslip)
- self.assertPayrollEqual(cats['CA_UIT_WAGES'], salary)
- self.assertPayrollEqual(cats['CA_UIT'], round((cats['CA_UIT_WAGES'] * ca_uit)/-100, 2))
- self.assertPayrollEqual(cats['CA_ETT_WAGES'], salary)
- self.assertPayrollEqual(cats['CA_ETT'], round((cats['CA_ETT_WAGES'] * ca_ett)/-100, 2))
- self.assertPayrollEqual(cats['CA_SDI_WAGES'], salary)
- self.assertPayrollEqual(cats['CA_SDI'], round((cats['CA_SDI_WAGES'] * ca_sdi)/-100, 2))
- self.assertPayrollEqual(cats['CA_WITHHOLD'], wh)
+ self.assertPayrollEqual(cats['WAGE_US_CA_UNEMP'], salary)
+ self.assertPayrollEqual(cats['ER_US_CA_UNEMP'], round((cats['WAGE_US_CA_UNEMP'] * self.CA_UIT), 2))
+ self.assertPayrollEqual(cats['WAGE_US_CA_ETT'], salary)
+ self.assertPayrollEqual(cats['ER_US_CA_ETT'], round((cats['WAGE_US_CA_ETT'] * self.CA_ETT), 2))
+ self.assertPayrollEqual(cats['WAGE_US_CA_SDI'], salary)
+ self.assertPayrollEqual(cats['EE_US_CA_SDI'], round((cats['WAGE_US_CA_SDI'] * self.CA_SDI), 2))
+ self.assertPayrollEqual(cats['EE_US_CA_INC_WITHHOLD'], wh)
process_payslip(payslip)
@@ -343,8 +309,8 @@ class TestUsCAPayslip(TestUsPayslip):
cats = self._getCategories(payslip)
- self.assertPayrollEqual(cats['CA_UIT_WAGES'], remaining_ca_uit_wages)
- self.assertPayrollEqual(cats['CA_UIT'], round((remaining_ca_uit_wages * ca_uit)/-100, 2))
+ self.assertPayrollEqual(cats['WAGE_US_CA_UNEMP'], remaining_ca_uit_wages)
+ self.assertPayrollEqual(cats['ER_US_CA_UNEMP'], round((remaining_ca_uit_wages * self.CA_UIT), 2))
def test_example_f(self):
salary = 45000
@@ -353,16 +319,8 @@ class TestUsCAPayslip(TestUsPayslip):
additional_allowances = 0
wh = -121.11
- # tax rates
- ca_uit = 2.6
- ca_ett = 0.1
- ca_sdi = 1.0
employee = self._createEmployee()
- employee.company_id.ca_uit_rate_2018 = ca_uit
- employee.company_id.ca_ett_rate_2018 = ca_ett
- employee.company_id.ca_sdi_rate_2018 = ca_sdi
-
contract = self._createContract(employee,
salary,
struct_id=self.ref(
@@ -389,10 +347,10 @@ class TestUsCAPayslip(TestUsPayslip):
cats = self._getCategories(payslip)
- self.assertPayrollEqual(cats['CA_UIT'], round((cats['CA_UIT_WAGES'] * ca_uit)/-100, 2))
- self.assertPayrollEqual(cats['CA_ETT'], round((cats['CA_ETT_WAGES'] * ca_ett)/-100, 2))
- self.assertPayrollEqual(cats['CA_SDI'], round((cats['CA_SDI_WAGES'] * ca_sdi)/-100, 2))
- self.assertPayrollEqual(cats['CA_WITHHOLD'], wh)
+ self.assertPayrollEqual(cats['ER_US_CA_UNEMP'], round((cats['WAGE_US_CA_UNEMP'] * self.CA_UIT), 2))
+ self.assertPayrollEqual(cats['ER_US_CA_ETT'], round((cats['WAGE_US_CA_ETT'] * self.CA_ETT), 2))
+ self.assertPayrollEqual(cats['EE_US_CA_SDI'], round((cats['WAGE_US_CA_SDI'] * self.CA_SDI), 2))
+ self.assertPayrollEqual(cats['EE_US_CA_INC_WITHHOLD'], wh)
process_payslip(payslip)
diff --git a/l10n_us_ca_hr_payroll/tests/test_us_ca_payslip_2019.py b/l10n_us_ca_hr_payroll/tests/test_us_ca_payslip_2019.py
new file mode 100755
index 00000000..b9a3e71d
--- /dev/null
+++ b/l10n_us_ca_hr_payroll/tests/test_us_ca_payslip_2019.py
@@ -0,0 +1,425 @@
+from odoo.addons.l10n_us_hr_payroll.tests.test_us_payslip import TestUsPayslip, process_payslip
+
+
+class TestUsCAPayslip(TestUsPayslip):
+ ###
+ # Taxes and Rates
+ ###
+ CA_UIT_MAX_WAGE = 7000
+ CA_UIT_MAX_WAGE = 7000
+ CA_SDI_MAX_WAGE = 18371
+
+ CA_UIT = -3.4 / 100.0
+ CA_ETT = -0.1 / 100.0
+ CA_SDI = -1.0 / 100.0
+
+ # Examples from http://www.edd.ca.gov/pdf_pub_ctr/18methb.pdf
+ def test_example_a(self):
+ salary = 210
+ schedule_pay = 'weekly'
+ allowances = 1
+ additional_allowances = 0
+
+ wh = 0.00
+
+ employee = self._createEmployee()
+
+ contract = self._createContract(employee,
+ salary,
+ struct_id=self.ref(
+ 'l10n_us_ca_hr_payroll.hr_payroll_salary_structure_us_ca_employee'),
+ schedule_pay=schedule_pay)
+ contract.ca_c4_exemptions = allowances
+ contract.ca_additional_allowances = additional_allowances
+ contract.ca_de4_filing_status = 'single'
+
+ self.assertEqual(contract.schedule_pay, 'weekly')
+
+ self._log('2018 California tax last payslip:')
+ payslip = self._createPayslip(employee, '2018-12-01', '2018-12-31')
+ payslip.compute_sheet()
+ process_payslip(payslip)
+
+ self._log('2019 California tax first payslip:')
+ payslip = self._createPayslip(employee, '2019-01-01', '2019-01-31')
+
+ payslip.compute_sheet()
+
+ cats = self._getCategories(payslip)
+
+ self.assertPayrollEqual(cats['WAGE_US_CA_UNEMP'], salary)
+ self.assertPayrollEqual(cats['ER_US_CA_UNEMP'], cats['WAGE_US_CA_UNEMP'] * self.CA_UIT)
+ self.assertPayrollEqual(cats['WAGE_US_CA_ETT'], salary)
+ self.assertPayrollEqual(cats['ER_US_CA_ETT'], cats['WAGE_US_CA_ETT'] * self.CA_ETT)
+ self.assertPayrollEqual(cats['WAGE_US_CA_SDI'], salary)
+ self.assertPayrollEqual(cats['EE_US_CA_SDI'], cats['WAGE_US_CA_SDI'] * self.CA_SDI)
+ self.assertPayrollEqual(cats['EE_US_CA_INC_WITHHOLD'], wh)
+
+ process_payslip(payslip)
+
+ # Make a new payslip, this one will have maximums
+
+ remaining_ca_uit_wages = self.CA_UIT_MAX_WAGE - salary if (self.CA_UIT_MAX_WAGE - 2 * salary < salary) \
+ else salary
+
+ self._log('2019 California tax second payslip:')
+ payslip = self._createPayslip(employee, '2019-02-01', '2019-02-28')
+
+ payslip.compute_sheet()
+
+ cats = self._getCategories(payslip)
+
+ self.assertPayrollEqual(cats['WAGE_US_CA_UNEMP'], remaining_ca_uit_wages)
+ self.assertPayrollEqual(cats['ER_US_CA_UNEMP'], remaining_ca_uit_wages * self.CA_UIT)
+
+ def test_example_b(self):
+ salary = 1250
+ schedule_pay = 'bi-weekly'
+ allowances = 2
+ additional_allowances = 1
+
+ # for additional allowances
+ wh = salary - 38
+ wh = wh - 339
+ wh = (wh - 632) * 0.022 + 6.95
+ wh = wh - 9.65
+ # 2.651 - 9.65
+ wh = -wh
+
+ employee = self._createEmployee()
+ contract = self._createContract(employee,
+ salary,
+ struct_id=self.ref(
+ 'l10n_us_ca_hr_payroll.hr_payroll_salary_structure_us_ca_employee'),
+ schedule_pay=schedule_pay)
+ contract.ca_de4_allowances = allowances
+ contract.ca_additional_allowances = additional_allowances
+ contract.ca_de4_filing_status = 'married'
+
+ self.assertEqual(contract.schedule_pay, 'bi-weekly')
+ self.assertEqual(contract.ca_de4_filing_status, 'married')
+ self.assertEqual(contract.ca_de4_allowances, 2)
+ self.assertEqual(contract.ca_additional_allowances, 1)
+
+ self._log('2018 California tax last payslip:')
+ payslip = self._createPayslip(employee, '2018-12-01', '2018-12-31')
+ payslip.compute_sheet()
+ process_payslip(payslip)
+
+ self._log('2019 California tax first payslip:')
+ payslip = self._createPayslip(employee, '2019-01-01', '2019-01-31')
+
+ payslip.compute_sheet()
+
+ cats = self._getCategories(payslip)
+
+ self.assertPayrollEqual(cats['WAGE_US_CA_UNEMP'], salary)
+ self.assertPayrollEqual(cats['ER_US_CA_UNEMP'], round((cats['WAGE_US_CA_UNEMP'] * self.CA_UIT), 2))
+ self.assertPayrollEqual(cats['WAGE_US_CA_ETT'], salary)
+ self.assertPayrollEqual(cats['ER_US_CA_ETT'], round((cats['WAGE_US_CA_ETT'] * self.CA_ETT), 2))
+ self.assertPayrollEqual(cats['WAGE_US_CA_SDI'], salary)
+ self.assertPayrollEqual(cats['EE_US_CA_SDI'], round((cats['WAGE_US_CA_SDI'] * self.CA_SDI), 2))
+ self.assertPayrollEqual(cats['EE_US_CA_INC_WITHHOLD'], wh)
+
+ process_payslip(payslip)
+
+ # Make a new payslip, this one will have maximums
+
+ remaining_ca_uit_wages = self.CA_UIT_MAX_WAGE - salary if (self.CA_UIT_MAX_WAGE - 2 * salary < salary) \
+ else salary
+
+ self._log('2019 California tax second payslip:')
+ payslip = self._createPayslip(employee, '2019-02-01', '2019-02-28')
+
+ payslip.compute_sheet()
+
+ cats = self._getCategories(payslip)
+
+ self.assertPayrollEqual(cats['WAGE_US_CA_UNEMP'], remaining_ca_uit_wages)
+ self.assertPayrollEqual(cats['ER_US_CA_UNEMP'], round((remaining_ca_uit_wages * self.CA_UIT), 2))
+
+ def test_example_c(self):
+ salary = 3800
+ schedule_pay = 'monthly'
+ allowances = 5
+ additional_allowances = 0.72
+
+ wh = -0.11
+
+ employee = self._createEmployee()
+ contract = self._createContract(employee,
+ salary,
+ struct_id=self.ref(
+ 'l10n_us_ca_hr_payroll.hr_payroll_salary_structure_us_ca_employee'),
+ schedule_pay=schedule_pay)
+ contract.ca_de4_allowances = allowances
+ contract.ca_additional_allowances = additional_allowances
+ contract.ca_de4_filing_status = 'married'
+
+ self.assertEqual(contract.schedule_pay, 'monthly')
+ self.assertEqual(contract.ca_de4_filing_status, 'married')
+ self.assertEqual(contract.ca_de4_allowances, 5)
+ self.assertEqual(contract.ca_additional_allowances, 0)
+
+ self._log('2018 California tax last payslip:')
+ payslip = self._createPayslip(employee, '2018-12-01', '2018-12-31')
+ payslip.compute_sheet()
+ process_payslip(payslip)
+
+ self._log('2019 California tax first payslip:')
+ payslip = self._createPayslip(employee, '2019-01-01', '2019-01-31')
+
+ payslip.compute_sheet()
+
+ cats = self._getCategories(payslip)
+
+ self.assertPayrollEqual(cats['WAGE_US_CA_UNEMP'], salary)
+ self.assertPayrollEqual(cats['ER_US_CA_UNEMP'], round((cats['WAGE_US_CA_UNEMP'] * self.CA_UIT), 2))
+ self.assertPayrollEqual(cats['WAGE_US_CA_ETT'], salary)
+ self.assertPayrollEqual(cats['ER_US_CA_ETT'], round((cats['WAGE_US_CA_ETT'] * self.CA_ETT), 2))
+ self.assertPayrollEqual(cats['WAGE_US_CA_SDI'], salary)
+ self.assertPayrollEqual(cats['EE_US_CA_SDI'], round((cats['WAGE_US_CA_SDI'] * self.CA_SDI), 2))
+ self.assertPayrollEqual(cats['EE_US_CA_INC_WITHHOLD'], wh)
+
+ process_payslip(payslip)
+
+ # Make a new payslip, this one will have maximums
+
+ remaining_ca_uit_wages = self.CA_UIT_MAX_WAGE - salary if (self.CA_UIT_MAX_WAGE - 2 * salary < salary) \
+ else salary
+
+ self._log('2019 California tax second payslip:')
+ payslip = self._createPayslip(employee, '2019-02-01', '2019-02-28')
+
+ payslip.compute_sheet()
+
+ cats = self._getCategories(payslip)
+
+ self.assertPayrollEqual(cats['WAGE_US_CA_UNEMP'], remaining_ca_uit_wages)
+ self.assertPayrollEqual(cats['ER_US_CA_UNEMP'], round((remaining_ca_uit_wages * self.CA_UIT), 2))
+
+ def test_example_d(self):
+ salary = 800
+ schedule_pay = 'weekly'
+ allowances = 3
+ additional_allowances = 0
+
+ wh = -3.18
+
+ employee = self._createEmployee()
+ contract = self._createContract(employee,
+ salary,
+ struct_id=self.ref(
+ 'l10n_us_ca_hr_payroll.hr_payroll_salary_structure_us_ca_employee'),
+ schedule_pay=schedule_pay)
+ contract.ca_de4_allowances = allowances
+ contract.ca_additional_allowances = additional_allowances
+ contract.ca_de4_filing_status = 'head_household'
+
+ self.assertEqual(contract.schedule_pay, 'weekly')
+ self.assertEqual(contract.ca_de4_filing_status, 'head_household')
+ self.assertEqual(contract.ca_de4_allowances, 3)
+ self.assertEqual(contract.ca_additional_allowances, 0)
+
+ self._log('2018 California tax last payslip:')
+ payslip = self._createPayslip(employee, '2018-12-01', '2018-12-31')
+ payslip.compute_sheet()
+ process_payslip(payslip)
+
+ self._log('2019 California tax first payslip:')
+ payslip = self._createPayslip(employee, '2019-01-01', '2019-01-31')
+
+ payslip.compute_sheet()
+
+ cats = self._getCategories(payslip)
+
+ self.assertPayrollEqual(cats['WAGE_US_CA_UNEMP'], salary)
+ self.assertPayrollEqual(cats['ER_US_CA_UNEMP'], round((cats['WAGE_US_CA_UNEMP'] * self.CA_UIT), 2))
+ self.assertPayrollEqual(cats['WAGE_US_CA_ETT'], salary)
+ self.assertPayrollEqual(cats['ER_US_CA_ETT'], round((cats['WAGE_US_CA_ETT'] * self.CA_ETT), 2))
+ self.assertPayrollEqual(cats['WAGE_US_CA_SDI'], salary)
+ self.assertPayrollEqual(cats['EE_US_CA_SDI'], round((cats['WAGE_US_CA_SDI'] * self.CA_SDI), 2))
+ self.assertPayrollEqual(cats['EE_US_CA_INC_WITHHOLD'], wh)
+
+ process_payslip(payslip)
+
+ # Make a new payslip, this one will have maximums
+
+ remaining_ca_uit_wages = self.CA_UIT_MAX_WAGE - salary if (self.CA_UIT_MAX_WAGE - 2 * salary < salary) \
+ else salary
+
+ self._log('2019 California tax second payslip:')
+ payslip = self._createPayslip(employee, '2019-02-01', '2019-02-28')
+
+ payslip.compute_sheet()
+
+ cats = self._getCategories(payslip)
+
+ self.assertPayrollEqual(cats['WAGE_US_CA_UNEMP'], remaining_ca_uit_wages)
+ self.assertPayrollEqual(cats['ER_US_CA_UNEMP'], round((remaining_ca_uit_wages * self.CA_UIT), 2))
+
+ def test_example_e(self):
+ salary = 1800
+ schedule_pay = 'semi-monthly'
+ allowances = 4
+ additional_allowances = 0
+
+ wh = -3.08
+
+ employee = self._createEmployee()
+ contract = self._createContract(employee,
+ salary,
+ struct_id=self.ref(
+ 'l10n_us_ca_hr_payroll.hr_payroll_salary_structure_us_ca_employee'),
+ schedule_pay=schedule_pay)
+ contract.ca_de4_allowances = allowances
+ contract.ca_additional_allowances = additional_allowances
+ contract.ca_de4_filing_status = 'married'
+
+ self.assertEqual(contract.schedule_pay, 'semi-monthly')
+ self.assertEqual(contract.ca_de4_filing_status, 'married')
+ self.assertEqual(contract.ca_de4_allowances, 4)
+ self.assertEqual(contract.ca_additional_allowances, 0)
+
+ self._log('2018 California tax last payslip:')
+ payslip = self._createPayslip(employee, '2018-12-01', '2018-12-31')
+ payslip.compute_sheet()
+ process_payslip(payslip)
+
+ self._log('2019 California tax first payslip:')
+ payslip = self._createPayslip(employee, '2019-01-01', '2019-01-31')
+
+ payslip.compute_sheet()
+
+ cats = self._getCategories(payslip)
+
+ self.assertPayrollEqual(cats['WAGE_US_CA_UNEMP'], salary)
+ self.assertPayrollEqual(cats['ER_US_CA_UNEMP'], round((cats['WAGE_US_CA_UNEMP'] * self.CA_UIT), 2))
+ self.assertPayrollEqual(cats['WAGE_US_CA_ETT'], salary)
+ self.assertPayrollEqual(cats['ER_US_CA_ETT'], round((cats['WAGE_US_CA_ETT'] * self.CA_ETT), 2))
+ self.assertPayrollEqual(cats['WAGE_US_CA_SDI'], salary)
+ self.assertPayrollEqual(cats['EE_US_CA_SDI'], round((cats['WAGE_US_CA_SDI'] * self.CA_SDI), 2))
+ self.assertPayrollEqual(cats['EE_US_CA_INC_WITHHOLD'], wh)
+
+ process_payslip(payslip)
+
+ # Make a new payslip, this one will have maximums
+
+ remaining_ca_uit_wages = self.CA_UIT_MAX_WAGE - salary if (self.CA_UIT_MAX_WAGE - 2 * salary < salary) \
+ else salary
+
+ self._log('2019 California tax second payslip:')
+ payslip = self._createPayslip(employee, '2019-02-01', '2019-02-28')
+
+ payslip.compute_sheet()
+
+ cats = self._getCategories(payslip)
+
+ self.assertPayrollEqual(cats['WAGE_US_CA_UNEMP'], remaining_ca_uit_wages)
+ self.assertPayrollEqual(cats['ER_US_CA_UNEMP'], round((remaining_ca_uit_wages * self.CA_UIT), 2))
+
+ def test_example_f(self):
+ salary = 45000
+ schedule_pay = 'annually'
+ allowances = 4
+ additional_allowances = 0
+
+ wh = -113.85
+
+ employee = self._createEmployee()
+ contract = self._createContract(employee,
+ salary,
+ struct_id=self.ref(
+ 'l10n_us_ca_hr_payroll.hr_payroll_salary_structure_us_ca_employee'),
+ schedule_pay=schedule_pay)
+ contract.ca_de4_allowances = allowances
+ contract.ca_additional_allowances = additional_allowances
+ contract.ca_de4_filing_status = 'married'
+
+ self.assertEqual(contract.schedule_pay, 'annually')
+ self.assertEqual(contract.ca_de4_filing_status, 'married')
+ self.assertEqual(contract.ca_de4_allowances, 4)
+ self.assertEqual(contract.ca_additional_allowances, 0)
+
+ self._log('2018 California tax last payslip:')
+ payslip = self._createPayslip(employee, '2018-12-01', '2018-12-31')
+ payslip.compute_sheet()
+ process_payslip(payslip)
+
+ self._log('2019 California tax first payslip:')
+ payslip = self._createPayslip(employee, '2019-01-01', '2019-01-31')
+
+ payslip.compute_sheet()
+
+ cats = self._getCategories(payslip)
+
+ self.assertPayrollEqual(cats['ER_US_CA_UNEMP'], round((cats['WAGE_US_CA_UNEMP'] * self.CA_UIT), 2))
+ self.assertPayrollEqual(cats['ER_US_CA_ETT'], round((cats['WAGE_US_CA_ETT'] * self.CA_ETT), 2))
+ self.assertPayrollEqual(cats['EE_US_CA_SDI'], round((cats['WAGE_US_CA_SDI'] * self.CA_SDI), 2))
+ self.assertPayrollEqual(cats['EE_US_CA_INC_WITHHOLD'], wh)
+
+ process_payslip(payslip)
+
+ def test_estimated_deduction_table(self):
+ salary = 600
+ allowances = 5
+ schedule_pay = 'bi-weekly'
+ expected_deduction = 192
+ deduction = 0
+ taxable_pay = 0
+ estimated_deduction_table = {
+ 'weekly': (19, 38, 58, 77, 96, 115, 135, 154, 173, 192),
+ 'bi-weekly': (38, 77, 115, 154, 192, 231, 269, 308, 346, 385),
+ 'semi-monthly': (42, 83, 125, 167, 208, 250, 292, 333, 375, 417),
+ 'monthly': (83, 167, 250, 333, 417, 500, 583, 667, 750, 833),
+ 'quarterly': (250, 500, 750, 1000, 1250, 1500, 1750, 2000, 2250, 2500),
+ 'semi-annual': (500, 1000, 1500, 2000, 2500, 3000, 3500, 4000, 4500, 5000),
+ 'annual': (1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000, 10000),
+ }
+
+ allowance_index = allowances - 1
+ if allowances > 10:
+ deduction = (estimated_deduction_table[schedule_pay][0]) * allowances
+ taxable_pay = salary - deduction
+ elif allowances > 0:
+ deduction = estimated_deduction_table[schedule_pay][allowance_index]
+ taxable_pay = salary - deduction
+
+ self.assertEqual(expected_deduction, deduction)
+ self.assertTrue(taxable_pay < salary)
+ self.assertEqual(taxable_pay, salary - deduction)
+
+ def test_standard_deduction_table(self):
+ salary = 3000
+ schedule_pay = 'monthly'
+ filing_status = 'head_household'
+ expected_deduction = 706
+ deduction = 0
+ taxable_pay = 0
+ standard_deduction_table = {
+ 'weekly': (81, 81, 163, 163),
+ 'bi-weekly': (163, 163, 326, 326),
+ 'semi-monthly': (177, 177, 353, 353),
+ 'monthly': (353, 352, 706, 706),
+ 'quarterly': (1059, 1059, 2188, 2188),
+ 'semi-annual': (2118, 2118, 4236, 4236),
+ 'annual': (4236, 4236, 8471, 8472),
+ }
+
+ if filing_status == 'head_household':
+ _, _, _, deduction = standard_deduction_table[schedule_pay]
+ taxable_pay = salary - deduction
+ elif filing_status == 'married':
+ if allowances >= 2:
+ _, _, deduction, _ = standard_deduction_table[schedule_pay]
+ taxable_pay = salary - deduction
+ else:
+ _, deduction, _, _ = standard_deduction_table[schedule_pay]
+ taxable_pay = salary - deduction
+ else:
+ deduction, _, _, _ = standard_deduction_table[schedule_pay]
+ taxable_pay = salary - deduction
+
+ self.assertEqual(expected_deduction, deduction)
+ self.assertTrue(taxable_pay < salary)
+ self.assertEqual(taxable_pay, salary - deduction)
diff --git a/l10n_us_ca_hr_payroll/hr_payroll_view.xml b/l10n_us_ca_hr_payroll/views/hr_payroll_views.xml
similarity index 62%
rename from l10n_us_ca_hr_payroll/hr_payroll_view.xml
rename to l10n_us_ca_hr_payroll/views/hr_payroll_views.xml
index 15707d29..2231f38a 100755
--- a/l10n_us_ca_hr_payroll/hr_payroll_view.xml
+++ b/l10n_us_ca_hr_payroll/views/hr_payroll_views.xml
@@ -1,19 +1,6 @@
-
- res.company.form
- res.company
- 64
-
-
-
-
-
-
-
-
-
hr.contract.form.inherit
hr.contract