diff --git a/l10n_us_ca_hr_payroll/data/rules.xml b/l10n_us_ca_hr_payroll/data/rules.xml index 9a31434f..c5e7d73c 100755 --- a/l10n_us_ca_hr_payroll/data/rules.xml +++ b/l10n_us_ca_hr_payroll/data/rules.xml @@ -15,7 +15,7 @@ ### rate = payslip.dict.get_rate('US_CA_UNEMP') -year = int(payslip.dict.date_from[:4]) +year = int(payslip.dict.date_to[: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 @@ -62,7 +62,7 @@ if result_rate == 0.0: ### rate = payslip.dict.get_rate('US_CA_ETT') -year = int(payslip.dict.date_from[:4]) +year = int(payslip.dict.date_to[: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 @@ -109,7 +109,7 @@ if result_rate == 0.0: ### rate = payslip.dict.get_rate('US_CA_SDI') -year = int(payslip.dict.date_from[:4]) +year = int(payslip.dict.date_to[: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 @@ -154,7 +154,7 @@ if result_rate == 0.0: result = True code -year = int(payslip.dict.date_from[:4]) +year = int(payslip.dict.date_to[:4]) wages = categories.GROSS allowances = contract.ca_de4_allowances additional_allowances = contract.ca_additional_allowances diff --git a/l10n_us_nc_hr_payroll/data/rules.xml b/l10n_us_nc_hr_payroll/data/rules.xml new file mode 100755 index 00000000..1885fe4c --- /dev/null +++ b/l10n_us_nc_hr_payroll/data/rules.xml @@ -0,0 +1,153 @@ + + + + + + + + + Wage: US-NC Unemployment + WAGE_US_NC_UNEMP + python + result = (contract.futa_type != contract.FUTA_TYPE_BASIC) + code + +rate = payslip.dict.get_rate('US_NC_UNEMP') +year = int(payslip.dict.date_to[:4]) +ytd = payslip.sum('NC_UNEMP_WAGES_2018', 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-NC Unemployment + ER_US_NC_UNEMP + python + result = (contract.futa_type != contract.FUTA_TYPE_BASIC) + code + +rate = payslip.dict.get_rate('US_NC_UNEMP') +result_rate = -rate.rate +result = categories.WAGE_US_NC_UNEMP + +# result_rate of 0 implies 100% due to bug +if result_rate == 0.0: + result = 0.0 + + + + + + + + + EE: US-NC Income Tax Withholding + EE_US_NC_INC_WITHHOLD + python + result = True + code + +wages = categories.GROSS +allowances = contract.nc_nc4_allowances +schedule_pay = contract.schedule_pay +val = 0.00 + + +# PST -> Portion of standard deduction +if year == 2018: + PST = 0.0 + allowance_multiplier = 0.0 + if 'weekly' == schedule_pay: + allowance_multiplier = 48.08 + if contract.nc_nc4_filing_status == 'head_household': + PST = 269.23 + else: + PST = 168.27 + elif 'bi-weekly' == schedule_pay: + allowance_multiplier = 96.15 + if contract.nc_nc4_filing_status == 'head_household': + PST = 538.46 + else: + PST = 336.54 + elif 'semi-monthly' == schedule_pay: + allowance_multiplier = 104.17 + if contract.nc_nc4_filing_status == 'head_household': + PST = 583.33 + else: + PST = 364.58 + elif 'monthly' == schedule_pay: + allowance_multiplier = 208.33 + if contract.nc_nc4_filing_status == 'head_household': + PST = 1166.67 + else: + PST = 729.17 + + else: + raise Exception('Invalid schedule_pay="' + schedule_pay + '" for NC Income Withholding calculation') + + # Algorithm derived from percentage method in https://files.nc.gov/ncdor/documents/files/nc-30_book_web.pdf + if contract.nc_nc4_filing_status == 'exempt': + result = 0 + else: + withholding = round(((wages - (PST + (allowance_multiplier * allowances))) * 0.05599) + contract.nc_nc4_additional_wh) + if withholding > 0.0: + result = - withholding + else: + result = 0 +else: + PST = 0.0 + allowance_multiplier = 0.0 + if 'weekly' == schedule_pay: + allowance_multiplier = 48.08 + if contract.nc_nc4_filing_status == 'head_household': + PST = 288.46 + else: + PST = 192.31 + elif 'bi-weekly' == schedule_pay: + allowance_multiplier = 96.15 + if contract.nc_nc4_filing_status == 'head_household': + PST = 576.92 + else: + PST = 384.62 + elif 'semi-monthly' == schedule_pay: + allowance_multiplier = 104.17 + if contract.nc_nc4_filing_status == 'head_household': + PST = 625.00 + else: + PST = 416.67 + elif 'monthly' == schedule_pay: + allowance_multiplier = 208.33 + if contract.nc_nc4_filing_status == 'head_household': + PST = 1250.00 + else: + PST = 833.33 + + else: + raise Exception('Invalid schedule_pay="' + schedule_pay + '" for NC Income Withholding calculation') + + # Algorithm derived from percentage method in https://files.nc.gov/ncdor/documents/files/nc-30_book_web.pdf + if contract.nc_nc4_filing_status == 'exempt': + result = 0 + else: + withholding = round(((wages - (PST + (allowance_multiplier * allowances))) * 0.0535) + contract.nc_nc4_additional_wh) + if withholding > 0.0: + result = - withholding + else: + result = 0 + + + + + + + diff --git a/l10n_us_nj_hr_payroll/data/rules.xml b/l10n_us_nj_hr_payroll/data/rules.xml new file mode 100755 index 00000000..45b095dc --- /dev/null +++ b/l10n_us_nj_hr_payroll/data/rules.xml @@ -0,0 +1,714 @@ + + + + + + + + + + Wage: US-NJ Unemployment Insurance + WAGE_US_NJ_UNEMP + python + result = (contract.futa_type != contract.FUTA_TYPE_BASIC) + code + +### +year = int(payslip.dict.date_to[:4]) +rate = payslip.dict.get_rate('ER_US_NJ_UNEMP') +ytd = payslip.sum('WAGE_US_NJ_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 + + + + + + + EE: US-NJ Unemployment + EE_US_NJ_UNEMP + python + result = (contract.futa_type != contract.FUTA_TYPE_BASIC) + code + +rate = payslip.dict.get_rate('EE_US_NJ_UNEMP') +result_rate = -rate.rate +result = categories.BASIC + +# result_rate of 0 implies 100% due to bug +if result_rate == 0.0: + result = 0.0 + + + + + + + + ER: US-NJ Unemployment + ER_US_NJ_UNEMP + python + result = (contract.futa_type != contract.FUTA_TYPE_BASIC) + code + +rate = payslip.dict.get_rate('ER_US_NJ_UNEMP') +result_rate = -rate.rate +result = categories.WAGE_US_NJ_UNEMP + +# result_rate of 0 implies 100% due to bug +if result_rate == 0.0: + result = 0.0 + + + + + + + + + + + Wage: US-NJ State Disability Insurance + WAGE_US_NJ_SDI + python + result = (contract.futa_type != contract.FUTA_TYPE_BASIC) + code + +### +year = int(payslip.dict.date_to[:4]) +rate = payslip.dict.get_rate('ER_US_NJ_SDI') +ytd = payslip.sum('WAGE_US_NJ_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-NJ State Disability Insurance + EE_US_NJ_SDI + python + result = (contract.futa_type != contract.FUTA_TYPE_BASIC) + code + +rate = payslip.dict.get_rate('EE_US_NJ_SDI') +result_rate = -rate.rate +result = categories.BASIC + +# result_rate of 0 implies 100% due to bug +if result_rate == 0.0: + result = 0.0 + + + + + + + + ER: US-NJ State Disability Insurance + ER_US_NJ_SDI + python + result = (contract.futa_type != contract.FUTA_TYPE_BASIC) + code + +rate = payslip.dict.get_rate('ER_US_NJ_SDI') +result_rate = -rate.rate +result = categories.WAGE_US_NJ_SDI + +# result_rate of 0 implies 100% due to bug +if result_rate == 0.0: + result = 0.0 + + + + + + + + + + Wage: US-NJ Family Leave Insurance + WAGE_US_NJ_FLI + python + result = (contract.futa_type != contract.FUTA_TYPE_BASIC) + code + +### +year = int(payslip.dict.date_to[:4]) +rate = payslip.dict.get_rate('ER_US_NJ_FLI') +ytd = payslip.sum('WAGE_US_NJ_FLI', 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-NJ Family Leave Insurance + EE_US_NJ_FLI + python + result = (contract.futa_type != contract.FUTA_TYPE_BASIC) + code + +rate = payslip.dict.get_rate('EE_US_NJ_FLI') +result_rate = -rate.rate +result = categories.BASIC + + + + + + + + + + Wage: US-NJ Workforce Development Funds + WAGE_US_NJ_WF + python + result = (contract.futa_type != contract.FUTA_TYPE_BASIC) + code + +### +year = int(payslip.dict.date_to[:4]) +rate = payslip.dict.get_rate('ER_US_NJ_WF') +ytd = payslip.sum('WAGE_US_NJ_WF', 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-NJ Workforce Development Funds + EE_US_NJ_WF + python + result = (contract.futa_type != contract.FUTA_TYPE_BASIC) + code + +rate = payslip.dict.get_rate('EE_US_NJ_WF') +result_rate = -rate.rate +result = categories.BASIC + +if result_rate == 0.0: + result = 0.0 + + + + + + + + + + EE: US-NJ Income Withholding + EE_US_NJ_INC_WITHHOLD + python + result = True + code + +wages = categories.GROSS +allowances = contract.nj_njw4_allowances +additional_withholding = contract.nj_additional_withholding +schedule_pay = contract.schedule_pay +filing_status = contract.nj_njw4_filing_status +rate_table = contract.nj_njw4_rate_table + +# Determine which rate table to use +if not rate_table: + if filing_status == 'single' or filing_status == 'married_separate': + rate_table = 'A' + elif filing_status == 'married_joint' or filing_status == 'widower' or filing_status == 'head_household': + rate_table = 'B' + +# Tables are found in http://www.state.nj.us/treasury/taxation/pdf/current/njwt.pdf +# Tax Rate Tables to calculate income withholding + +#### RATE 'A' #### +if rate_table == 'A': + ### WEEKLY ### + if schedule_pay == 'weekly': + wages -= 19.20 * allowances + tax_rate_table = [ + (384, 0.015, 0.0), + (673, 0.02, 5.76), + (769, 0.039, 11.54), + (1442, 0.061, 15.28), + (9615, 0.07, 56.34), + (float('inf'), 0.099, 628.45), + ] + + ### BI-WEEKLY ### + elif schedule_pay == 'bi-weekly': + wages -= 38.40 * allowances + tax_rate_table = [ + (769, 0.015, 0.0), + (1346, 0.02, 11.54), + (1538, 0.039, 23.08), + (2884, 0.061, 30.56), + (19231, 0.07, 112.67), + (float('inf'), 0.099, 1256.96), + ] + + ### SEMI-MONTHLY ### + elif schedule_pay == 'semi-monthly': + wages -= 41.60 * allowances + tax_rate_table = [ + (833, 0.015, 0.0), + (1458, 0.02, 12.50), + (1666, 0.039, 25.00), + (3125, 0.061, 33.11), + (20833, 0.07, 112.11), + (float('inf'), 0.099, 1361.67), + ] + + ### MONTHLY ### + elif schedule_pay == 'monthly': + wages -= 83.30 * allowances + tax_rate_table = [ + (1666, 0.015, 0.0), + (2916, 0.02, 24.99), + (3333, 0.039, 49.99), + (6250, 0.061, 66.25), + (41667, 0.07, 244.19), + (float('inf'), 0.099, 2723.38), + ] + + ### QUARTERLY ### + elif schedule_pay == 'quarterly': + wages -= 250.00 * allowances + tax_rate_table = [ + (5000, 0.015, 0.0), + (8750, 0.02, 75.00), + (10000, 0.039, 150.00), + (18750, 0.061, 198.75), + (125000, 0.07, 732.50), + (float('inf'), 0.099, 8170.00), + ] + + ### SEMI-ANNUAL ### + elif schedule_pay == 'semi-annual': + wages -= 500 * allowances + tax_rate_table = [ + (10000, 0.015, 0.0), + (17500, 0.02, 150.00), + (20000, 0.039, 300.00), + (37500, 0.061, 397.50), + (250000, 0.07, 1465.00), + (float('inf'), 0.099, 16340.00), + ] + + ### ANNUAL ### + elif schedule_pay == 'annually': + wages -= 1000.00 * allowances + tax_rate_table = [ + (20000, 0.015, 0.0), + (35000, 0.02, 300.00), + (40000, 0.039, 600.00), + (75000, 0.061, 795.00), + (500000, 0.07, 2930.00), + (float('inf'), 0.099, 32680.00), + ] + +#### RATE 'B' #### +elif rate_table == 'B': + ### WEEKLY ### + if schedule_pay == 'weekly': + wages -= 19.20 * allowances + tax_rate_table = [ + (384, 0.015, 0.0), + (961, 0.02, 5.76), + (1346, 0.027, 17.30), + (1538, 0.039, 27.70), + (2884, 0.061, 35.18), + (9615, 0.07, 117.29), + (float('inf'), 0.099, 588.46), + ] + + ### BI-WEEKLY ### + elif schedule_pay == 'bi-weekly': + wages -= 38.40 * allowances + tax_rate_table = [ + (769, 0.015, 0.0), + (1923, 0.02, 11.54), + (2692, 0.027, 34.62), + (3076, 0.039, 55.38), + (5769, 0.061, 70.35), + (19231, 0.07, 234.63), + (float('inf'), 0.099, 1176.97), + ] + + ### SEMI-MONTHLY ### + elif schedule_pay == 'semi-monthly': + wages -= 41.60 * allowances + tax_rate_table = [ + (833, 0.015, 0.0), + (2083, 0.02, 12.50), + (2916, 0.027, 37.50), + (3333, 0.039, 59.99), + (6250, 0.061, 76.25), + (20833, 0.07, 254.19), + (float('inf'), 0.099, 1275), + ] + + ### MONTHLY ### + elif schedule_pay == 'monthly': + wages -= 83.30 * allowances + tax_rate_table = [ + (1666, 0.015, 0.0), + (4166, 0.02, 24.99), + (5833, 0.027, 74.99), + (6666, 0.039, 120.00), + (12500, 0.061, 152.49), + (41667, 0.07, 508.36), + (float('inf'), 0.099, 2550.05), + ] + + ### QUARTERLY ### + elif schedule_pay == 'quarterly': + wages -= 250.00 * allowances + tax_rate_table = [ + (5000, 0.015, 0.0), + (12500, 0.02, 75.00), + (17500, 0.027, 225.00), + (20000, 0.039, 360.00), + (37500, 0.061, 457.50), + (125000, 0.07, 1525.00), + (float('inf'), 0.099, 7650.00), + ] + + ### SEMI-ANNUAL ### + elif schedule_pay == 'semi-annual': + wages -= 500.00 * allowances + tax_rate_table = [ + (10000, 0.015, 0.0), + (25000, 0.02, 150.00), + (35000, 0.027, 450.00), + (40000, 0.039, 720.00), + (75000, 0.061, 915.00), + (250000, 0.07, 3050.00), + (float('inf'), 0.099, 15300.00), + ] + + ### ANNUAL ### + elif schedule_pay == 'annually': + wages -= 1000.00 * allowances + tax_rate_table = [ + (20000, 0.015, 0.0), + (50000, 0.02, 300.00), + (70000, 0.027, 900.00), + (80000, 0.039, 1440.00), + (150000, 0.061, 1830.00), + (500000, 0.07, 6100.00), + (float('inf'), 0.099, 30600.00), + ] + +#### RATE 'C' #### +elif rate_table == 'C': + ### WEEKLY ### + if schedule_pay == 'weekly': + wages -= 19.20 * allowances + tax_rate_table = [ + (384, 0.015, 0.0), + (769, 0.023, 5.76), + (961, 0.028, 14.62), + (1153, 0.035, 19.99), + (2884, 0.056, 26.71), + (9615, 0.066, 123.65), + (float('inf'), 0.099, 567.90), + ] + + ### BI-WEEKLY ### + elif schedule_pay == 'bi-weekly': + wages -= 38.40 * allowances + tax_rate_table = [ + (769, 0.015, 0.0), + (1538, 0.023, 11.54), + (1923, 0.028, 29.22), + (2307, 0.035, 40.00), + (5769, 0.056, 53.44), + (19231, 0.066, 247.31), + (float('inf'), 0.099, 1135.80), + ] + + ### SEMI-MONTHLY ### + elif schedule_pay == 'semi-monthly': + wages -= 41.60 * allowances + tax_rate_table = [ + (833, 0.015, 0.0), + (1666, 0.023, 12.50), + (2083, 0.028, 31.65), + (2500, 0.035, 43.33), + (6250, 0.056, 57.93), + (20833, 0.066, 26793), + (float('inf'), 0.099, 1230.41), + ] + + ### MONTHLY ### + elif schedule_pay == 'monthly': + wages -= 83.30 * allowances + tax_rate_table = [ + (1666, 0.015, 0.0), + (3333, 0.023, 24.99), + (4166, 0.028, 63.33), + (5000, 0.035, 86.66), + (12500, 0.056, 115.85), + (41667, 0.066, 535.85), + (float('inf'), 0.099, 2460.87), + ] + + ### QUARTERLY ### + elif schedule_pay == 'quarterly': + wages -= 250.00 * allowances + tax_rate_table = [ + (5000, 0.015, 0.0), + (10000, 0.023, 75.00), + (12500, 0.028, 190.00), + (15000, 0.035, 260.00), + (37500, 0.056, 347.50), + (125000, 0.066, 1607.50), + (float('inf'), 0.099, 7382.50), + ] + + ### SEMI-ANNUAL ### + elif schedule_pay == 'semi-annual': + wages -= 500.00 * allowances + tax_rate_table = [ + (10000, 0.015, 0.0), + (20000, 0.023, 150.00), + (25000, 0.028, 380.00), + (30000, 0.035, 520.00), + (75000, 0.056, 695.00), + (250000, 0.066, 3215.00), + (float('inf'), 0.099, 14765.00), + ] + + ### ANNUAL ### + elif schedule_pay == 'annually': + wages -= 1000.00 * allowances + tax_rate_table = [ + (20000, 0.015, 0.0), + (40000, 0.023, 300.00), + (50000, 0.028, 760.00), + (60000, 0.035, 1040.00), + (150000, 0.056, 1390.00), + (500000, 0.066, 6430.00), + (float('inf'), 0.099, 29530.00), + ] + +#### RATE 'D' #### +elif rate_table == 'D': + ### WEEKLY ### + if schedule_pay == 'weekly': + wages -= 19.20 * allowances + tax_rate_table = [ + (384, 0.015, 0.0), + (769, 0.027, 5.76), + (961, 0.034, 16.16), + (1153, 0.043, 22.68), + (2884, 0.056, 30.94), + (9615, 0.065, 127.88), + (float('inf'), 0.099, 565.40), + ] + + ### BI-WEEKLY ### + elif schedule_pay == 'bi-weekly': + wages -= 38.40 * allowances + tax_rate_table = [ + (769, 0.015, 0.0), + (1538, 0.027, 11.54), + (1923, 0.034, 32.30), + (2307, 0.043, 45.39), + (5769, 0.056, 61.90), + (19231, 0.065, 255.77), + (float('inf'), 0.099, 1130.80), + ] + + ### SEMI-MONTHLY ### + elif schedule_pay == 'semi-monthly': + wages -= 41.60 * allowances + tax_rate_table = [ + (833, 0.015, 0.0), + (1666, 0.027, 12.50), + (2083, 0.034, 34.99), + (2500, 0.043, 49.16), + (6250, 0.056, 67.10), + (20833, 0.065, 277.10), + (float('inf'), 0.099, 1225.00), + ] + + ### MONTHLY ### + elif schedule_pay == 'monthly': + wages -= 83.30 * allowances + tax_rate_table = [ + (1666, 0.015, 0.0), + (3333, 0.027, 24.99), + (4166, 0.034, 70.00), + (5000, 0.043, 98.32), + (12500, 0.056, 134.18), + (41667, 0.065, 554.18), + (float('inf'), 0.099, 2450.04), + ] + + ### QUARTERLY ### + elif schedule_pay == 'quarterly': + wages -= 250.00 * allowances + tax_rate_table = [ + (5000, 0.015, 0.0), + (10000, 0.027, 75.00), + (12500, 0.034, 210.00), + (15000, 0.043, 295.00), + (37500, 0.056, 402.50), + (125000, 0.065, 1662.50), + (float('inf'), 0.099, 7350.00), + ] + + ### SEMI-ANNUAL ### + elif schedule_pay == 'semi-annual': + wages -= 500.00 * allowances + tax_rate_table = [ + (10000, 0.015, 0.0), + (20000, 0.027, 150.00), + (25000, 0.034, 420.00), + (30000, 0.043, 590.00), + (75000, 0.056, 805.00), + (250000, 0.065, 3325.00), + (float('inf'), 0.099, 14700.00), + ] + + ### ANNUAL ### + elif schedule_pay == 'annually': + wages -= 1000.00 * allowances + tax_rate_table = [ + (20000, 0.015, 0.0), + (40000, 0.027, 300.00), + (50000, 0.034, 840.00), + (60000, 0.043, 1180.00), + (150000, 0.056, 1610.00), + (250000, 0.065, 6650.00), + (float('inf'), 0.099, 29400.00), + ] + +#### RATE 'E' #### +elif rate_table == 'E': + ### WEEKLY ### + if schedule_pay == 'weekly': + wages -= 19.20 * allowances + tax_rate_table = [ + (384, 0.015, 0.0), + (673, 0.02, 5.76), + (1923, 0.058, 11.54), + (9615, 0.065, 84.04), + (float('inf'), 0.099, 584.02), + ] + + ### BI-WEEKLY ### + elif schedule_pay == 'bi-weekly': + wages -= 38.40 * allowances + tax_rate_table = [ + (769, 0.015, 0.0), + (1346, 0.02, 11.54), + (3846, 0.058, 23.08), + (19231, 0.065, 168.08), + (float('inf'), 0.099, 1168.11), + ] + + ### SEMI-MONTHLY ### + elif schedule_pay == 'semi-monthly': + wages -= 41.60 * allowances + tax_rate_table = [ + (833, 0.015, 0.0), + (1458, 0.02, 12.50), + (4166, 0.058, 25.00), + (20833, 0.065, 182.06), + (float('inf'), 0.099, 1265.42), + ] + + ### MONTHLY ### + elif schedule_pay == 'monthly': + wages -= 83.30 * allowances + tax_rate_table = [ + (1666, 0.015, 0.0), + (2916, 0.02, 24.99), + (8333, 0.058, 49.99), + (41667, 0.065, 364.18), + (float('inf'), 0.099, 2530.89), + ] + + ### QUARTERLY ### + elif schedule_pay == 'quarterly': + wages -= 250.00 * allowances + tax_rate_table = [ + (5000, 0.015, 0.0), + (8750, 0.02, 75.00), + (25000, 0.058, 150.00), + (125000, 0.065, 1092.50), + (float('inf'), 0.099, 7592.50), + ] + + ### SEMI-ANNUAL ### + elif schedule_pay == 'semi-annual': + wages -= 500.00 * allowances + tax_rate_table = [ + (10000, 0.015, 0.0), + (17500, 0.02, 150.00), + (50000, 0.058, 300.00), + (250000, 0.065, 2185.00), + (float('inf'), 0.099, 15,185.00), + ] + + ### ANNUAL ### + elif schedule_pay == 'annually': + wages -= 1000.00 * allowances + tax_rate_table = [ + (20000, 0.015, 0.0), + (35000, 0.02, 300.00), + (100000, 0.058, 600.00), + (500000, 0.065, 4370.00), + (float('inf'), 0.099, 30370.00), + ] + + +over = 0.0 +tax = 0.0 +for row in tax_rate_table: + if wages <= row[0]: + tax = ((wages - over) * row[1]) + row[2] + tax += additional_withholding + break + over = row[0] + +result = -tax + + + + + + + diff --git a/l10n_us_oh_hr_payroll/data/rules.xml b/l10n_us_oh_hr_payroll/data/rules.xml index 5f67e8b9..fcd486d0 100755 --- a/l10n_us_oh_hr_payroll/data/rules.xml +++ b/l10n_us_oh_hr_payroll/data/rules.xml @@ -14,7 +14,7 @@ ### rate = payslip.dict.get_rate('US_OH_UNEMP') -year = int(payslip.dict.date_from[:4]) +year = int(payslip.dict.date_to[:4]) ytd = payslip.sum('WAGE_US_OH_UNEMP', str(year) + '-01-01', str(year+1) + '-01-01') ytd += contract.external_wages remaining = rate.wage_limit_year - ytd @@ -57,6 +57,7 @@ if result_rate == 0.0: result = True code +year = int(payslip.dict.date_to[:4]) wages = categories.GROSS allowances = contract.oh_income_allowances schedule_pay = contract.schedule_pay @@ -80,24 +81,44 @@ elif 'annually' == schedule_pay: else: raise Exception('Invalid schedule_pay="' + schedule_pay + '" for OH Income Withholding calculation') -# Algorithm from http://www.tax.ohio.gov/Portals/0/employer_withholding/August2015Rates/WTH_OptionalComputerFormula_073015.pdf -TW = (wages * PP) - (650 * allowances) -if TW <= 5000.0: - WD = ((TW * 0.005) / PP) * 1.112 -elif TW <= 10000.0: - WD = ((((TW - 5000.0) * 0.01) + 25.0) / PP) * 1.112 -elif TW <= 15000.0: - WD = ((((TW - 10000.0) * 0.02) + 75.0) / PP) * 1.112 -elif TW <= 20000.0: - WD = ((((TW - 15000.0) * 0.025) + 175.0) / PP) * 1.112 -elif TW <= 40000.0: - WD = ((((TW - 20000.0) * 0.03) + 300.0) / PP) * 1.112 -elif TW <= 80000.0: - WD = ((((TW - 40000.0) * 0.035) + 900.0) / PP) * 1.112 -elif TW <= 100000.0: - WD = ((((TW - 80000.0) * 0.04) + 2300.0) / PP) * 1.112 +# Algorithm from https://www.tax.ohio.gov/Portals/0/employer_withholding/2019%20tables/WTH_OptionalComputerFormula_2019.pdf +if year == 2018: + TW = (wages * PP) - (650 * allowances) + if TW <= 5000.0: + WD = ((TW * 0.005) / PP) * 1.112 + elif TW <= 10000.0: + WD = ((((TW - 5000.0) * 0.01) + 25.0) / PP) * 1.112 + elif TW <= 15000.0: + WD = ((((TW - 10000.0) * 0.02) + 75.0) / PP) * 1.112 + elif TW <= 20000.0: + WD = ((((TW - 15000.0) * 0.025) + 175.0) / PP) * 1.112 + elif TW <= 40000.0: + WD = ((((TW - 20000.0) * 0.03) + 300.0) / PP) * 1.112 + elif TW <= 80000.0: + WD = ((((TW - 40000.0) * 0.035) + 900.0) / PP) * 1.112 + elif TW <= 100000.0: + WD = ((((TW - 80000.0) * 0.04) + 2300.0) / PP) * 1.112 + else: + WD = ((((TW - 100000.0) * 0.05) + 3100.0) / PP) * 1.112 else: - WD = ((((TW - 100000.0) * 0.05) + 3100.0) / PP) * 1.112 + TW = (wages * PP) - (650 * allowances) + if TW <= 5000.0: + WD = ((TW * 0.005) / PP) * 1.112 + elif TW <= 10000.0: + WD = ((((TW - 5000.0) * 0.01) + 25.0) / PP) * 1.075 + elif TW <= 15000.0: + WD = ((((TW - 10000.0) * 0.02) + 75.0) / PP) * 1.075 + elif TW <= 20000.0: + WD = ((((TW - 15000.0) * 0.025) + 175.0) / PP) * 1.075 + elif TW <= 40000.0: + WD = ((((TW - 20000.0) * 0.03) + 300.0) / PP) * 1.075 + elif TW <= 80000.0: + WD = ((((TW - 40000.0) * 0.035) + 900.0) / PP) * 1.075 + elif TW <= 100000.0: + WD = ((((TW - 80000.0) * 0.04) + 2300.0) / PP) * 1.075 + else: + WD = ((((TW - 100000.0) * 0.05) + 3100.0) / PP) * 1.075 + result = -WD diff --git a/l10n_us_oh_hr_payroll/tests/test_us_oh_payslip_2019.py b/l10n_us_oh_hr_payroll/tests/test_us_oh_payslip_2019.py index 7fc73657..0bc43efa 100755 --- a/l10n_us_oh_hr_payroll/tests/test_us_oh_payslip_2019.py +++ b/l10n_us_oh_hr_payroll/tests/test_us_oh_payslip_2019.py @@ -17,7 +17,7 @@ class TestUsOhPayslip(TestUsPayslip): # For formula here # http://www.tax.ohio.gov/Portals/0/employer_withholding/August2015Rates/WTH_OptionalComputerFormula_073015.pdf tw = salary * 12 # = 60000 - wd = ((tw - 40000) * 0.035 + 900) / 12 * 1.112 + wd = ((tw - 40000) * 0.035 + 900) / 12 * 1.075 employee = self._createEmployee() diff --git a/l10n_us_pa_hr_payroll/data/rules.xml b/l10n_us_pa_hr_payroll/data/rules.xml index 8ea08781..3bdb8576 100755 --- a/l10n_us_pa_hr_payroll/data/rules.xml +++ b/l10n_us_pa_hr_payroll/data/rules.xml @@ -13,7 +13,7 @@ code ### -year = int(payslip.dict.date_from[:4]) +year = int(payslip.dict.date_to[:4]) rate = payslip.dict.get_rate('ER_US_PA_UNEMP') ytd = payslip.sum('WAGE_ER_US_PA_UNEMP', str(year) + '-01-01', str(year+1) + '-01-01') ytd += contract.external_wages diff --git a/l10n_us_tx_hr_payroll/data/rules.xml b/l10n_us_tx_hr_payroll/data/rules.xml new file mode 100755 index 00000000..240ee79d --- /dev/null +++ b/l10n_us_tx_hr_payroll/data/rules.xml @@ -0,0 +1,92 @@ + + + + + + + + + Wage: US-TX Unemployment + WAGE_US_TX_UNEMP + python + result = (contract.futa_type != contract.FUTA_TYPE_BASIC) + code + +### +rate = payslip.dict.get_rate('US_TX_UNEMP') +year = int(payslip.dict.date_to[:4]) +ytd = payslip.sum('WAGE_US_TX_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-TX Unemployment + ER_US_TX_UNEMP + python + result = (contract.futa_type != contract.FUTA_TYPE_BASIC) + code + +rate = payslip.dict.get_rate('US_TX_UNEMP') +result_rate = -rate.rate +result = categories.WAGE_US_TX_UNEMP + +# result_rate of 0 implies 100% due to bug +if result_rate == 0.0: + result = 0.0 + + + + + + + + ER: US-TX Obligation Assessment + ER_US_TX_OA + python + result = (contract.futa_type != contract.FUTA_TYPE_BASIC) + code + +rate = payslip.dict.get_rate('US_TX_OA') +result_rate = -rate.rate +result = categories.WAGE_US_TX_UNEMP + +# result_rate of 0 implies 100% due to bug +if result_rate == 0.0: + result = 0.0 + + + + + + + + ER: US-TX Employment & Training Investment Assessment + ER_US_TX_ETIA + python + result = (contract.futa_type != contract.FUTA_TYPE_BASIC) + code + +rate = payslip.dict.get_rate('US_TX_ETIA') +result_rate = -rate.rate +result = categories.WAGE_US_TX_UNEMP + +# result_rate of 0 implies 100% due to bug +if result_rate == 0.0: + result = 0.0 + + + + + + +