diff --git a/setup/stock_lot_product_packaging/odoo/addons/stock_lot_product_packaging b/setup/stock_lot_product_packaging/odoo/addons/stock_lot_product_packaging new file mode 120000 index 0000000000..824804c667 --- /dev/null +++ b/setup/stock_lot_product_packaging/odoo/addons/stock_lot_product_packaging @@ -0,0 +1 @@ +../../../../stock_lot_product_packaging \ No newline at end of file diff --git a/setup/stock_lot_product_packaging/setup.py b/setup/stock_lot_product_packaging/setup.py new file mode 100644 index 0000000000..28c57bb640 --- /dev/null +++ b/setup/stock_lot_product_packaging/setup.py @@ -0,0 +1,6 @@ +import setuptools + +setuptools.setup( + setup_requires=['setuptools-odoo'], + odoo_addon=True, +) diff --git a/stock_lot_product_packaging/README.rst b/stock_lot_product_packaging/README.rst new file mode 100644 index 0000000000..254ce059ac --- /dev/null +++ b/stock_lot_product_packaging/README.rst @@ -0,0 +1,32 @@ +.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg + :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html + :alt: License: AGPL-3 + +=========================== +Stock lot product packaging +=========================== + +* In lots new fields "Product Packaging" and "Packaging Units". +* In products new fields "product_density, and "Package types" and new button + "Generate Packaging In Products", to generate packaging for each product + variant. +* If the quant has a lot, show the related field of the lot's packaging units. + +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 smash it by providing detailed and welcomed feedback. + +Do not contact contributors directly about support or help with technical issues. + +Credits +======= + +Contributors +------------ + +* Ana Juaristi +* Alfredo de la Fuente diff --git a/stock_lot_product_packaging/__init__.py b/stock_lot_product_packaging/__init__.py new file mode 100644 index 0000000000..0650744f6b --- /dev/null +++ b/stock_lot_product_packaging/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/stock_lot_product_packaging/__manifest__.py b/stock_lot_product_packaging/__manifest__.py new file mode 100644 index 0000000000..1b59c7fc20 --- /dev/null +++ b/stock_lot_product_packaging/__manifest__.py @@ -0,0 +1,19 @@ +# Copyright 2024 Alfredo de la Fuente - AvanzOSC +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). +{ + "name": "Stock Lot Product Packaging", + "version": "16.0.1.0.0", + "author": "Avanzosc", + "category": "Inventory/Inventory", + "website": "https://github.com/avanzosc/odoo-addons", + "depends": ["product", "stock", "product_logistics_uom"], + "data": [ + "views/stock_package_type_views.xml", + "views/product_template_views.xml", + "views/product_product_views.xml", + "views/stock_lot_views.xml", + "views/stock_quant_views.xml", + ], + "license": "AGPL-3", + "installable": True, +} diff --git a/stock_lot_product_packaging/i18n/en_US.po b/stock_lot_product_packaging/i18n/en_US.po new file mode 100644 index 0000000000..0576dd7089 --- /dev/null +++ b/stock_lot_product_packaging/i18n/en_US.po @@ -0,0 +1,90 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * stock_lot_product_packaging +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 16.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2024-12-04 12:30+0000\n" +"PO-Revision-Date: 2024-12-04 12:30+0000\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_lot_product_packaging +#: model:ir.model.fields,field_description:stock_lot_product_packaging.field_product_product__product_density +#: model:ir.model.fields,field_description:stock_lot_product_packaging.field_product_template__product_density +#: model_terms:ir.ui.view,arch_db:stock_lot_product_packaging.product_template_form_view2 +msgid "Density" +msgstr "" + +#. module: stock_lot_product_packaging +#: model_terms:ir.ui.view,arch_db:stock_lot_product_packaging.product_template_form_view +msgid "Generate Packaging In Products" +msgstr "" + +#. module: stock_lot_product_packaging +#: model_terms:ir.ui.view,arch_db:stock_lot_product_packaging.stock_package_type_search_view +msgid "Group By" +msgstr "" + +#. module: stock_lot_product_packaging +#: model:ir.model,name:stock_lot_product_packaging.model_stock_lot +msgid "Lot/Serial" +msgstr "" + +#. module: stock_lot_product_packaging +#: model:ir.model.fields,field_description:stock_lot_product_packaging.field_product_product__package_type_ids +#: model:ir.model.fields,field_description:stock_lot_product_packaging.field_product_template__package_type_ids +#: model_terms:ir.ui.view,arch_db:stock_lot_product_packaging.product_template_form_view +msgid "Package types" +msgstr "" + +#. module: stock_lot_product_packaging +#: model:ir.model.fields,field_description:stock_lot_product_packaging.field_stock_lot__packaging_units +#: model:ir.model.fields,field_description:stock_lot_product_packaging.field_stock_quant__packaging_units +#: model_terms:ir.ui.view,arch_db:stock_lot_product_packaging.view_stock_quant_form_editable +msgid "Packaging Units" +msgstr "" + +#. module: stock_lot_product_packaging +#: model:ir.model,name:stock_lot_product_packaging.model_product_template +#: model:ir.model.fields,field_description:stock_lot_product_packaging.field_stock_package_type__product_tmpl_id +#: model_terms:ir.ui.view,arch_db:stock_lot_product_packaging.stock_package_type_search_view +msgid "Product" +msgstr "" + +#. module: stock_lot_product_packaging +#: model:ir.model.fields,field_description:stock_lot_product_packaging.field_product_product__product_package_ids +#: model_terms:ir.ui.view,arch_db:stock_lot_product_packaging.product_normal_form_view +msgid "Product Packages" +msgstr "" + +#. module: stock_lot_product_packaging +#: model:ir.model.fields,field_description:stock_lot_product_packaging.field_stock_lot__product_packaging_id +msgid "Product Packaging" +msgstr "" + +#. module: stock_lot_product_packaging +#: model:ir.model,name:stock_lot_product_packaging.model_product_product +msgid "Product Variant" +msgstr "" + +#. module: stock_lot_product_packaging +#: model:ir.model,name:stock_lot_product_packaging.model_stock_quant +msgid "Quants" +msgstr "" + +#. module: stock_lot_product_packaging +#: model_terms:ir.ui.view,arch_db:stock_lot_product_packaging.stock_package_type_search_view +msgid "Search Package Types" +msgstr "" + +#. module: stock_lot_product_packaging +#: model:ir.model,name:stock_lot_product_packaging.model_stock_package_type +msgid "Stock package type" +msgstr "" diff --git a/stock_lot_product_packaging/i18n/es.po b/stock_lot_product_packaging/i18n/es.po new file mode 100644 index 0000000000..ccc3d7b980 --- /dev/null +++ b/stock_lot_product_packaging/i18n/es.po @@ -0,0 +1,90 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * stock_lot_product_packaging +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 16.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2024-12-04 12:30+0000\n" +"PO-Revision-Date: 2024-12-04 12:30+0000\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_lot_product_packaging +#: model:ir.model.fields,field_description:stock_lot_product_packaging.field_product_product__product_density +#: model:ir.model.fields,field_description:stock_lot_product_packaging.field_product_template__product_density +#: model_terms:ir.ui.view,arch_db:stock_lot_product_packaging.product_template_form_view2 +msgid "Density" +msgstr "Densidad" + +#. module: stock_lot_product_packaging +#: model_terms:ir.ui.view,arch_db:stock_lot_product_packaging.product_template_form_view +msgid "Generate Packaging In Products" +msgstr "Generar empaquetados en productos" + +#. module: stock_lot_product_packaging +#: model_terms:ir.ui.view,arch_db:stock_lot_product_packaging.stock_package_type_search_view +msgid "Group By" +msgstr "Agrupar por" + +#. module: stock_lot_product_packaging +#: model:ir.model,name:stock_lot_product_packaging.model_stock_lot +msgid "Lot/Serial" +msgstr "Lote/serie" + +#. module: stock_lot_product_packaging +#: model:ir.model.fields,field_description:stock_lot_product_packaging.field_product_product__package_type_ids +#: model:ir.model.fields,field_description:stock_lot_product_packaging.field_product_template__package_type_ids +#: model_terms:ir.ui.view,arch_db:stock_lot_product_packaging.product_template_form_view +msgid "Package types" +msgstr "Tipos empaquetados" + +#. module: stock_lot_product_packaging +#: model:ir.model.fields,field_description:stock_lot_product_packaging.field_stock_lot__packaging_units +#: model:ir.model.fields,field_description:stock_lot_product_packaging.field_stock_quant__packaging_units +#: model_terms:ir.ui.view,arch_db:stock_lot_product_packaging.view_stock_quant_form_editable +msgid "Packaging Units" +msgstr "Unidades envase" + +#. module: stock_lot_product_packaging +#: model:ir.model,name:stock_lot_product_packaging.model_product_template +#: model:ir.model.fields,field_description:stock_lot_product_packaging.field_stock_package_type__product_tmpl_id +#: model_terms:ir.ui.view,arch_db:stock_lot_product_packaging.stock_package_type_search_view +msgid "Product" +msgstr "Producto" + +#. module: stock_lot_product_packaging +#: model:ir.model.fields,field_description:stock_lot_product_packaging.field_product_product__product_package_ids +#: model_terms:ir.ui.view,arch_db:stock_lot_product_packaging.product_normal_form_view +msgid "Product Packages" +msgstr "Empaquetados producto" + +#. module: stock_lot_product_packaging +#: model:ir.model.fields,field_description:stock_lot_product_packaging.field_stock_lot__product_packaging_id +msgid "Product Packaging" +msgstr "Empaquetado producto" + +#. module: stock_lot_product_packaging +#: model:ir.model,name:stock_lot_product_packaging.model_product_product +msgid "Product Variant" +msgstr "Variante de producto" + +#. module: stock_lot_product_packaging +#: model:ir.model,name:stock_lot_product_packaging.model_stock_quant +msgid "Quants" +msgstr "Cuantos" + +#. module: stock_lot_product_packaging +#: model_terms:ir.ui.view,arch_db:stock_lot_product_packaging.stock_package_type_search_view +msgid "Search Package Types" +msgstr "Buscar tipos paquete" + +#. module: stock_lot_product_packaging +#: model:ir.model,name:stock_lot_product_packaging.model_stock_package_type +msgid "Stock package type" +msgstr "Tipo de paquete de stock" diff --git a/stock_lot_product_packaging/i18n/stock_lot_product_packaging.pot b/stock_lot_product_packaging/i18n/stock_lot_product_packaging.pot new file mode 100644 index 0000000000..0576dd7089 --- /dev/null +++ b/stock_lot_product_packaging/i18n/stock_lot_product_packaging.pot @@ -0,0 +1,90 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * stock_lot_product_packaging +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 16.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2024-12-04 12:30+0000\n" +"PO-Revision-Date: 2024-12-04 12:30+0000\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_lot_product_packaging +#: model:ir.model.fields,field_description:stock_lot_product_packaging.field_product_product__product_density +#: model:ir.model.fields,field_description:stock_lot_product_packaging.field_product_template__product_density +#: model_terms:ir.ui.view,arch_db:stock_lot_product_packaging.product_template_form_view2 +msgid "Density" +msgstr "" + +#. module: stock_lot_product_packaging +#: model_terms:ir.ui.view,arch_db:stock_lot_product_packaging.product_template_form_view +msgid "Generate Packaging In Products" +msgstr "" + +#. module: stock_lot_product_packaging +#: model_terms:ir.ui.view,arch_db:stock_lot_product_packaging.stock_package_type_search_view +msgid "Group By" +msgstr "" + +#. module: stock_lot_product_packaging +#: model:ir.model,name:stock_lot_product_packaging.model_stock_lot +msgid "Lot/Serial" +msgstr "" + +#. module: stock_lot_product_packaging +#: model:ir.model.fields,field_description:stock_lot_product_packaging.field_product_product__package_type_ids +#: model:ir.model.fields,field_description:stock_lot_product_packaging.field_product_template__package_type_ids +#: model_terms:ir.ui.view,arch_db:stock_lot_product_packaging.product_template_form_view +msgid "Package types" +msgstr "" + +#. module: stock_lot_product_packaging +#: model:ir.model.fields,field_description:stock_lot_product_packaging.field_stock_lot__packaging_units +#: model:ir.model.fields,field_description:stock_lot_product_packaging.field_stock_quant__packaging_units +#: model_terms:ir.ui.view,arch_db:stock_lot_product_packaging.view_stock_quant_form_editable +msgid "Packaging Units" +msgstr "" + +#. module: stock_lot_product_packaging +#: model:ir.model,name:stock_lot_product_packaging.model_product_template +#: model:ir.model.fields,field_description:stock_lot_product_packaging.field_stock_package_type__product_tmpl_id +#: model_terms:ir.ui.view,arch_db:stock_lot_product_packaging.stock_package_type_search_view +msgid "Product" +msgstr "" + +#. module: stock_lot_product_packaging +#: model:ir.model.fields,field_description:stock_lot_product_packaging.field_product_product__product_package_ids +#: model_terms:ir.ui.view,arch_db:stock_lot_product_packaging.product_normal_form_view +msgid "Product Packages" +msgstr "" + +#. module: stock_lot_product_packaging +#: model:ir.model.fields,field_description:stock_lot_product_packaging.field_stock_lot__product_packaging_id +msgid "Product Packaging" +msgstr "" + +#. module: stock_lot_product_packaging +#: model:ir.model,name:stock_lot_product_packaging.model_product_product +msgid "Product Variant" +msgstr "" + +#. module: stock_lot_product_packaging +#: model:ir.model,name:stock_lot_product_packaging.model_stock_quant +msgid "Quants" +msgstr "" + +#. module: stock_lot_product_packaging +#: model_terms:ir.ui.view,arch_db:stock_lot_product_packaging.stock_package_type_search_view +msgid "Search Package Types" +msgstr "" + +#. module: stock_lot_product_packaging +#: model:ir.model,name:stock_lot_product_packaging.model_stock_package_type +msgid "Stock package type" +msgstr "" diff --git a/stock_lot_product_packaging/models/__init__.py b/stock_lot_product_packaging/models/__init__.py new file mode 100644 index 0000000000..059ccb133b --- /dev/null +++ b/stock_lot_product_packaging/models/__init__.py @@ -0,0 +1,5 @@ +from . import product_product +from . import product_template +from . import stock_lot +from . import stock_package_type +from . import stock_quant diff --git a/stock_lot_product_packaging/models/product_product.py b/stock_lot_product_packaging/models/product_product.py new file mode 100644 index 0000000000..d7db1118ca --- /dev/null +++ b/stock_lot_product_packaging/models/product_product.py @@ -0,0 +1,66 @@ +# Copyright 2024 Alfredo de la Fuente - AvanzOSC +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). +from odoo import api, fields, models + + +class ProductProduct(models.Model): + _inherit = "product.product" + + product_package_ids = fields.One2many( + string="Product Packages", + comodel_name="product.packaging", + inverse_name="product_id", + copy=False, + ) + + def action_create_product_packages(self): + for product in self: + for package_type in product.product_tmpl_id.package_type_ids: + product_package = product._search_product_package(package_type) + product._search_stock_lot_product_package(product_package) + + def _search_product_package(self, package_type): + product_packaging_obj = self.env["product.packaging"] + cond = [("product_id", "=", self.id), + ("package_type_id", "=", package_type.id)] + product_package = product_packaging_obj.search(cond, limit=1) + if product_package: + return product_package + vals = self._get_vals_product_packaging(package_type) + return product_packaging_obj.create(vals) + + def _get_vals_product_packaging(self, package_type): + weight_uom = self.env["product.template"]._get_weight_uom_id_from_ir_config_parameter() + density = ( + self.product_density * package_type.packaging_length * + package_type.width * package_type.height + ) + vals = { + "product_id": self.id, + "name": package_type.name, + "package_type_id": package_type.id, + "height": package_type.height, + "width": package_type.width, + "weight": package_type.base_weight, + "packaging_length": package_type.packaging_length, + "max_weight": package_type.max_weight, + "weight_uom_id": weight_uom.id, + "qty": density + } + return vals + + def _search_stock_lot_product_package(self, product_package): + stock_lot_obj = self.env["stock.lot"] + cond = [("product_id", "=", self.id), + ("product_packaging_id", "=", product_package.id)] + stock_lot = stock_lot_obj.search(cond, limit=1) + if not stock_lot: + vals = self._get_vals_stock_lot_packaging(product_package) + stock_lot_obj.create(vals) + + def _get_vals_stock_lot_packaging(self, product_package): + vals = { + "product_id": self.id, + "product_packaging_id": product_package.id + } + return vals \ No newline at end of file diff --git a/stock_lot_product_packaging/models/product_template.py b/stock_lot_product_packaging/models/product_template.py new file mode 100644 index 0000000000..047c8a4c7c --- /dev/null +++ b/stock_lot_product_packaging/models/product_template.py @@ -0,0 +1,22 @@ +# Copyright 2024 Alfredo de la Fuente - AvanzOSC +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). +from odoo import api, fields, models + + +class ProductTemplate(models.Model): + _inherit = "product.template" + + package_type_ids = fields.One2many( + string="Package types", + comodel_name="stock.package.type", + inverse_name="product_tmpl_id", + copy=False, + ) + product_density = fields.Float(string="Density", copy=False) + + def action_create_product_packages(self): + for template in self: + for product in template.product_variant_ids: + for package_type in template.package_type_ids: + product_package = product._search_product_package(package_type) + product._search_stock_lot_product_package(product_package) diff --git a/stock_lot_product_packaging/models/stock_lot.py b/stock_lot_product_packaging/models/stock_lot.py new file mode 100644 index 0000000000..4dd080d142 --- /dev/null +++ b/stock_lot_product_packaging/models/stock_lot.py @@ -0,0 +1,26 @@ +# Copyright 2024 Alfredo de la Fuente - AvanzOSC +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). +from odoo import api, fields, models + + +class StockLot(models.Model): + _inherit = "stock.lot" + + product_packaging_id = fields.Many2one( + string="Product Packaging", + comodel_name="product.packaging", + copy=False, + ) + packaging_units = fields.Float( + compute="_compute_packaging_units", store=True, copy=False + ) + + @api.depends("product_packaging_id", "product_packaging_id.qty", + "product_qty") + def _compute_packaging_units(self): + for lot in self: + packaging_units = 0 + if (lot.product_packaging_id and lot.product_packaging_id.qty and + lot.product_qty): + packaging_units = lot.product_qty / lot.product_packaging_id.qty + lot.packaging_units = packaging_units diff --git a/stock_lot_product_packaging/models/stock_package_type.py b/stock_lot_product_packaging/models/stock_package_type.py new file mode 100644 index 0000000000..05eb383b86 --- /dev/null +++ b/stock_lot_product_packaging/models/stock_package_type.py @@ -0,0 +1,13 @@ +# Copyright 2024 Alfredo de la Fuente - AvanzOSC +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). +from odoo import fields, models + + +class StockPackageType(models.Model): + _inherit = "stock.package.type" + + product_tmpl_id = fields.Many2one( + string="Product", + comodel_name="product.template", + copy=False, + ) diff --git a/stock_lot_product_packaging/models/stock_quant.py b/stock_lot_product_packaging/models/stock_quant.py new file mode 100644 index 0000000000..1db33286f6 --- /dev/null +++ b/stock_lot_product_packaging/models/stock_quant.py @@ -0,0 +1,12 @@ +# Copyright 2024 Alfredo de la Fuente - AvanzOSC +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). +from odoo import fields, models + + +class StockQuant(models.Model): + _inherit = "stock.quant" + + packaging_units = fields.Float( + string="Packaging Units", related="lot_id.packaging_units", + store=True, copy=False + ) diff --git a/stock_lot_product_packaging/views/product_product_views.xml b/stock_lot_product_packaging/views/product_product_views.xml new file mode 100644 index 0000000000..8399da6ba7 --- /dev/null +++ b/stock_lot_product_packaging/views/product_product_views.xml @@ -0,0 +1,22 @@ + + + + product.product + + + + 1 + + + + + + + + + + + + diff --git a/stock_lot_product_packaging/views/product_template_views.xml b/stock_lot_product_packaging/views/product_template_views.xml new file mode 100644 index 0000000000..25c90fec38 --- /dev/null +++ b/stock_lot_product_packaging/views/product_template_views.xml @@ -0,0 +1,30 @@ + + + + product.template + + + + + + + + + + + + + product.template + + + + + + + diff --git a/stock_lot_product_packaging/views/stock_lot_views.xml b/stock_lot_product_packaging/views/stock_lot_views.xml new file mode 100644 index 0000000000..387702535d --- /dev/null +++ b/stock_lot_product_packaging/views/stock_lot_views.xml @@ -0,0 +1,36 @@ + + + + stock.lot + + + + + + + + + + + + + stock.lot + + + + + + + + + + + stock.lot + + + + + + + + diff --git a/stock_lot_product_packaging/views/stock_package_type_views.xml b/stock_lot_product_packaging/views/stock_package_type_views.xml new file mode 100644 index 0000000000..558baa8cbe --- /dev/null +++ b/stock_lot_product_packaging/views/stock_package_type_views.xml @@ -0,0 +1,36 @@ + + + + stock.package.type + + + + + + + + + + stock.package.type + + + + + + + + stock.package.type.search.view + stock.package.type + + + + + + + + + + + diff --git a/stock_lot_product_packaging/views/stock_quant_views.xml b/stock_lot_product_packaging/views/stock_quant_views.xml new file mode 100644 index 0000000000..92779d334a --- /dev/null +++ b/stock_lot_product_packaging/views/stock_quant_views.xml @@ -0,0 +1,45 @@ + + + + stock.quant + + + + + + + + + stock.quant + + + + + + + + + + stock.quant + + + + + + + + + + stock.quant + + + + + + + +