Skip to content

Commit 06a486a

Browse files
committed
[REF] hr_timesheet_begin_end: Make more extensible
The separation of checks into separate methods is needed because I want to disable one check in another module. This makes the module more extensible. The unit_amount_from_start_stop method also makes the module more extensible. I have also moved the onchange to the top of the file, according to the OCA contribution guidelines. Signed-off-by: Carmen Bianca BAKKER <[email protected]>
1 parent 80446c6 commit 06a486a

File tree

1 file changed

+48
-26
lines changed

1 file changed

+48
-26
lines changed

hr_timesheet_begin_end/models/account_analytic_line.py

Lines changed: 48 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# Copyright 2015 Camptocamp SA - Guewen Baconnier
22
# Copyright 2017 Tecnativa, S.L. - Luis M. Ontalba
3+
# Copyright 2024 Coop IT Easy SC - Carmen Bianca BAKKER
34
# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html
45

56
from datetime import timedelta
@@ -15,16 +16,16 @@ class AccountAnalyticLine(models.Model):
1516
time_start = fields.Float(string="Begin Hour")
1617
time_stop = fields.Float(string="End Hour")
1718

18-
@api.constrains("time_start", "time_stop", "unit_amount")
19-
def _check_time_start_stop(self):
20-
for line in self:
21-
value_to_html = self.env["ir.qweb.field.float_time"].value_to_html
22-
start = timedelta(hours=line.time_start)
23-
stop = timedelta(hours=line.time_stop)
24-
if stop < start:
25-
value_to_html(line.time_start, None)
26-
value_to_html(line.time_stop, None)
19+
@api.onchange("time_start", "time_stop")
20+
def onchange_hours_start_stop(self):
21+
self.unit_amount = self.unit_amount_from_start_stop(
22+
self.time_start, self.time_stop
23+
)
2724

25+
def _validate_start_before_stop(self):
26+
value_to_html = self.env["ir.qweb.field.float_time"].value_to_html
27+
for line in self:
28+
if line.time_stop < line.time_start:
2829
raise exceptions.ValidationError(
2930
_(
3031
"The beginning hour (%(html_start)s) must "
@@ -35,7 +36,11 @@ def _check_time_start_stop(self):
3536
"html_stop": value_to_html(line.time_stop, None),
3637
}
3738
)
38-
hours = (stop - start).seconds / 3600
39+
40+
def _validate_unit_amount_equal_to_time_diff(self):
41+
value_to_html = self.env["ir.qweb.field.float_time"].value_to_html
42+
for line in self:
43+
hours = line.unit_amount_from_start_stop(line.time_start, line.time_stop)
3944
rounding = self.env.ref("uom.product_uom_hour").rounding
4045
if hours and float_compare(
4146
hours, line.unit_amount, precision_rounding=rounding
@@ -50,16 +55,21 @@ def _check_time_start_stop(self):
5055
"html_hours": value_to_html(hours, None),
5156
}
5257
)
53-
# check if lines overlap
54-
others = self.search(
55-
[
56-
("id", "!=", line.id),
57-
("employee_id", "=", line.employee_id.id),
58-
("date", "=", line.date),
59-
("time_start", "<", line.time_stop),
60-
("time_stop", ">", line.time_start),
61-
]
62-
)
58+
59+
def _overlap_domain(self):
60+
self.ensure_one()
61+
return [
62+
("id", "!=", self.id),
63+
("employee_id", "=", self.employee_id.id),
64+
("date", "=", self.date),
65+
("time_start", "<", self.time_stop),
66+
("time_stop", ">", self.time_start),
67+
]
68+
69+
def _validate_no_overlap(self):
70+
value_to_html = self.env["ir.qweb.field.float_time"].value_to_html
71+
for line in self:
72+
others = self.search(line._overlap_domain())
6373
if others:
6474
message = _("Lines can't overlap:\n")
6575
message += "\n".join(
@@ -74,13 +84,25 @@ def _check_time_start_stop(self):
7484
)
7585
raise exceptions.ValidationError(message)
7686

77-
@api.onchange("time_start", "time_stop")
78-
def onchange_hours_start_stop(self):
79-
start = timedelta(hours=self.time_start)
80-
stop = timedelta(hours=self.time_stop)
87+
@api.constrains("time_start", "time_stop", "unit_amount")
88+
def _check_time_start_stop(self):
89+
self._validate_start_before_stop()
90+
self._validate_unit_amount_equal_to_time_diff()
91+
self._validate_no_overlap()
92+
93+
@api.model
94+
def _hours_from_start_stop(self, time_start, time_stop):
95+
start = timedelta(hours=time_start)
96+
stop = timedelta(hours=time_stop)
8197
if stop < start:
82-
return
83-
self.unit_amount = (stop - start).seconds / 3600
98+
# Invalid case, but return something sensible.
99+
return 0
100+
return (stop - start).seconds / 3600
101+
102+
@api.model
103+
def unit_amount_from_start_stop(self, time_start, time_stop, **kwargs):
104+
# kwargs may be used to extend this method.
105+
return self._hours_from_start_stop(time_start, time_stop)
84106

85107
def merge_timesheets(self): # pragma: no cover
86108
"""This method is needed in case hr_timesheet_sheet is installed"""

0 commit comments

Comments
 (0)