diff --git a/README.md b/README.md index 70e9517880c5..0d9e9e04bfc5 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,7 @@ addon | version | maintainers | summary --- | --- | --- | --- [sale_order_global_stock_route](sale_order_global_stock_route/) | 18.0.1.0.0 | | Add the possibility to choose one warehouse path for an order [stock_account_product_run_fifo_hook](stock_account_product_run_fifo_hook/) | 18.0.1.0.1 | | Add more flexibility in the run fifo method. +[stock_dangerous_goods](stock_dangerous_goods/) | 18.0.1.0.0 | [![mmequignon](https://github.com/mmequignon.png?size=30px)](https://github.com/mmequignon) | Adds utility fields to manage dangerous goods [stock_no_negative](stock_no_negative/) | 18.0.1.0.0 | | Disallow negative stock levels by default [stock_owner_restriction](stock_owner_restriction/) | 18.0.1.0.0 | | Do not reserve quantity with assigned owner [stock_picking_auto_create_lot](stock_picking_auto_create_lot/) | 18.0.1.0.0 | [![sergio-teruel](https://github.com/sergio-teruel.png?size=30px)](https://github.com/sergio-teruel) | Auto create lots for incoming pickings diff --git a/setup/_metapackage/pyproject.toml b/setup/_metapackage/pyproject.toml index 86fc56194776..76207cbedc89 100644 --- a/setup/_metapackage/pyproject.toml +++ b/setup/_metapackage/pyproject.toml @@ -1,9 +1,10 @@ [project] name = "odoo-addons-oca-stock-logistics-workflow" -version = "18.0.20250131.1" +version = "18.0.20250204.0" dependencies = [ "odoo-addon-sale_order_global_stock_route==18.0.*", "odoo-addon-stock_account_product_run_fifo_hook==18.0.*", + "odoo-addon-stock_dangerous_goods==18.0.*", "odoo-addon-stock_no_negative==18.0.*", "odoo-addon-stock_owner_restriction==18.0.*", "odoo-addon-stock_picking_auto_create_lot==18.0.*", diff --git a/stock_dangerous_goods/README.rst b/stock_dangerous_goods/README.rst new file mode 100644 index 000000000000..b381751fb282 --- /dev/null +++ b/stock_dangerous_goods/README.rst @@ -0,0 +1,92 @@ +===================== +Stock Dangerous Goods +===================== + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:d9eb3b01b33f5e6d4ecacb127a8c964ce26a12f8645cb538474bbfe26729d8e3 + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |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--workflow-lightgray.png?logo=github + :target: https://github.com/OCA/stock-logistics-workflow/tree/18.0/stock_dangerous_goods + :alt: OCA/stock-logistics-workflow +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/stock-logistics-workflow-18-0/stock-logistics-workflow-18-0-stock_dangerous_goods + :alt: Translate me on Weblate +.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png + :target: https://runboat.odoo-community.org/builds?repo=OCA/stock-logistics-workflow&target_branch=18.0 + :alt: Try me on Runboat + +|badge1| |badge2| |badge3| |badge4| |badge5| + +This is a glue module between stock and l10n_eu_product_adr. This +modules adds a few utility fields about dangerous products. + +**Table of contents** + +.. contents:: + :local: + +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 to smash it by providing a detailed and welcomed +`feedback `_. + +Do not contact contributors directly about support or help with technical issues. + +Credits +======= + +Authors +------- + +* Camptocamp SA + +Contributors +------------ + +- Matthieu Méquignon +- Do Anh Duy + +Other credits +------------- + +The migration of this module from 14.0 to 18.0 was financially supported +by Camptocamp. + +Maintainers +----------- + +This module is maintained by the OCA. + +.. image:: https://odoo-community.org/logo.png + :alt: Odoo Community Association + :target: https://odoo-community.org + +OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use. + +.. |maintainer-mmequignon| image:: https://github.com/mmequignon.png?size=40px + :target: https://github.com/mmequignon + :alt: mmequignon + +Current `maintainer `__: + +|maintainer-mmequignon| + +This module is part of the `OCA/stock-logistics-workflow `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/stock_dangerous_goods/__init__.py b/stock_dangerous_goods/__init__.py new file mode 100644 index 000000000000..0650744f6bc6 --- /dev/null +++ b/stock_dangerous_goods/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/stock_dangerous_goods/__manifest__.py b/stock_dangerous_goods/__manifest__.py new file mode 100644 index 000000000000..32a5425a8a13 --- /dev/null +++ b/stock_dangerous_goods/__manifest__.py @@ -0,0 +1,18 @@ +# Copyright 2021 Camptocamp SA +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl) +{ + "name": "Stock Dangerous Goods", + "summary": "Adds utility fields to manage dangerous goods", + "version": "18.0.1.0.0", + "category": "Inventory", + "website": "https://github.com/OCA/stock-logistics-workflow", + "author": "Camptocamp SA, Odoo Community Association (OCA)", + "maintainers": ["mmequignon"], + "license": "AGPL-3", + "installable": True, + "depends": [ + "stock", + # OCA/community-data-files + "l10n_eu_product_adr_dangerous_goods", + ], +} diff --git a/stock_dangerous_goods/i18n/it.po b/stock_dangerous_goods/i18n/it.po new file mode 100644 index 000000000000..4ae6f042024a --- /dev/null +++ b/stock_dangerous_goods/i18n/it.po @@ -0,0 +1,47 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * stock_dangerous_goods +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 14.0\n" +"Report-Msgid-Bugs-To: \n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" + +#. module: stock_dangerous_goods +#: model:ir.model.fields,field_description:stock_dangerous_goods.field_stock_quant_package__has_lq_products +msgid "Has Lq Products" +msgstr "" + +#. module: stock_dangerous_goods +#: model:ir.model.fields,field_description:stock_dangerous_goods.field_product_product__is_lq_product +#: model:ir.model.fields,field_description:stock_dangerous_goods.field_stock_move_line__has_lq_products +msgid "Is Lq Product" +msgstr "" + +#. module: stock_dangerous_goods +#: model:ir.model,name:stock_dangerous_goods.model_stock_quant_package +msgid "Packages" +msgstr "" + +#. module: stock_dangerous_goods +#: model:ir.model,name:stock_dangerous_goods.model_stock_move_line +msgid "Product Moves (Stock Move Line)" +msgstr "" + +#. module: stock_dangerous_goods +#: model:ir.model,name:stock_dangerous_goods.model_product_product +msgid "Product Variant" +msgstr "" + +#. module: stock_dangerous_goods +#: model:ir.model.fields,help:stock_dangerous_goods.field_product_product__is_lq_product +#: model:ir.model.fields,help:stock_dangerous_goods.field_stock_move_line__has_lq_products +msgid "Whether this product is a Limited Quantity product or not" +msgstr "" diff --git a/stock_dangerous_goods/i18n/stock_dangerous_goods.pot b/stock_dangerous_goods/i18n/stock_dangerous_goods.pot new file mode 100644 index 000000000000..0bfa7298cf0a --- /dev/null +++ b/stock_dangerous_goods/i18n/stock_dangerous_goods.pot @@ -0,0 +1,46 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * stock_dangerous_goods +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 18.0\n" +"Report-Msgid-Bugs-To: \n" +"Last-Translator: \n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" + +#. module: stock_dangerous_goods +#: model:ir.model.fields,field_description:stock_dangerous_goods.field_stock_quant_package__has_lq_products +msgid "Has Lq Products" +msgstr "" + +#. module: stock_dangerous_goods +#: model:ir.model.fields,field_description:stock_dangerous_goods.field_product_product__is_lq_product +#: model:ir.model.fields,field_description:stock_dangerous_goods.field_stock_move_line__has_lq_products +msgid "Is Lq Product" +msgstr "" + +#. module: stock_dangerous_goods +#: model:ir.model,name:stock_dangerous_goods.model_stock_quant_package +msgid "Packages" +msgstr "" + +#. module: stock_dangerous_goods +#: model:ir.model,name:stock_dangerous_goods.model_stock_move_line +msgid "Product Moves (Stock Move Line)" +msgstr "" + +#. module: stock_dangerous_goods +#: model:ir.model,name:stock_dangerous_goods.model_product_product +msgid "Product Variant" +msgstr "" + +#. module: stock_dangerous_goods +#: model:ir.model.fields,help:stock_dangerous_goods.field_product_product__is_lq_product +#: model:ir.model.fields,help:stock_dangerous_goods.field_stock_move_line__has_lq_products +msgid "Whether this product is a Limited Quantity product or not" +msgstr "" diff --git a/stock_dangerous_goods/models/__init__.py b/stock_dangerous_goods/models/__init__.py new file mode 100644 index 000000000000..50a151d1d98d --- /dev/null +++ b/stock_dangerous_goods/models/__init__.py @@ -0,0 +1,3 @@ +from . import stock_move_line +from . import stock_quant_package +from . import product_product diff --git a/stock_dangerous_goods/models/product_product.py b/stock_dangerous_goods/models/product_product.py new file mode 100644 index 000000000000..c95a55b31d8d --- /dev/null +++ b/stock_dangerous_goods/models/product_product.py @@ -0,0 +1,23 @@ +# Copyright 2021 Camptocamp SA +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl) + +from odoo import api, fields, models + + +class ProductProduct(models.Model): + _inherit = "product.product" + + is_lq_product = fields.Boolean( + compute="_compute_is_lq_product", + help="Whether this product is a Limited Quantity product or not", + ) + + @api.depends("limited_amount_id", "is_dangerous") + def _compute_is_lq_product(self): + limited_amount_lq = self.env.ref( + "l10n_eu_product_adr_dangerous_goods.limited_amount_1" + ) + for record in self: + record.is_lq_product = ( + record.is_dangerous and record.limited_amount_id == limited_amount_lq + ) diff --git a/stock_dangerous_goods/models/stock_move_line.py b/stock_dangerous_goods/models/stock_move_line.py new file mode 100644 index 000000000000..3a4e26b0ecae --- /dev/null +++ b/stock_dangerous_goods/models/stock_move_line.py @@ -0,0 +1,10 @@ +# Copyright 2021 Camptocamp SA +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl) + +from odoo import fields, models + + +class StockMoveLine(models.Model): + _inherit = "stock.move.line" + + has_lq_products = fields.Boolean(related="product_id.is_lq_product") diff --git a/stock_dangerous_goods/models/stock_quant_package.py b/stock_dangerous_goods/models/stock_quant_package.py new file mode 100644 index 000000000000..f23b670d8ef7 --- /dev/null +++ b/stock_dangerous_goods/models/stock_quant_package.py @@ -0,0 +1,22 @@ +# Copyright 2021 Camptocamp SA +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl) + +from odoo import api, fields, models + + +class StockQuantPackage(models.Model): + _inherit = "stock.quant.package" + + has_lq_products = fields.Boolean(compute="_compute_has_lq_products") + + @api.depends("quant_ids.product_id.is_lq_product") + def _compute_has_lq_products(self): + for record in self: + record.has_lq_products = record._has_lq_products() + + def _has_lq_products(self): + self.ensure_one() + for quant in self.quant_ids: + if quant.product_id.is_lq_product: + return True + return False diff --git a/stock_dangerous_goods/pyproject.toml b/stock_dangerous_goods/pyproject.toml new file mode 100644 index 000000000000..4231d0cccb3d --- /dev/null +++ b/stock_dangerous_goods/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["whool"] +build-backend = "whool.buildapi" diff --git a/stock_dangerous_goods/readme/CONTRIBUTORS.md b/stock_dangerous_goods/readme/CONTRIBUTORS.md new file mode 100644 index 000000000000..bc6c38a1c5c0 --- /dev/null +++ b/stock_dangerous_goods/readme/CONTRIBUTORS.md @@ -0,0 +1,2 @@ +- Matthieu Méquignon \<\> +- Do Anh Duy \<\> diff --git a/stock_dangerous_goods/readme/CREDITS.md b/stock_dangerous_goods/readme/CREDITS.md new file mode 100644 index 000000000000..573d68b7e861 --- /dev/null +++ b/stock_dangerous_goods/readme/CREDITS.md @@ -0,0 +1 @@ +The migration of this module from 14.0 to 18.0 was financially supported by Camptocamp. diff --git a/stock_dangerous_goods/readme/DESCRIPTION.md b/stock_dangerous_goods/readme/DESCRIPTION.md new file mode 100644 index 000000000000..4f514a28595a --- /dev/null +++ b/stock_dangerous_goods/readme/DESCRIPTION.md @@ -0,0 +1,2 @@ +This is a glue module between stock and l10n_eu_product_adr. This +modules adds a few utility fields about dangerous products. diff --git a/stock_dangerous_goods/static/description/icon.png b/stock_dangerous_goods/static/description/icon.png new file mode 100644 index 000000000000..3a0328b516c4 Binary files /dev/null and b/stock_dangerous_goods/static/description/icon.png differ diff --git a/stock_dangerous_goods/static/description/index.html b/stock_dangerous_goods/static/description/index.html new file mode 100644 index 000000000000..21431261304a --- /dev/null +++ b/stock_dangerous_goods/static/description/index.html @@ -0,0 +1,433 @@ + + + + + +Stock Dangerous Goods + + + +
+

Stock Dangerous Goods

+ + +

Beta License: AGPL-3 OCA/stock-logistics-workflow Translate me on Weblate Try me on Runboat

+

This is a glue module between stock and l10n_eu_product_adr. This +modules adds a few utility fields about dangerous products.

+

Table of contents

+ +
+

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 to smash it by providing a detailed and welcomed +feedback.

+

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

+
+
+

Credits

+
+

Authors

+
    +
  • Camptocamp SA
  • +
+
+
+

Contributors

+ +
+
+

Other credits

+

The migration of this module from 14.0 to 18.0 was financially supported +by Camptocamp.

+
+
+

Maintainers

+

This module is maintained by the OCA.

+ +Odoo Community Association + +

OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use.

+

Current maintainer:

+

mmequignon

+

This module is part of the OCA/stock-logistics-workflow project on GitHub.

+

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

+
+
+
+ + diff --git a/stock_dangerous_goods/tests/__init__.py b/stock_dangerous_goods/tests/__init__.py new file mode 100644 index 000000000000..e849cf8b6c51 --- /dev/null +++ b/stock_dangerous_goods/tests/__init__.py @@ -0,0 +1 @@ +from . import test_has_lq_products diff --git a/stock_dangerous_goods/tests/test_has_lq_products.py b/stock_dangerous_goods/tests/test_has_lq_products.py new file mode 100644 index 000000000000..934cbeb11663 --- /dev/null +++ b/stock_dangerous_goods/tests/test_has_lq_products.py @@ -0,0 +1,146 @@ +from odoo.tests import TransactionCase + + +class TestProductProduct(TransactionCase): + @classmethod + def setUpClass(cls): + super().setUpClass() + # Create a reference for the limited amount + cls.limited_amount_lq = cls.env.ref( + "l10n_eu_product_adr_dangerous_goods.limited_amount_1" + ) + # Create a product that is dangerous and has the limited amount + cls.dangerous_product = cls.env["product.product"].create( + { + "name": "Dangerous Product", + "is_dangerous": True, + "limited_amount_id": cls.limited_amount_lq.id, + "is_storable": True, + } + ) + # Create a product that is not dangerous + cls.non_dangerous_product = cls.env["product.product"].create( + { + "name": "Non-Dangerous Product", + "is_dangerous": False, + "is_storable": True, + } + ) + # Create a product that is dangerous but does not have the limited amount + cls.dangerous_product_no_limit = cls.env["product.product"].create( + { + "name": "Dangerous Product No Limit", + "is_dangerous": True, + "limited_amount_id": False, + } + ) + + partner = cls.env["res.partner"].create( + { + "name": "Test Partner", + } + ) + + # Create a stock picking + cls.picking = cls.env["stock.picking"].create( + { + "partner_id": partner.id, + "location_id": cls.env.ref("stock.stock_location_stock").id, + "location_dest_id": cls.env.ref("stock.stock_location_customers").id, + "picking_type_id": cls.env.ref("stock.picking_type_out").id, + } + ) + + def test_is_lq_product(self): + # Test the dangerous product with limited amount + self.assertTrue( + self.dangerous_product.is_lq_product, + "The dangerous product should be a limited quantity product.", + ) + + # Test the non-dangerous product + self.assertFalse( + self.non_dangerous_product.is_lq_product, + "The non-dangerous product should not be a limited quantity product.", + ) + + # Test the dangerous product without limited amount + self.assertFalse( + self.dangerous_product_no_limit.is_lq_product, + "The dangerous product without limited amount should not be a limited" + " quantity product.", + ) + + def test_has_lq_products_with_package(self): + # Create stock move line for a dangerous product + move_line_1 = self.env["stock.move.line"].create( + { + "picking_id": self.picking.id, + "location_id": self.env.ref("stock.stock_location_stock").id, + "location_dest_id": self.env.ref("stock.stock_location_customers").id, + "product_id": self.dangerous_product.id, + "quantity": 10, + } + ) + + # Create stock move line for a non-dangerous product + move_line_2 = self.env["stock.move.line"].create( + { + "picking_id": self.picking.id, + "location_id": self.env.ref("stock.stock_location_stock").id, + "location_dest_id": self.env.ref("stock.stock_location_customers").id, + "product_id": self.non_dangerous_product.id, + "quantity": 5, + } + ) + + # Confirm picking and make it available to process + self.picking.action_confirm() + self.picking.action_assign() + + # Create a stock.quant.package + package = self.env["stock.quant.package"].create( + { + "name": "Test Package", + } + ) + + # Assign the move lines to the package + move_line_1.package_id = package.id + move_line_2.package_id = package.id + + # Simulate stock quant creation for the products + self.env["stock.quant"]._update_available_quantity( + self.dangerous_product, + self.env.ref("stock.stock_location_stock"), + 10, + package_id=package, + ) + self.env["stock.quant"]._update_available_quantity( + self.non_dangerous_product, + self.env.ref("stock.stock_location_stock"), + 5, + package_id=package, + ) + + # Validate that the package has LQ products + self.assertTrue( + package.has_lq_products, + "The package should have LQ products as it contains a dangerous product.", + ) + + # Remove the dangerous product's quant + dangerous_quant = self.env["stock.quant"].search( + [ + ("product_id", "=", self.dangerous_product.id), + ("package_id", "=", package.id), + ] + ) + dangerous_quant.unlink() + + # Validate that the package no longer has LQ products + self.assertFalse( + package.has_lq_products, + "The package should not have LQ products after removing the dangerous" + " product.", + )