stock_location_package_restriction: show violations

Show and search locations that does not respect the restriction.
This commit is contained in:
Jacques-Etienne Baudoux
2024-05-31 16:18:41 +02:00
parent 8bb53050df
commit f2712ab21d
3 changed files with 141 additions and 2 deletions

View File

@@ -4,6 +4,7 @@
from odoo import _, api, fields, models
from odoo.exceptions import ValidationError
from odoo.osv.expression import NEGATIVE_TERM_OPERATORS
NOPACKAGE = "nopackage"
SINGLEPACKAGE = "singlepackage"
@@ -39,6 +40,67 @@ class StockLocation(models.Model):
(SINGLEPACKAGE, "Mandatory and unique"),
]
has_package_restriction_violation = fields.Boolean(
compute="_compute_has_package_restriction_violation",
search="_search_has_package_restriction_violation",
)
def _has_package_restriction_violation_query(self):
self.flush()
query = """
SELECT stock_quant.location_id
FROM stock_quant
JOIN stock_location ON stock_location.id = stock_quant.location_id
WHERE
quantity != 0
AND stock_location.package_restriction IS NOT NULL
"""
if self:
query += "AND stock_quant.location_id in %s"
query += f"""
GROUP BY
stock_quant.location_id, stock_location.package_restriction
HAVING
(
stock_location.package_restriction = '{NOPACKAGE}'
AND count(distinct(stock_quant.package_id)) > 0
) OR (
stock_location.package_restriction = '{SINGLEPACKAGE}'
AND (
count(distinct(stock_quant.package_id)) > 1
OR count(*) FILTER (WHERE stock_quant.package_id IS NULL) > 0
)
) OR (
stock_location.package_restriction = '{MULTIPACKAGE}'
AND count(*) FILTER (WHERE stock_quant.package_id IS NULL) > 0
)
"""
return query
@api.depends("package_restriction")
def _compute_has_package_restriction_violation(self):
self.env.cr.execute(
self._has_package_restriction_violation_query(), (tuple(self.ids),)
)
error_ids = [r[0] for r in self.env.cr.fetchall()]
for location in self:
location.has_package_restriction_violation = location.id in error_ids
def _search_has_package_restriction_violation(self, operator, value):
search_has_violation = (
# has_restriction_violation != False
(operator in NEGATIVE_TERM_OPERATORS and not value)
# has_restriction_violation = True
or (operator not in NEGATIVE_TERM_OPERATORS and value)
)
self.env.cr.execute(self._has_package_restriction_violation_query())
error_ids = [r[0] for r in self.env.cr.fetchall()]
if search_has_violation:
op = "in"
else:
op = "not in"
return [("id", op, error_ids)]
def _check_package_restriction(self, move_lines=None):
"""Check if the location respect the package restrictions

View File

@@ -0,0 +1,50 @@
# Copyright 2024 Jacques-Etienne Baudoux (BCIM) <je@bcim.be>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from odoo.addons.stock_location_package_restriction.models.stock_location import (
MULTIPACKAGE,
NOPACKAGE,
SINGLEPACKAGE,
)
from .common import TestLocationPackageRestrictionCommon
class TestStockLocation(TestLocationPackageRestrictionCommon):
def test_location_no_package_location_ok(self):
self._change_product_qty(self.product_1, self.location_1, False, 50)
self.location_1.package_restriction = NOPACKAGE
self.assertFalse(self.location_1.has_package_restriction_violation)
def test_location_no_package_location_ko(self):
self._change_product_qty(self.product_1, self.location_1, self.pack_1, 50)
self.location_1.package_restriction = NOPACKAGE
self.assertTrue(self.location_1.has_package_restriction_violation)
def test_location_multi_package_location_ok(self):
self._change_product_qty(self.product_1, self.location_1, self.pack_1, 50)
self._change_product_qty(self.product_1, self.location_1, self.pack_2, 50)
self.location_1.package_restriction = MULTIPACKAGE
self.assertFalse(self.location_1.has_package_restriction_violation)
def test_location_multi_package_location_ko(self):
self._change_product_qty(self.product_1, self.location_1, False, 50)
self.location_1.package_restriction = MULTIPACKAGE
self.assertTrue(self.location_1.has_package_restriction_violation)
def test_location_single_package_location_ok(self):
self._change_product_qty(self.product_1, self.location_1, self.pack_1, 50)
self.location_1.package_restriction = SINGLEPACKAGE
self.assertFalse(self.location_1.has_package_restriction_violation)
def test_location_single_package_location_ko_multi(self):
self._change_product_qty(self.product_1, self.location_1, self.pack_1, 50)
self._change_product_qty(self.product_1, self.location_1, self.pack_2, 50)
self.location_1.package_restriction = SINGLEPACKAGE
self.assertTrue(self.location_1.has_package_restriction_violation)
def test_location_single_package_location_ko_no(self):
self._change_product_qty(self.product_1, self.location_1, False, 50)
self.location_1.package_restriction = SINGLEPACKAGE
self.assertTrue(self.location_1.has_package_restriction_violation)

View File

@@ -7,6 +7,14 @@
<field name="model">stock.location</field>
<field name="inherit_id" ref="stock.view_location_form" />
<field name="arch" type="xml">
<div name="button_box" position="after">
<field name="has_package_restriction_violation" invisible="1" />
<div
class="alert alert-danger"
role="alert"
attrs="{'invisible': [('has_package_restriction_violation','=',False)]}"
>Package restriction is not respected</div>
</div>
<xpath expr="//group[last()]">
<group name="restrictions" string="Restrictions">
<field name="package_restriction" />
@@ -14,15 +22,34 @@
</xpath>
</field>
</record>
<record model="ir.ui.view" id="stock_location_search_view">
<field
name="name"
>stock.location.search (in stock_location_package_restriction)</field>
<field name="model">stock.location</field>
<field name="inherit_id" ref="stock.view_location_search" />
<field name="arch" type="xml">
<filter name="inactive" position="after">
<filter
string="With package restriction violation"
name="has_package_restriction_violation"
domain="[('has_package_restriction_violation','=',True)]"
/>
</filter>
</field>
</record>
<record model="ir.ui.view" id="stock_location_tree_view">
<field
name="name"
>stock.location.tree (in stock_location_unique_product)</field>
>stock.location.tree (in stock_location_package_restriction)</field>
<field name="model">stock.location</field>
<field name="inherit_id" ref="stock.view_location_tree2" />
<field name="arch" type="xml">
<field name="company_id" position="before">
<field name="package_restriction" />
<field name="has_package_restriction_violation" />
<field name="package_restriction" optional="hide" />
</field>
</field>
</record>