summaryrefslogtreecommitdiff
path: root/addons
diff options
context:
space:
mode:
authorSimon Lejeune <sle@openerp.com>2019-10-21 12:42:58 +0000
committersvs-odoo <svs@odoo.com>2020-01-31 12:40:08 +0000
commit2b314aad5c7dff0ac9dc1b89cb9e9becaec14e1f (patch)
treeacca40dfc4678fd242cb63d3c3f23712627a4b0a /addons
parent2105895bb609c871e10acae7fd813b8ccb7c8b24 (diff)
[IMP] stock_picking_batch: display moves and move lines
* allow to directly edit the move lines of the batched transfers * add a check availability button if any move is not assigned yet task-2069646
Diffstat (limited to 'addons')
-rw-r--r--addons/stock_picking_batch/data/stock_picking_batch_demo.xml2
-rw-r--r--addons/stock_picking_batch/models/stock_picking.py17
-rw-r--r--addons/stock_picking_batch/models/stock_picking_batch.py139
-rw-r--r--addons/stock_picking_batch/tests/test_batch_picking.py58
-rw-r--r--addons/stock_picking_batch/views/stock_picking_batch_views.xml133
5 files changed, 292 insertions, 57 deletions
diff --git a/addons/stock_picking_batch/data/stock_picking_batch_demo.xml b/addons/stock_picking_batch/data/stock_picking_batch_demo.xml
index b4f00288029..69c8edf0e76 100644
--- a/addons/stock_picking_batch/data/stock_picking_batch_demo.xml
+++ b/addons/stock_picking_batch/data/stock_picking_batch_demo.xml
@@ -4,10 +4,12 @@
<!-- Add batch picking -->
<record id="stock_picking_batch_dry_1" model="stock.picking.batch">
<field name="state">in_progress</field>
+ <field name="picking_type_id" ref="stock.picking_type_internal"/>
<field name="company_id" ref="base.main_company"/>
</record>
<record id="stock_picking_batch_freeze_1" model="stock.picking.batch">
<field name="state">in_progress</field>
+ <field name="picking_type_id" ref="stock.picking_type_internal"/>
<field name="company_id" ref="base.main_company"/>
</record>
diff --git a/addons/stock_picking_batch/models/stock_picking.py b/addons/stock_picking_batch/models/stock_picking.py
index b7501f41de0..dd8470bee70 100644
--- a/addons/stock_picking_batch/models/stock_picking.py
+++ b/addons/stock_picking_batch/models/stock_picking.py
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
-from odoo import fields, models
+from odoo import api, fields, models
class StockPicking(models.Model):
@@ -13,6 +13,21 @@ class StockPicking(models.Model):
states={'done': [('readonly', True)], 'cancel': [('readonly', True)]},
help='Batch associated to this transfer', copy=False)
+ @api.model
+ def create(self, vals):
+ res = super().create(vals)
+ if vals.get('batch_id'):
+ self.batch_id._sanity_check()
+ return res
+
+ def write(self, vals):
+ res = super().write(vals)
+ if vals.get('batch_id'):
+ if not self.batch_id.picking_type_id:
+ self.batch_id.picking_type_id = self.picking_type_id[0]
+ self.batch_id._sanity_check()
+ return res
+
def _should_show_transfers(self):
if len(self.batch_id) == 1 and self == self.batch_id.picking_ids:
return False
diff --git a/addons/stock_picking_batch/models/stock_picking_batch.py b/addons/stock_picking_batch/models/stock_picking_batch.py
index 70e4c1b17f2..5e13a4649a9 100644
--- a/addons/stock_picking_batch/models/stock_picking_batch.py
+++ b/addons/stock_picking_batch/models/stock_picking_batch.py
@@ -17,48 +17,134 @@ class StockPickingBatch(models.Model):
help='Name of the batch transfer')
user_id = fields.Many2one(
'res.users', string='Responsible', tracking=True, check_company=True,
+ readonly=True, states={'draft': [('readonly', False)], 'in_progress': [('readonly', False)]},
help='Person responsible for this batch transfer')
company_id = fields.Many2one(
'res.company', string="Company", required=True, readonly=True,
index=True, default=lambda self: self.env.company)
picking_ids = fields.One2many(
- 'stock.picking', 'batch_id', string='Transfers',
- domain="[('company_id', '=', company_id), ('state', 'not in', ('done', 'cancel'))]",
+ 'stock.picking', 'batch_id', string='Transfers', readonly=True,
+ domain="[('id', 'in', allowed_picking_ids)]", check_company=True,
+ states={'draft': [('readonly', False)], 'in_progress': [('readonly', False)]},
help='List of transfers associated to this batch')
+ show_check_availability = fields.Boolean(
+ compute='_compute_move_ids',
+ help='Technical field used to compute whether the check availability button should be shown.')
+ allowed_picking_ids = fields.One2many('stock.picking', compute='_compute_allowed_picking_ids')
+ move_ids = fields.One2many(
+ 'stock.move', string="Stock moves", compute='_compute_move_ids')
+ move_line_ids = fields.One2many(
+ 'stock.move.line', string='Stock move lines',
+ compute='_compute_move_ids', inverse='_set_move_line_ids', readonly=True,
+ states={'draft': [('readonly', False)], 'in_progress': [('readonly', False)]})
state = fields.Selection([
('draft', 'Draft'),
('in_progress', 'In progress'),
('done', 'Done'),
('cancel', 'Cancelled')], default='draft',
copy=False, tracking=True, required=True, readonly=True)
+ picking_type_id = fields.Many2one(
+ 'stock.picking.type', 'Operation Type', check_company=True, copy=False,
+ readonly=True, states={'draft': [('readonly', False)]})
+ @api.depends('company_id', 'picking_type_id', 'state')
+ def _compute_allowed_picking_ids(self):
+ allowed_picking_states = ['waiting', 'confirmed', 'assigned']
+ cancelled_batchs = self.env['stock.picking.batch'].search_read(
+ [('state', '=', 'cancel')], ['id']
+ )
+ cancelled_batch_ids = [batch['id'] for batch in cancelled_batchs]
+
+ for batch in self:
+ domain_states = list(allowed_picking_states)
+ # Allows to add draft pickings only if batch is in draft as well.
+ if batch.state == 'draft':
+ domain_states.append('draft')
+ domain = [
+ ('company_id', '=', batch.company_id.id),
+ ('immediate_transfer', '=', False),
+ ('state', 'in', domain_states),
+ '|',
+ '|',
+ ('batch_id', '=', False),
+ ('batch_id', '=', batch.id),
+ ('batch_id', 'in', cancelled_batch_ids),
+ ]
+ if batch.picking_type_id:
+ domain += [('picking_type_id', '=', batch.picking_type_id.id)]
+ batch.allowed_picking_ids = self.env['stock.picking'].search(domain)
+
+ @api.depends('picking_ids', 'picking_ids.move_line_ids', 'picking_ids.move_lines', 'picking_ids.move_lines.state')
+ def _compute_move_ids(self):
+ for batch in self:
+ batch.move_ids = batch.picking_ids.move_lines
+ batch.move_line_ids = batch.picking_ids.move_line_ids
+ batch.show_check_availability = any(m.state != 'assigned' for m in batch.move_ids)
+
+
+ def _set_move_line_ids(self):
+ new_move_lines = self[0].move_line_ids
+ for picking in self.picking_ids:
+ old_move_lines = picking.move_line_ids
+ picking.move_line_ids = new_move_lines.filtered(lambda ml: ml.picking_id.id == picking.id)
+ move_lines_to_unlink = old_move_lines - new_move_lines
+ if move_lines_to_unlink:
+ move_lines_to_unlink.unlink()
+
+ # -------------------------------------------------------------------------
+ # CRUD
+ # -------------------------------------------------------------------------
@api.model
def create(self, vals):
if vals.get('name', '/') == '/':
vals['name'] = self.env['ir.sequence'].next_by_code('picking.batch') or '/'
- return super(StockPickingBatch, self).create(vals)
+ return super().create(vals)
+
+ def write(self, vals):
+ res = super().write(vals)
+ if vals.get('picking_type_id'):
+ self._sanity_check()
+ if vals.get('picking_ids'):
+ batch_without_picking_type = self.filtered(lambda batch: not batch.picking_type_id)
+ if batch_without_picking_type:
+ picking = self.picking_ids and self.picking_ids[0]
+ batch_without_picking_type.picking_type_id = picking.picking_type_id.id
+ return res
- def confirm_picking(self):
+ def unlink(self):
+ if any(batch.state != 'draft' for batch in self):
+ raise UserError(_("You can only delete draft batch transfers."))
+ return super().unlink()
+
+ # -------------------------------------------------------------------------
+ # Action methods
+ # -------------------------------------------------------------------------
+ def action_confirm(self):
+ """Sanity checks, confirm the pickings and mark the batch as confirmed."""
+ self.ensure_one()
+ if not self.picking_ids:
+ raise UserError(_("You have to set some pickings to batch."))
+ self.picking_ids.action_confirm()
self._check_company()
- pickings_todo = self.mapped('picking_ids')
- self.write({'state': 'in_progress'})
- return pickings_todo.action_assign()
-
- def cancel_picking(self):
- self.mapped('picking_ids').action_cancel()
- return self.write({'state': 'cancel'})
-
- def print_picking(self):
- pickings = self.mapped('picking_ids')
- if not pickings:
- raise UserError(_('Nothing to print.'))
+ self.state = 'in_progress'
+ return True
+
+ def action_cancel(self):
+ self.ensure_one()
+ self.state = 'cancel'
+ return True
+
+ def action_print(self):
+ self.ensure_one()
return self.env.ref('stock_picking_batch.action_report_picking_batch').report_action(self)
- def done(self):
+ def action_done(self):
+ self.ensure_one()
self._check_company()
pickings = self.mapped('picking_ids').filtered(lambda picking: picking.state not in ('cancel', 'done'))
if any(picking.state not in ('assigned') for picking in pickings):
raise UserError(_('Some transfers are still waiting for goods. Please check or force their availability before setting this batch to done.'))
+
for picking in pickings:
picking.message_post(
body="<b>%s:</b> %s <a href=#id=%s&view_type=form&model=stock.picking.batch>%s</a>" % (
@@ -70,8 +156,25 @@ class StockPickingBatch(models.Model):
self.write({'state': 'done'})
return self.picking_ids.button_validate()
+ def action_assign(self):
+ self.ensure_one()
+ self.picking_ids.action_assign()
+
+ # -------------------------------------------------------------------------
+ # Miscellaneous
+ # -------------------------------------------------------------------------
+ def _sanity_check(self):
+ for batch in self:
+ if not batch.picking_ids <= batch.allowed_picking_ids:
+ erroneous_pickings = batch.picking_ids - batch.allowed_picking_ids
+ raise UserError(_(
+ "The following transfers cannot be added to batch transfer %s. "
+ "Please check their states and operation types, if they aren't immediate " +
+ "transfers or if they're not already part of another batch transfer.\n\n"
+ "Incompatibilities: %s") % (batch.name, ', '.join(erroneous_pickings.mapped('name'))))
+
def _track_subtype(self, init_values):
if 'state' in init_values:
return self.env.ref('stock_picking_batch.mt_batch_state')
- return super(StockPickingBatch, self)._track_subtype(init_values)
+ return super()._track_subtype(init_values)
diff --git a/addons/stock_picking_batch/tests/test_batch_picking.py b/addons/stock_picking_batch/tests/test_batch_picking.py
index 1a41622bb99..f23270e003c 100644
--- a/addons/stock_picking_batch/tests/test_batch_picking.py
+++ b/addons/stock_picking_batch/tests/test_batch_picking.py
@@ -71,14 +71,18 @@ class TestBatchPicking(TransactionCase):
self.env['stock.quant']._update_available_quantity(self.productA, self.stock_location, 10.0)
self.env['stock.quant']._update_available_quantity(self.productB, self.stock_location, 10.0)
- # confirm batch, picking should be assigned
- self.batch.confirm_picking()
- self.assertEqual(self.picking_client_1.state, 'assigned', 'Picking 1 should be reserved')
- self.assertEqual(self.picking_client_2.state, 'assigned', 'Picking 2 should be reserved')
+ # Confirm batch, pickings should not be automatically assigned.
+ self.batch.action_confirm()
+ self.assertEqual(self.picking_client_1.state, 'confirmed', 'Picking 1 should be confirmed')
+ self.assertEqual(self.picking_client_2.state, 'confirmed', 'Picking 2 should be confirmed')
+ # Ask to assign, so pickings should be assigned now.
+ self.batch.action_assign()
+ self.assertEqual(self.picking_client_1.state, 'assigned', 'Picking 1 should be ready')
+ self.assertEqual(self.picking_client_2.state, 'assigned', 'Picking 2 should be ready')
self.picking_client_1.move_lines.quantity_done = 10
self.picking_client_2.move_lines.quantity_done = 10
- self.batch.done()
+ self.batch.action_done()
self.assertEqual(self.picking_client_1.state, 'done', 'Picking 1 should be done')
self.assertEqual(self.picking_client_2.state, 'done', 'Picking 2 should be done')
@@ -98,13 +102,17 @@ class TestBatchPicking(TransactionCase):
self.env['stock.quant']._update_available_quantity(self.productA, self.stock_location, 10.0)
self.env['stock.quant']._update_available_quantity(self.productB, self.stock_location, 10.0)
- # confirm batch, picking should be assigned
- self.batch.confirm_picking()
- self.assertEqual(self.picking_client_1.state, 'assigned', 'Picking 1 should be reserved')
- self.assertEqual(self.picking_client_2.state, 'assigned', 'Picking 2 should be reserved')
+ # Confirm batch, pickings should not be automatically assigned.
+ self.batch.action_confirm()
+ self.assertEqual(self.picking_client_1.state, 'confirmed', 'Picking 1 should be confirmed')
+ self.assertEqual(self.picking_client_2.state, 'confirmed', 'Picking 2 should be confirmed')
+ # Ask to assign, so pickings should be assigned now.
+ self.batch.action_assign()
+ self.assertEqual(self.picking_client_1.state, 'assigned', 'Picking 1 should be ready')
+ self.assertEqual(self.picking_client_2.state, 'assigned', 'Picking 2 should be ready')
# There should be a wizard asking to process picking without quantity done
- immediate_transfer_wizard_dict = self.batch.done()
+ immediate_transfer_wizard_dict = self.batch.action_done()
self.assertTrue(immediate_transfer_wizard_dict)
immediate_transfer_wizard = Form(self.env[(immediate_transfer_wizard_dict.get('res_model'))].with_context(immediate_transfer_wizard_dict['context'])).save()
self.assertEqual(len(immediate_transfer_wizard.pick_ids), 2)
@@ -128,8 +136,12 @@ class TestBatchPicking(TransactionCase):
self.env['stock.quant']._update_available_quantity(self.productA, self.stock_location, 5.0)
self.env['stock.quant']._update_available_quantity(self.productB, self.stock_location, 10.0)
- # confirm batch, picking should be assigned
- self.batch.confirm_picking()
+ # Confirm batch, pickings should not be automatically assigned.
+ self.batch.action_confirm()
+ self.assertEqual(self.picking_client_1.state, 'confirmed', 'Picking 1 should be confirmed')
+ self.assertEqual(self.picking_client_2.state, 'confirmed', 'Picking 2 should be confirmed')
+ # Ask to assign, so pickings should be assigned now.
+ self.batch.action_assign()
self.assertEqual(self.picking_client_1.state, 'assigned', 'Picking 1 should be ready')
self.assertEqual(self.picking_client_2.state, 'assigned', 'Picking 2 should be ready')
@@ -137,7 +149,7 @@ class TestBatchPicking(TransactionCase):
self.picking_client_2.move_lines.quantity_done = 10
# There should be a wizard asking to process picking without quantity done
- back_order_wizard_dict = self.batch.done()
+ back_order_wizard_dict = self.batch.action_done()
self.assertTrue(back_order_wizard_dict)
back_order_wizard = Form(self.env[(back_order_wizard_dict.get('res_model'))].with_context(back_order_wizard_dict['context'])).save()
self.assertEqual(len(back_order_wizard.pick_ids), 1)
@@ -164,13 +176,17 @@ class TestBatchPicking(TransactionCase):
self.env['stock.quant']._update_available_quantity(self.productA, self.stock_location, 5.0)
self.env['stock.quant']._update_available_quantity(self.productB, self.stock_location, 10.0)
- # confirm batch, picking should be assigned
- self.batch.confirm_picking()
+ # Confirm batch, pickings should not be automatically assigned.
+ self.batch.action_confirm()
+ self.assertEqual(self.picking_client_1.state, 'confirmed', 'Picking 1 should be confirmed')
+ self.assertEqual(self.picking_client_2.state, 'confirmed', 'Picking 2 should be confirmed')
+ # Ask to assign, so pickings should be assigned now.
+ self.batch.action_assign()
self.assertEqual(self.picking_client_1.state, 'assigned', 'Picking 1 should be ready')
self.assertEqual(self.picking_client_2.state, 'assigned', 'Picking 2 should be ready')
# There should be a wizard asking to process picking without quantity done
- immediate_transfer_wizard_dict = self.batch.done()
+ immediate_transfer_wizard_dict = self.batch.action_done()
self.assertTrue(immediate_transfer_wizard_dict)
immediate_transfer_wizard = Form(self.env[(immediate_transfer_wizard_dict.get('res_model'))].with_context(immediate_transfer_wizard_dict['context'])).save()
self.assertEqual(len(immediate_transfer_wizard.pick_ids), 2)
@@ -200,14 +216,18 @@ class TestBatchPicking(TransactionCase):
self.env['stock.quant']._update_available_quantity(self.productA, self.stock_location, 5.0)
self.env['stock.quant']._update_available_quantity(self.productB, self.stock_location, 10.0)
- # confirm batch, picking should be assigned
- self.batch.confirm_picking()
+ # Confirm batch, pickings should not be automatically assigned.
+ self.batch.action_confirm()
+ self.assertEqual(self.picking_client_1.state, 'confirmed', 'Picking 1 should be confirmed')
+ self.assertEqual(self.picking_client_2.state, 'confirmed', 'Picking 2 should be confirmed')
+ # Ask to assign, so pickings should be assigned now.
+ self.batch.action_assign()
self.assertEqual(self.picking_client_1.state, 'assigned', 'Picking 1 should be ready')
self.assertEqual(self.picking_client_2.state, 'assigned', 'Picking 2 should be ready')
self.picking_client_1.move_lines.quantity_done = 5
# There should be a wizard asking to process picking without quantity done
- immediate_transfer_wizard_dict = self.batch.done()
+ immediate_transfer_wizard_dict = self.batch.action_done()
self.assertTrue(immediate_transfer_wizard_dict)
immediate_transfer_wizard = Form(self.env[(immediate_transfer_wizard_dict.get('res_model'))].with_context(immediate_transfer_wizard_dict['context'])).save()
self.assertEqual(len(immediate_transfer_wizard.pick_ids), 1)
diff --git a/addons/stock_picking_batch/views/stock_picking_batch_views.xml b/addons/stock_picking_batch/views/stock_picking_batch_views.xml
index a53e19c8c06..b37fd782c9f 100644
--- a/addons/stock_picking_batch/views/stock_picking_batch_views.xml
+++ b/addons/stock_picking_batch/views/stock_picking_batch_views.xml
@@ -1,17 +1,96 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
+ <record id="view_picking_form_inherited" model="ir.ui.view">
+ <field name="name">stock_picking_batch.picking.form</field>
+ <field name="model">stock.picking</field>
+ <field name="inherit_id" ref="stock.view_picking_form"/>
+ <field name="mode">primary</field>
+ <field name="priority" eval="1000"/>
+ <field name="arch" type="xml">
+ <xpath expr="//header" position="replace">
+ <header>
+ <field name="state" widget="statusbar" statusbar_visible="draft,confirmed,partially_available,assigned,done"/>
+ </header>
+ </xpath>
+ </field>
+ </record>
+
+
+ <record id="view_picking_move_tree_inherited" model="ir.ui.view">
+ <field name="name">stock_picking_batch.picking.move.tree</field>
+ <field name="model">stock.move</field>
+ <field name="inherit_id" ref="stock.view_picking_move_tree"/>
+ <field name="mode">primary</field>
+ <field name="priority" eval="1000"/>
+ <field name="arch" type="xml">
+ <xpath expr="//tree" position="attributes">
+ <attribute name="delete">0</attribute>
+ </xpath>
+ <xpath expr="//field[@name='product_id']" position="after">
+ <field name="picking_id" required="1"
+ attrs="{'readonly': [('id', '!=', False)]}"
+ domain="[('id', 'in', parent.picking_ids)]"
+ options="{'no_create_edit': True}"/>
+ </xpath>
+ <xpath expr="//field[@name='quantity_done']" position="attributes">
+ <attribute name="readonly">1</attribute>
+ </xpath>
+ </field>
+ </record>
+
+ <record id="view_move_line_tree" model="ir.ui.view">
+ <field name="name">stock_picking_batch.move.line.tree</field>
+ <field name="model">stock.move.line</field>
+ <field name="arch" type="xml">
+ <tree editable="top" decoration-muted="state == 'cancel'" string="Move Lines" default_order="location_id">
+ <field name="tracking" invisible="1"/>
+ <field name="state" invisible="1"/>
+ <field name="product_id" required="1" attrs="{'readonly': [('id', '!=', False)]}"/>
+ <field name="picking_id" required="1" attrs="{'readonly': [('id', '!=', False)]}"
+ options="{'no_create_edit': True}" domain="[('id', 'in', parent.picking_ids)]"/>
+ <field name="lot_id" groups="stock.group_production_lot" attrs="{'readonly': [('tracking', 'not in', ['lot', 'serial'])]}"/>
+ <field name="location_id"/>
+ <field name="location_dest_id"/>
+ <field name="product_uom_qty" readonly="1"/>
+ <field name="product_uom_id" options="{'no_create': True}"
+ groups="uom.group_uom" readonly="1" force_save="1"/>
+ <field name="qty_done"/>
+ <field name="company_id" groups="base.group_multi_company" force_save="1"/>
+ </tree>
+ </field>
+ </record>
<record id="stock_picking_batch_form" model="ir.ui.view">
<field name="name">stock.picking.batch.form</field>
<field name="model">stock.picking.batch</field>
<field name="arch" type="xml">
<form string="Stock Batch Transfer">
+ <field name="show_check_availability" invisible="1"/>
<header>
- <button name="confirm_picking" states="draft" string="Confirm" type="object" class="oe_highlight"/>
- <button name="print_picking" string="Print" type="object" class="oe_highlight"/>
- <button name="done" states="in_progress" string="Done" type="object" class="oe_highlight"/>
- <button name="cancel_picking" string="Cancel" type="object" states="in_progress"/>
- <field name="state" widget="statusbar" statusbar_visible="in_progress,done"/>
+ <button name="action_confirm" states="draft" string="Confirm" type="object" class="oe_highlight"/>
+ <button name="action_done" string="Validate" type="object" class="oe_highlight"
+ attrs="{'invisible': [
+ '|',
+ ('state', '!=', 'in_progress'),
+ ('show_check_availability', '=', True)]}"/>
+ <button name="action_assign" string="Check Availability" type="object" class="oe_highlight"
+ attrs="{'invisible': [
+ '|',
+ ('state', '!=', 'in_progress'),
+ ('show_check_availability', '=', False)]}"/>
+ <button name="action_done" string="Validate" type="object"
+ attrs="{'invisible': [
+ '|',
+ ('state', '!=', 'in_progress'),
+ ('show_check_availability', '=', False)]}"/>
+ <button name="action_assign" string="Check Availability" type="object"
+ attrs="{'invisible': [
+ '|',
+ ('state', '!=', 'draft'),
+ ('show_check_availability', '=', False)]}"/>
+ <button name="action_print" states="in_progress,done" string="Print" type="object"/>
+ <button name="action_cancel" string="Cancel" type="object" states="in_progress"/>
+ <field name="state" widget="statusbar" statusbar_visible="draft,in_progress,done"/>
</header>
<sheet>
<div class="oe_title">
@@ -20,22 +99,31 @@
<group>
<group>
<field name="user_id"/>
+ <field name="picking_type_id"/>
<field name="company_id" groups="base.group_multi_company" attrs="{'readonly': [('picking_ids', '!=', [])]}" force_save="1"/>
</group>
</group>
- <separator string="Transfers"/>
- <field name="picking_ids" widget="many2many" options="{'not_delete': True}">
- <tree>
- <field name="name"/>
- <field name="scheduled_date"/>
- <field name="location_id"/>
- <field name="backorder_id"/>
- <field name="origin"/>
- <field name="state"/>
- <button name="action_assign" string="Confirm picking" type="object" icon="fa-check text-success" attrs="{'invisible': [('state', 'in', ('done', 'cancel', 'confirmed', 'assigned'))]}"/>
- <button name="action_cancel" string="Cancel picking" type="object" icon="fa-times-circle text-danger" attrs="{'invisible': [('state', 'in', ('done', 'cancel'))]}"/>
- </tree>
- </field>
+ <notebook>
+ <page string="Detailed Operations" attrs="{'invisible': [('state', '=', 'draft')]}">
+ <field name="move_line_ids" context="{'tree_view_ref': 'stock_picking_batch.view_move_line_tree'}"/>
+ </page>
+ <page string="Operations" attrs="{'invisible': [('state', '=', 'draft')]}">
+ <field name="move_ids" context="{'tree_view_ref': 'stock_picking_batch.view_picking_move_tree_inherited'}"/>
+ </page>
+ <page string="Transfers">
+ <field name="allowed_picking_ids" invisible="1"/>
+ <field name="picking_ids" widget="many2many" context="{'form_view_ref': 'stock_picking_batch.view_picking_form_inherited'}">
+ <tree>
+ <field name="name"/>
+ <field name="scheduled_date"/>
+ <field name="location_id"/>
+ <field name="backorder_id"/>
+ <field name="origin"/>
+ <field name="state"/>
+ </tree>
+ </field>
+ </page>
+ </notebook>
</sheet>
<div class="oe_chatter">
<field name="message_follower_ids" widget="mail_followers" groups="base.group_user"/>
@@ -139,7 +227,14 @@
<field name="inherit_id" ref="stock.vpicktree"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='state']" position="before">
- <field name="batch_id" optional="show"/>
+ <field name="batch_id" optional="show"
+ domain="[
+ ('state', 'in', ['draft', 'in_progress']),
+ '|',
+ ('picking_type_id', '=', picking_type_id),
+ ('picking_type_id', '=', False),
+ ]"
+ context="{'default_picking_type_id': picking_type_id}"/>
</xpath>
</field>
</record>