[REF] mrp: update MO according to "To Comsume"
Previously, when we upate the "Quantity to Produce" on a MO, we update the components to consume according to the BOM we use. After this commit, we now update the components according their current number set on the MO. For example, if we have a MO to use x component A to produce y product B. When we update the number y to z, the number of A we want to consume will be updated from x to x / y * z, regardless of the setting on the BOM. If multiple components are used, all components will be updated according to this rule. Task: 2241471
This commit is contained in:
@@ -861,6 +861,25 @@ class MrpProduction(models.Model):
|
||||
move = self.env['stock.move'].create(move_values)
|
||||
return move, 0, quantity
|
||||
|
||||
def _update_raw_moves(self, factor):
|
||||
self.ensure_one()
|
||||
update_info = []
|
||||
move_to_unlink = self.env['stock.move']
|
||||
for move in self.move_raw_ids.filtered(lambda m: m.state not in ('done', 'cancel')):
|
||||
old_qty = move.product_uom_qty
|
||||
new_qty = old_qty * factor
|
||||
if new_qty > 0:
|
||||
move.write({'product_uom_qty': new_qty})
|
||||
move._action_assign()
|
||||
update_info.append((move, old_qty, new_qty))
|
||||
else:
|
||||
if move.quantity_done > 0:
|
||||
raise UserError(_('Lines need to be deleted, but can not as you still have some quantities to consume in them. '))
|
||||
move._action_cancel()
|
||||
move_to_unlink |= move
|
||||
move_to_unlink.unlink()
|
||||
return update_info
|
||||
|
||||
def _get_ready_to_produce_state(self):
|
||||
""" returns 'assigned' if enough components are reserved in order to complete
|
||||
the first operation of the bom. If not returns 'waiting'
|
||||
|
||||
@@ -137,7 +137,11 @@
|
||||
<field name="qty_producing" digits="[12,3]" class="text-left" attrs="{'readonly': ['|', ('state', '=', 'cancel'), '&', ('state', '=', 'done'), ('is_locked', '=', True)]}"/>
|
||||
/
|
||||
</div>
|
||||
<field name="product_qty" class="oe_inline text-left" attrs="{'readonly': [('state', '!=', 'draft')]}"/>
|
||||
<field name="product_qty" class="oe_inline text-left" attrs="{'readonly': [('state', '!=', 'draft')], 'invisible': [('state', 'not in', ('draft', 'done'))]}"/>
|
||||
<button type="action" name="%(mrp.action_change_production_qty)d"
|
||||
context="{'default_mo_id': id}" class="oe_link oe_inline" attrs="{'invisible': ['|', ('state', 'in', ('draft', 'done','cancel')), ('id', '=', False)]}">
|
||||
<field name="product_qty" class="oe_inline" attrs="{'readonly': [('state', '!=', 'draft')]}"/>
|
||||
</button>
|
||||
<label for="product_uom_id" string="" class="oe_inline"/>
|
||||
<field name="product_uom_category_id" invisible="1"/>
|
||||
<field name="product_uom_id" options="{'no_open': True, 'no_create': True}" force_save="1" groups="uom.group_uom" attrs="{'readonly': [('state', '!=', 'draft')]}" class="oe_inline"/>
|
||||
@@ -206,13 +210,9 @@
|
||||
</group>
|
||||
<notebook>
|
||||
<page string="Components" name="components">
|
||||
<<<<<<< HEAD
|
||||
<field name="move_raw_ids" context="{'default_location_id': location_src_id, 'default_location_dest_id': production_location_id, 'default_state': 'draft', 'default_raw_material_production_id': id, 'default_picking_type_id': picking_type_id, 'default_company_id': company_id}" attrs="{'readonly': ['|', ('state', '=', 'cancel'), '&', ('state', '=', 'done'), ('is_locked', '=', True)]}">
|
||||
=======
|
||||
<field name="move_raw_ids"
|
||||
context="{'default_date_expected': date_planned_start, 'default_location_id': location_src_id, 'default_location_dest_id': production_location_id, 'default_state': 'draft', 'default_raw_material_production_id': id, 'default_picking_type_id': picking_type_id, 'default_company_id': company_id}"
|
||||
attrs="{'readonly': ['|', ('state', '=', 'cancel'), '&', ('state', '=', 'done'), ('is_locked', '=', True)]}">
|
||||
>>>>>>> dd9359b6fbe... fixup! [REF] mrp: no more produce wizard
|
||||
<tree delete="0" default_order="is_done,sequence" editable="bottom">
|
||||
<field name="product_id" required="1" attrs="{'readonly': ['|', '|', ('has_move_lines', '=', True), ('state', '=', 'cancel'), '&', ('state', '!=', 'draft'), ('additional', '=', False) ]}"/>
|
||||
|
||||
|
||||
@@ -53,46 +53,27 @@ class ChangeProductionQty(models.TransientModel):
|
||||
production.write({'product_qty': wizard.product_qty})
|
||||
done_moves = production.move_finished_ids.filtered(lambda x: x.state == 'done' and x.product_id == production.product_id)
|
||||
qty_produced = production.product_id.uom_id._compute_quantity(sum(done_moves.mapped('product_qty')), production.product_uom_id)
|
||||
factor = production.product_uom_id._compute_quantity(production.product_qty - qty_produced, production.bom_id.product_uom_id) / production.bom_id.product_qty
|
||||
boms, lines = production.bom_id.explode(production.product_id, factor, picking_type=production.bom_id.picking_type_id)
|
||||
|
||||
factor = (production.product_qty - qty_produced) / (old_production_qty - qty_produced)
|
||||
update_info = production._update_raw_moves(factor)
|
||||
documents = {}
|
||||
for line, line_data in lines:
|
||||
if line.child_bom_id and line.child_bom_id.type == 'phantom' or\
|
||||
line.product_id.type not in ['product', 'consu']:
|
||||
continue
|
||||
move = production.move_raw_ids.filtered(lambda x: x.bom_line_id.id == line.id and x.state not in ('done', 'cancel'))
|
||||
if move:
|
||||
move = move[0]
|
||||
old_qty = move.product_uom_qty
|
||||
else:
|
||||
old_qty = 0
|
||||
for move, old_qty, new_qty in update_info:
|
||||
iterate_key = production._get_document_iterate_key(move)
|
||||
if iterate_key:
|
||||
document = self.env['stock.picking']._log_activity_get_documents({move: (line_data['qty'], old_qty)}, iterate_key, 'UP')
|
||||
document = self.env['stock.picking']._log_activity_get_documents({move: (new_qty, old_qty)}, iterate_key, 'UP')
|
||||
for key, value in document.items():
|
||||
if documents.get(key):
|
||||
documents[key] += [value]
|
||||
else:
|
||||
documents[key] = [value]
|
||||
|
||||
production._update_raw_move(line, line_data)
|
||||
production._log_manufacture_exception(documents)
|
||||
operation_bom_qty = {}
|
||||
for bom, bom_data in boms:
|
||||
for operation in bom.operation_ids:
|
||||
operation_bom_qty[operation.id] = bom_data['qty']
|
||||
finished_moves_modification = self._update_finished_moves(production, production.product_qty - qty_produced, old_production_qty)
|
||||
finished_moves_modification = self._update_finished_moves(production, production.product_qty - qty_produced, old_production_qty - qty_produced)
|
||||
if finished_moves_modification:
|
||||
production._log_downside_manufactured_quantity(finished_moves_modification)
|
||||
moves = production.move_raw_ids.filtered(lambda x: x.state not in ('done', 'cancel'))
|
||||
moves._action_assign()
|
||||
|
||||
for wo in production.workorder_ids:
|
||||
operation = wo.operation_id
|
||||
if operation_bom_qty.get(operation.id):
|
||||
cycle_number = float_round(operation_bom_qty[operation.id] / operation.workcenter_id.capacity, precision_digits=0, rounding_method='UP')
|
||||
wo.duration_expected = (operation.workcenter_id.time_start +
|
||||
operation.workcenter_id.time_stop +
|
||||
cycle_number * operation.time_cycle * 100.0 / operation.workcenter_id.time_efficiency)
|
||||
wo._onchange_expected_duration()
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user