mirror of
https://gitlab.com/hibou-io/hibou-odoo/suite.git
synced 2025-01-20 12:37:31 +02:00
[IMP] hr_payroll_overtime: detect recursion and prevent the simplest type in the form view
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
from odoo import models
|
from odoo import models
|
||||||
|
from odoo.exceptions import UserError
|
||||||
|
|
||||||
|
|
||||||
class HRPayslip(models.Model):
|
class HRPayslip(models.Model):
|
||||||
@@ -30,10 +31,15 @@ class HRPayslip(models.Model):
|
|||||||
day_hours = defaultdict(float)
|
day_hours = defaultdict(float)
|
||||||
week_hours = defaultdict(float)
|
week_hours = defaultdict(float)
|
||||||
iso_days = set()
|
iso_days = set()
|
||||||
for iso_date, entries in work_data:
|
try:
|
||||||
iso_date = _adjust_week(iso_date)
|
for iso_date, entries in work_data:
|
||||||
for work_type, hours, _ in entries:
|
iso_date = _adjust_week(iso_date)
|
||||||
self._aggregate_overtime_add_work_type_hours(work_type, hours, iso_date, result, iso_days, day_hours, week_hours)
|
for work_type, hours, _ in entries:
|
||||||
|
self._aggregate_overtime_add_work_type_hours(work_type, hours, iso_date, result, iso_days, day_hours, week_hours)
|
||||||
|
except RecursionError:
|
||||||
|
raise UserError('RecursionError raised. Ensure you have not overtime loops, you should have an '
|
||||||
|
'end work type that does not have any "overtime" version, and would be considered '
|
||||||
|
'the "highest overtime" work type and rate.')
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
@@ -75,6 +81,9 @@ class HRPayslip(models.Model):
|
|||||||
# we need to save this because it won't be set once it reenter, we won't know what the original
|
# we need to save this because it won't be set once it reenter, we won't know what the original
|
||||||
# overtime multiplier was
|
# overtime multiplier was
|
||||||
working_aggregation[work_type.overtime_work_type_id][2] = work_type.overtime_type_id.multiplier
|
working_aggregation[work_type.overtime_work_type_id][2] = work_type.overtime_type_id.multiplier
|
||||||
|
if work_type == work_type.overtime_work_type_id:
|
||||||
|
# trivial infinite recursion
|
||||||
|
raise UserError('Work type %s (id %s) must not have itself as its next overtime type.' % (work_type.name, work_type.id))
|
||||||
self._aggregate_overtime_add_work_type_hours(work_type.overtime_work_type_id, ot_hours, iso_date,
|
self._aggregate_overtime_add_work_type_hours(work_type.overtime_work_type_id, ot_hours, iso_date,
|
||||||
working_aggregation, iso_days, day_hours, week_hours)
|
working_aggregation, iso_days, day_hours, week_hours)
|
||||||
else:
|
else:
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
from odoo.tests import common
|
from odoo.tests import common
|
||||||
|
from odoo.exceptions import UserError
|
||||||
|
|
||||||
|
|
||||||
class TestOvertime(common.TransactionCase):
|
class TestOvertime(common.TransactionCase):
|
||||||
@@ -321,3 +322,41 @@ class TestOvertime(common.TransactionCase):
|
|||||||
self.assertTrue(self.work_type_overtime2 in result_data)
|
self.assertTrue(self.work_type_overtime2 in result_data)
|
||||||
self.assertEqual(result_data[self.work_type_overtime2][0], 0)
|
self.assertEqual(result_data[self.work_type_overtime2][0], 0)
|
||||||
self.assertEqual(result_data[self.work_type_overtime2][1], 2.0)
|
self.assertEqual(result_data[self.work_type_overtime2][1], 2.0)
|
||||||
|
|
||||||
|
def test_13_recursive_infinite_trivial(self):
|
||||||
|
# recursive should will use a second overtime, but not this time!
|
||||||
|
self.overtime_rules.hours_per_day = 8.0
|
||||||
|
self.overtime_rules.multiplier_per_day = 1.5
|
||||||
|
self.work_type.overtime_type_id = self.overtime_rules
|
||||||
|
# overtime goes to itself
|
||||||
|
self.work_type.overtime_work_type_id = self.work_type
|
||||||
|
|
||||||
|
work_data = [
|
||||||
|
((2020, 24, 2), [
|
||||||
|
# 2hr overtime
|
||||||
|
(self.work_type, 4.0, None),
|
||||||
|
(self.work_type, 6.0, None),
|
||||||
|
]),
|
||||||
|
]
|
||||||
|
|
||||||
|
with self.assertRaises(UserError):
|
||||||
|
result_data = self.payslip.aggregate_overtime(work_data)
|
||||||
|
|
||||||
|
def test_14_recursive_infinite_loop(self):
|
||||||
|
# recursive will use a second overtime, but not this time!
|
||||||
|
self.overtime_rules.hours_per_day = 8.0
|
||||||
|
self.overtime_rules.multiplier_per_day = 1.5
|
||||||
|
self.work_type_overtime.overtime_type_id = self.overtime_rules
|
||||||
|
# overtime goes back to worktype
|
||||||
|
self.work_type_overtime.overtime_work_type_id = self.work_type
|
||||||
|
|
||||||
|
work_data = [
|
||||||
|
((2020, 24, 2), [
|
||||||
|
# 2hr overtime
|
||||||
|
(self.work_type, 4.0, None),
|
||||||
|
(self.work_type, 6.0, None),
|
||||||
|
]),
|
||||||
|
]
|
||||||
|
|
||||||
|
with self.assertRaises(UserError):
|
||||||
|
result_data = self.payslip.aggregate_overtime(work_data)
|
||||||
|
|||||||
@@ -9,8 +9,12 @@
|
|||||||
<field name="arch" type="xml">
|
<field name="arch" type="xml">
|
||||||
<xpath expr="//group[@name='main_group']" position="after">
|
<xpath expr="//group[@name='main_group']" position="after">
|
||||||
<group name="overtime_group">
|
<group name="overtime_group">
|
||||||
<field name="overtime_work_type_id" attrs="{'required': [('overtime_type_id', '!=', False)]}"/>
|
<field name="overtime_work_type_id"
|
||||||
<field name="overtime_type_id" attrs="{'required': [('overtime_work_type_id', '!=', False)]}"/>
|
domain="[('id', '!=', id)]"
|
||||||
|
attrs="{'required': [('overtime_type_id', '!=', False)]}" />
|
||||||
|
<field name="overtime_type_id"
|
||||||
|
domain="[('id', '!=', id)]"
|
||||||
|
attrs="{'required': [('overtime_work_type_id', '!=', False)]}" />
|
||||||
</group>
|
</group>
|
||||||
</xpath>
|
</xpath>
|
||||||
</field>
|
</field>
|
||||||
|
|||||||
Reference in New Issue
Block a user