From 4ee367d6ef8bc8a5603364a86d2d17bfad8f91f1 Mon Sep 17 00:00:00 2001 From: MerlinGuillaume Date: Tue, 9 Aug 2022 13:19:27 +0000 Subject: [PATCH] [FIX] mrp: keep end time and duration consistent when moving work order When drag and dropping a work order in the Work Orders Planning, the end time wasn't recomputed. This can make the end time inconsistent with the duration when the work order spans across a non-working time. Steps to reproduce: 1. Install Manufacturing 2. Go to Settings > Manufacturing > Operations and enable Work Orders 3. Go to Manufacturing > Master Data > Routings and edit routing 'Primary Assembly' to last 120:00 minutes 4. Go to Manufacturing > Operations > Manufacturing Orders and create one with values: - Product: Table Top - Plan From: today's date at 11:00:00 5. Save, mark as todo and plan the manufacturing order 6. Go to Manufacturing > Planning > Planning by Workcenter and trigger the day view 7. Move the work order to 8 am 8. The work order still lasts for 3 hours (according to its start and finish time) even though its expected duration is 2 hours Solution: Recompute `date_planned_finished` when we move a work order in the planning (`date_planned_start` and `date_planned_finished` are passed in values), and recompute `expected_duration` when we extend it (only one of them is passed depending on the way we extend the work order). (`duration_expected` is never passed in values when we manipulate a work order through the planning) Problem: `date_planned_finished` wasn't recomputed when moving the work order in the planning opw-2893622 closes odoo/odoo#100988 X-original-commit: 2515482d5a706c65a7d8e27028f43987f17e6e67 Related: odoo/enterprise#31720 Signed-off-by: William Henrotin (whe) Signed-off-by: Guillaume Merlin (megu) --- addons/mrp/models/mrp_workorder.py | 44 ++++++++++++++++++++---------- 1 file changed, 30 insertions(+), 14 deletions(-) diff --git a/addons/mrp/models/mrp_workorder.py b/addons/mrp/models/mrp_workorder.py index 8488e56a640..ff9a7979737 100644 --- a/addons/mrp/models/mrp_workorder.py +++ b/addons/mrp/models/mrp_workorder.py @@ -408,15 +408,6 @@ class MrpWorkorder(models.Model): for workorder in self: workorder.scrap_count = count_data.get(workorder.id, 0) - @api.onchange('date_planned_finished') - def _onchange_date_planned_finished(self): - if self.date_planned_start and self.date_planned_finished: - interval = self.workcenter_id.resource_calendar_id.get_work_duration_data( - self.date_planned_start, self.date_planned_finished, - domain=[('time_type', 'in', ['leave', 'other'])] - ) - self.duration_expected = interval['hours'] * 60 - @api.onchange('operation_id') def _onchange_operation_id(self): if self.operation_id: @@ -426,10 +417,25 @@ class MrpWorkorder(models.Model): @api.onchange('date_planned_start', 'duration_expected', 'workcenter_id') def _onchange_date_planned_start(self): if self.date_planned_start and self.duration_expected and self.workcenter_id: - self.date_planned_finished = self.workcenter_id.resource_calendar_id.plan_hours( - self.duration_expected / 60.0, self.date_planned_start, - compute_leaves=True, domain=[('time_type', 'in', ['leave', 'other'])] - ) + self.date_planned_finished = self._calculate_date_planned_finished() + + def _calculate_date_planned_finished(self, date_planned_start=False): + return self.workcenter_id.resource_calendar_id.plan_hours( + self.duration_expected / 60.0, date_planned_start or self.date_planned_start, + compute_leaves=True, domain=[('time_type', 'in', ['leave', 'other'])] + ) + + @api.onchange('date_planned_finished') + def _onchange_date_planned_finished(self): + if self.date_planned_start and self.date_planned_finished: + self.duration_expected = self._calculate_duration_expected() + + def _calculate_duration_expected(self, date_planned_start=False, date_planned_finished=False): + interval = self.workcenter_id.resource_calendar_id.get_work_duration_data( + date_planned_start or self.date_planned_start, date_planned_finished or self.date_planned_finished, + domain=[('time_type', 'in', ['leave', 'other'])] + ) + return interval['hours'] * 60 def write(self, values): if 'production_id' in values and any(values['production_id'] != w.production_id.id for w in self): @@ -446,6 +452,16 @@ class MrpWorkorder(models.Model): end_date = fields.Datetime.to_datetime(values.get('date_planned_finished')) or workorder.date_planned_finished if start_date and end_date and start_date > end_date: raise UserError(_('The planned end date of the work order cannot be prior to the planned start date, please correct this to save the work order.')) + if 'duration_expected' not in values and not self.env.context.get('bypass_duration_calculation'): + if values.get('date_planned_start') and values.get('date_planned_finished'): + computed_finished_time = self._calculate_date_planned_finished(start_date) + values['date_planned_finished'] = computed_finished_time + elif values.get('date_planned_start'): + computed_duration = self._calculate_duration_expected(date_planned_start=start_date) + values['duration_expected'] = computed_duration + elif values.get('date_planned_finished'): + computed_duration = self._calculate_duration_expected(date_planned_finished=end_date) + values['duration_expected'] = computed_duration # Update MO dates if the start date of the first WO or the # finished date of the last WO is update. if workorder == workorder.production_id.workorder_ids[0] and 'date_planned_start' in values: @@ -613,7 +629,7 @@ class MrpWorkorder(models.Model): vals['date_planned_start'] = start_date if self.date_planned_finished and self.date_planned_finished < start_date: vals['date_planned_finished'] = start_date - return self.write(vals) + return self.with_context(bypass_duration_calculation=True).write(vals) def button_finish(self): end_date = datetime.now()