summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--addons/mrp/models/mrp_abstract_workorder.py39
-rw-r--r--addons/mrp/models/mrp_production.py3
-rw-r--r--addons/mrp/models/mrp_workorder.py28
3 files changed, 61 insertions, 9 deletions
diff --git a/addons/mrp/models/mrp_abstract_workorder.py b/addons/mrp/models/mrp_abstract_workorder.py
index 7e05d187f5a..c4e156ec4bb 100644
--- a/addons/mrp/models/mrp_abstract_workorder.py
+++ b/addons/mrp/models/mrp_abstract_workorder.py
@@ -75,18 +75,24 @@ class MrpAbstractWorkorder(models.AbstractModel):
# Remove or lower quantity on exisiting workorder lines
if float_compare(qty_todo, 0.0, precision_rounding=rounding) < 0:
qty_todo = abs(qty_todo)
- for workorder_line in move_workorder_lines.sorted(key=lambda wl: wl.qty_reserved):
+ # Try to decrease or remove lines that are not reserved and
+ # partialy reserved first. A different decrease strategy could
+ # be define in _unreserve_order method.
+ for workorder_line in move_workorder_lines.sorted(key=lambda wl: wl._unreserve_order()):
if float_compare(qty_todo, 0, precision_rounding=rounding) <= 0:
break
+ # If the quantity to consume on the line is lower than the
+ # quantity to remove, the line could be remove.
if float_compare(workorder_line.qty_to_consume, qty_todo, precision_rounding=rounding) <= 0:
- # update qty_todo for next wo_line
qty_todo = float_round(qty_todo - workorder_line.qty_to_consume, precision_rounding=rounding)
if line_values['to_delete']:
line_values['to_delete'] |= workorder_line
else:
line_values['to_delete'] = workorder_line
+ # decrease the quantity on the line
else:
new_val = workorder_line.qty_to_consume - qty_todo
+ # avoid to write a negative reserved quantity
new_reserved = max(0, workorder_line.qty_reserved - qty_todo)
line_values['to_update'][workorder_line] = {
'qty_to_consume': new_val,
@@ -97,12 +103,17 @@ class MrpAbstractWorkorder(models.AbstractModel):
else:
# Search among wo lines which one could be updated
qty_reserved_wl = defaultdict(float)
+ # Try to update the line with the greater reservation first in
+ # order to promote bigger batch.
for workorder_line in move_workorder_lines.sorted(key=lambda wl: wl.qty_reserved, reverse=True):
rounding = workorder_line.product_uom_id.rounding
if float_compare(qty_todo, 0, precision_rounding=rounding) <= 0:
break
move_lines = workorder_line._get_move_lines()
qty_reserved_wl[workorder_line.lot_id] += workorder_line.qty_reserved
+ # The reserved quantity according to exisiting move line
+ # already produced (with qty_done set) and other production
+ # lines with the same lot that are currently on production.
qty_reserved_remaining = sum(move_lines.mapped('product_uom_qty')) - sum(move_lines.mapped('qty_done')) - qty_reserved_wl[workorder_line.lot_id]
if float_compare(qty_reserved_remaining, 0, precision_rounding=rounding) > 0:
qty_to_add = min(qty_reserved_remaining, qty_todo)
@@ -114,6 +125,13 @@ class MrpAbstractWorkorder(models.AbstractModel):
qty_todo -= qty_to_add
qty_reserved_wl[workorder_line.lot_id] += qty_to_add
+ # If a line exists without reservation and without lot. It
+ # means that previous operations could not find any reserved
+ # quantity and created a line without lot prefilled. In this
+ # case, the system will not find an existing move line with
+ # available reservation anymore and will increase this line
+ # instead of creating a new line without lot and reserved
+ # quantities.
if not workorder_line.qty_reserved and not workorder_line.lot_id and workorder_line.product_tracking != 'serial':
line_values['to_update'][workorder_line] = {
'qty_done': workorder_line.qty_to_consume + qty_todo,
@@ -130,9 +148,10 @@ class MrpAbstractWorkorder(models.AbstractModel):
@api.model
def _generate_lines_values(self, move, qty_to_consume):
""" Create workorder line. First generate line based on the reservation,
- in order to match the reservation. If the quantity to consume is greater
- than the reservation quantity then create line with the correct quantity
- to consume but without lot or serial number.
+ in order to prefill reserved quantity, lot and serial number.
+ If the quantity to consume is greater than the reservation quantity then
+ create line with the correct quantity to consume but without lot or
+ serial number.
"""
lines = []
is_tracked = move.product_id.tracking != 'none'
@@ -227,8 +246,9 @@ class MrpAbstractWorkorder(models.AbstractModel):
)
def _update_raw_moves(self):
- """ Once the production is done, the lots written on workorder lines
- are saved on stock move lines"""
+ """ Once the production is done. Modify the workorder lines into
+ stock move line with the registered lot and quantity done.
+ """
# Before writting produce quantities, we ensure they respect the bom strictness
self._strict_consumption_check()
vals_list = []
@@ -389,6 +409,11 @@ class MrpAbstractWorkorderLine(models.AbstractModel):
return vals_list
+ def _unreserve_order(self):
+ """ Unreserve line with lower reserved quantity first """
+ self.ensure_one()
+ return (self.qty_reserved,)
+
def _get_move_lines(self):
return self.move_id.move_line_ids.filtered(lambda ml:
ml.lot_id == self.lot_id and ml.product_id == self.product_id)
diff --git a/addons/mrp/models/mrp_production.py b/addons/mrp/models/mrp_production.py
index de09754e2da..e50ba0a7e0e 100644
--- a/addons/mrp/models/mrp_production.py
+++ b/addons/mrp/models/mrp_production.py
@@ -592,6 +592,7 @@ class MrpProduction(models.Model):
def action_assign(self):
for production in self:
production.move_raw_ids._action_assign()
+ production.workorder_ids._refresh_wo_lines()
return True
@api.multi
@@ -729,7 +730,7 @@ class MrpProduction(models.Model):
moves_raw.mapped('move_line_ids').write({'workorder_id': workorder.id})
(moves_finished + moves_raw).write({'workorder_id': workorder.id})
- workorder.generate_wo_lines()
+ workorder._generate_wo_lines()
return workorders
def _check_lots(self):
diff --git a/addons/mrp/models/mrp_workorder.py b/addons/mrp/models/mrp_workorder.py
index 4df8c4611e4..6384b5a78ff 100644
--- a/addons/mrp/models/mrp_workorder.py
+++ b/addons/mrp/models/mrp_workorder.py
@@ -220,7 +220,7 @@ class MrpWorkorder(models.Model):
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.'))
return super(MrpWorkorder, self).write(values)
- def generate_wo_lines(self):
+ def _generate_wo_lines(self):
""" Generate workorder line """
self.ensure_one()
raw_moves = self.move_raw_ids.filtered(
@@ -247,6 +247,32 @@ class MrpWorkorder(models.Model):
for line, vals in line_values['to_update'].items():
line.write(vals)
+ def _refresh_wo_lines(self):
+ for workorder in self:
+ raw_moves = workorder.move_raw_ids.filtered(
+ lambda move: move.state not in ('done', 'cancel')
+ )
+ wl_to_unlink = self.env['mrp.workorder.line']
+ for move in raw_moves:
+ rounding = move.product_uom.rounding
+ qty_already_consumed = 0.0
+ workorder_lines = workorder.workorder_line_ids.filtered(lambda w: w.move_id == move)
+ for wl in workorder_lines:
+ if not wl.qty_done:
+ wl_to_unlink |= wl
+ continue
+
+ qty_already_consumed += wl.qty_done
+ qty_to_consume = move.product_uom._compute_quantity(
+ workorder.qty_producing * move.unit_factor,
+ move.product_id.uom_id,
+ round=False
+ )
+ wl_to_unlink.unlink()
+ if float_compare(qty_to_consume, qty_already_consumed, precision_rounding=rounding) > 0:
+ line_values = workorder._generate_lines_values(move, qty_to_consume - qty_already_consumed)
+ workorder.workorder_line_ids |= self.env['mrp.workorder.line'].create(line_values)
+
def _defaults_from_finished_workorder_line(self, reference_lot_lines):
for r_line in reference_lot_lines:
# see which lot we could suggest and its related qty_producing