diff --git a/hr_timesheet_begin_end/models/account_analytic_line.py b/hr_timesheet_begin_end/models/account_analytic_line.py index 40bbbeac0..70a6e4dcf 100644 --- a/hr_timesheet_begin_end/models/account_analytic_line.py +++ b/hr_timesheet_begin_end/models/account_analytic_line.py @@ -16,9 +16,29 @@ class AccountAnalyticLine(models.Model): time_start = fields.Float(string="Begin Hour") time_stop = fields.Float(string="End Hour") - @api.onchange("time_start", "time_stop", "project_id") - def onchange_hours_start_stop(self): - self.unit_amount = self.unit_amount_from_start_stop() + # Override to be a computed field. + unit_amount = fields.Float( + compute="_compute_unit_amount", + store=True, + readonly=False, + # This default is a workaround for a bizarre situation: if a line is + # created with a time range but WITHOUT defining unit_amount, then you + # would expect unit_amount to be computed from the range. But this never + # happens, and it is instead set to default value 0. Subsequently the + # constraint _validate_unit_amount_equal_to_time_diff kicks in and + # raises an exception. + # + # By setting the default to None, the computation is correctly + # triggered. If nothing is computed, None falls back to 0. + default=None, + ) + + @api.depends("time_start", "time_stop", "project_id") + def _compute_unit_amount(self): + # Do not compute/adjust the unit_amount of non-timesheets. + lines = self.filtered(lambda line: line.project_id) + for line in lines: + line.unit_amount = line.unit_amount_from_start_stop() def _validate_start_before_stop(self): value_to_html = self.env["ir.qweb.field.float_time"].value_to_html diff --git a/hr_timesheet_begin_end/readme/newsfragments/692.feature.2.rst b/hr_timesheet_begin_end/readme/newsfragments/692.feature.2.rst new file mode 100644 index 000000000..185296c90 --- /dev/null +++ b/hr_timesheet_begin_end/readme/newsfragments/692.feature.2.rst @@ -0,0 +1 @@ +Changed ``unit_amount`` into a computed (stored, writeable) field. diff --git a/hr_timesheet_begin_end/tests/test_timesheet_begin_end.py b/hr_timesheet_begin_end/tests/test_timesheet_begin_end.py index 85ee99d01..7992565ae 100644 --- a/hr_timesheet_begin_end/tests/test_timesheet_begin_end.py +++ b/hr_timesheet_begin_end/tests/test_timesheet_begin_end.py @@ -21,18 +21,39 @@ def setUp(self): "employee_id": self.employee.id, } - def test_onchange(self): - line = self.timesheet_line_model.new( - {"name": "test", "time_start": 10.0, "time_stop": 12.0} - ) - line.onchange_hours_start_stop() - self.assertEqual(line.unit_amount, 2) + def test_compute_unit_amount(self): + line = self.base_line.copy() + del line["unit_amount"] + line_record = self.timesheet_line_model.create(line) + self.assertEqual(line_record.unit_amount, 2) + line_record.time_stop = 14.0 + self.assertEqual(line_record.unit_amount, 4) + + def test_compute_unit_amount_no_compute_if_no_times(self): + line = self.base_line.copy() + del line["time_start"] + del line["time_stop"] + line_record = self.timesheet_line_model.create(line) + self.assertEqual(line_record.unit_amount, 2.0) + line_record.unit_amount = 3.0 + self.assertEqual(line_record.unit_amount, 3.0) + + def test_compute_unit_amount_to_zero(self): + line = self.base_line.copy() + del line["unit_amount"] + line_record = self.timesheet_line_model.create(line) + self.assertEqual(line_record.unit_amount, 2) + line_record.write({"time_start": 0, "time_stop": 0}) + self.assertEqual(line_record.unit_amount, 0) - def test_onchange_no_update(self): + def test_compute_unit_amount_to_zero_no_record(self): + # Cannot create/save this model because it breaks a constraint, so using + # .new(). line = self.timesheet_line_model.new( {"name": "test", "time_start": 13.0, "time_stop": 12.0} ) - line.onchange_hours_start_stop() + self.assertEqual(line.unit_amount, 0) + line.time_stop = 10.0 self.assertEqual(line.unit_amount, 0) def test_check_begin_before_end(self):