[IMP] mrp: suggest lot on workorder
On a manufactoring order, 'checking availability' will make the reservation of the components to consume. If those components are tracked by lot or serial numbers, the reservation will also set a available lot/sn on the move lines and workorder lines. The reservation already works on product produce wizard lines and workorder line (form view). We need this commit as preliminary work to being able to suggest them on the workorders tablet view too. In case of requesting the reservation after planning the production (applying reservation on already created workorder lines and checks), we deleted all lines not yet consumed. They are then recreated with the reservation. The user can obiously still use the lot/sn he wants by changing it onto the workorder. Task : 1891864 closes odoo/odoo#28020 Signed-off-by: Simon Lejeune (sle) <sle@openerp.com>
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user