From 6bc9fa515fe7e19b86db0f7ffbf11ec85e918cd5 Mon Sep 17 00:00:00 2001 From: Alexis de Lattre Date: Wed, 25 Aug 2021 15:24:35 +0200 Subject: [PATCH] [ADD] stock_inventory_preparation_filter_pos: filter inventory on POS categs This module replaces the module stock_inventory_pos_category proposed in this PR for odoo v10: https://github.com/OCA/stock-logistics-warehouse/pull/393 Adapt stock_inventory_preparation_filter to allow inheritance by adding a prepare method --- .../stock_inventory_preparation_filter_pos | 1 + .../setup.py | 6 ++ .../models/stock_inventory.py | 30 ++++--- .../views/stock_inventory_view.xml | 4 +- .../README.rst | 1 + .../__init__.py | 1 + .../__manifest__.py | 17 ++++ .../models/__init__.py | 1 + .../models/stock_inventory.py | 32 ++++++++ .../readme/CONTRIBUTORS.rst | 1 + .../readme/DESCRIPTION.rst | 1 + .../readme/USAGE.rst | 3 + .../tests/__init__.py | 1 + .../tests/test_preparation_filter_pos.py | 80 +++++++++++++++++++ .../views/stock_inventory.xml | 26 ++++++ 15 files changed, 192 insertions(+), 13 deletions(-) create mode 120000 setup/stock_inventory_preparation_filter_pos/odoo/addons/stock_inventory_preparation_filter_pos create mode 100644 setup/stock_inventory_preparation_filter_pos/setup.py create mode 100644 stock_inventory_preparation_filter_pos/README.rst create mode 100644 stock_inventory_preparation_filter_pos/__init__.py create mode 100644 stock_inventory_preparation_filter_pos/__manifest__.py create mode 100644 stock_inventory_preparation_filter_pos/models/__init__.py create mode 100644 stock_inventory_preparation_filter_pos/models/stock_inventory.py create mode 100644 stock_inventory_preparation_filter_pos/readme/CONTRIBUTORS.rst create mode 100644 stock_inventory_preparation_filter_pos/readme/DESCRIPTION.rst create mode 100644 stock_inventory_preparation_filter_pos/readme/USAGE.rst create mode 100644 stock_inventory_preparation_filter_pos/tests/__init__.py create mode 100644 stock_inventory_preparation_filter_pos/tests/test_preparation_filter_pos.py create mode 100644 stock_inventory_preparation_filter_pos/views/stock_inventory.xml diff --git a/setup/stock_inventory_preparation_filter_pos/odoo/addons/stock_inventory_preparation_filter_pos b/setup/stock_inventory_preparation_filter_pos/odoo/addons/stock_inventory_preparation_filter_pos new file mode 120000 index 000000000..060f10a66 --- /dev/null +++ b/setup/stock_inventory_preparation_filter_pos/odoo/addons/stock_inventory_preparation_filter_pos @@ -0,0 +1 @@ +../../../../stock_inventory_preparation_filter_pos \ No newline at end of file diff --git a/setup/stock_inventory_preparation_filter_pos/setup.py b/setup/stock_inventory_preparation_filter_pos/setup.py new file mode 100644 index 000000000..28c57bb64 --- /dev/null +++ b/setup/stock_inventory_preparation_filter_pos/setup.py @@ -0,0 +1,6 @@ +import setuptools + +setuptools.setup( + setup_requires=['setuptools-odoo'], + odoo_addon=True, +) diff --git a/stock_inventory_preparation_filter/models/stock_inventory.py b/stock_inventory_preparation_filter/models/stock_inventory.py index 9197f5796..2c67721ab 100644 --- a/stock_inventory_preparation_filter/models/stock_inventory.py +++ b/stock_inventory_preparation_filter/models/stock_inventory.py @@ -52,18 +52,26 @@ class StockInventory(models.Model): product_domain = fields.Char("Domain", default=[("name", "ilike", "")]) def _action_start(self): - Product = self.env["product.product"] for inventory in self: - products = Product.browse() if inventory.state != "draft": continue - if inventory.filter == "categories": - products = Product.search([("categ_id", "in", inventory.categ_ids.ids)]) - if inventory.filter == "lots": - products = inventory.lot_ids.mapped("product_id") - if inventory.filter == "domain": - domain = safe_eval(inventory.product_domain) - products = Product.search(domain) - if products: - inventory.product_ids = [(6, 0, products.ids)] + if inventory.filter: + products = inventory._prepare_inventory_filter() + if products: + inventory.product_ids = [(6, 0, products.ids)] return super()._action_start() + + def _prepare_inventory_filter(self): + # This method is designed to be inherited by other modules + # such as the OCA module stock_inventory_preparation_filter_pos + self.ensure_one() + Product = self.env["product.product"] + products = Product + if self.filter == "categories": + products = Product.search([("categ_id", "in", self.categ_ids.ids)]) + elif self.filter == "lots": + products = self.lot_ids.product_id + elif self.filter == "domain": + domain = safe_eval(self.product_domain) + products = Product.search(domain) + return products diff --git a/stock_inventory_preparation_filter/views/stock_inventory_view.xml b/stock_inventory_preparation_filter/views/stock_inventory_view.xml index e71cd0168..a6ada2253 100644 --- a/stock_inventory_preparation_filter/views/stock_inventory_view.xml +++ b/stock_inventory_preparation_filter/views/stock_inventory_view.xml @@ -34,12 +34,12 @@ diff --git a/stock_inventory_preparation_filter_pos/README.rst b/stock_inventory_preparation_filter_pos/README.rst new file mode 100644 index 000000000..afb488df6 --- /dev/null +++ b/stock_inventory_preparation_filter_pos/README.rst @@ -0,0 +1 @@ +Will be generated from readme subdir diff --git a/stock_inventory_preparation_filter_pos/__init__.py b/stock_inventory_preparation_filter_pos/__init__.py new file mode 100644 index 000000000..0650744f6 --- /dev/null +++ b/stock_inventory_preparation_filter_pos/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/stock_inventory_preparation_filter_pos/__manifest__.py b/stock_inventory_preparation_filter_pos/__manifest__.py new file mode 100644 index 000000000..b54ddb987 --- /dev/null +++ b/stock_inventory_preparation_filter_pos/__manifest__.py @@ -0,0 +1,17 @@ +# Copyright 2021 Akretion France (http://www.akretion.com/) +# @author: Alexis de Lattre +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +{ + "name": "Inventory Preparation Filters POS", + "version": "14.0.1.0.0", + "license": "AGPL-3", + "summary": "Add POS category filter on inventory adjustments", + "depends": ["stock_inventory_preparation_filter", "point_of_sale"], + "author": "Akretion, Odoo Community Association (OCA)", + "maintainers": ["alexis-via"], + "category": "Inventory, Logistic, Storage", + "website": "https://github.com/OCA/stock-logistics-warehouse", + "data": ["views/stock_inventory.xml"], + "installable": True, +} diff --git a/stock_inventory_preparation_filter_pos/models/__init__.py b/stock_inventory_preparation_filter_pos/models/__init__.py new file mode 100644 index 000000000..35536816e --- /dev/null +++ b/stock_inventory_preparation_filter_pos/models/__init__.py @@ -0,0 +1 @@ +from . import stock_inventory diff --git a/stock_inventory_preparation_filter_pos/models/stock_inventory.py b/stock_inventory_preparation_filter_pos/models/stock_inventory.py new file mode 100644 index 000000000..739d822a4 --- /dev/null +++ b/stock_inventory_preparation_filter_pos/models/stock_inventory.py @@ -0,0 +1,32 @@ +# Copyright 2021 Akretion France (http://www.akretion.com/) +# @author: Alexis de Lattre +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import _, api, fields, models + + +class StockInventory(models.Model): + _inherit = "stock.inventory" + + pos_categ_ids = fields.Many2many( + "pos.category", + string="Point of Sale Categories", + readonly=True, + states={"draft": [("readonly", False)]}, + ) + + @api.model + def _selection_filter(self): + res_filter = super()._selection_filter() + res_filter.insert( + -1, ("pos_categories", _("Selected Point of Sale Categories")) + ) + return res_filter + + def _prepare_inventory_filter(self): + products = super()._prepare_inventory_filter() + if self.filter == "pos_categories": + products = self.env["product.product"].search( + [("pos_categ_id", "child_of", self.pos_categ_ids.ids)] + ) + return products diff --git a/stock_inventory_preparation_filter_pos/readme/CONTRIBUTORS.rst b/stock_inventory_preparation_filter_pos/readme/CONTRIBUTORS.rst new file mode 100644 index 000000000..ff65d68ce --- /dev/null +++ b/stock_inventory_preparation_filter_pos/readme/CONTRIBUTORS.rst @@ -0,0 +1 @@ +* Alexis de Lattre diff --git a/stock_inventory_preparation_filter_pos/readme/DESCRIPTION.rst b/stock_inventory_preparation_filter_pos/readme/DESCRIPTION.rst new file mode 100644 index 000000000..cfe7ec6ca --- /dev/null +++ b/stock_inventory_preparation_filter_pos/readme/DESCRIPTION.rst @@ -0,0 +1 @@ +with this module, when you create an inventory, you can filter the inventory on one or several point of sale categories. diff --git a/stock_inventory_preparation_filter_pos/readme/USAGE.rst b/stock_inventory_preparation_filter_pos/readme/USAGE.rst new file mode 100644 index 000000000..f64aa0877 --- /dev/null +++ b/stock_inventory_preparation_filter_pos/readme/USAGE.rst @@ -0,0 +1,3 @@ +Go to the menu *Inventory > Operations > Inventory Adjustments*, create a new inventory, choose **Selected Point of Sale Categories** and then select the point of sale categories that you want to filter on. + +Note that, if you select a parent point of sale category, Odoo will also select the products attached to the children point of sale categories. diff --git a/stock_inventory_preparation_filter_pos/tests/__init__.py b/stock_inventory_preparation_filter_pos/tests/__init__.py new file mode 100644 index 000000000..b64a88dad --- /dev/null +++ b/stock_inventory_preparation_filter_pos/tests/__init__.py @@ -0,0 +1 @@ +from . import test_preparation_filter_pos diff --git a/stock_inventory_preparation_filter_pos/tests/test_preparation_filter_pos.py b/stock_inventory_preparation_filter_pos/tests/test_preparation_filter_pos.py new file mode 100644 index 000000000..11191d9e6 --- /dev/null +++ b/stock_inventory_preparation_filter_pos/tests/test_preparation_filter_pos.py @@ -0,0 +1,80 @@ +# Copyright 2021 Akretion France (http://www.akretion.com/) +# @author: Alexis de Lattre +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo.tests import common + + +class TestStockInventoryPreparationFilterPos(common.TransactionCase): + def setUp(self): + super().setUp() + self.location = self.env.ref("stock.stock_location_stock") + ppo = self.env["product.product"] + pcateg_id = self.env["product.category"].create({"name": "Test1"}).id + self.pos_categ1 = self.env["pos.category"].create({"name": "Test POS Categ"}) + self.pos_categ2 = self.env["pos.category"].create( + {"name": "Test POS Categ2", "parent_id": self.pos_categ1.id} + ) + # Create products + self.product1 = ppo.create( + { + "name": "Product POS test1", + "type": "product", + "categ_id": pcateg_id, + "pos_categ_id": self.pos_categ1.id, + } + ) + self.product2 = ppo.create( + { + "name": "Product POS test2", + "type": "product", + "categ_id": pcateg_id, + "pos_categ_id": self.pos_categ1.id, + } + ) + self.product3 = ppo.create( + { + "name": "Product POS test3", + "type": "product", + "categ_id": pcateg_id, + "pos_categ_id": self.pos_categ2.id, + } + ) + + # Add stock levels for these products + self.env["stock.quant"].create( + [ + { + "product_id": self.product1.id, + "product_uom_id": self.product1.uom_id.id, + "location_id": self.location.id, + "quantity": 42.0, + }, + { + "product_id": self.product2.id, + "product_uom_id": self.product2.uom_id.id, + "location_id": self.location.id, + "quantity": 43.0, + }, + { + "product_id": self.product3.id, + "product_uom_id": self.product3.uom_id.id, + "location_id": self.location.id, + "quantity": 44.0, + }, + ] + ) + + def test_inventory_filter_pos(self): + inventory = self.env["stock.inventory"].create( + { + "name": "Test POS filter", + "filter": "pos_categories", + "pos_categ_ids": [(6, 0, self.pos_categ1.ids)], + } + ) + inventory.action_start() + # We make sure that the products of children categs are also included + self.assertEqual(len(inventory.product_ids), 3) + self.assertEqual(len(inventory.line_ids), 3) + inventory.action_cancel_draft() diff --git a/stock_inventory_preparation_filter_pos/views/stock_inventory.xml b/stock_inventory_preparation_filter_pos/views/stock_inventory.xml new file mode 100644 index 000000000..0ecbc1888 --- /dev/null +++ b/stock_inventory_preparation_filter_pos/views/stock_inventory.xml @@ -0,0 +1,26 @@ + + + + + + stock.inventory + + + + + + + + +