mirror of
https://gitlab.com/hibou-io/hibou-odoo/suite.git
synced 2025-01-20 12:37:31 +02:00
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:
@@ -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.
|
||||
==================
|
||||
|
||||
@@ -86,4 +86,4 @@
|
||||
<field name="appears_on_payslip" eval="True"/>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
</odoo>
|
||||
@@ -206,4 +206,4 @@
|
||||
<field name="appears_on_payslip" eval="True"/>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
</odoo>
|
||||
@@ -138,4 +138,4 @@
|
||||
<field name="appears_on_payslip" eval="True"/>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
</odoo>
|
||||
@@ -80,4 +80,4 @@
|
||||
<field name="appears_on_payslip" eval="True"/>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
</odoo>
|
||||
@@ -803,4 +803,4 @@
|
||||
<field name="appears_on_payslip" eval="True"/>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
</odoo>
|
||||
@@ -86,4 +86,4 @@
|
||||
<field name="appears_on_payslip" eval="True"/>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
</odoo>
|
||||
@@ -1221,4 +1221,4 @@
|
||||
<field name="appears_on_payslip" eval="True"/>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
</odoo>
|
||||
@@ -104,4 +104,4 @@
|
||||
<field name="appears_on_payslip" eval="True"/>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
</odoo>
|
||||
@@ -174,4 +174,4 @@
|
||||
<field name="appears_on_payslip" eval="True"/>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
</odoo>
|
||||
@@ -294,4 +294,4 @@
|
||||
<field name="appears_on_payslip" eval="True"/>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
</odoo>
|
||||
@@ -441,4 +441,4 @@
|
||||
<field name="appears_on_payslip" eval="True"/>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
</odoo>
|
||||
@@ -110,4 +110,4 @@
|
||||
<field name="appears_on_payslip" eval="True"/>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
</odoo>
|
||||
@@ -183,4 +183,4 @@
|
||||
<field name="appears_on_payslip" eval="True"/>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
</odoo>
|
||||
@@ -88,4 +88,4 @@
|
||||
<field name="appears_on_payslip" eval="True"/>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
</odoo>
|
||||
@@ -116,4 +116,4 @@
|
||||
<field name="appears_on_payslip" eval="True"/>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
</odoo>
|
||||
@@ -93,4 +93,4 @@
|
||||
<field name="appears_on_payslip" eval="True"/>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
</odoo>
|
||||
@@ -138,4 +138,4 @@
|
||||
<field name="appears_on_payslip" eval="True"/>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
</odoo>
|
||||
@@ -144,4 +144,4 @@
|
||||
<field name="appears_on_payslip" eval="True"/>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
</odoo>
|
||||
@@ -107,4 +107,4 @@
|
||||
<field name="appears_on_payslip" eval="True"/>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
</odoo>
|
||||
@@ -269,4 +269,4 @@
|
||||
<field name="appears_on_payslip" eval="True"/>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
</odoo>
|
||||
@@ -227,4 +227,4 @@
|
||||
<field name="appears_on_payslip" eval="True"/>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
</odoo>
|
||||
@@ -1013,4 +1013,4 @@
|
||||
<field name="appears_on_payslip" eval="True"/>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
</odoo>
|
||||
@@ -294,4 +294,4 @@
|
||||
<field name="appears_on_payslip" eval="True"/>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
</odoo>
|
||||
@@ -46,4 +46,4 @@
|
||||
<field name="appears_on_payslip" eval="False"/>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
</odoo>
|
||||
@@ -291,4 +291,4 @@
|
||||
<field name="appears_on_payslip" eval="True"/>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
</odoo>
|
||||
@@ -132,4 +132,4 @@
|
||||
<field name="appears_on_payslip" eval="True"/>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
</odoo>
|
||||
@@ -143,4 +143,4 @@
|
||||
<field name="appears_on_payslip" eval="True"/>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
</odoo>
|
||||
@@ -150,4 +150,4 @@
|
||||
<field name="appears_on_payslip" eval="True"/>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
</odoo>
|
||||
@@ -182,4 +182,4 @@
|
||||
<field name="appears_on_payslip" eval="True"/>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
</odoo>
|
||||
@@ -206,4 +206,4 @@
|
||||
<field name="appears_on_payslip" eval="True"/>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
</odoo>
|
||||
@@ -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
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
26
l10n_us_hr_payroll/models/update.py
Normal file
26
l10n_us_hr_payroll/models/update.py
Normal 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
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user