[FIX] mrp: cancelling and validating impact on planning

The commit 0679d0d introduced a new
planning mechanism for the workorder. Two issues have been instroduced
since this patch.
  1. Cancelling a workorder didn't free the time slot in the workcenter
    calendar
  2. Validation a workorder sooner than the planned date didn't update
    the workcenter calendar to plan another production sooner.

This commit update the date_planned_start and date_planned_finished
at cancellation and validation to impact the workcenters calendar.
To keep the original planning dates, they are now tracked

This commit also fix the button_start() method that always rewrited the
date_start even if the production had already been started.

Task : 2082442

closes odoo/odoo#38947

X-original-commit: 4ca6c773a00320865142e4efb3645f36c54ce9a2
Signed-off-by: Simon Lejeune (sle) <sle@openerp.com>
This commit is contained in:
William Henrotin
2019-10-17 12:17:49 +00:00
committed by fw-bot
parent 32caafd5bd
commit b86bc6e979
2 changed files with 87 additions and 10 deletions
+29 -8
View File
@@ -69,13 +69,15 @@ class MrpWorkorder(models.Model):
compute='_compute_dates_planned',
inverse='_set_dates_planned',
states={'done': [('readonly', True)], 'cancel': [('readonly', True)]},
store=True)
store=True,
tracking=True)
date_planned_finished = fields.Datetime(
'Scheduled Date Finished',
compute='_compute_dates_planned',
inverse='_set_dates_planned',
states={'done': [('readonly', True)], 'cancel': [('readonly', True)]},
store=True)
store=True,
tracking=True)
date_start = fields.Datetime(
'Effective Start Date',
states={'done': [('readonly', True)], 'cancel': [('readonly', True)]})
@@ -541,14 +543,28 @@ class MrpWorkorder(models.Model):
'user_id': self.env.user.id, # FIXME sle: can be inconsistent with company_id
'company_id': self.company_id.id,
})
return self.write({'state': 'progress',
'date_start': datetime.now(),
})
if self.state == 'progress':
return True
else:
start_date = datetime.now()
vals = {
'state': 'progress',
'date_start': start_date,
'date_planned_start': start_date,
}
if self.date_planned_finished < start_date:
vals['date_planned_finished'] = start_date
return self.write(vals)
def button_finish(self):
self.ensure_one()
self.end_all()
return self.write({'state': 'done', 'date_finished': fields.Datetime.now()})
end_date = datetime.now()
return self.write({
'state': 'done',
'date_finished': end_date,
'date_planned_finished': end_date
})
def end_previous(self, doall=False):
"""
@@ -595,14 +611,19 @@ class MrpWorkorder(models.Model):
return True
def action_cancel(self):
self.leave_id.unlink()
return self.write({'state': 'cancel'})
def button_done(self):
if any([x.state in ('done', 'cancel') for x in self]):
raise UserError(_('A Manufacturing Order is already done or cancelled.'))
self.end_all()
return self.write({'state': 'done',
'date_finished': datetime.now()})
end_date = datetime.now()
return self.write({
'state': 'done',
'date_finished': end_date,
'date_planned_finished': end_date,
})
def button_scrap(self):
self.ensure_one()
+58 -2
View File
@@ -410,6 +410,7 @@ class TestWorkOrderProcess(TestMrpCommon):
# first operation of main bom
finished_lot = self.env['stock.production.lot'].create({'product_id': man_order.product_id.id, 'company_id': self.env.company.id})
door_wo_1.button_start()
door_wo_1.write({
'finished_lot_id': finished_lot.id,
'qty_producing': 48
@@ -419,6 +420,7 @@ class TestWorkOrderProcess(TestMrpCommon):
# second operation of main bom
self.assertEqual(door_wo_2.state, 'ready', "Workorder should be in ready state.")
door_wo_2.button_start()
door_wo_2.record_production()
self.assertEqual(door_wo_2.state, 'done', "Workorder should be in done state.")
@@ -751,6 +753,7 @@ class TestWorkOrderProcess(TestMrpCommon):
self.assertEqual(workorders[0].state, 'done')
for workorder in workorders - workorders[0]:
workorder.button_start()
self.assertEqual(workorder.finished_lot_id, serial_a)
workorder.record_production()
self.assertEqual(workorder.finished_lot_id, serial_b)
@@ -797,12 +800,12 @@ class TestWorkOrderProcess(TestMrpCommon):
mo.button_plan()
workorder_0 = mo.workorder_ids[0]
workorder_0.button_start()
workorder_0.record_production()
workorder_0.record_production()
with self.assertRaises(UserError):
workorder_0.record_production()
workorder_1 = mo.workorder_ids[1]
workorder_1.button_start()
with Form(workorder_1) as wo:
wo.finished_lot_id = lot_1
workorder_1.record_production()
@@ -1043,6 +1046,59 @@ class TestWorkOrderProcess(TestMrpCommon):
with self.assertRaises(UserError):
mo.button_plan()
def test_planning_5(self):
""" Cancelling a production with workorders should free all reserved slot
in the related workcenters calendars """
mo_form = Form(self.env['mrp.production'])
mo_form.product_id = self.product_4
mo_form.bom_id = self.planning_bom
mo_form.product_qty = 1
mo = mo_form.save()
mo.action_confirm()
mo.button_plan()
mo.action_cancel()
self.assertEqual(mo.workorder_ids.mapped('date_start'), [False])
self.assertEqual(mo.workorder_ids.mapped('date_finished'), [False])
def test_planning_6(self):
""" Marking a workorder as done before the theoretical date should update
the reservation slot in the calendar the be able to reserve the next
production sooner """
self.workcenter_1.alternative_workcenter_ids = self.wc_alt_1 | self.wc_alt_2
self.env['mrp.workcenter'].search([]).write({'tz': 'UTC'}) # compute all date in UTC
self.planning_bom.routing = self.env.ref("mrp.mrp_routing_0")
mo_form = Form(self.env['mrp.production'])
mo_form.product_id = self.product_4
mo_form.bom_id = self.planning_bom
mo_form.product_qty = 1
mo_form.date_start_wo = datetime(2019, 5, 13, 9, 0, 0, 0)
mo = mo_form.save()
mo.action_confirm()
mo.button_plan()
wo = mo.workorder_ids
self.assertAlmostEqual(wo.date_planned_start, datetime(2019, 5, 13, 9, 0, 0, 0), delta=timedelta(seconds=10))
self.assertAlmostEqual(wo.date_planned_finished, datetime(2019, 5, 13, 9, 0, 0, 0) + timedelta(minutes=85.58), delta=timedelta(seconds=10))
wo.button_start()
wo.record_production()
# Marking workorder as done should change the finished date
self.assertAlmostEqual(wo.date_finished, datetime.now(), delta=timedelta(seconds=10))
self.assertAlmostEqual(wo.date_planned_finished, datetime.now(), delta=timedelta(seconds=10))
mo_form = Form(self.env['mrp.production'])
mo_form.product_id = self.product_4
mo_form.bom_id = self.planning_bom
mo_form.product_qty = 1
mo_form.date_start_wo = datetime(2019, 5, 13, 9, 0, 0, 0)
mo = mo_form.save()
mo.action_confirm()
mo.button_plan()
wo = mo.workorder_ids
wo.button_start()
self.assertAlmostEqual(wo.date_start, datetime.now(), delta=timedelta(seconds=10))
self.assertAlmostEqual(wo.date_planned_start, datetime.now(), delta=timedelta(seconds=10))
self.assertAlmostEqual(wo.date_planned_finished, datetime.now(), delta=timedelta(seconds=10))
def test_plan_unplan_date(self):
""" Testing planning a workorder then cancel it and then plan it again.
The planned date must be the same the first time and the second time the