diff --git a/procurement_auto_create_group_by_product/README.rst b/procurement_auto_create_group_by_product/README.rst new file mode 100644 index 000000000000..0e399112b975 --- /dev/null +++ b/procurement_auto_create_group_by_product/README.rst @@ -0,0 +1 @@ +will be generated by the boat diff --git a/procurement_auto_create_group_by_product/__init__.py b/procurement_auto_create_group_by_product/__init__.py new file mode 100644 index 000000000000..0650744f6bc6 --- /dev/null +++ b/procurement_auto_create_group_by_product/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/procurement_auto_create_group_by_product/__manifest__.py b/procurement_auto_create_group_by_product/__manifest__.py new file mode 100644 index 000000000000..f33946f26169 --- /dev/null +++ b/procurement_auto_create_group_by_product/__manifest__.py @@ -0,0 +1,17 @@ +# Copyright 2023 Jacques-Etienne Baudoux (BCIM) +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). +{ + "name": "Procurement Auto Create Group By Product", + "version": "14.0.1.0.0", + "license": "AGPL-3", + "summary": "Generate one picking per product on the procurement run.", + "author": "BCIM, Odoo Community Association (OCA)", + "website": "https://github.com/OCA/stock-logistics-warehouse", + "category": "Warehouse", + "depends": ["procurement_auto_create_group"], + "data": [ + "views/stock_rule.xml", + "views/procurement_group.xml", + ], + "installable": True, +} diff --git a/procurement_auto_create_group_by_product/models/__init__.py b/procurement_auto_create_group_by_product/models/__init__.py new file mode 100644 index 000000000000..02c83c38a889 --- /dev/null +++ b/procurement_auto_create_group_by_product/models/__init__.py @@ -0,0 +1,3 @@ +from . import stock_rule +from . import procurement_group +from . import product_product diff --git a/procurement_auto_create_group_by_product/models/procurement_group.py b/procurement_auto_create_group_by_product/models/procurement_group.py new file mode 100644 index 000000000000..277667ac2271 --- /dev/null +++ b/procurement_auto_create_group_by_product/models/procurement_group.py @@ -0,0 +1,10 @@ +# Copyright 2023 Jacques-Etienne Baudoux (BCIM) +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). + +from odoo import fields, models + + +class ProcurementGroup(models.Model): + _inherit = "procurement.group" + + product_id = fields.Many2one("product.product", index=True) diff --git a/procurement_auto_create_group_by_product/models/product_product.py b/procurement_auto_create_group_by_product/models/product_product.py new file mode 100644 index 000000000000..aa8ec989b7ce --- /dev/null +++ b/procurement_auto_create_group_by_product/models/product_product.py @@ -0,0 +1,12 @@ +# Copyright 2023 Jacques-Etienne Baudoux (BCIM) +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). + +from odoo import fields, models + + +class ProductProduct(models.Model): + _inherit = "product.product" + + auto_create_procurement_group_ids = fields.One2many( + "procurement.group", "product_id" + ) diff --git a/procurement_auto_create_group_by_product/models/stock_rule.py b/procurement_auto_create_group_by_product/models/stock_rule.py new file mode 100644 index 000000000000..2c7dd28c709d --- /dev/null +++ b/procurement_auto_create_group_by_product/models/stock_rule.py @@ -0,0 +1,23 @@ +# Copyright 2023 Jacques-Etienne Baudoux (BCIM) +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). + +from odoo import fields, models + + +class StockRule(models.Model): + _inherit = "stock.rule" + + auto_create_group_by_product = fields.Boolean(string="Procurement Group by Product") + + def _get_auto_procurement_group(self, product): + if self.auto_create_group_by_product: + if product.auto_create_procurement_group_ids: + return fields.first(product.auto_create_procurement_group_ids) + return super()._get_auto_procurement_group(product) + + def _prepare_auto_procurement_group_data(self, product): + result = super()._prepare_auto_procurement_group_data(product) + if self.auto_create_group_by_product: + result["product_id"] = product.id + result["partner_id"] = False + return result diff --git a/procurement_auto_create_group_by_product/readme/CONFIGURE.rst b/procurement_auto_create_group_by_product/readme/CONFIGURE.rst new file mode 100644 index 000000000000..880b08f08b8a --- /dev/null +++ b/procurement_auto_create_group_by_product/readme/CONFIGURE.rst @@ -0,0 +1,10 @@ +#. Go to *Inventory / Configuration / Settings* and check the option + 'Multi-Step Routes' and press the 'Save' button. +#. Activate the developer mode. +#. Go to *Inventory / Configuration / Warehouse Management / Routes* + and select the route you want to change. Select the rule you wish + to change, and in case of a Pull rule or Push & Pull rule Select + 'Propagation of Procurement Group': 'Propagate'. The checkbox + 'Auto-create Procurement Group' will then appear and you can set + it if you want to procurement group to be automatically created. + Activate also the checkbox 'Procurement Group by Product'. diff --git a/procurement_auto_create_group_by_product/readme/CONTRIBUTORS.rst b/procurement_auto_create_group_by_product/readme/CONTRIBUTORS.rst new file mode 100644 index 000000000000..3c6c5c696a80 --- /dev/null +++ b/procurement_auto_create_group_by_product/readme/CONTRIBUTORS.rst @@ -0,0 +1 @@ +* Jacques-Etienne Baudoux (BCIM) diff --git a/procurement_auto_create_group_by_product/readme/DESCRIPTION.rst b/procurement_auto_create_group_by_product/readme/DESCRIPTION.rst new file mode 100644 index 000000000000..4ac611af4025 --- /dev/null +++ b/procurement_auto_create_group_by_product/readme/DESCRIPTION.rst @@ -0,0 +1,2 @@ +Allow to have one picking per product by using a procurement group per product +during the procurement run. diff --git a/procurement_auto_create_group_by_product/tests/__init__.py b/procurement_auto_create_group_by_product/tests/__init__.py new file mode 100644 index 000000000000..a0a7f64d1593 --- /dev/null +++ b/procurement_auto_create_group_by_product/tests/__init__.py @@ -0,0 +1 @@ +from . import test_auto_create_by_product diff --git a/procurement_auto_create_group_by_product/tests/test_auto_create_by_product.py b/procurement_auto_create_group_by_product/tests/test_auto_create_by_product.py new file mode 100644 index 000000000000..906290a4187e --- /dev/null +++ b/procurement_auto_create_group_by_product/tests/test_auto_create_by_product.py @@ -0,0 +1,110 @@ +# Copyright 2023 Jacques-Etienne Baudoux (BCIM) +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). + +from odoo.addons.procurement_auto_create_group.tests.test_auto_create import ( + TestProcurementAutoCreateGroup, +) + + +class TestProcurementAutoCreateGroupByProduct(TestProcurementAutoCreateGroup): + def test_pull_push_auto_create_group_not_by_product(self): + """Test pull flow that without option to group by product""" + self.pull_push_rule_auto.auto_create_group_by_product = False + # Behavior should be the same + super( + TestProcurementAutoCreateGroupByProduct, self + ).test_02_pull_push_auto_create_group() + + def test_pull_push_auto_create_group_by_product(self): + """Test pull flow that with option to group by product""" + self.pull_push_rule_auto.auto_create_group_by_product = True + move = self.move_obj.search([("product_id", "=", self.prod_auto_pull_push.id)]) + self.assertFalse(move) + group = self.group_obj.search( + [("product_id", "=", self.prod_auto_pull_push.id)] + ) + self.assertFalse(move) + self._procure(self.prod_auto_pull_push) + move = self.move_obj.search([("product_id", "=", self.prod_auto_pull_push.id)]) + self.assertTrue(move) + self.assertTrue(move.group_id, "Procurement Group not assigned.") + self.assertEqual( + move.group_id.product_id, + self.prod_auto_pull_push, + "Procurement Group product missing.", + ) + self.assertEqual( + move.product_uom_qty, + 5.0, + "Move invalid quantity.", + ) + self._procure(self.prod_auto_pull_push) + group = self.group_obj.search( + [("product_id", "=", self.prod_auto_pull_push.id)] + ) + self.assertEqual( + len(group), + 1, + "Procurement Group per product should be unique.", + ) + # The second move should be merged with the previous one + self.assertEqual( + move.product_uom_qty, + 10.0, + "Move invalid quantity.", + ) + + def test_push_auto_create_group_not_by_product(self): + """Test push flow that without option to group by product""" + self.push_rule_auto.auto_create_group_by_product = False + super( + TestProcurementAutoCreateGroupByProduct, self + ).test_05_push_auto_create_group() + + def test_push_auto_create_group_by_product(self): + """Test push flow that with option to group by product""" + self.push_rule_auto.auto_create_group_by_product = True + move = self.move_obj.search( + [ + ("product_id", "=", self.prod_auto_push.id), + ("location_dest_id", "=", self.loc_components.id), + ] + ) + self.assertFalse(move) + self._push_trigger(self.prod_auto_push) + move = self.move_obj.search( + [ + ("product_id", "=", self.prod_auto_push.id), + ("location_dest_id", "=", self.loc_components.id), + ] + ) + self.assertTrue(move) + self.assertTrue(move.group_id, "Procurement Group not assigned.") + self.assertEqual( + move.group_id.product_id, + self.prod_auto_push, + "Procurement Group product missing.", + ) + self._push_trigger(self.prod_auto_push) + group = self.group_obj.search([("product_id", "=", self.prod_auto_push.id)]) + self.assertEqual( + len(group), + 1, + "Procurement Group per product should be unique.", + ) + move = self.move_obj.search( + [ + ("product_id", "=", self.prod_auto_push.id), + ("location_dest_id", "=", self.loc_components.id), + ] + ) + self.assertEqual( + len(move), + 1, + "Invalid amount of moves.", + ) + self.assertEqual( + move.group_id.product_id, + self.prod_auto_push, + "Procurement Group product missing.", + ) diff --git a/procurement_auto_create_group_by_product/views/procurement_group.xml b/procurement_auto_create_group_by_product/views/procurement_group.xml new file mode 100644 index 000000000000..07613641e486 --- /dev/null +++ b/procurement_auto_create_group_by_product/views/procurement_group.xml @@ -0,0 +1,13 @@ + + + + procurement_auto_create_group_by_product + procurement.group + + + + + + + + diff --git a/procurement_auto_create_group_by_product/views/stock_rule.xml b/procurement_auto_create_group_by_product/views/stock_rule.xml new file mode 100644 index 000000000000..2149c0e6ab1b --- /dev/null +++ b/procurement_auto_create_group_by_product/views/stock_rule.xml @@ -0,0 +1,33 @@ + + + + stock.rule.form - procurement_auto_create_group_by_product + stock.rule + + + + + + + + + + + diff --git a/setup/procurement_auto_create_group_by_product/odoo/addons/procurement_auto_create_group_by_product b/setup/procurement_auto_create_group_by_product/odoo/addons/procurement_auto_create_group_by_product new file mode 120000 index 000000000000..50a5a35561e7 --- /dev/null +++ b/setup/procurement_auto_create_group_by_product/odoo/addons/procurement_auto_create_group_by_product @@ -0,0 +1 @@ +../../../../procurement_auto_create_group_by_product \ No newline at end of file diff --git a/setup/procurement_auto_create_group_by_product/setup.py b/setup/procurement_auto_create_group_by_product/setup.py new file mode 100644 index 000000000000..28c57bb64031 --- /dev/null +++ b/setup/procurement_auto_create_group_by_product/setup.py @@ -0,0 +1,6 @@ +import setuptools + +setuptools.setup( + setup_requires=['setuptools-odoo'], + odoo_addon=True, +)