Skip to content
Permalink
Browse files

[IMP] mrp,stock,product: usability improvements

- Hid the column reserved in the detailed operation wizard when the picking is a receipt.
- Removed red line of detailed operations from receipt.
- Increased the size of kanban cards in workorders.
- Some wording improvements
- Changed order of fields in product supplier form view

Task ID:1940358
  • Loading branch information...
pch-odoo committed Feb 18, 2019
1 parent 39e7135 commit 5a002500e7b124ab28303ff9471130565bc7eb1b
@@ -78,7 +78,7 @@ def _get_default_location_dest_id(self):
'stock.picking.type', 'Operation Type',
default=_get_default_picking_type, required=True)
location_src_id = fields.Many2one(
'stock.location', 'Raw Materials Location',
'stock.location', 'Components Location',
default=_get_default_location_src_id,
readonly=True, required=True,
states={'draft': [('readonly', False)]},
@@ -115,7 +115,7 @@ def _get_default_location_dest_id(self):
bom_id = fields.Many2one(
'mrp.bom', 'Bill of Material',
readonly=True, states={'draft': [('readonly', False)]},
help="Bill of Materials allow you to define the list of required raw materials to make a finished product.")
help="Bill of Materials allow you to define the list of required components to make a finished product.")
routing_id = fields.Many2one(
'mrp.routing', 'Routing',
readonly=True, compute='_compute_routing', store=True,
@@ -153,7 +153,7 @@ def _get_default_location_dest_id(self):
defined on the BoM.")

move_raw_ids = fields.One2many(
'stock.move', 'raw_material_production_id', 'Raw Materials', oldname='move_lines',
'stock.move', 'raw_material_production_id', 'Components', oldname='move_lines',
copy=True, states={'done': [('readonly', True)], 'cancel': [('readonly', True)]},
domain=[('scrapped', '=', False)])
move_finished_ids = fields.One2many(
@@ -757,14 +757,14 @@ def _workorders_create(self, bom, bom_data):
return workorders

def _check_lots(self):
# Check that the raw materials were consumed for lots that we have produced.
# Check that the components were consumed for lots that we have produced.
if self.product_id.tracking != 'none':
finished_lots = set(self.finished_move_line_ids.mapped('lot_id'))
raw_finished_lots = set(self.move_raw_ids.mapped('move_line_ids.lot_produced_id'))
if not (raw_finished_lots <= finished_lots):
lots_short = raw_finished_lots - finished_lots
error_msg = _(
'Some raw materials have been consumed for a lot/serial number that has not been produced. '
'Some components have been consumed for a lot/serial number that has not been produced. '
'Unlock the MO and click on the components lines to correct it.\n'
'List of the components:\n'
)
@@ -22,7 +22,7 @@ class MrpRouting(models.Model):
copy=True, oldname='workcenter_lines')
location_id = fields.Many2one(
'stock.location', 'Production Location',
help="Keep empty if you produce at the location where you find the raw materials. "
help="Keep empty if you produce at the location where you find the components. "
"Set a location if you produce at a fixed location. This can be a partner location "
"if you subcontract the manufacturing operations.")
company_id = fields.Many2one(
@@ -59,7 +59,7 @@ class StockMove(models.Model):
production_id = fields.Many2one(
'mrp.production', 'Production Order for finished products')
raw_material_production_id = fields.Many2one(
'mrp.production', 'Production Order for raw materials')
'mrp.production', 'Production Order for components')
unbuild_id = fields.Many2one(
'mrp.unbuild', 'Disassembly Order')
consume_unbuild_id = fields.Many2one(
@@ -29,9 +29,9 @@ class StockWarehouse(models.Model):
('pbm', 'Pick components and then manufacture (2 steps)'),
('pbm_sam', 'Pick components, manufacture and then store products (3 steps)')],
'Manufacture', default='mrp_one_step', required=True,
help="Produce : Move the raw materials to the production location\
help="Produce : Move the components to the production location\
directly and start the manufacturing process.\nPick / Produce : Unload\
the raw materials from the Stock to Input location first, and then\
the components from the Stock to Input location first, and then\
transfer it to the Production location.")

pbm_route_id = fields.Many2one('stock.location.route', 'Picking Before Manufacturing Route', ondelete='restrict')
@@ -589,7 +589,7 @@ def test_product_produce_3(self):
self.assertEqual(mo.state, 'done', "Production order should be in done state.")

def test_product_produce_4(self):
""" Possibility to produce with a given raw material in multiple locations. """
""" Possibility to produce with a given component in multiple locations. """
self.stock_location = self.env.ref('stock.stock_location_stock')
self.stock_shelf_1 = self.env.ref('stock.stock_location_components')
self.stock_shelf_2 = self.env.ref('stock.stock_location_14')
@@ -326,10 +326,10 @@ def test_01_without_workorder(self):
mo_custom_laptop.action_assign()
self.assertEqual(mo_custom_laptop.reservation_state, 'assigned')

# Check current status of raw materials.
# Check current status of components.
for move in mo_custom_laptop.move_raw_ids:
self.assertEqual(move.product_uom_qty, 20, "Wrong consume quantity of raw material %s: %s instead of %s" % (move.product_id.name, move.product_uom_qty, 20))
self.assertEqual(move.quantity_done, 0, "Wrong produced quantity on raw material %s: %s instead of %s" % (move.product_id.name, move.quantity_done, 0))
self.assertEqual(move.product_uom_qty, 20, "Wrong consume quantity of component %s: %s instead of %s" % (move.product_id.name, move.product_uom_qty, 20))
self.assertEqual(move.quantity_done, 0, "Wrong produced quantity on component %s: %s instead of %s" % (move.product_id.name, move.quantity_done, 0))

# -----------------
# Start production
@@ -347,7 +347,7 @@ def test_01_without_workorder(self):

# Check consumed move after produce 6 quantity of customized laptop.
for move in mo_custom_laptop.move_raw_ids:
self.assertEqual(move.quantity_done, 12, "Wrong produced quantity on raw material %s" % (move.product_id.name))
self.assertEqual(move.quantity_done, 12, "Wrong produced quantity on component %s" % (move.product_id.name))
self.assertEqual(len(mo_custom_laptop.move_raw_ids), 2)
mo_custom_laptop.post_inventory()
self.assertEqual(len(mo_custom_laptop.move_raw_ids), 4)
@@ -120,7 +120,7 @@
</group>
</group>
<notebook>
<page string="Consumed Materials">
<page string="Components">
<field name="move_raw_ids" context="{'final_lots': show_final_lots, 'form_view_ref': 'mrp.view_stock_move_lots', '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}" attrs="{'readonly': ['&amp;', ('state', '!=', 'draft'), ('is_locked', '=', True)]}">
<tree delete="0" default_order="is_done,sequence" decoration-muted="is_done" decoration-warning="quantity_done&gt;product_uom_qty" decoration-success="not is_done and quantity_done==product_uom_qty" decoration-danger="not is_done and reserved_availability &lt; product_uom_qty">
<field name="product_id" required="1"/>
@@ -285,7 +285,7 @@
domain="[('activity_ids.user_id', '=', uid)]"/>
<separator/>
<field name="product_id"/>
<field name="move_raw_ids" string="Raw Material" filter_domain="[('move_raw_ids.product_id','ilike',self)]"/>
<field name="move_raw_ids" string="Components" filter_domain="[('move_raw_ids.product_id','ilike',self)]"/>
<field name="name" string="Work Center" filter_domain="[('routing_id.operation_ids.workcenter_id','ilike',self)]"/>
<field name="routing_id" groups="mrp.group_mrp_routings"/>
<separator/>
@@ -357,7 +357,7 @@
<t t-name="kanban-box">
<div t-attf-class="oe_kanban_card oe_kanban_global_click">
<div class="oe_kanban_content">
<div class="o_kanban_record_top">
<div class="o_kanban_record_top mb16">
<strong class="o_kanban_record_headings">
<span><t t-esc="record.production_id.value"/></span> - <span><t t-esc="record.name.value"/></span>
</strong>
@@ -367,7 +367,7 @@
</div>
<div class="o_kanban_record_bottom">
<div class="oe_kanban_bottom_left">
<span><t t-esc="record.product_id.value"/></span> <span><t t-esc="record.qty_production.value"/> <t t-esc="record.product_uom_id.value"/></span>
<span><t t-esc="record.product_id.value"/>, </span> <span><t t-esc="record.qty_production.value"/> <t t-esc="record.product_uom_id.value"/></span>
</div>
<div class="oe_kanban_bottom_right" t-if="record.state.raw_value == 'progress'">
<span t-if="record.working_state.raw_value != 'blocked' and record.working_user_ids.raw_value.length > 0"><i class="fa fa-play" role="img" aria-label="Run" title="Run"/></span>
@@ -420,7 +420,7 @@
<p class="o_view_nocontent_smiling_face">
Start a new work order
</p><p>
To manufacture or assemble products, and use raw materials and
To manufacture or assemble products, and use components and
finished products you must also handle manufacturing operations.
Manufacturing operations are often called Work Orders. The various
operations will have different impacts on the costs of
@@ -11,7 +11,7 @@
<div class="app_settings_block" data-string="Manufacturing" string="Manufacturing" data-key="mrp" groups="mrp.group_mrp_manager">
<h2>Operations</h2>
<div class="row mt16 o_settings_container">
<div class="col-lg-6 col-12 o_setting_box" id="work_order" title="Work Order Operations allow you to create and manage the manufacturing operations that should be followed within your work centers in order to produce a product. They are attached to bills of materials that will define the required raw materials.">
<div class="col-lg-6 col-12 o_setting_box" id="work_order" title="Work Order Operations allow you to create and manage the manufacturing operations that should be followed within your work centers in order to produce a product. They are attached to bills of materials that will define the required components.">
<div class="o_setting_left_pane">
<field name="group_mrp_routings"/>
<field name="module_mrp_workorder" invisible="1"/>
@@ -620,10 +620,10 @@
<group>
<group string="Vendor">
<field name="product_variant_count" invisible="1"/>
<field name="product_id" groups="product.group_product_variant" domain="[('product_tmpl_id', '=', product_tmpl_id)]" options="{'no_create_edit': True}"/>
<field name="name" context="{'default_customer': 0, 'search_default_supplier': 1, 'default_supplier': 1}"/>
<field name="product_name"/>
<field name="product_code"/>
<field name="product_id" groups="product.group_product_variant" domain="[('product_tmpl_id', '=', product_tmpl_id)]" options="{'no_create_edit': True}"/>
<label for="delay"/>
<div>
<field name="delay" class="oe_inline"/> days
@@ -458,7 +458,6 @@ def action_show_details(self):
checked on the picking type.
"""
self.ensure_one()

# If "show suggestions" is not checked on the picking type, we have to filter out the
# reserved move lines. We do this by displaying `move_line_nosuggest_ids`. We use
# different views to display one field or another so that the webclient doesn't have to
@@ -485,7 +484,7 @@ def action_show_details(self):
show_source_location=self.location_id.child_ids and self.picking_type_id.code != 'incoming',
show_destination_location=self.location_dest_id.child_ids and self.picking_type_id.code != 'outgoing',
show_package=not self.location_id.usage == 'supplier',
show_reserved_quantity=self.state != 'done' and not self.picking_id.immediate_transfer
show_reserved_quantity=self.state != 'done' and not self.picking_id.immediate_transfer and self.picking_type_id.code != 'incoming'
),
}

@@ -42,6 +42,7 @@ class StockMoveLine(models.Model):
location_id = fields.Many2one('stock.location', 'From', required=True)
location_dest_id = fields.Many2one('stock.location', 'To', required=True)
lots_visible = fields.Boolean(compute='_compute_lots_visible')
picking_code = fields.Selection(related='picking_id.picking_type_id.code', readonly=True)
picking_type_use_create_lots = fields.Boolean(related='picking_id.picking_type_id.use_create_lots', readonly=True)
picking_type_use_existing_lots = fields.Boolean(related='picking_id.picking_type_id.use_existing_lots', readonly=True)
state = fields.Selection(related='move_id.state', store=True, related_sudo=False, readonly=False)
@@ -185,7 +185,7 @@
<field name="model">stock.move.line</field>
<field name="priority">1000</field>
<field name="arch" type="xml">
<tree editable="bottom" decoration-muted="state == 'done' and is_locked == True" decoration-success="product_uom_qty==qty_done" decoration-danger="qty_done &gt; product_uom_qty and state != 'done'">
<tree editable="bottom" decoration-muted="state == 'done' and is_locked == True" decoration-success="product_uom_qty==qty_done" decoration-danger="qty_done &gt; product_uom_qty and state != 'done' and picking_code != 'incoming'">
<field name="picking_id" invisible="1"/>
<field name="product_id" invisible="1"/>
<field name="package_level_id" invisible="1"/>
@@ -200,6 +200,7 @@
<field name="product_uom_qty" invisible="not context.get('show_reserved_quantity')" readonly="1"/>
<field name="state" invisible="1"/>
<field name="is_locked" invisible="1"/>
<field name="picking_code" invisible="1"/>
<field name="qty_done" attrs="{'readonly': ['|', '|', ('is_initial_demand_editable', '=', True), '&amp;', ('state', '=', 'done'), ('is_locked', '=', True), '&amp;', ('package_level_id', '!=', False), ('parent.picking_type_entire_packs', '=', True)]}"/>
<field name="product_uom_id" options="{'no_open': True, 'no_create': True}" attrs="{'readonly': ['|', ('product_uom_qty', '!=', 0.0), '&amp;', ('package_level_id', '!=', False), ('parent.picking_type_entire_packs', '=', True)]}" string="Unit of Measure" groups="uom.group_uom"/>
</tree>
@@ -269,7 +269,7 @@
<notebook>
<page string="Detailed Operations" attrs="{'invisible': [('show_operations', '=', False)]}">
<field name="move_line_ids_without_package" attrs="{'readonly': ['|', '|', ('show_operations', '=', False), ('state', '=', 'cancel'), '&amp;', ('state', '=', 'done'), ('is_locked', '=', True)]}" context="{'default_picking_id': id, 'default_location_id': location_id, 'default_location_dest_id': location_dest_id}">
<tree editable="bottom" decoration-muted="(state == 'done' and is_locked == True)" decoration-danger="qty_done&gt;product_uom_qty and state!='done'" decoration-success="qty_done==product_uom_qty and state!='done' and not result_package_id">
<tree editable="bottom" decoration-muted="(state == 'done' and is_locked == True)" decoration-danger="qty_done&gt;product_uom_qty and state!='done' and parent.picking_type_code != 'incoming'" decoration-success="qty_done==product_uom_qty and state!='done' and not result_package_id">
<field name="product_id" required="1" attrs="{'readonly': ['|', ('state', '=', 'done'), ('move_id', '!=', False)]}"/>
<field name="move_id" invisible="1"/>
<field name="product_uom_id" force_save="1" attrs="{'readonly': [('state', '!=', 'draft')]}" groups="uom.group_uom"/>
@@ -283,7 +283,7 @@
<field name="lot_id" groups="stock.group_production_lot" attrs="{'column_invisible': [('parent.show_lots_text', '=', True)], 'invisible': [('lots_visible', '=', False)]}" domain="[('product_id', '=', product_id)]" context="{'default_product_id': product_id}"/>
<field name="lot_name" groups="stock.group_production_lot" attrs="{'column_invisible': [('parent.show_lots_text', '=', False)], 'invisible': [('lots_visible', '=', False)]}" context="{'default_product_id': product_id}"/>
<field name="is_initial_demand_editable" invisible="1"/>
<field name="product_uom_qty" readonly="1" attrs="{'column_invisible': [('parent.immediate_transfer', '=', True)]}"/>
<field name="product_uom_qty" readonly="1" attrs="{'column_invisible': ['|',('parent.immediate_transfer', '=', True),('parent.picking_type_code','=','incoming')]}"/>
<field name="is_locked" invisible="1"/>
<field name="qty_done" attrs="{'readonly': [('state', 'in', ('done', 'cancel')), ('is_locked', '=', True)]}" force_save="1"/>
</tree>

0 comments on commit 5a00250

Please sign in to comment.
You can’t perform that action at this time.