From f2712ab21d7f2917483e4ce78523fa54669e560a Mon Sep 17 00:00:00 2001 From: Jacques-Etienne Baudoux Date: Fri, 31 May 2024 16:18:41 +0200 Subject: [PATCH] stock_location_package_restriction: show violations Show and search locations that does not respect the restriction. --- .../models/stock_location.py | 62 +++++++++++++++++++ .../tests/test_stock_location.py | 50 +++++++++++++++ .../views/stock_location.xml | 31 +++++++++- 3 files changed, 141 insertions(+), 2 deletions(-) create mode 100644 stock_location_package_restriction/tests/test_stock_location.py diff --git a/stock_location_package_restriction/models/stock_location.py b/stock_location_package_restriction/models/stock_location.py index 9fe6523d7..862dd69c9 100644 --- a/stock_location_package_restriction/models/stock_location.py +++ b/stock_location_package_restriction/models/stock_location.py @@ -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 diff --git a/stock_location_package_restriction/tests/test_stock_location.py b/stock_location_package_restriction/tests/test_stock_location.py new file mode 100644 index 000000000..9c1772c26 --- /dev/null +++ b/stock_location_package_restriction/tests/test_stock_location.py @@ -0,0 +1,50 @@ +# Copyright 2024 Jacques-Etienne Baudoux (BCIM) +# 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) diff --git a/stock_location_package_restriction/views/stock_location.xml b/stock_location_package_restriction/views/stock_location.xml index 291dcdd94..2ec7e232e 100644 --- a/stock_location_package_restriction/views/stock_location.xml +++ b/stock_location_package_restriction/views/stock_location.xml @@ -7,6 +7,14 @@ stock.location +
+ + +
@@ -14,15 +22,34 @@
+ + + stock.location.search (in stock_location_package_restriction) + stock.location + + + + + + + + stock.location.tree (in stock_location_unique_product) + >stock.location.tree (in stock_location_package_restriction)
stock.location - + +