mirror of
https://github.com/OCA/stock-logistics-warehouse.git
synced 2025-01-21 14:27:28 +02:00
@@ -0,0 +1 @@
|
||||
../../../../stock_picking_completion_info
|
||||
6
setup/stock_picking_completion_info/setup.py
Normal file
6
setup/stock_picking_completion_info/setup.py
Normal file
@@ -0,0 +1,6 @@
|
||||
import setuptools
|
||||
|
||||
setuptools.setup(
|
||||
setup_requires=['setuptools-odoo'],
|
||||
odoo_addon=True,
|
||||
)
|
||||
@@ -10,17 +10,12 @@ class StockMove(models.Model):
|
||||
common_dest_move_ids = fields.Many2many(
|
||||
"stock.move",
|
||||
compute="_compute_common_dest_move_ids",
|
||||
search="_search_compute_dest_move_ids",
|
||||
help="All the stock moves having a chained destination move sharing the"
|
||||
" same picking as the actual move's destination move",
|
||||
)
|
||||
|
||||
@api.depends(
|
||||
"move_dest_ids",
|
||||
"move_dest_ids.picking_id",
|
||||
"move_dest_ids.picking_id.move_lines",
|
||||
"move_dest_ids.picking_id.move_lines.move_orig_ids",
|
||||
)
|
||||
def _compute_common_dest_move_ids(self):
|
||||
def _common_dest_move_query(self):
|
||||
sql = """SELECT smmr.move_orig_id move_id
|
||||
, array_agg(smmr2.move_orig_id) common_move_dest_ids
|
||||
FROM stock_move_move_rel smmr
|
||||
@@ -36,6 +31,16 @@ class StockMove(models.Model):
|
||||
AND smmr.move_orig_id IN %s
|
||||
GROUP BY smmr.move_orig_id;
|
||||
"""
|
||||
return sql
|
||||
|
||||
@api.depends(
|
||||
"move_dest_ids",
|
||||
"move_dest_ids.picking_id",
|
||||
"move_dest_ids.picking_id.move_lines",
|
||||
"move_dest_ids.picking_id.move_lines.move_orig_ids",
|
||||
)
|
||||
def _compute_common_dest_move_ids(self):
|
||||
sql = self._common_dest_move_query()
|
||||
self.env.cr.execute(sql, (tuple(self.ids),))
|
||||
res = {
|
||||
row.get("move_id"): row.get("common_move_dest_ids")
|
||||
@@ -47,3 +52,16 @@ class StockMove(models.Model):
|
||||
move.common_dest_move_ids = [(6, 0, common_move_ids)]
|
||||
else:
|
||||
move.common_dest_move_ids = [(5, 0, 0)]
|
||||
|
||||
def _search_compute_dest_move_ids(self, operator, value):
|
||||
moves = self.search([("id", operator, value)])
|
||||
if not moves:
|
||||
return [("id", "=", 0)]
|
||||
sql = self._common_dest_move_query()
|
||||
self.env.cr.execute(sql, (tuple(moves.ids),))
|
||||
res = [
|
||||
move_dest_id
|
||||
for row in self.env.cr.dictfetchall()
|
||||
for move_dest_id in row.get("common_move_dest_ids") or []
|
||||
]
|
||||
return [("id", "in", res)]
|
||||
|
||||
@@ -154,3 +154,21 @@ class TestCommonMoveDest(SavepointCase):
|
||||
self.assertEqual(pack_move_1b.common_dest_move_ids, pack_move_1a)
|
||||
self.assertFalse(ship_move_1a.common_dest_move_ids)
|
||||
self.assertFalse(ship_move_1b.common_dest_move_ids)
|
||||
self.assertEqual(
|
||||
self.env["stock.move"].search(
|
||||
[("common_dest_move_ids", "=", pick_move_1b.id)]
|
||||
),
|
||||
pick_move_1a,
|
||||
)
|
||||
self.assertEqual(
|
||||
self.env["stock.move"].search(
|
||||
[("common_dest_move_ids", "=", pick_move_1a.id)]
|
||||
),
|
||||
pick_move_1b,
|
||||
)
|
||||
self.assertEqual(
|
||||
self.env["stock.move"].search(
|
||||
[("common_dest_move_ids", "in", (pick_move_1a | pick_move_1b).ids)]
|
||||
),
|
||||
pick_move_1a | pick_move_1b,
|
||||
)
|
||||
|
||||
1
stock_picking_completion_info/__init__.py
Normal file
1
stock_picking_completion_info/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from . import models
|
||||
17
stock_picking_completion_info/__manifest__.py
Normal file
17
stock_picking_completion_info/__manifest__.py
Normal file
@@ -0,0 +1,17 @@
|
||||
# Copyright 2019 Camptocamp SA
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl)
|
||||
{
|
||||
"name": "Stock Picking Completion Info",
|
||||
"summary": "Display on current document completion information according "
|
||||
"to next operations",
|
||||
"version": "13.0.1.0.0",
|
||||
"development_status": "Alpha",
|
||||
"category": "Warehouse Management",
|
||||
"website": "https://github.com/OCA/stock-logistics-warehouse",
|
||||
"author": "Camptocamp, Odoo Community Association (OCA)",
|
||||
"license": "AGPL-3",
|
||||
"application": False,
|
||||
"installable": True,
|
||||
"depends": ["stock_move_common_dest"],
|
||||
"data": ["views/stock_picking.xml"],
|
||||
}
|
||||
1
stock_picking_completion_info/models/__init__.py
Normal file
1
stock_picking_completion_info/models/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from . import stock_picking
|
||||
86
stock_picking_completion_info/models/stock_picking.py
Normal file
86
stock_picking_completion_info/models/stock_picking.py
Normal file
@@ -0,0 +1,86 @@
|
||||
# Copyright 2019 Camptocamp SA
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl)
|
||||
from odoo import api, fields, models
|
||||
|
||||
|
||||
class PickingType(models.Model):
|
||||
|
||||
_inherit = "stock.picking.type"
|
||||
|
||||
display_completion_info = fields.Boolean(
|
||||
help="Inform operator of a completed operation at processing and at"
|
||||
" completion"
|
||||
)
|
||||
|
||||
|
||||
class StockPicking(models.Model):
|
||||
|
||||
_inherit = "stock.picking"
|
||||
|
||||
completion_info = fields.Selection(
|
||||
[
|
||||
("no", "No"),
|
||||
(
|
||||
"last_picking",
|
||||
"Last picking: Completion of this operation allows next "
|
||||
"operations to be processed.",
|
||||
),
|
||||
("next_picking_ready", "Next operations are ready to be processed."),
|
||||
(
|
||||
"full_order_picking",
|
||||
"Full order picking: You are processing a full order picking "
|
||||
"that will allow next operation to be processed",
|
||||
),
|
||||
],
|
||||
compute="_compute_completion_info",
|
||||
)
|
||||
|
||||
@api.depends(
|
||||
"picking_type_id.display_completion_info",
|
||||
"move_lines.common_dest_move_ids.state",
|
||||
)
|
||||
def _compute_completion_info(self):
|
||||
for picking in self:
|
||||
if (
|
||||
picking.state == "draft"
|
||||
or not picking.picking_type_id.display_completion_info
|
||||
):
|
||||
picking.completion_info = "no"
|
||||
continue
|
||||
# Depending moves are all the origin moves linked to the
|
||||
# destination pickings' moves
|
||||
depending_moves = picking.move_lines.mapped("common_dest_move_ids")
|
||||
# If all the depending moves are done or canceled then next picking
|
||||
# is ready to be processed
|
||||
if picking.state == "done" and all(
|
||||
m.state in ("done", "cancel") for m in depending_moves
|
||||
):
|
||||
picking.completion_info = "next_picking_ready"
|
||||
continue
|
||||
# If all the depending moves are the moves on the actual picking
|
||||
# then it's a full order and next picking is ready to be processed
|
||||
if depending_moves == picking.move_lines:
|
||||
picking.completion_info = "full_order_picking"
|
||||
continue
|
||||
# If there aren't any depending move from another picking that is
|
||||
# not done, then actual picking is the last to process
|
||||
other_depending_moves = (depending_moves - picking.move_lines).filtered(
|
||||
lambda m: m.state not in ("done", "cancel")
|
||||
)
|
||||
if not other_depending_moves:
|
||||
picking.completion_info = "last_picking"
|
||||
continue
|
||||
picking.completion_info = "no"
|
||||
|
||||
|
||||
class StockMove(models.Model):
|
||||
|
||||
_inherit = "stock.move"
|
||||
|
||||
def write(self, vals):
|
||||
super().write(vals)
|
||||
if "state" in vals:
|
||||
# invalidate cache, the api.depends do not allow to find all
|
||||
# the conditions to invalidate the field
|
||||
self.env["stock.picking"].invalidate_cache(fnames=["completion_info"])
|
||||
return True
|
||||
1
stock_picking_completion_info/readme/CONTRIBUTORS.rst
Normal file
1
stock_picking_completion_info/readme/CONTRIBUTORS.rst
Normal file
@@ -0,0 +1 @@
|
||||
* Akim Juillerat <akim.juillerat@camptocamp.com>
|
||||
9
stock_picking_completion_info/readme/DESCRIPTION.rst
Normal file
9
stock_picking_completion_info/readme/DESCRIPTION.rst
Normal file
@@ -0,0 +1,9 @@
|
||||
This module adds completion information on stock picking.
|
||||
|
||||
If activated on the picking type, completion information is computed according
|
||||
to the next chained pickings related to the stock moves of the actual picking.
|
||||
|
||||
In other words, if all the previous moves linked to the destination pickings
|
||||
moves are done, the completion of the actual picking allows the destination
|
||||
pickings to be processed. In such case, a ribbon will appear on the stock
|
||||
picking form view, to inform the stock operator.
|
||||
1
stock_picking_completion_info/tests/__init__.py
Normal file
1
stock_picking_completion_info/tests/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from . import test_stock_picking_completion_info
|
||||
@@ -0,0 +1,285 @@
|
||||
# Copyright 2019 Camptocamp SA
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl)
|
||||
from odoo.tests import SavepointCase
|
||||
|
||||
|
||||
class TestStockPickingCompletionInfo(SavepointCase):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super().setUpClass()
|
||||
cls.env = cls.env(context=dict(cls.env.context, tracking_disable=True))
|
||||
cls.partner_delta = cls.env.ref("base.res_partner_4")
|
||||
cls.warehouse = cls.env.ref("stock.warehouse0")
|
||||
cls.warehouse.write({"delivery_steps": "pick_pack_ship"})
|
||||
cls.customers_location = cls.env.ref("stock.stock_location_customers")
|
||||
cls.output_location = cls.env.ref("stock.stock_location_output")
|
||||
cls.packing_location = cls.env.ref("stock.location_pack_zone")
|
||||
cls.stock_shelf_location = cls.env.ref("stock.stock_location_components")
|
||||
cls.stock_shelf_2_location = cls.env.ref("stock.stock_location_14")
|
||||
|
||||
cls.out_type = cls.warehouse.out_type_id
|
||||
cls.pack_type = cls.warehouse.pack_type_id
|
||||
cls.pick_type = cls.warehouse.pick_type_id
|
||||
cls.pick_type.write({"display_completion_info": True})
|
||||
|
||||
cls.product_1 = cls.env["product.product"].create(
|
||||
{"name": "Product 1", "type": "product"}
|
||||
)
|
||||
cls.product_2 = cls.env["product.product"].create(
|
||||
{"name": "Product 2", "type": "product"}
|
||||
)
|
||||
|
||||
def _init_inventory(self, same_location=True):
|
||||
# Product 1 on shelf 1
|
||||
# Product 2 on shelf 2
|
||||
inventory = self.env["stock.inventory"].create({"name": "Test init"})
|
||||
inventory.action_start()
|
||||
if not same_location:
|
||||
product_location_list = [
|
||||
(self.product_1, self.stock_shelf_location),
|
||||
(self.product_2, self.stock_shelf_2_location),
|
||||
]
|
||||
else:
|
||||
product_location_list = [
|
||||
(self.product_1, self.stock_shelf_location),
|
||||
(self.product_2, self.stock_shelf_location),
|
||||
]
|
||||
lines_vals = list()
|
||||
for product, location in product_location_list:
|
||||
lines_vals.append(
|
||||
(
|
||||
0,
|
||||
0,
|
||||
{
|
||||
"product_id": product.id,
|
||||
"product_uom_id": product.uom_id.id,
|
||||
"product_qty": 10.0,
|
||||
"location_id": location.id,
|
||||
},
|
||||
)
|
||||
)
|
||||
inventory.write({"line_ids": lines_vals})
|
||||
inventory.action_validate()
|
||||
|
||||
def _create_pickings(self, same_pick_location=True):
|
||||
# Create delivery order
|
||||
ship_order = self.env["stock.picking"].create(
|
||||
{
|
||||
"partner_id": self.partner_delta.id,
|
||||
"location_id": self.output_location.id,
|
||||
"location_dest_id": self.customers_location.id,
|
||||
"picking_type_id": self.out_type.id,
|
||||
}
|
||||
)
|
||||
pack_order = self.env["stock.picking"].create(
|
||||
{
|
||||
"partner_id": self.partner_delta.id,
|
||||
"location_id": self.packing_location.id,
|
||||
"location_dest_id": self.output_location.id,
|
||||
"picking_type_id": self.pack_type.id,
|
||||
}
|
||||
)
|
||||
pick_order = self.env["stock.picking"].create(
|
||||
{
|
||||
"partner_id": self.partner_delta.id,
|
||||
"location_id": self.stock_shelf_location.id,
|
||||
"location_dest_id": self.packing_location.id,
|
||||
"picking_type_id": self.pick_type.id,
|
||||
}
|
||||
)
|
||||
if same_pick_location:
|
||||
return ship_order, pack_order, pick_order
|
||||
pick_order_2 = self.env["stock.picking"].create(
|
||||
{
|
||||
"partner_id": self.partner_delta.id,
|
||||
"location_id": self.stock_shelf_2_location.id,
|
||||
"location_dest_id": self.packing_location.id,
|
||||
"picking_type_id": self.pick_type.id,
|
||||
}
|
||||
)
|
||||
return ship_order, pack_order, pick_order, pick_order_2
|
||||
|
||||
def _create_move(
|
||||
self,
|
||||
picking,
|
||||
product,
|
||||
state="waiting",
|
||||
procure_method="make_to_order",
|
||||
move_dest=None,
|
||||
):
|
||||
move_vals = {
|
||||
"name": product.name,
|
||||
"product_id": product.id,
|
||||
"product_uom_qty": 2.0,
|
||||
"product_uom": product.uom_id.id,
|
||||
"picking_id": picking.id,
|
||||
"location_id": picking.location_id.id,
|
||||
"location_dest_id": picking.location_dest_id.id,
|
||||
"state": state,
|
||||
"procure_method": procure_method,
|
||||
}
|
||||
if move_dest:
|
||||
move_vals["move_dest_ids"] = [(4, move_dest.id, False)]
|
||||
return self.env["stock.move"].create(move_vals)
|
||||
|
||||
def test_picking_all_at_once(self):
|
||||
self._init_inventory()
|
||||
ship_order, pack_order, pick_order = self._create_pickings()
|
||||
ship_move_1 = self._create_move(ship_order, self.product_1)
|
||||
pack_move_1 = self._create_move(
|
||||
pack_order, self.product_1, move_dest=ship_move_1
|
||||
)
|
||||
pick_move_1 = self._create_move(
|
||||
pick_order,
|
||||
self.product_1,
|
||||
state="confirmed",
|
||||
procure_method="make_to_stock",
|
||||
move_dest=pack_move_1,
|
||||
)
|
||||
ship_move_2 = self._create_move(ship_order, self.product_2)
|
||||
pack_move_2 = self._create_move(
|
||||
pack_order, self.product_2, move_dest=ship_move_2
|
||||
)
|
||||
pick_move_2 = self._create_move(
|
||||
pick_order,
|
||||
self.product_2,
|
||||
state="confirmed",
|
||||
procure_method="make_to_stock",
|
||||
move_dest=pack_move_2,
|
||||
)
|
||||
self.assertEqual(pick_move_1.state, "confirmed")
|
||||
self.assertEqual(pick_move_2.state, "confirmed")
|
||||
self.assertEqual(pick_order.state, "confirmed")
|
||||
self.assertEqual(pick_order.completion_info, "full_order_picking")
|
||||
pick_order.action_assign()
|
||||
self.assertEqual(pick_move_1.state, "assigned")
|
||||
self.assertEqual(pick_move_2.state, "assigned")
|
||||
self.assertEqual(pick_order.state, "assigned")
|
||||
self.assertEqual(pick_order.completion_info, "full_order_picking")
|
||||
wiz = self.env["stock.immediate.transfer"].create(
|
||||
{"pick_ids": [(4, pick_order.id)]}
|
||||
)
|
||||
wiz.process()
|
||||
self.assertEqual(pick_move_1.state, "done")
|
||||
self.assertEqual(pick_move_2.state, "done")
|
||||
self.assertEqual(pick_order.state, "done")
|
||||
self.assertEqual(pick_order.completion_info, "next_picking_ready")
|
||||
|
||||
def test_picking_from_different_locations(self):
|
||||
self._init_inventory(same_location=False)
|
||||
ship_order, pack_order, pick_order_1, pick_order_2 = self._create_pickings(
|
||||
same_pick_location=False
|
||||
)
|
||||
ship_move_1 = self._create_move(ship_order, self.product_1)
|
||||
pack_move_1 = self._create_move(
|
||||
pack_order, self.product_1, move_dest=ship_move_1
|
||||
)
|
||||
pick_move_1 = self._create_move(
|
||||
pick_order_1,
|
||||
self.product_1,
|
||||
state="confirmed",
|
||||
procure_method="make_to_stock",
|
||||
move_dest=pack_move_1,
|
||||
)
|
||||
ship_move_2 = self._create_move(ship_order, self.product_2)
|
||||
pack_move_2 = self._create_move(
|
||||
pack_order, self.product_2, move_dest=ship_move_2
|
||||
)
|
||||
pick_move_2 = self._create_move(
|
||||
pick_order_2,
|
||||
self.product_2,
|
||||
state="confirmed",
|
||||
procure_method="make_to_stock",
|
||||
move_dest=pack_move_2,
|
||||
)
|
||||
self.assertEqual(pick_move_1.state, "confirmed")
|
||||
self.assertEqual(pick_move_2.state, "confirmed")
|
||||
self.assertEqual(pick_order_1.state, "confirmed")
|
||||
self.assertEqual(pick_order_1.completion_info, "no")
|
||||
self.assertEqual(pick_order_2.state, "confirmed")
|
||||
self.assertEqual(pick_order_2.completion_info, "no")
|
||||
pick_order_1.action_assign()
|
||||
self.assertEqual(pick_move_1.state, "assigned")
|
||||
self.assertEqual(pick_order_1.state, "assigned")
|
||||
self.assertEqual(pick_order_1.completion_info, "no")
|
||||
pick_order_2.action_assign()
|
||||
self.assertEqual(pick_move_2.state, "assigned")
|
||||
self.assertEqual(pick_order_2.state, "assigned")
|
||||
self.assertEqual(pick_order_2.completion_info, "no")
|
||||
wiz = self.env["stock.immediate.transfer"].create(
|
||||
{"pick_ids": [(4, pick_order_1.id)]}
|
||||
)
|
||||
wiz.process()
|
||||
self.assertEqual(pick_move_1.state, "done")
|
||||
self.assertEqual(pick_order_1.state, "done")
|
||||
self.assertEqual(pick_order_1.completion_info, "no")
|
||||
self.assertNotEqual(pick_move_2.state, "done")
|
||||
self.assertNotEqual(pick_order_2.state, "done")
|
||||
self.assertEqual(pick_order_2.completion_info, "last_picking")
|
||||
wiz = self.env["stock.immediate.transfer"].create(
|
||||
{"pick_ids": [(4, pick_order_2.id)]}
|
||||
)
|
||||
wiz.process()
|
||||
self.assertEqual(pick_move_2.state, "done")
|
||||
self.assertEqual(pick_order_2.state, "done")
|
||||
self.assertEqual(pick_order_2.completion_info, "next_picking_ready")
|
||||
self.assertEqual(pick_order_1.completion_info, "next_picking_ready")
|
||||
|
||||
def test_picking_with_backorder(self):
|
||||
self._init_inventory()
|
||||
ship_order, pack_order, pick_order = self._create_pickings()
|
||||
ship_move_1 = self._create_move(ship_order, self.product_1)
|
||||
pack_move_1 = self._create_move(
|
||||
pack_order, self.product_1, move_dest=ship_move_1
|
||||
)
|
||||
pick_move_1 = self._create_move(
|
||||
pick_order,
|
||||
self.product_1,
|
||||
state="confirmed",
|
||||
procure_method="make_to_stock",
|
||||
move_dest=pack_move_1,
|
||||
)
|
||||
ship_move_2 = self._create_move(ship_order, self.product_2)
|
||||
pack_move_2 = self._create_move(
|
||||
pack_order, self.product_2, move_dest=ship_move_2
|
||||
)
|
||||
pick_move_2 = self._create_move(
|
||||
pick_order,
|
||||
self.product_2,
|
||||
state="confirmed",
|
||||
procure_method="make_to_stock",
|
||||
move_dest=pack_move_2,
|
||||
)
|
||||
self.assertEqual(pick_move_1.state, "confirmed")
|
||||
self.assertEqual(pick_move_2.state, "confirmed")
|
||||
self.assertEqual(pick_order.state, "confirmed")
|
||||
self.assertEqual(pick_order.completion_info, "full_order_picking")
|
||||
pick_order.action_assign()
|
||||
self.assertEqual(pick_move_1.state, "assigned")
|
||||
self.assertEqual(pick_move_2.state, "assigned")
|
||||
self.assertEqual(pick_order.state, "assigned")
|
||||
self.assertEqual(pick_order.completion_info, "full_order_picking")
|
||||
# Process partially to create backorder
|
||||
pick_move_1.move_line_ids.qty_done = 1.0
|
||||
pick_move_2.move_line_ids.qty_done = pick_move_2.move_line_ids.product_uom_qty
|
||||
pick_order.action_done()
|
||||
pick_backorder = self.env["stock.picking"].search(
|
||||
[("backorder_id", "=", pick_order.id)]
|
||||
)
|
||||
pick_backorder_move = pick_backorder.move_lines
|
||||
self.assertEqual(pick_move_1.state, "done")
|
||||
self.assertEqual(pick_move_2.state, "done")
|
||||
self.assertEqual(pick_order.state, "done")
|
||||
self.assertEqual(pick_backorder_move.state, "assigned")
|
||||
self.assertEqual(pick_backorder.state, "assigned")
|
||||
self.assertEqual(pick_order.completion_info, "no")
|
||||
self.assertEqual(pick_backorder.completion_info, "last_picking")
|
||||
# Process backorder
|
||||
pick_backorder_move.move_line_ids.qty_done = (
|
||||
pick_backorder_move.move_line_ids.product_uom_qty
|
||||
)
|
||||
pick_backorder.action_done()
|
||||
self.assertEqual(pick_backorder_move.state, "done")
|
||||
self.assertEqual(pick_backorder.state, "done")
|
||||
self.assertEqual(pick_order.completion_info, "next_picking_ready")
|
||||
self.assertEqual(pick_backorder.completion_info, "next_picking_ready")
|
||||
44
stock_picking_completion_info/views/stock_picking.xml
Normal file
44
stock_picking_completion_info/views/stock_picking.xml
Normal file
@@ -0,0 +1,44 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<odoo>
|
||||
<record id="view_picking_type_form_inherit" model="ir.ui.view">
|
||||
<field name="name">Operation Types inherit</field>
|
||||
<field name="inherit_id" ref="stock.view_picking_type_form" />
|
||||
<field name="model">stock.picking.type</field>
|
||||
<field name="arch" type="xml">
|
||||
<field name="show_reserved" position="after">
|
||||
<field name="display_completion_info" />
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
<record id="view_picking_form_inherit" model="ir.ui.view">
|
||||
<field name="name">stock.picking.form.inherit</field>
|
||||
<field name="inherit_id" ref="stock.view_picking_form" />
|
||||
<field name="model">stock.picking</field>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//h1" position="after">
|
||||
<label for="completion_info" invisible="1" />
|
||||
<div
|
||||
class="alert alert-success"
|
||||
attrs="{'invisible': [('completion_info', '!=', 'next_picking_ready')]}"
|
||||
role="alert"
|
||||
>
|
||||
<field name="completion_info" nolabel="1" />
|
||||
</div>
|
||||
<div
|
||||
class="alert alert-warning"
|
||||
attrs="{'invisible': [('completion_info', '!=', 'last_picking')]}"
|
||||
role="alert"
|
||||
>
|
||||
<field name="completion_info" nolabel="1" />
|
||||
</div>
|
||||
<div
|
||||
class="alert alert-primary"
|
||||
attrs="{'invisible': [('completion_info', '!=', 'full_order_picking')]}"
|
||||
role="alert"
|
||||
>
|
||||
<field name="completion_info" nolabel="1" />
|
||||
</div>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
</odoo>
|
||||
Reference in New Issue
Block a user