diff --git a/stock_putaway_product_template/README.rst b/stock_putaway_product_template/README.rst new file mode 100644 index 000000000..d7ab84bc4 --- /dev/null +++ b/stock_putaway_product_template/README.rst @@ -0,0 +1,72 @@ +======================================= +Putaway strategies on product form view +======================================= + +.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png + :target: https://odoo-community.org/page/development-status + :alt: Beta +.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png + :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html + :alt: License: AGPL-3 +.. |badge3| image:: https://img.shields.io/badge/github-oca%2Fstock--logistics--warehouse-lightgray.png?logo=github + :target: https://github.com/oca/stock-logistics-warehouse/tree/12.0/stock_putaway_product_form + :alt: oca/stock-logistics-warehouse + +|badge1| |badge2| |badge3| + +This module adds an easy way to modify product-specific putaway strategies from the product view for a better UX. + +**Table of contents** + +.. contents:: + :local: + +Usage +===== + +* In Settings, set "Storage Locations" to True +* User should be in "Manage push and pull inventory flows" +* Open the form view of a product template or a product and use the fields located under the "Inventory" tab + +Bug Tracker +=========== + +Bugs are tracked on `GitHub Issues `_. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us smashing it by providing a detailed and welcomed +`feedback `_. + +Do not contact contributors directly about support or help with technical issues. + +Credits +======= + +Contributors +~~~~~~~~~~~~ + +* Akretion + + * Kevin Khao + +Maintainers +~~~~~~~~~~~ + +.. |maintainer-kevinkhao| image:: https://github.com/kevinkhao.png?size=40px + :target: https://github.com/kevinkhao + :alt: kevinkhao +.. |maintainer-sebastienbeau| image:: https://github.com/sebastienbeau.png?size=40px + :target: https://github.com/sebastienbeau + :alt: sebastienbeau + +Current maintainers: + +|maintainer-kevinkhao| |maintainer-sebastienbeau| + +This module is part of the `oca/stock-logistics-warehouse `_ project on GitHub. + +You are welcome to contribute. diff --git a/stock_putaway_product_template/__init__.py b/stock_putaway_product_template/__init__.py new file mode 100644 index 000000000..8a3fd4c08 --- /dev/null +++ b/stock_putaway_product_template/__init__.py @@ -0,0 +1,4 @@ +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from . import models +from . import tests diff --git a/stock_putaway_product_template/__manifest__.py b/stock_putaway_product_template/__manifest__.py new file mode 100644 index 000000000..f50b53ab7 --- /dev/null +++ b/stock_putaway_product_template/__manifest__.py @@ -0,0 +1,14 @@ +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +{ + "name": "Putaway strategies on product form view", + "summary": "Edit putaway strategies directly from the product form view", + "version": "12.0.1.0.0", + "category": "Inventory", + "website": "https://github.com/OCA/stock-logistics-warehouse", + "author": "Akretion, Odoo Community Association (OCA)", + "license": "AGPL-3", + "depends": ["stock"], + "data": ["views/product.xml"], + "demo": ["demo/putaway_strategies.xml"], + "maintainers": ["kevinkhao", "sebastienbeau"], +} diff --git a/stock_putaway_product_template/demo/putaway_strategies.xml b/stock_putaway_product_template/demo/putaway_strategies.xml new file mode 100644 index 000000000..40ea4ce98 --- /dev/null +++ b/stock_putaway_product_template/demo/putaway_strategies.xml @@ -0,0 +1,36 @@ + + + + + + Putaway Strategy 1 + + + + + + + + + + + + + + + + Putaway Strategy 2 + + + + + + + + + + + + + + diff --git a/stock_putaway_product_template/models/__init__.py b/stock_putaway_product_template/models/__init__.py new file mode 100644 index 000000000..46b77487a --- /dev/null +++ b/stock_putaway_product_template/models/__init__.py @@ -0,0 +1,3 @@ +from . import product_product +from . import product_template +from . import putaway_strategy diff --git a/stock_putaway_product_template/models/product_product.py b/stock_putaway_product_template/models/product_product.py new file mode 100644 index 000000000..d6bd5d145 --- /dev/null +++ b/stock_putaway_product_template/models/product_product.py @@ -0,0 +1,13 @@ +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import fields, models + + +class ProductProduct(models.Model): + _inherit = "product.product" + + product_product_putaway_ids = fields.One2many( + comodel_name="stock.fixed.putaway.strat", + inverse_name="product_id", + string="Product putaway strategies by product variant", + ) diff --git a/stock_putaway_product_template/models/product_template.py b/stock_putaway_product_template/models/product_template.py new file mode 100644 index 000000000..5098eca07 --- /dev/null +++ b/stock_putaway_product_template/models/product_template.py @@ -0,0 +1,62 @@ +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import api, fields, models + + +class ProductTemplate(models.Model): + _inherit = "product.template" + + product_tmpl_putaway_ids = fields.One2many( + comodel_name="stock.fixed.putaway.strat", + inverse_name="product_tmpl_id", + string="Product putaway strategies by product", + ) + + product_putaway_categ_ids = fields.Many2many( + comodel_name="stock.fixed.putaway.strat", + string="Product putaway strategies by category", + compute="_compute_putaway_categ_ids", + ) + + def _find_closest_categ_match(self, categ, putaway_lines): + """Returns the putaway line with the nearest product category""" + lines_match_categ = putaway_lines.filtered( + lambda r: r.category_id == categ + ) + if lines_match_categ: + return lines_match_categ[0] + elif categ.parent_id: + return self._find_closest_categ_match( + categ.parent_id, putaway_lines + ) + else: + return self.env["stock.fixed.putaway.strat"] + + def _get_categ_and_parents(self, categ): + parent_categ_iterator = categ + res = self.env["product.category"] + while parent_categ_iterator: + res += parent_categ_iterator + parent_categ_iterator = parent_categ_iterator.parent_id + return res + + @api.depends("categ_id") + def _compute_putaway_categ_ids(self): + """Pay attention to keep only 1 (most specific, + i.e closest to our product category's parents) + putaway.strat per product.putaway""" + for rec in self: + res = self.env["stock.fixed.putaway.strat"] + categ = rec.categ_id + categs = self._get_categ_and_parents(categ) + # get matching lines from our category or its parents + product_putaway_categ_lines = self.env[ + "stock.fixed.putaway.strat" + ].search([("category_id", "in", categs.ids)]) + # from these, get the matching putaway.strats and find + # the lowest-level category match + product_putaways = product_putaway_categ_lines.mapped("putaway_id") + for el in product_putaways: + lines = el.fixed_location_ids + res += self._find_closest_categ_match(categ, lines) + rec.product_putaway_categ_ids = res diff --git a/stock_putaway_product_template/models/putaway_strategy.py b/stock_putaway_product_template/models/putaway_strategy.py new file mode 100644 index 000000000..64eeb8f54 --- /dev/null +++ b/stock_putaway_product_template/models/putaway_strategy.py @@ -0,0 +1,15 @@ +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import fields, models + + +class FixedPutAwayStrategy(models.Model): + _inherit = "stock.fixed.putaway.strat" + + product_tmpl_id = fields.Many2one( + comodel_name="product.template", + ondelete="cascade", + readonly=True, + related="product_id.product_tmpl_id", + store=True + ) diff --git a/stock_putaway_product_template/readme/CONTRIBUTORS.rst b/stock_putaway_product_template/readme/CONTRIBUTORS.rst new file mode 100644 index 000000000..3a6013026 --- /dev/null +++ b/stock_putaway_product_template/readme/CONTRIBUTORS.rst @@ -0,0 +1,3 @@ +* Akretion + + * Kevin Khao diff --git a/stock_putaway_product_template/readme/DESCRIPTION.rst b/stock_putaway_product_template/readme/DESCRIPTION.rst new file mode 100644 index 000000000..d4507868e --- /dev/null +++ b/stock_putaway_product_template/readme/DESCRIPTION.rst @@ -0,0 +1 @@ +This module adds an easy way to modify product-specific putaway strategies from the product view for a better UX. diff --git a/stock_putaway_product_template/readme/USAGE.rst b/stock_putaway_product_template/readme/USAGE.rst new file mode 100644 index 000000000..7657200db --- /dev/null +++ b/stock_putaway_product_template/readme/USAGE.rst @@ -0,0 +1,3 @@ +* In Settings, set "Storage Locations" to True +* User should be in "Manage push and pull inventory flows" +* Open the form view of a product template or a product and use the fields located under the "Inventory" tab diff --git a/stock_putaway_product_template/static/description/icon.png b/stock_putaway_product_template/static/description/icon.png new file mode 100644 index 000000000..3a0328b51 Binary files /dev/null and b/stock_putaway_product_template/static/description/icon.png differ diff --git a/stock_putaway_product_template/static/description/index.html b/stock_putaway_product_template/static/description/index.html new file mode 100644 index 000000000..7c0c0f01f --- /dev/null +++ b/stock_putaway_product_template/static/description/index.html @@ -0,0 +1,421 @@ + + + + + + +Putaway strategies on product form view + + + +
+

Putaway strategies on product form view

+ + +

Beta License: AGPL-3 oca/stock-logistics-warehouse

+

This module adds an easy way to modify product-specific putaway strategies from the product view for a better UX.

+

Table of contents

+ +
+

Usage

+
    +
  • In Settings, set “Storage Locations” to True
  • +
  • User should be in “Manage push and pull inventory flows”
  • +
  • Open the form view of a product template or a product and use the fields located under the “Inventory” tab
  • +
+
+
+

Bug Tracker

+

Bugs are tracked on GitHub Issues. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us smashing it by providing a detailed and welcomed +feedback.

+

Do not contact contributors directly about support or help with technical issues.

+
+
+

Credits

+
+

Contributors

+ +
+
+

Maintainers

+

Current maintainers:

+

kevinkhao sebastienbeau

+

This module is part of the oca/stock-logistics-warehouse project on GitHub.

+

You are welcome to contribute.

+
+
+
+ + diff --git a/stock_putaway_product_template/tests/__init__.py b/stock_putaway_product_template/tests/__init__.py new file mode 100644 index 000000000..a5b56cbc2 --- /dev/null +++ b/stock_putaway_product_template/tests/__init__.py @@ -0,0 +1,3 @@ +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from . import test_product_putaway diff --git a/stock_putaway_product_template/tests/test_product_putaway.py b/stock_putaway_product_template/tests/test_product_putaway.py new file mode 100644 index 000000000..ea309f022 --- /dev/null +++ b/stock_putaway_product_template/tests/test_product_putaway.py @@ -0,0 +1,61 @@ +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo.tests.common import TransactionCase + + +class TestProductPutaway(TransactionCase): + def setUp(self): + super().setUp() + self.putawayObj = self.env["product.putaway"] + self.putawayLineObj = self.env["stock.fixed.putaway.strat"] + ref = self.env.ref + self.product_tmpl_chair = ref( + "product.product_product_11_product_template" + ) + self.product_product_chair = ref("product.product_product_11") + self.category_services = ref("product.product_category_3") + self.putaway_line_1 = ref( + "stock_putaway_product_form.putaway_strat_1_line_1" + ) + self.putaway_line_2 = ref( + "stock_putaway_product_form.putaway_strat_1_line_2" + ) + self.putaway_line_3 = ref( + "stock_putaway_product_form.putaway_strat_2_line_1" + ) + self.putaway_line_4 = ref( + "stock_putaway_product_form.putaway_strat_2_line_2" + ) + + def test_tmpl_has_putaways_from_products(self): + self.assertIn( + self.putaway_line_1, + self.product_tmpl_chair.product_tmpl_putaway_ids, + ) + self.putaway_line_1.product_id = self.env["product.product"] + self.assertNotIn( + self.putaway_line_1, + self.product_tmpl_chair.product_tmpl_putaway_ids, + ) + + def test_tmpl_has_putaways_from_category_simple(self): + self.assertIn( + self.putaway_line_2, + self.product_tmpl_chair.product_putaway_categ_ids, + ) + self.product_tmpl_chair.categ_id = self.category_services + self.assertNotIn( + self.putaway_line_2, + self.product_tmpl_chair.product_putaway_categ_ids, + ) + + def test_tmpl_has_putaways_from_category_parent(self): + # chair is under category: all/saleable/office + self.assertIn( + self.putaway_line_3, + self.product_tmpl_chair.product_putaway_categ_ids, + ) + self.assertNotIn( + self.putaway_line_4, + self.product_tmpl_chair.product_putaway_categ_ids, + ) diff --git a/stock_putaway_product_template/views/product.xml b/stock_putaway_product_template/views/product.xml new file mode 100644 index 000000000..27a3e7781 --- /dev/null +++ b/stock_putaway_product_template/views/product.xml @@ -0,0 +1,65 @@ + + + + + product.template.product.form + product.template + + + +
+ + + + +

+ The rules defined per product will be applied before the rules defined per product category. +

+
+ + + + + + + +
+ + + + + + + + + +
+
+
+
+ + + product.product.form.putaway + product.product + + + + + + + + + + + + + + + +