[REF] stock: views refactoring
We adapted the views to the new stock model, and differenciate two different views: - The first one is more adapted for simple operations, or when no suggestion of location, lot, pack is needed. We have a line with the initial demand of each product and you can complete the lot numer, location, etc in the detailed window of a move. - The second one is more adapted for pick and barcode operations, all each line is fully detailed with the system reservation, you can see the lot, location, etc you must scan in the list view. You can choose the view you want to use in the picking type settings by check the box 'Show Operations'
This commit is contained in:
committed by
Simon Lejeune
parent
0469d2e712
commit
5d25900cd8
@@ -50,7 +50,7 @@ class StockMove(models.Model):
|
||||
digits=0, store=True,
|
||||
help='Quantity in the default UoM of the product')
|
||||
product_uom_qty = fields.Float(
|
||||
'Quantity',
|
||||
'Initial Demand',
|
||||
digits=dp.get_precision('Product Unit of Measure'),
|
||||
default=1.0, required=True, states={'done': [('readonly', True)]},
|
||||
help="This is the quantity of products from an inventory "
|
||||
@@ -121,10 +121,6 @@ class StockMove(models.Model):
|
||||
"its current stock) to gather products. If we want to chain moves and have this one to wait for the previous,"
|
||||
"this second option should be chosen.")
|
||||
scrapped = fields.Boolean('Scrapped', related='location_dest_id.scrap_location', readonly=True, store=True)
|
||||
remaining_qty = fields.Float(
|
||||
'Remaining Quantity', compute='_get_remaining_qty',
|
||||
digits=0, states={'done': [('readonly', True)]},
|
||||
help="Remaining Quantity in default UoM according to operations matched with this move")
|
||||
procurement_id = fields.Many2one('procurement.order', 'Procurement')
|
||||
group_id = fields.Many2one('procurement.group', 'Procurement Group', default=_default_group_id)
|
||||
rule_id = fields.Many2one('procurement.rule', 'Procurement Rule', ondelete='restrict', help='The procurement rule that created this stock move')
|
||||
@@ -135,10 +131,12 @@ class StockMove(models.Model):
|
||||
picking_type_id = fields.Many2one('stock.picking.type', 'Operation Type')
|
||||
inventory_id = fields.Many2one('stock.inventory', 'Inventory')
|
||||
pack_operation_ids = fields.One2many('stock.pack.operation', 'move_id')
|
||||
pack_operation_nosuggest_ids = fields.One2many('stock.pack.operation', 'move_id', domain=[('product_qty', '=', 0.0)])
|
||||
origin_returned_move_id = fields.Many2one('stock.move', 'Origin return move', copy=False, help='Move that created the return move')
|
||||
returned_move_ids = fields.One2many('stock.move', 'origin_returned_move_id', 'All returned moves', help='Optional: all returned moves created from this move')
|
||||
reserved_availability = fields.Float(
|
||||
'Quantity Reserved', compute='_compute_reserved_availability',
|
||||
digits=dp.get_precision('Product Unit of Measure'),
|
||||
readonly=True, help='Quantity that has already been reserved for this move')
|
||||
availability = fields.Float(
|
||||
'Forecasted Quantity', compute='_compute_product_availability',
|
||||
@@ -151,7 +149,63 @@ class StockMove(models.Model):
|
||||
route_ids = fields.Many2many('stock.location.route', 'stock_location_route_move', 'move_id', 'route_id', 'Destination route', help="Preferred route to be followed by the procurement order")
|
||||
warehouse_id = fields.Many2one('stock.warehouse', 'Warehouse', help="Technical field depicting the warehouse to consider for the route selection on the next procurement (if any).")
|
||||
has_tracking = fields.Selection(related='product_id.tracking', string='Product with Tracking')
|
||||
quantity_done = fields.Float('Quantity', compute='_qty_done_compute', digits=dp.get_precision('Product Unit of Measure'))
|
||||
quantity_done = fields.Float('Quantity Done', compute='_quantity_done_compute', digits=dp.get_precision('Product Unit of Measure'), inverse='_quantity_done_set',
|
||||
states={'done': [('readonly', True)]})
|
||||
show_operations = fields.Boolean(related='picking_id.picking_type_id.show_operations')
|
||||
show_details_visible = fields.Boolean('Details Visible', compute='_compute_show_details_visible')
|
||||
show_reserved_availability = fields.Boolean('From Supplier', compute='_compute_show_reserved_availability')
|
||||
picking_code = fields.Selection(related='picking_id.picking_type_id.code', readonly=True)
|
||||
product_type = fields.Selection(related='product_id.type', readonly=True)
|
||||
additional = fields.Boolean("Whether the move was added after the picking's confirmation", default=False)
|
||||
is_editable = fields.Boolean('Is editable when done', compute='_compute_is_editable')
|
||||
is_initial_demand_editable = fields.Boolean('Is initial demand editable', compute='_compute_is_initial_demand_editable')
|
||||
|
||||
@api.multi
|
||||
@api.depends('has_tracking', 'pack_operation_ids', 'location_id', 'location_dest_id', 'is_editable')
|
||||
def _compute_show_details_visible(self):
|
||||
""" According to this field, the button that calls `action_show_details` will be displayed
|
||||
to work on a move from its picking form view, or not.
|
||||
"""
|
||||
for move in self:
|
||||
if not move.product_id:
|
||||
move.show_details_visible = False
|
||||
continue
|
||||
|
||||
if move.is_editable:
|
||||
move.show_details_visible = True
|
||||
continue
|
||||
|
||||
multi_locations_enabled = False
|
||||
if self.user_has_groups('stock.group_stock_multi_locations'):
|
||||
multi_locations_enabled = move.location_id.child_ids or move.location_dest_id.child_ids
|
||||
|
||||
if move.picking_id.picking_type_id.show_operations is False\
|
||||
and move.state not in ['cancel', 'draft', 'confirmed']\
|
||||
and (multi_locations_enabled or move.has_tracking != 'none' or len(move.pack_operation_ids) > 1):
|
||||
move.show_details_visible = True
|
||||
else:
|
||||
move.show_details_visible = False
|
||||
|
||||
@api.multi
|
||||
def _compute_show_reserved_availability(self):
|
||||
""" This field is only of use in an attrs in the picking view, in order to hide the
|
||||
"available" column if the move is coming from a supplier.
|
||||
"""
|
||||
for move in self:
|
||||
move.show_reserved_availability = not move.location_id.usage == 'supplier'
|
||||
|
||||
@api.multi
|
||||
def _compute_is_editable(self):
|
||||
""" This field is only of use in an attrs in the picking view, in order to show
|
||||
the button to edit move when they're done.
|
||||
"""
|
||||
for move in self:
|
||||
move.is_editable = move.state == 'done' and self.user_has_groups('stock.group_stock_manager')
|
||||
|
||||
@api.multi
|
||||
def _compute_is_initial_demand_editable(self):
|
||||
for move in self:
|
||||
move.is_initial_demand_editable = move.state not in ['done', 'cancel'] and self.user_has_groups('stock.group_stock_manager')
|
||||
|
||||
@api.one
|
||||
@api.depends('product_id', 'product_uom', 'product_uom_qty')
|
||||
@@ -194,11 +248,6 @@ class StockMove(models.Model):
|
||||
detect errors. """
|
||||
raise UserError(_('The requested operation cannot be processed because of a programming error setting the `product_qty` field instead of the `product_uom_qty`.'))
|
||||
|
||||
@api.one
|
||||
def _get_remaining_qty(self):
|
||||
# TODO: sle jco
|
||||
pass
|
||||
|
||||
|
||||
@api.one
|
||||
@api.depends('pack_operation_ids.product_qty')
|
||||
@@ -258,6 +307,20 @@ class StockMove(models.Model):
|
||||
if not self._cr.fetchone():
|
||||
self._cr.execute('CREATE INDEX stock_move_product_location_index ON stock_move (product_id, location_id, location_dest_id, company_id, state)')
|
||||
|
||||
@api.model
|
||||
def default_get(self, fields_list):
|
||||
# We override the default_get to make stock moves created after the picking was confirmed
|
||||
# directly as available (like a force_assign). This allows to create extra move lines in
|
||||
# the fp view.
|
||||
defaults = super(StockMove, self).default_get(fields_list)
|
||||
if self.env.context.get('default_picking_id'):
|
||||
picking_id = self.env['stock.picking'].browse(self.env.context['default_picking_id'])
|
||||
if picking_id.state not in ['draft', 'confirmed']:
|
||||
defaults['state'] = 'assigned'
|
||||
defaults['product_uom_qty'] = 0.0
|
||||
defaults['additional'] = True
|
||||
return defaults
|
||||
|
||||
@api.multi
|
||||
def name_get(self):
|
||||
res = []
|
||||
@@ -387,10 +450,6 @@ class StockMove(models.Model):
|
||||
forgot some of them, use this tool instead. """
|
||||
return self.filtered(lambda move: move.state not in ('done', 'cancel'))
|
||||
|
||||
|
||||
# Main actions
|
||||
# ------------------------------------------------------------
|
||||
|
||||
@api.multi
|
||||
def do_unreserve(self):
|
||||
if any(move.state in ('done', 'cancel') for move in self):
|
||||
@@ -443,7 +502,8 @@ class StockMove(models.Model):
|
||||
product = self.product_id.with_context(lang=self.partner_id.lang or self.env.user.lang)
|
||||
self.name = product.partner_ref
|
||||
self.product_uom = product.uom_id.id
|
||||
self.product_uom_qty = 1.0
|
||||
if self.product_uom_qty:
|
||||
self.product_uom_qty = 1.0
|
||||
return {'domain': {'product_uom': [('category_id', '=', product.uom_id.category_id.id)]}}
|
||||
|
||||
@api.onchange('date')
|
||||
@@ -945,4 +1005,3 @@ class StockMove(models.Model):
|
||||
'target': 'new',
|
||||
'res_id': self.id}
|
||||
show_picking = action_show_picking
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ from odoo.tools.float_utils import float_round, float_compare, float_is_zero
|
||||
|
||||
|
||||
class PackOperation(models.Model):
|
||||
_name = "stock.pack.operation"
|
||||
_name = "stock.pack.operation" #TODO: change to stock.move.operation
|
||||
_description = "Packing Operation"
|
||||
_order = "result_package_id desc, id"
|
||||
|
||||
@@ -30,11 +30,12 @@ class PackOperation(models.Model):
|
||||
ordered_qty = fields.Float('Ordered Quantity', digits=dp.get_precision('Product Unit of Measure'))
|
||||
qty_done = fields.Float('Done', default=0.0, digits=dp.get_precision('Product Unit of Measure'), copy=False)
|
||||
package_id = fields.Many2one('stock.quant.package', 'Source Package')
|
||||
lot_id = fields.Many2one('stock.production.lot', 'Lot')
|
||||
lot_name = fields.Char('Lot/Serial Number')
|
||||
result_package_id = fields.Many2one(
|
||||
'stock.quant.package', 'Destination Package',
|
||||
ondelete='cascade', required=False,
|
||||
help="If set, the operations are packed into this package")
|
||||
lot_id = fields.Many2one('stock.production.lot', 'Lot')
|
||||
date = fields.Datetime('Date', default=fields.Datetime.now(), required=True)
|
||||
owner_id = fields.Many2one('res.partner', 'Owner', help="Owner of the quants")
|
||||
location_id = fields.Many2one('stock.location', 'From', required=True)
|
||||
@@ -54,9 +55,10 @@ class PackOperation(models.Model):
|
||||
operation.to_loc = '%s%s' % (operation_sudo.location_dest_id.name, operation_sudo.result_package_id.name or '')
|
||||
|
||||
@api.one
|
||||
@api.depends('picking_id.picking_type_id', 'product_id.tracking')
|
||||
def _compute_lots_visible(self):
|
||||
if self.picking_id.picking_type_id and self.product_id.tracking != 'none': # TDE FIXME: not sure correctly migrated
|
||||
picking = self.picking_id
|
||||
picking = self.picking_id
|
||||
if picking.picking_type_id and self.product_id.tracking != 'none': # TDE FIXME: not sure correctly migrated
|
||||
self.lots_visible = picking.picking_type_id.use_existing_lots or picking.picking_type_id.use_create_lots
|
||||
else:
|
||||
self.lots_visible = self.product_id.tracking != 'none'
|
||||
|
||||
@@ -40,6 +40,10 @@ class PickingType(models.Model):
|
||||
use_existing_lots = fields.Boolean(
|
||||
'Use Existing Lots/Serial Numbers', default=True,
|
||||
help="If this is checked, you will be able to choose the Lots/Serial Numbers. You can also decide to not put lots in this operation type. This means it will create stock with no lot or not put a restriction on the lot taken. ")
|
||||
show_operations = fields.Boolean(
|
||||
'Show Operations', default=False)
|
||||
show_reserved = fields.Boolean(
|
||||
'Show Reserved', default=True)
|
||||
|
||||
# Statistics for the kanban view
|
||||
last_done_picking = fields.Char('Last 10 Done Pickings', compute='_compute_last_done_picking')
|
||||
@@ -263,7 +267,7 @@ class Picking(models.Model):
|
||||
states={'done': [('readonly', True)], 'cancel': [('readonly', True)]})
|
||||
|
||||
pack_operation_ids = fields.One2many(
|
||||
'stock.pack.operation', 'picking_id', 'Related Packing Operations',
|
||||
'stock.pack.operation', 'picking_id', 'Operations',
|
||||
states={'done': [('readonly', True)], 'cancel': [('readonly', True)]})
|
||||
|
||||
pack_operation_exist = fields.Boolean(
|
||||
@@ -296,7 +300,6 @@ class Picking(models.Model):
|
||||
- one of the move is assigned or partially available: partially available
|
||||
- otherwise in waiting or confirmed state
|
||||
'''
|
||||
# FIXME: goes in 3 times at each write?
|
||||
if not self.move_lines:
|
||||
self.state = 'draft'
|
||||
elif any(move.state == 'draft' for move in self.move_lines): # TDE FIXME: should be all ?
|
||||
@@ -514,7 +517,6 @@ class Picking(models.Model):
|
||||
# 'picking_id': pick.id
|
||||
# }) # Might change first element
|
||||
# # Link existing moves or add moves when no one is related
|
||||
|
||||
for ops in pick.pack_operation_ids.filtered(lambda x: not x.move_id):
|
||||
# Search move with this product
|
||||
moves = pick.move_lines.filtered(lambda x: x.product_id == ops.product_id)
|
||||
|
||||
@@ -131,12 +131,94 @@
|
||||
<field name="availability" invisible="1"/>
|
||||
<field name="reserved_availability" invisible="1"/>
|
||||
<field name="location_dest_id" invisible="1"/>
|
||||
<field name="remaining_qty" invisible="1"/>
|
||||
<field name="state"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_stock_move_operations" model="ir.ui.view">
|
||||
<field name="name">stock.move.operations.form</field>
|
||||
<field name="model">stock.move</field>
|
||||
<field name="priority">1000</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Move Detail">
|
||||
<field name="state" invisible="1"/>
|
||||
<field name="location_id" invisible="1"/>
|
||||
<field name="location_dest_id" invisible="1"/>
|
||||
<field name="picking_id" invisible="1"/>
|
||||
<field name="is_editable" invisible="1"/>
|
||||
<group>
|
||||
<group>
|
||||
<field name="product_id" readonly="1"/>
|
||||
<label for="product_uom_qty"/>
|
||||
<div class="o_row">
|
||||
<span><field name="product_uom_qty" readonly="1" nolabel="1"/></span>
|
||||
<span><field name="product_uom" readonly="1" nolabel="1"/></span>
|
||||
</div>
|
||||
<label for="quantity_done"/>
|
||||
<div class="o_row">
|
||||
<span><field name="quantity_done" readonly="1" nolabel="1"/></span>
|
||||
<span> / </span>
|
||||
<span><field name="reserved_availability" nolabel="1"/></span>
|
||||
<span><field name="product_uom" readonly="1" nolabel="1"/></span>
|
||||
</div>
|
||||
|
||||
</group>
|
||||
</group>
|
||||
<field name="pack_operation_ids" attrs="{'readonly': ['&', ('state', 'in', ('done', 'cancel')), ('is_editable', '=', False)]}" context="{'default_product_uom_id': product_uom, 'default_picking_id': picking_id, 'default_move_id': id, 'default_product_id': product_id, 'default_location_id': location_id, 'default_location_dest_id': location_dest_id}">
|
||||
<tree editable="bottom" decoration-succes="product_uom_qty==qty_done" decoration-danger="qty_done > product_uom_qty)">
|
||||
<field name="picking_id" invisible="1"/>
|
||||
<field name="product_id" invisible="1"/>
|
||||
<field name="location_id" invisible="not context.get('show_source_location')" domain="[('id', 'child_of', parent.location_id)])" groups="stock.group_stock_multi_locations"/>
|
||||
<field name="location_dest_id" invisible="not context.get('show_destination_location')" domain="[('id', 'child_of', parent.location_dest_id)]" groups="stock.group_stock_multi_locations"/>
|
||||
<field name="lot_id" invisible="not context.get('show_lots_m2o')" domain="[('product_id', '=', parent.product_id)]" groups="stock.group_production_lot" context="{'default_product_id': parent.product_id}"/>
|
||||
<field name="lot_name" invisible="not context.get('show_lots_text')" groups="stock.group_production_lot"/>
|
||||
<field name="package_id" invisible="not context.get('show_package')" groups="stock.group_tracking_lot"/>
|
||||
<field name="result_package_id" groups="stock.group_tracking_lot"/>
|
||||
<field name="product_uom_qty" readonly="1"/>
|
||||
<field name="qty_done"/>
|
||||
<field name="product_uom_id" options="{'no_open': True, 'no_create': True}" attrs="{'readonly': [('product_uom_qty', '!=', 0.0)]}" string="Unit of Measure" groups="product.group_uom"/>
|
||||
</tree>
|
||||
</field>
|
||||
<footer class="oe_edit_only">
|
||||
<button string="Confirm" special="save" class="oe_highlight"/>
|
||||
<button string="Discard" special="cancel"/>
|
||||
</footer>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_stock_move_nosuggest_operations" model="ir.ui.view">
|
||||
<field name="name">stock.move.operations.nosuggest.form</field>
|
||||
<field name="model">stock.move</field>
|
||||
<field name="priority">1000</field>
|
||||
<field name="mode">primary</field>
|
||||
<field name="inherit_id" ref="stock.view_stock_move_operations"/>
|
||||
<field name="arch" type="xml">
|
||||
<field name="pack_operation_ids" position="before">
|
||||
<field name="quantity_done" readonly="1"/>
|
||||
<field name="product_uom_qty" readonly="1"/>
|
||||
</field>
|
||||
<field name="pack_operation_ids" position="replace">
|
||||
<field name="pack_operation_nosuggest_ids" attrs="{'readonly': [('state', 'in', ('done', 'cancel'))]}" context="{'default_picking_id': picking_id, 'default_move_id': id, 'default_product_id': product_id, 'default_location_id': location_id, 'default_location_dest_id': location_dest_id}">
|
||||
<tree editable="bottom" decoration-succes="product_uom_qty==qty_done" decoration-danger="(product_uom_qty > 0) and (qty_done>product_uom_qty)">
|
||||
<field name="location_id" invisible="context.get('hide_source')" domain="[('id', 'child_of', parent.location_id)])" groups="stock.group_stock_multi_locations"/>
|
||||
<field name="package_id" groups="stock.group_tracking_lot" invisible="context.get('from_supplier')"/>
|
||||
<field name="lot_id" domain="[('product_id', '=', parent.product_id)]" invisible="context.get('show_lots_inv', True)" context="{'default_product_id': parent.product_id}"/>
|
||||
<field name="lot_name" invisible="context.get('show_lots_name_inv', True)"/>
|
||||
<field name="product_uom_qty" invisible="1"/>
|
||||
<field name="location_dest_id" invisible="context.get('hide_dest')" domain="[('id', 'child_of', parent.location_dest_id)]" groups="stock.group_stock_multi_locations"/>
|
||||
<field name="qty_done"/>
|
||||
<field name="product_uom_id" options="{'no_open': True, 'no_create': True}" attrs="{'readonly': [('product_uom_qty', '!=', 0.0)]}" string="Unit of Measure" groups="product.group_uom"/>
|
||||
<field name="result_package_id" groups="stock.group_tracking_lot"/>
|
||||
<field name="picking_id" invisible="1"/>
|
||||
<field name="product_id" invisible="1"/>
|
||||
</tree>
|
||||
</field>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_move_form" model="ir.ui.view">
|
||||
<field name="name">stock.move.form</field>
|
||||
<field name="model">stock.move</field>
|
||||
@@ -183,6 +265,9 @@
|
||||
<group name="quants_grp" string="Reserved Quants" colspan="2" groups="base.group_no_one" attrs="{'invisible': [('state', '=', 'done')]}">
|
||||
<field name="string_availability_info"/>
|
||||
</group>
|
||||
<group name="moved_quants_grp" string="Moved Quants" colspan="4" groups="base.group_no_one" attrs="{'invisible': [('state', '!=', 'done')]}">
|
||||
<!--<field name="quant_ids" readonly="1" nolabel="1"/>-->
|
||||
</group>
|
||||
</group>
|
||||
</sheet>
|
||||
</form>
|
||||
@@ -227,6 +312,9 @@
|
||||
<group name="quants_grp" string="Reserved" attrs="{'invisible': [('state', '=', 'draft')]}">
|
||||
<field name="string_availability_info"/>
|
||||
</group>
|
||||
<group name="moved_quants_grp" string="Moved Quants" colspan="4" groups="base.group_no_one" attrs="{'invisible': [('state', '!=', 'done')]}">
|
||||
<!--<field name="quant_ids" readonly="1" nolabel="1"/>-->
|
||||
</group>
|
||||
</group>
|
||||
</form>
|
||||
</field>
|
||||
|
||||
@@ -46,6 +46,8 @@
|
||||
<field name="code"/>
|
||||
<field attrs='{"invisible": [("code", "not in", ["incoming", "outgoing", "internal"])]}' name="return_picking_type_id"/>
|
||||
<field attrs='{"invisible": [("code", "not in", ["incoming", "outgoing", "internal"])]}' name="barcode_nomenclature_id" groups="base.group_no_one"/>
|
||||
<field name="show_operations"/>
|
||||
<field name="show_reserved"/>
|
||||
</group>
|
||||
</group>
|
||||
<group>
|
||||
@@ -209,12 +211,13 @@
|
||||
<button name="%(action_report_delivery)d" string="Print" states="done" type="action" groups="base.group_user"/>
|
||||
<button name="%(act_stock_return_picking)d" string="Return" states="done" type="action" groups="base.group_user"/>
|
||||
<button name="action_cancel" states="assigned,confirmed,partially_available,draft,waiting" string="Cancel" groups="base.group_user" type="object"/>
|
||||
<button name="do_unreserve" string="Unreserve" groups="base.group_user" type="object" attrs="{'invisible': ['|', ('state', 'not in', ('assigned', 'partially_available')), ('location_id', 'in', ('supplier', 'inventory', 'production'))]}"/>
|
||||
<!--<button name="do_prepare_partial" attrs="{'invisible': ['|', ('launch_pack_operations', '=', True), '|', ('state', 'not in', ('assigned', 'partially_available')), ('pack_operation_ids', '!=', [])]}"-->
|
||||
<!--string="Reset Operations" type="object"/>-->
|
||||
<!--<field name="launch_pack_operations" invisible="1"/>-->
|
||||
<button name="button_scrap" type="object" string="Scrap" attrs="{'invisible': ['|', ('state', 'in', ('draft', 'cancel')), '&', ('picking_type_code', '=', 'incoming'), ('state', '!=', 'done')]}"/>
|
||||
<field name="picking_type_code" invisible="1"/>
|
||||
<button name="do_unreserve" string="Unreserve" groups="base.group_user" type="object" attrs="{'invisible': ['|', ('picking_type_code', '=', 'incoming'), ('state', 'not in', ('assigned', 'partially_available'))]}"/>
|
||||
<field name="show_operations" invisible="1"/>
|
||||
<field name="pack_operation_exist" invisible="1"/>
|
||||
<button name="button_scrap" type="object" string="Scrap" attrs="{'invisible': ['|', '&', ('picking_type_code', '!=', 'incoming'), ('state', 'in', ('draft', 'cancel', 'waiting')), '&', ('picking_type_code', '=', 'incoming'), ('state', '!=', 'done')]}"/>
|
||||
<field name="state" widget="statusbar" statusbar_visible="draft,confirmed,partially_available,assigned,done" />
|
||||
<field name="picking_type_entire_packs" invisible="1"/>
|
||||
</header>
|
||||
<sheet>
|
||||
<div class="oe_button_box" name="button_box">
|
||||
@@ -236,68 +239,35 @@
|
||||
<group>
|
||||
<field name="min_date"/>
|
||||
<field name="origin" placeholder="e.g. PO0032" class="oe_inline"/>
|
||||
<label for="owner_id" groups="stock.group_tracking_owner"/>
|
||||
<!--<label for="owner_id" groups="stock.group_tracking_owner"/>-->
|
||||
<div groups="stock.group_tracking_owner">
|
||||
<field name="owner_id"/>
|
||||
<!--<field name="owner_id"/>-->
|
||||
<button name="action_assign_owner" string="Assign Owner" type="object" attrs="{'invisible': ['|',('pack_operation_exist', '=', False),('state', 'not in', ('draft','assigned','confirmed'))]}"
|
||||
class="oe_link oe_edit_only"/>
|
||||
</div>
|
||||
</group>
|
||||
</group>
|
||||
<notebook>
|
||||
<page string="Operations" attrs="{'invisible': [('state', 'in', ('draft', 'confirmed', 'waiting'))]}">
|
||||
<button name="do_prepare_partial" type="object" string="Recompute" attrs="{'invisible': [('recompute_pack_op','=', False)]}"/>
|
||||
<field name="recompute_pack_op" invisible="1"/>
|
||||
<field name="pack_operation_ids" options="{'reload_on_button': True}" context="{'default_picking_id': id, 'default_location_id': location_id, 'default_location_dest_id': location_dest_id}" mode="tree,kanban">
|
||||
<tree editable="bottom">
|
||||
<page string="Detailed Operations" attrs="{'invisible': ['|', '&', ('show_operations', '=', True), ('state', '=', 'draft'), ('show_operations', '=', False)]}">
|
||||
<field name="pack_operation_ids" context="{'default_picking_id': id, 'default_location_id': location_id, 'default_location_dest_id': location_dest_id}">
|
||||
<tree editable="bottom" decoration-muted="result_package_id" decoration-danger="qty_done>product_uom_qty" decoration-success="qty_done==product_uom_qty and state!='done' and not result_package_id">
|
||||
<field name="product_id" required="1"/>
|
||||
<field name="product_uom_id" attrs="{'readonly': [('state', '!=', 'draft')]}" groups="product.group_uom"/>
|
||||
<field name="from_loc" groups="stock.group_stock_multi_locations,stock.group_tracking_lot"/>
|
||||
<field name="to_loc" groups="stock.group_stock_multi_locations,stock.group_tracking_lot"/>
|
||||
<field name="state" invisible="1"/>
|
||||
<field name="product_qty" readonly="1" attrs="{'required': [('product_id', '!=', False)]}"/>
|
||||
<field name="qty_done"/>
|
||||
<button name="action_split_lots" string="Lot Split" type="object" icon="fa-list" groups="stock.group_production_lot"
|
||||
attrs="{'invisible': ['|', ('state', 'not in', ['confirmed', 'assigned', 'waiting', 'partially_available','done'])]}"/>
|
||||
<button name="show_details" string="Modify" type="object" icon="fa-pencil" groups="stock.group_stock_multi_locations"
|
||||
states="confirmed,assigned,waiting,partially_available"/>
|
||||
</tree>
|
||||
<kanban class="o_kanban_mobile">
|
||||
<field name="product_id" required="1" attrs="{'readonly': [('fresh_record', '=', False)]}"/>
|
||||
<field name="fresh_record" invisible="1"/>
|
||||
<field name="product_uom_id" attrs="{'readonly': [('fresh_record', '=', False)]}" groups="product.group_uom"/>
|
||||
<field name="owner_id" groups="stock.group_tracking_owner"/>
|
||||
<field name="package_id" groups="stock.group_tracking_lot" invisible="1"/>
|
||||
<field name="location_id" domain="[('id', 'child_of', parent.location_id)]" invisible="1"/>
|
||||
<field name="location_dest_id" domain="[('id', 'child_of', parent.location_dest_id)]" invisible="1"/>
|
||||
<field name="from_loc" groups="stock.group_stock_multi_locations,stock.group_tracking_lot"/>
|
||||
<field name="to_loc" groups="stock.group_stock_multi_locations,stock.group_tracking_lot"/>
|
||||
<field name="result_package_id" readonly="1" groups="stock.group_tracking_lot" context="{'default_location_id': location_dest_id}" invisible="1"/>
|
||||
<field name="lots_visible" invisible="1"/>
|
||||
<field name="owner_id" groups="stock.group_tracking_owner"/>
|
||||
<field name="state" invisible="1"/>
|
||||
<field name="product_qty" readonly="1" attrs="{'required': [('product_id', '!=', False)]}"/>
|
||||
<field name="lot_id" attrs="{'invisible': [('lots_visible', '=', False)]}" domain="[('product_id', '=', product_id)]" context="{'default_product_id': product_id}"/>
|
||||
<field name="product_uom_qty" readonly="1" attrs="{'required': [('product_id', '!=', False)]}"/>
|
||||
<field name="qty_done"/>
|
||||
<templates>
|
||||
<t t-name="kanban-box">
|
||||
<div>
|
||||
<div class="row">
|
||||
<div class="col-xs-12">
|
||||
<strong><span><t t-esc="record.product_id.value"/></span></strong>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-xs-12 text-muted">
|
||||
<span><t t-esc="record.from_loc.value"/> to <t t-esc="record.to_loc.value"/></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-xs-12 text-muted">
|
||||
<span><t t-esc="record.qty_done.value"/> of <t t-esc="record.product_qty.value"/> <t t-esc="record.product_uom_id.value"/></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
</templates>
|
||||
</kanban>
|
||||
<button name="show_details" string="Modify" type="object" icon="fa-pencil" groups="stock.group_stock_multi_locations" states="confirmed,assigned,waiting,partially_available"/>
|
||||
</tree>
|
||||
</field>
|
||||
<field name="picking_type_entire_packs" invisible="1"/>
|
||||
<button class="oe_link oe_right" name="put_in_pack" type="object" string="↳Put in Pack" attrs="{'invisible': [('state', 'in', ('done', 'cancel'))]}" groups="stock.group_tracking_lot"/>
|
||||
</page>
|
||||
<page string="Operations">
|
||||
@@ -318,15 +288,15 @@
|
||||
<field name="additional" invisible="1"/>
|
||||
|
||||
<field name="product_id" required="1" attrs="{'readonly': ['&', ('state', '!=', 'draft'), ('additional', '=', False)]}"/>
|
||||
<field name="product_uom_qty" string="Initial Demand" attrs="{'readonly': [('state', '!=', 'draft')]}"/>
|
||||
<field name="is_initial_demand_editable" invisible="1"/>
|
||||
<field name="product_uom_qty" string="Initial Demand" attrs="{'readonly': [('is_initial_demand_editable', '=', False), ('state', '!=', 'draft')]}"/>
|
||||
<field name="product_uom" attrs="{'readonly': [('state', '!=', 'draft')]}" options="{'no_open': True, 'no_create': True}" string="Unit of Measure" groups="product.group_uom"/>
|
||||
<field name="reserved_availability" string="Reserved"/>
|
||||
<field name="quantity_done" string="Done" attrs="{'readonly': [('show_details_visible', '=', True)], 'invisible': ['|', ('state', 'in', ['draft', 'confirmed', 'waiting']), ('show_operations', '=', True)]}"/>
|
||||
<button name="action_show_details" string="Register lots, packs, location" type="object" icon="fa-list" attrs="{'invisible': [('show_details_visible', '=', False)]}"/>
|
||||
</tree>
|
||||
</field>
|
||||
<field name="pack_operation_exist" invisible="1"/>
|
||||
<field name="note" placeholder="Add an internal note that will be printed on the Picking Operations sheet" class="oe_inline"/>
|
||||
<button class="oe_link oe_right" name="put_in_pack" type="object" string="↳Put in Pack" attrs="{'invisible': [('state', 'in', ('done', 'cancel'))]}" groups="stock.group_tracking_lot"/>
|
||||
</page>
|
||||
<page string="Additional Info" name="extra">
|
||||
<group>
|
||||
@@ -759,7 +729,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
|
||||
</templates>
|
||||
</kanban>
|
||||
</field>
|
||||
|
||||
Reference in New Issue
Block a user