diff --git a/addons/mrp/models/mrp_production.py b/addons/mrp/models/mrp_production.py index 8594263bc64..5afd01bd5cc 100644 --- a/addons/mrp/models/mrp_production.py +++ b/addons/mrp/models/mrp_production.py @@ -574,7 +574,10 @@ class MrpProduction(models.Model): def _onchange_product_qty(self): for workorder in self.workorder_ids: workorder.product_uom_id = self.product_uom_id - workorder.duration_expected = workorder._get_duration_expected() + if self._origin.product_qty: + workorder.duration_expected = workorder._get_duration_expected(ratio=self.product_qty / self._origin.product_qty) + else: + workorder.duration_expected = workorder._get_duration_expected() if workorder.date_planned_start and workorder.duration_expected: workorder.date_planned_finished = workorder.date_planned_start + relativedelta(minutes=workorder.duration_expected) diff --git a/addons/mrp/models/mrp_workorder.py b/addons/mrp/models/mrp_workorder.py index f100c361984..5ffb7ffc860 100644 --- a/addons/mrp/models/mrp_workorder.py +++ b/addons/mrp/models/mrp_workorder.py @@ -671,10 +671,15 @@ class MrpWorkorder(models.Model): for wo in self: wo.qty_remaining = float_round(wo.qty_production - wo.qty_produced, precision_rounding=wo.production_id.product_uom_id.rounding) - def _get_duration_expected(self, alternative_workcenter=False): + def _get_duration_expected(self, alternative_workcenter=False, ratio=1): self.ensure_one() if not self.workcenter_id: return False + if not self.operation_id: + duration_expected_working = (self.duration_expected - self.workcenter_id.time_start - self.workcenter_id.time_stop) * self.workcenter_id.time_efficiency / 100.0 + if duration_expected_working < 0: + duration_expected_working = 0 + return self.workcenter_id.time_start + self.workcenter_id.time_stop + duration_expected_working * ratio * 100.0 / self.workcenter_id.time_efficiency qty_production = self.production_id.product_uom_id._compute_quantity(self.qty_production, self.production_id.product_id.uom_id) cycle_number = float_round(qty_production / self.workcenter_id.capacity, precision_digits=0, rounding_method='UP') if alternative_workcenter: diff --git a/addons/mrp/tests/test_order.py b/addons/mrp/tests/test_order.py index cd7015a90ce..3dfa1500625 100644 --- a/addons/mrp/tests/test_order.py +++ b/addons/mrp/tests/test_order.py @@ -259,6 +259,63 @@ class TestMrpOrder(TestMrpCommon): self.assertEqual(sum(mo.move_raw_ids.filtered(lambda m: m.product_id == p1).mapped('quantity_done')), 20) self.assertEqual(sum(mo.move_finished_ids.mapped('quantity_done')), 5) + def test_update_quantity_3(self): + bom = self.env['mrp.bom'].create({ + 'product_id': self.product_6.id, + 'product_tmpl_id': self.product_6.product_tmpl_id.id, + 'product_qty': 1, + 'product_uom_id': self.product_6.uom_id.id, + 'type': 'normal', + 'bom_line_ids': [ + (0, 0, {'product_id': self.product_2.id, 'product_qty': 2.03}), + (0, 0, {'product_id': self.product_8.id, 'product_qty': 4.16}) + ], + 'operation_ids': [ + (0, 0, {'name': 'Gift Wrap Maching', 'workcenter_id': self.workcenter_1.id, 'time_cycle': 15, 'sequence': 1}), + ] + }) + production_form = Form(self.env['mrp.production']) + production_form.product_id = self.product_6 + production_form.bom_id = bom + production_form.product_qty = 1 + production_form.product_uom_id = self.product_6.uom_id + production = production_form.save() + self.assertEqual(production.workorder_ids.duration_expected, 90) + mo_form = Form(production) + mo_form.product_qty = 3 + production = mo_form.save() + self.assertEqual(production.workorder_ids.duration_expected, 165) + + def test_update_quantity_4(self): + bom = self.env['mrp.bom'].create({ + 'product_id': self.product_6.id, + 'product_tmpl_id': self.product_6.product_tmpl_id.id, + 'product_qty': 1, + 'product_uom_id': self.product_6.uom_id.id, + 'type': 'normal', + 'bom_line_ids': [ + (0, 0, {'product_id': self.product_2.id, 'product_qty': 2.03}), + (0, 0, {'product_id': self.product_8.id, 'product_qty': 4.16}) + ], + }) + production_form = Form(self.env['mrp.production']) + production_form.product_id = self.product_6 + production_form.bom_id = bom + production_form.product_qty = 1 + production_form.product_uom_id = self.product_6.uom_id + production = production_form.save() + production_form = Form(production) + with production_form.workorder_ids.new() as wo: + wo.name = 'OP1' + wo.workcenter_id = self.workcenter_1 + wo.duration_expected = 40 + production = production_form.save() + self.assertEqual(production.workorder_ids.duration_expected, 40) + mo_form = Form(production) + mo_form.product_qty = 3 + production = mo_form.save() + self.assertEqual(production.workorder_ids.duration_expected, 90) + def test_rounding(self): """ Checks we round up when bringing goods to produce and round half-up when producing. This implementation allows to implement an efficiency notion (see rev 347f140fe63612ee05e). diff --git a/addons/mrp/wizard/change_production_qty.py b/addons/mrp/wizard/change_production_qty.py index cd82ca389f6..9170d3eff2d 100644 --- a/addons/mrp/wizard/change_production_qty.py +++ b/addons/mrp/wizard/change_production_qty.py @@ -78,7 +78,7 @@ class ChangeProductionQty(models.TransientModel): for wo in production.workorder_ids: operation = wo.operation_id - wo._onchange_expected_duration() + wo.duration_expected = wo._get_duration_expected(ratio=new_production_qty / old_production_qty) quantity = wo.qty_production - wo.qty_produced if production.product_id.tracking == 'serial': quantity = 1.0 if not float_is_zero(quantity, precision_digits=precision) else 0.0