Merge branch '11.0' into 11.0-test

# Conflicts:
#	l10n_us_hr_payroll/data/state/ak_alaska.xml
#	l10n_us_hr_payroll/data/state/al_alabama.xml
#	l10n_us_hr_payroll/data/state/ar_arkansas.xml
#	l10n_us_hr_payroll/data/state/az_arizona.xml
#	l10n_us_hr_payroll/data/state/ca_california.xml
#	l10n_us_hr_payroll/data/state/co_colorado.xml
#	l10n_us_hr_payroll/data/state/ct_connecticut.xml
#	l10n_us_hr_payroll/data/state/de_delaware.xml
#	l10n_us_hr_payroll/data/state/hi_hawaii.xml
#	l10n_us_hr_payroll/data/state/ia_iowa.xml
#	l10n_us_hr_payroll/data/state/id_idaho.xml
#	l10n_us_hr_payroll/data/state/il_illinois.xml
#	l10n_us_hr_payroll/data/state/ks_kansas.xml
#	l10n_us_hr_payroll/data/state/ky_kentucky.xml
#	l10n_us_hr_payroll/data/state/me_maine.xml
#	l10n_us_hr_payroll/data/state/mi_michigan.xml
#	l10n_us_hr_payroll/data/state/mn_minnesota.xml
#	l10n_us_hr_payroll/data/state/mo_missouri.xml
#	l10n_us_hr_payroll/data/state/nc_northcarolina.xml
#	l10n_us_hr_payroll/data/state/nd_north_dakota.xml
#	l10n_us_hr_payroll/data/state/ne_nebraska.xml
#	l10n_us_hr_payroll/data/state/nj_newjersey.xml
#	l10n_us_hr_payroll/data/state/nm_new_mexico.xml
#	l10n_us_hr_payroll/data/state/nv_nevada.xml
#	l10n_us_hr_payroll/data/state/ok_oklahoma.xml
#	l10n_us_hr_payroll/data/state/ri_rhode_island.xml
#	l10n_us_hr_payroll/data/state/sc_south_carolina.xml
#	l10n_us_hr_payroll/data/state/ut_utah.xml
#	l10n_us_hr_payroll/data/state/vt_vermont.xml
#	l10n_us_hr_payroll/data/state/wv_west_virginia.xml
#	l10n_us_hr_payroll/models/__init__.py
#	l10n_us_hr_payroll/models/federal/fed_941.py
#	l10n_us_hr_payroll/models/hr_payslip.py
#	l10n_us_hr_payroll/tests/test_special.py
This commit is contained in:
Jared Kipe
2020-11-21 15:43:12 -08:00
37 changed files with 169 additions and 54 deletions

View File

@@ -2,8 +2,12 @@
'name': 'USA - Payroll',
'author': 'Hibou Corp. <hello@hibou.io>',
'category': 'Localization',
'depends': ['hr_payroll', 'hr_payroll_rate'],
'version': '11.0.2020.1.0',
'depends': [
'hr_payroll',
'hr_payroll_rate',
'hibou_professional',
],
'version': '11.0.2020.2.2',
'description': """
USA Payroll Rules.
==================

View File

@@ -86,4 +86,4 @@
<field name="appears_on_payslip" eval="True"/>
</record>
</odoo>
</odoo>

View File

@@ -206,4 +206,4 @@
<field name="appears_on_payslip" eval="True"/>
</record>
</odoo>
</odoo>

View File

@@ -138,4 +138,4 @@
<field name="appears_on_payslip" eval="True"/>
</record>
</odoo>
</odoo>

View File

@@ -80,4 +80,4 @@
<field name="appears_on_payslip" eval="True"/>
</record>
</odoo>
</odoo>

View File

@@ -803,4 +803,4 @@
<field name="appears_on_payslip" eval="True"/>
</record>
</odoo>
</odoo>

View File

@@ -86,4 +86,4 @@
<field name="appears_on_payslip" eval="True"/>
</record>
</odoo>
</odoo>

View File

@@ -1221,4 +1221,4 @@
<field name="appears_on_payslip" eval="True"/>
</record>
</odoo>
</odoo>

View File

@@ -104,4 +104,4 @@
<field name="appears_on_payslip" eval="True"/>
</record>
</odoo>
</odoo>

View File

@@ -174,4 +174,4 @@
<field name="appears_on_payslip" eval="True"/>
</record>
</odoo>
</odoo>

View File

@@ -294,4 +294,4 @@
<field name="appears_on_payslip" eval="True"/>
</record>
</odoo>
</odoo>

View File

@@ -441,4 +441,4 @@
<field name="appears_on_payslip" eval="True"/>
</record>
</odoo>
</odoo>

View File

@@ -110,4 +110,4 @@
<field name="appears_on_payslip" eval="True"/>
</record>
</odoo>
</odoo>

View File

@@ -183,4 +183,4 @@
<field name="appears_on_payslip" eval="True"/>
</record>
</odoo>
</odoo>

View File

@@ -88,4 +88,4 @@
<field name="appears_on_payslip" eval="True"/>
</record>
</odoo>
</odoo>

View File

@@ -116,4 +116,4 @@
<field name="appears_on_payslip" eval="True"/>
</record>
</odoo>
</odoo>

View File

@@ -93,4 +93,4 @@
<field name="appears_on_payslip" eval="True"/>
</record>
</odoo>
</odoo>

View File

@@ -138,4 +138,4 @@
<field name="appears_on_payslip" eval="True"/>
</record>
</odoo>
</odoo>

View File

@@ -144,4 +144,4 @@
<field name="appears_on_payslip" eval="True"/>
</record>
</odoo>
</odoo>

View File

@@ -107,4 +107,4 @@
<field name="appears_on_payslip" eval="True"/>
</record>
</odoo>
</odoo>

View File

@@ -269,4 +269,4 @@
<field name="appears_on_payslip" eval="True"/>
</record>
</odoo>
</odoo>

View File

@@ -227,4 +227,4 @@
<field name="appears_on_payslip" eval="True"/>
</record>
</odoo>
</odoo>

View File

@@ -1013,4 +1013,4 @@
<field name="appears_on_payslip" eval="True"/>
</record>
</odoo>
</odoo>

View File

@@ -294,4 +294,4 @@
<field name="appears_on_payslip" eval="True"/>
</record>
</odoo>
</odoo>

View File

@@ -46,4 +46,4 @@
<field name="appears_on_payslip" eval="False"/>
</record>
</odoo>
</odoo>

View File

@@ -291,4 +291,4 @@
<field name="appears_on_payslip" eval="True"/>
</record>
</odoo>
</odoo>

View File

@@ -132,4 +132,4 @@
<field name="appears_on_payslip" eval="True"/>
</record>
</odoo>
</odoo>

View File

@@ -143,4 +143,4 @@
<field name="appears_on_payslip" eval="True"/>
</record>
</odoo>
</odoo>

View File

@@ -150,4 +150,4 @@
<field name="appears_on_payslip" eval="True"/>
</record>
</odoo>
</odoo>

View File

@@ -182,4 +182,4 @@
<field name="appears_on_payslip" eval="True"/>
</record>
</odoo>
</odoo>

View File

@@ -206,4 +206,4 @@
<field name="appears_on_payslip" eval="True"/>
</record>
</odoo>
</odoo>

View File

@@ -4,4 +4,5 @@ from . import hr_contract
from . import hr_payslip
from . import hr_salary_rule
from . import res_config_settings
from . import update
from . import us_payroll_config

View File

@@ -12,17 +12,18 @@ def fica_wage(payslip, categories):
"""
wage = categories.GROSS
wage -= categories.ALW_FICA_EXEMPT + \
categories.ALW_FIT_FICA_EXEMPT + \
categories.ALW_FIT_FICA_FUTA_EXEMPT + \
categories.ALW_FICA_FUTA_EXEMPT
wage += categories.DED_FICA_EXEMPT + \
categories.DED_FIT_FICA_EXEMPT + \
categories.DED_FIT_FICA_FUTA_EXEMPT + \
categories.DED_FICA_FUTA_EXEMPT
less_exempt = categories.ALW_FICA_EXEMPT + \
categories.ALW_FIT_FICA_EXEMPT + \
categories.ALW_FIT_FICA_FUTA_EXEMPT + \
categories.ALW_FICA_FUTA_EXEMPT
return wage
plus_exempt = categories.DED_FICA_EXEMPT + \
categories.DED_FIT_FICA_EXEMPT + \
categories.DED_FIT_FICA_FUTA_EXEMPT + \
categories.DED_FICA_FUTA_EXEMPT
# _logger.info('fica wage GROSS: %0.2f less exempt ALW: %0.2f plus exempt DED: %0.2f' % (wage, less_exempt, plus_exempt))
return wage - less_exempt + plus_exempt
def fica_wage_ytd(payslip, categories):
@@ -34,18 +35,19 @@ def fica_wage_ytd(payslip, categories):
year = payslip.dict.get_year()
ytd_wage = payslip.sum_category('GROSS', str(year) + '-01-01', str(year+1) + '-01-01')
ytd_wage -= payslip.sum_category('ALW_FICA_EXEMPT', str(year) + '-01-01', str(year+1) + '-01-01') + \
payslip.sum_category('ALW_FIT_FICA_EXEMPT', str(year) + '-01-01', str(year+1) + '-01-01') + \
payslip.sum_category('ALW_FIT_FICA_FUTA_EXEMPT', str(year) + '-01-01', str(year+1) + '-01-01') + \
payslip.sum_category('ALW_FICA_FUTA_EXEMPT', str(year) + '-01-01', str(year+1) + '-01-01')
less_exempt = payslip.sum_category('ALW_FICA_EXEMPT', str(year) + '-01-01', str(year+1) + '-01-01') + \
payslip.sum_category('ALW_FIT_FICA_EXEMPT', str(year) + '-01-01', str(year+1) + '-01-01') + \
payslip.sum_category('ALW_FIT_FICA_FUTA_EXEMPT', str(year) + '-01-01', str(year+1) + '-01-01') + \
payslip.sum_category('ALW_FICA_FUTA_EXEMPT', str(year) + '-01-01', str(year+1) + '-01-01')
ytd_wage += payslip.sum_category('DED_FICA_EXEMPT', str(year) + '-01-01', str(year+1) + '-01-01') + \
payslip.sum_category('DED_FIT_FICA_EXEMPT', str(year) + '-01-01', str(year+1) + '-01-01') + \
payslip.sum_category('DED_FIT_FICA_FUTA_EXEMPT', str(year) + '-01-01', str(year+1) + '-01-01') + \
payslip.sum_category('DED_FICA_FUTA_EXEMPT', str(year) + '-01-01', str(year+1) + '-01-01')
plus_exempt = payslip.sum_category('DED_FICA_EXEMPT', str(year) + '-01-01', str(year+1) + '-01-01') + \
payslip.sum_category('DED_FIT_FICA_EXEMPT', str(year) + '-01-01', str(year+1) + '-01-01') + \
payslip.sum_category('DED_FIT_FICA_FUTA_EXEMPT', str(year) + '-01-01', str(year+1) + '-01-01') + \
payslip.sum_category('DED_FICA_FUTA_EXEMPT', str(year) + '-01-01', str(year+1) + '-01-01')
ytd_wage += payslip.dict.contract_id.external_wages
return ytd_wage
external_wages = payslip.dict.contract_id.external_wages
# _logger.info('fica ytd wage GROSS: %0.2f less exempt ALW: %0.2f plus exempt DED: %0.2f plus external: %0.2f' % (ytd_wage, less_exempt, plus_exempt, external_wages))
return ytd_wage - less_exempt + plus_exempt + external_wages
def ee_us_941_fica_ss(payslip, categories, worked_days, inputs):

View File

@@ -213,12 +213,36 @@ class HRPayslip(models.Model):
FROM hr_payslip as hp, hr_payslip_line as pl
WHERE hp.employee_id = %s AND hp.state = 'done'
AND hp.{sum_field} >= %s AND hp.date_to <= %s AND hp.id = pl.slip_id AND pl.code = %s""".format(sum_field=sum_field)
# Original (non-recursive)
# self.__browsable_query_category = """
# SELECT sum(case when hp.credit_note is not True then (pl.total) else (-pl.total) end)
# FROM hr_payslip as hp, hr_payslip_line as pl, hr_salary_rule_category as rc
# WHERE hp.employee_id = %s AND hp.state = 'done'
# AND hp.{sum_field} >= %s AND hp.date_to <= %s AND hp.id = pl.slip_id
# AND rc.id = pl.category_id AND rc.code = %s""".format(sum_field=sum_field)
# Hibou Recursive version
self.__browsable_query_category = """
WITH RECURSIVE
category_by_code as (
SELECT id
FROM hr_salary_rule_category
WHERE code = %s
),
category_ids as (
SELECT COALESCE((SELECT id FROM category_by_code), -1) AS id
UNION ALL
SELECT rc.id
FROM hr_salary_rule_category AS rc
JOIN category_ids AS rcs ON rcs.id = rc.parent_id
)
SELECT sum(case when hp.credit_note is not True then (pl.total) else (-pl.total) end)
FROM hr_payslip as hp, hr_payslip_line as pl, hr_salary_rule_category as rc
FROM hr_payslip as hp, hr_payslip_line as pl
WHERE hp.employee_id = %s AND hp.state = 'done'
AND hp.{sum_field} >= %s AND hp.date_to <= %s AND hp.id = pl.slip_id
AND rc.id = pl.category_id AND rc.code = %s""".format(sum_field=sum_field)
AND pl.category_id in (SELECT id from category_ids)""".format(sum_field=sum_field)
def sum(self, code, from_date, to_date=None):
if to_date is None:
@@ -235,7 +259,10 @@ class HRPayslip(models.Model):
if to_date is None:
to_date = fields.Date.today()
self.env.cr.execute(self.__browsable_query_category, (self.employee_id, from_date, to_date, code))
# standard version
# self.env.cr.execute(self.__browsable_query_category, (self.employee_id, from_date, to_date, code))
# recursive category version
self.env.cr.execute(self.__browsable_query_category, (code, self.employee_id, from_date, to_date))
res = self.env.cr.fetchone()
return res and res[0] or 0.0

View File

@@ -1,3 +1,5 @@
# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details.
from odoo import api, fields, models, _
from odoo.tools.safe_eval import safe_eval
from odoo.exceptions import UserError

View File

@@ -0,0 +1,26 @@
# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details.
import datetime
from odoo import fields, models
class PublisherWarrantyContract(models.AbstractModel):
_inherit = 'publisher_warranty.contract'
def _get_hibou_modules(self):
modules = super(PublisherWarrantyContract, self)._get_hibou_modules()
try:
today_date = fields.Date.today()
last_thirty_date = today_date - datetime.timedelta(days=30)
today = fields.Date.to_string(today_date + datetime.timedelta(days=1)) # Dates vs Datetimes, pad out a day
last_thirty = fields.Date.to_string(last_thirty_date)
self.env.cr.execute(
'SELECT COUNT(DISTINCT(employee_id)) FROM hr_payslip WHERE create_date BETWEEN %s AND %s',
(last_thirty, today))
employee_count = self.env.cr.fetchone()[0] or 0
modules.update({
'l10n_us_hr_payroll': employee_count,
})
except:
pass
return modules

View File

@@ -64,3 +64,56 @@ elif ytd_rule == 0.0:
payslip.compute_sheet()
cats = self._getCategories(payslip)
self.assertEqual(cats['test_sum_behavior'], 0.0)
def test_recursive_salary_rule_category(self):
self.debug = True
# In this scenario, you are in rule code that will check for the category
# and a subcategory will also
alw_category = self.env.ref('hr_payroll.ALW')
ded_category = self.env.ref('hr_payroll.DED')
test_category = self.env['hr.salary.rule.category'].create({
'name': 'Special ALW',
'code': 'ALW_SPECIAL_RECURSIVE',
'parent_id': alw_category.id,
})
test_special_alw = self.env['hr.salary.rule'].create({
'name': 'Flat amount 200',
'code': 'ALW_SPECIAL_RECURSIVE',
'category_id': test_category.id,
'condition_select': 'none',
'amount_select': 'fix',
'amount_fix': 200.0,
})
test_recursion = self.env['hr.salary.rule'].create({
'name': 'Actual Test Behavior',
'code': 'RECURSION_TEST',
'category_id': ded_category.id,
'condition_select': 'none',
'amount_select': 'code',
'amount_python_compute': """
# this rule will always be the total of the ALW category and YTD ALW category
result = categories.ALW
year = payslip.dict.get_year()
result += payslip.sum_category('ALW', str(year) + '-01-01', str(year+1) + '-01-01')
""",
'sequence': 101,
})
struct = self.env.ref('l10n_us_hr_payroll.structure_type_employee')
struct.rule_ids = test_special_alw + test_recursion
salary = 80000.0
employee = self._createEmployee()
contract = self._createContract(employee, wage=salary, schedule_pay='bi-weekly')
payslip = self._createPayslip(employee, '2020-01-01', '2020-01-14')
payslip.compute_sheet()
cats = self._getCategories(payslip)
rules = self._getRules(payslip)
self.assertEqual(rules['RECURSION_TEST'], 200.0)
process_payslip(payslip)
payslip = self._createPayslip(employee, '2020-01-15', '2020-01-27')
payslip.compute_sheet()
cats = self._getCategories(payslip)
rules = self._getRules(payslip)
# two hundred is in the YTD ALW
self.assertEqual(rules['RECURSION_TEST'], 200.0 + 200.0)