[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
This commit is contained in:
@@ -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>
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 confirm_picking(self):
|
||||
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 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()
|
||||
self.state = 'in_progress'
|
||||
return True
|
||||
|
||||
def cancel_picking(self):
|
||||
self.mapped('picking_ids').action_cancel()
|
||||
return self.write({'state': 'cancel'})
|
||||
def action_cancel(self):
|
||||
self.ensure_one()
|
||||
self.state = 'cancel'
|
||||
return True
|
||||
|
||||
def print_picking(self):
|
||||
pickings = self.mapped('picking_ids')
|
||||
if not pickings:
|
||||
raise UserError(_('Nothing to print.'))
|
||||
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)
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user