[IMP] mrp: don't require consumed widget when multi-location
Before this commit, it was required to always use the widget to edit the consumed quantity of a component when multi-location or packages setting is active. This was not user friendly so this commit relaxes the requirement to only tracked products and gives users the option to still edit the consumed move lines directly if desired. We also distinguish between when using the widget is required or not with the widget button color. Note that if quantity consumed is greater than amount reserved in different locations, the difference will default to the move's source location (this is consistent with what happens when the `qty_producing` is changed in the MO and the consumed quantities are scaled to match.) Task: 2518523 Upgrade PR: odoo/upgrade#2655 closes odoo/odoo#73939 Related: odoo/enterprise#19732 Signed-off-by: Arnold Moyaux <amoyaux@users.noreply.github.com>
This commit is contained in:
@@ -419,3 +419,10 @@ class StockMove(models.Model):
|
||||
candidate_moves_list.append(production.move_raw_ids)
|
||||
for production in self.mapped('production_id'):
|
||||
candidate_moves_list.append(production.move_finished_ids)
|
||||
|
||||
def _multi_line_quantity_done_set(self, quantity_done):
|
||||
if self.raw_material_production_id:
|
||||
self.move_line_ids.filtered(lambda ml: ml.state not in ('done', 'cancel')).qty_done = 0
|
||||
self.move_line_ids = self._set_quantity_done_prepare_vals(quantity_done)
|
||||
else:
|
||||
super()._multi_line_quantity_done_set(quantity_done)
|
||||
|
||||
@@ -9,3 +9,11 @@
|
||||
.o_should_consume{
|
||||
padding-left: 0.3em;
|
||||
}
|
||||
|
||||
.btn-link.o_optional_button{
|
||||
color: gray;
|
||||
|
||||
&:hover {
|
||||
filter: brightness(0.9);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,7 +94,7 @@
|
||||
<button name="button_scrap" type="object" string="Scrap" attrs="{'invisible': [('state', 'in', ('cancel', 'draft'))]}" data-hotkey="z"/>
|
||||
<field name="state" widget="statusbar" statusbar_visible="draft,confirmed,progress,done"/>
|
||||
<button name="action_toggle_is_locked" attrs="{'invisible': ['|', ('show_lock', '=', False), ('is_locked', '=', False)]}" string="Unlock" groups="mrp.group_mrp_manager" type="object" help="Unlock the manufacturing order to adjust what has been consumed or produced." data-hotkey="l"/>
|
||||
<button name="action_toggle_is_locked" attrs="{'invisible': ['|', ('show_lock', '=', False), ('is_locked', '=', True)]}" string="Lock" groups="mrp.group_mrp_manager" type="object" help="Lock the manufacturing order to prevent changes to what has been consumed or produced." data-hotkey="l"/>/>
|
||||
<button name="action_toggle_is_locked" attrs="{'invisible': ['|', ('show_lock', '=', False), ('is_locked', '=', True)]}" string="Lock" groups="mrp.group_mrp_manager" type="object" help="Lock the manufacturing order to prevent changes to what has been consumed or produced." data-hotkey="l"/>
|
||||
<button name="action_cancel" type="object" string="Cancel" data-hotkey="z"
|
||||
attrs="{'invisible': ['|', '|', ('id', '=', False), ('state', 'in', ('done', 'cancel')), ('confirm_cancel', '=', True)]}"/>
|
||||
<button name="action_cancel" type="object" string="Cancel" data-hotkey="z"
|
||||
@@ -232,8 +232,8 @@
|
||||
context="{'default_date': date_planned_start, 'default_date_deadline': date_deadline, '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)]}" options="{'delete': [('state', '=', 'draft')]}">
|
||||
<tree default_order="is_done,sequence" editable="bottom">
|
||||
<field name="product_id" force_save="1" required="1" context="{'default_type': 'product'}" attrs="{'readonly': ['|', '|', ('has_move_lines', '=', True), ('state', '=', 'cancel'), '&', ('state', '!=', 'draft'), ('additional', '=', False) ]}"/>
|
||||
|
||||
<field name="product_id" force_save="1" required="1" context="{'default_type': 'product'}" attrs="{'readonly': ['|', '|', ('move_lines_count', '>', 0), ('state', '=', 'cancel'), '&', ('state', '!=', 'draft'), ('additional', '=', False) ]}"/>
|
||||
<field name="location_id" string="From" readonly="1" groups="stock.group_stock_multi_locations"/>
|
||||
<field name="move_line_ids" invisible="1">
|
||||
<tree>
|
||||
<field name="lot_id" invisible="1"/>
|
||||
@@ -271,7 +271,7 @@
|
||||
<field name="location_id" invisible="1"/>
|
||||
<field name="warehouse_id" invisible="1"/>
|
||||
<field name="is_locked" invisible="1"/>
|
||||
<field name="has_move_lines" invisible="1"/>
|
||||
<field name="move_lines_count" invisible="1"/>
|
||||
<field name="location_dest_id" domain="[('id', 'child_of', parent.location_dest_id)]" invisible="1"/>
|
||||
<field name="state" invisible="1" force_save="1"/>
|
||||
<field name="should_consume_qty" invisible="1"/>
|
||||
@@ -285,7 +285,7 @@
|
||||
<field name="quantity_done" string="Consumed"
|
||||
decoration-success="not is_done and (quantity_done - should_consume_qty == 0)"
|
||||
decoration-warning="not is_done and (quantity_done - should_consume_qty > 0.0001)"
|
||||
attrs="{'column_invisible': [('parent.state', '=', 'draft')], 'readonly': [('show_details_visible', '=', True)]}"/>
|
||||
attrs="{'column_invisible': [('parent.state', '=', 'draft')], 'readonly': [('has_tracking', '!=','none')]}"/>
|
||||
<field name="product_uom" attrs="{'readonly': [('state', '!=', 'draft')]}" options="{'no_open': True, 'no_create': True}" groups="uom.group_uom"/>
|
||||
<field name="show_details_visible" invisible="1"/>
|
||||
<field name="lot_ids" widget="many2many_tags"
|
||||
@@ -296,7 +296,8 @@
|
||||
domain="[('product_id','=',product_id)]"
|
||||
/>
|
||||
<field name="group_id" invisible="1"/>
|
||||
<button name="action_show_details" type="object" icon="fa-list" context="{'default_product_uom_qty': 0}" attrs="{'invisible': [('show_details_visible', '=', False)]}" options="{"warn": true}"/>
|
||||
<button name="action_show_details" type="object" icon="fa-list" context="{'default_product_uom_qty': 0}" attrs="{'invisible': ['|', ('show_details_visible', '=', False), ('has_tracking', '=','none')]}" options="{"warn": true}"/>
|
||||
<button class="o_optional_button" name="action_show_details" type="object" icon="fa-list" context="{'default_product_uom_qty': 0}" attrs="{'invisible': ['|', ('has_tracking', '!=','none'), ('show_details_visible', '=', False)]}" options="{"warn": true}"/>
|
||||
</tree>
|
||||
</field>
|
||||
</page>
|
||||
@@ -308,6 +309,7 @@
|
||||
<tree default_order="is_done,sequence" decoration-muted="is_done" editable="bottom">
|
||||
<field name="byproduct_id" invisible="1"/>
|
||||
<field name="product_id" context="{'default_type': 'product'}" domain="[('id', '!=', parent.product_id)]" required="1"/>
|
||||
<field name="location_dest_id" string="To" readonly="1" groups="stock.group_stock_multi_locations"/>
|
||||
|
||||
<field name="move_line_ids" invisible="1">
|
||||
<tree>
|
||||
@@ -343,7 +345,7 @@
|
||||
<field name="location_id" invisible="1"/>
|
||||
<field name="warehouse_id" invisible="1"/>
|
||||
<field name="is_locked" invisible="1"/>
|
||||
<field name="has_move_lines" invisible="1"/>
|
||||
<field name="move_lines_count" invisible="1"/>
|
||||
<field name="location_dest_id" domain="[('id', 'child_of', parent.location_dest_id)]" invisible="1"/>
|
||||
<field name="state" invisible="1" force_save="1"/>
|
||||
<field name="product_uom_qty" string="To Produce" attrs="{'readonly': ['&', ('parent.state', '!=', 'draft'), '|', '&', ('parent.state', 'not in', ('confirmed', 'progress', 'to_close')), ('parent.is_planned', '!=', True), ('parent.is_locked', '=', True)]}"/>
|
||||
@@ -358,7 +360,8 @@
|
||||
context="{'default_company_id': company_id, 'default_product_id': product_id}"
|
||||
domain="[('product_id','=',product_id)]"
|
||||
/>
|
||||
<button name="action_show_details" type="object" icon="fa-list" attrs="{'invisible': [('show_details_visible', '=', False)]}" options="{"warn": true}"/>
|
||||
<button name="action_show_details" type="object" icon="fa-list" attrs="{'invisible': ['|', ('has_tracking', '=','none'), ('show_details_visible', '=', False)]}" options="{"warn": true}"/>
|
||||
<button class="o_optional_button" name="action_show_details" type="object" icon="fa-list" attrs="{'invisible': ['|', ('has_tracking', '!=','none'), ('show_details_visible', '=', False)]}" options="{"warn": true}"/>
|
||||
</tree>
|
||||
</field>
|
||||
</page>
|
||||
|
||||
@@ -163,7 +163,7 @@ class StockMove(models.Model):
|
||||
is_initial_demand_editable = fields.Boolean('Is initial demand editable', compute='_compute_is_initial_demand_editable')
|
||||
is_quantity_done_editable = fields.Boolean('Is quantity done editable', compute='_compute_is_quantity_done_editable')
|
||||
reference = fields.Char(compute='_compute_reference', string="Reference", store=True)
|
||||
has_move_lines = fields.Boolean(compute='_compute_has_move_lines')
|
||||
move_lines_count = fields.Integer(compute='_compute_move_lines_count')
|
||||
package_level_id = fields.Many2one('stock.package_level', 'Package Level', check_company=True, copy=False)
|
||||
picking_type_entire_packs = fields.Boolean(related='picking_type_id.show_entire_packs', readonly=True)
|
||||
display_assign_serial = fields.Boolean(compute='_compute_display_assign_serial')
|
||||
@@ -268,9 +268,9 @@ class StockMove(models.Model):
|
||||
move.reference = move.picking_id.name if move.picking_id else move.name
|
||||
|
||||
@api.depends('move_line_ids')
|
||||
def _compute_has_move_lines(self):
|
||||
def _compute_move_lines_count(self):
|
||||
for move in self:
|
||||
move.has_move_lines = bool(move.move_line_ids)
|
||||
move.move_lines_count = len(move.move_line_ids)
|
||||
|
||||
@api.depends('product_id', 'product_uom', 'product_uom_qty')
|
||||
def _compute_product_qty(self):
|
||||
@@ -352,12 +352,16 @@ class StockMove(models.Model):
|
||||
elif len(move_lines) == 1:
|
||||
move_lines[0].qty_done = quantity_done
|
||||
else:
|
||||
# Bypass the error if we're trying to write the same value.
|
||||
ml_quantity_done = 0
|
||||
for move_line in move_lines:
|
||||
ml_quantity_done += move_line.product_uom_id._compute_quantity(move_line.qty_done, move.product_uom, round=False)
|
||||
if float_compare(quantity_done, ml_quantity_done, precision_rounding=move.product_uom.rounding) != 0:
|
||||
raise UserError(_("Cannot set the done quantity from this stock move, work directly with the move lines."))
|
||||
move._multi_line_quantity_done_set(quantity_done)
|
||||
|
||||
def _multi_line_quantity_done_set(self, quantity_done):
|
||||
move_lines = self._get_move_lines()
|
||||
# Bypass the error if we're trying to write the same value.
|
||||
ml_quantity_done = 0
|
||||
for move_line in move_lines:
|
||||
ml_quantity_done += move_line.product_uom_id._compute_quantity(move_line.qty_done, self.product_uom, round=False)
|
||||
if float_compare(quantity_done, ml_quantity_done, precision_rounding=self.product_uom.rounding) != 0:
|
||||
raise UserError(_("Cannot set the done quantity from this stock move, work directly with the move lines."))
|
||||
|
||||
def _set_product_qty(self):
|
||||
""" The meaning of product_qty field changed lately and is now a functional field computing the quantity
|
||||
|
||||
@@ -66,10 +66,10 @@
|
||||
<field name="show_reserved_availability" invisible="1"/>
|
||||
<field name="show_operations" invisible="1" readonly="1"/>
|
||||
<field name="additional" invisible="1"/>
|
||||
<field name="has_move_lines" invisible="1"/>
|
||||
<field name="move_lines_count" invisible="1"/>
|
||||
<field name="is_locked" invisible="1"/>
|
||||
<field name="product_uom_category_id" invisible="1"/>
|
||||
<field name="product_id" required="1" attrs="{'readonly': ['|', '&', ('state', '!=', 'draft'), ('additional', '=', False), ('has_move_lines', '=', True)]}"/>
|
||||
<field name="product_id" required="1" attrs="{'readonly': ['|', '&', ('state', '!=', 'draft'), ('additional', '=', False), ('move_lines_count', '>', 0)]}"/>
|
||||
<field name="is_initial_demand_editable" invisible="1"/>
|
||||
<field name="is_quantity_done_editable" invisible="1"/>
|
||||
<field name="product_uom_qty" string="Demand" attrs="{'readonly': [('is_initial_demand_editable', '=', False)]}"/>
|
||||
|
||||
@@ -351,12 +351,12 @@
|
||||
<field name="show_reserved_availability" invisible="1"/>
|
||||
<field name="show_operations" invisible="1" readonly="1"/>
|
||||
<field name="additional" invisible="1"/>
|
||||
<field name="has_move_lines" invisible="1"/>
|
||||
<field name="move_lines_count" invisible="1"/>
|
||||
<field name="is_locked" invisible="1"/>
|
||||
<field name="product_uom_category_id" invisible="1"/>
|
||||
<field name="has_tracking" invisible="1"/>
|
||||
<field name="display_assign_serial" invisible="1"/>
|
||||
<field name="product_id" required="1" context="{'default_type': 'product'}" attrs="{'readonly': ['|', '&', ('state', '!=', 'draft'), ('additional', '=', False), ('has_move_lines', '=', True)]}"/>
|
||||
<field name="product_id" required="1" context="{'default_type': 'product'}" attrs="{'readonly': ['|', '&', ('state', '!=', 'draft'), ('additional', '=', False), ('move_lines_count', '>', 0)]}"/>
|
||||
<field name="description_picking" string="Description" optional="hide"/>
|
||||
<field name="date" invisible="1"/>
|
||||
<field name="date_deadline" optional="hide"/>
|
||||
@@ -395,9 +395,9 @@
|
||||
<group>
|
||||
<field name="product_uom_category_id" invisible="1"/>
|
||||
<field name="additional" invisible="1"/>
|
||||
<field name="has_move_lines" invisible="1"/>
|
||||
<field name="move_lines_count" invisible="1"/>
|
||||
<field name="company_id" invisible="1"/>
|
||||
<field name="product_id" required="1" attrs="{'readonly': ['|', '&', ('state', '!=', 'draft'), ('additional', '=', False), ('has_move_lines', '=', True)]}"/>
|
||||
<field name="product_id" required="1" attrs="{'readonly': ['|', '&', ('state', '!=', 'draft'), ('additional', '=', False), ('move_lines_count', '>', 0)]}"/>
|
||||
<field name="is_initial_demand_editable" invisible="1"/>
|
||||
<field name="is_quantity_done_editable" invisible="1"/>
|
||||
<field name="product_uom_qty" attrs="{'invisible': [('parent.immediate_transfer', '=', True)], 'readonly': [('is_initial_demand_editable', '=', False)]}"/>
|
||||
|
||||
Reference in New Issue
Block a user