diff --git a/product_ingredient/README.rst b/product_ingredient/README.rst new file mode 100644 index 00000000000..b1a5d744400 --- /dev/null +++ b/product_ingredient/README.rst @@ -0,0 +1,103 @@ +.. image:: https://odoo-community.org/readme-banner-image + :target: https://odoo-community.org/get-involved?utm_source=readme + :alt: Odoo Community Association + +=================== +Product Ingredients +=================== + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:8182b2531e945caaaf3b9f2e6eb279e48e9ccaffa0ff52c8f17f041f09022306 + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |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/license-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%2Fproduct--attribute-lightgray.png?logo=github + :target: https://github.com/OCA/product-attribute/tree/16.0/product_ingredient + :alt: OCA/product-attribute +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/product-attribute-16-0/product-attribute-16-0-product_ingredient + :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/product-attribute&target_branch=16.0 + :alt: Try me on Runboat + +|badge1| |badge2| |badge3| |badge4| |badge5| + +This module allows to set ingredients information for a given product. + +**Table of contents** + +.. contents:: + :local: + +Usage +===== + +To use this module you have to: + +- Create or edit a product variant or product template with just a + variant. +- Go to ingredients page +- Create some ingredients for the product. + +Now you can print the "Ingredients Info" report label. + +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 +------- + +* Tecnativa + +Contributors +------------ + +- `Tecnativa `__ + + - Sergio Teruel + - Carlos Dauden + +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-sergio-teruel| image:: https://github.com/sergio-teruel.png?size=40px + :target: https://github.com/sergio-teruel + :alt: sergio-teruel + +Current `maintainer `__: + +|maintainer-sergio-teruel| + +This module is part of the `OCA/product-attribute `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/product_ingredient/__init__.py b/product_ingredient/__init__.py new file mode 100644 index 00000000000..6d58305f5dd --- /dev/null +++ b/product_ingredient/__init__.py @@ -0,0 +1,2 @@ +from . import models +from .hooks import pre_init_hook diff --git a/product_ingredient/__manifest__.py b/product_ingredient/__manifest__.py new file mode 100644 index 00000000000..37a52609f7a --- /dev/null +++ b/product_ingredient/__manifest__.py @@ -0,0 +1,26 @@ +# Copyright 2023 Tecnativa - Sergio Teruel +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +{ + "name": "Product Ingredients", + "summary": "Product ingredients", + "version": "16.0.1.0.1", + "development_status": "Beta", + "category": "Technical Settings", + "website": "https://github.com/OCA/product-attribute", + "author": "Tecnativa, Odoo Community Association (OCA)", + "maintainers": ["sergio-teruel"], + "license": "AGPL-3", + "depends": ["product", "stock"], + "external_dependencies": {"python": ["openupgradelib"]}, + "data": [ + "security/ir.model.access.csv", + "data/product_allergen_data.xml", + "views/product_attribute_value_views.xml", + "views/product_ingredient_views.xml", + "views/product_views.xml", + "views/stock_lot_view.xml", + ], + "pre_init_hook": "pre_init_hook", + "application": False, + "installable": True, +} diff --git a/product_ingredient/data/product_allergen_data.xml b/product_ingredient/data/product_allergen_data.xml new file mode 100644 index 00000000000..b092685c9d8 --- /dev/null +++ b/product_ingredient/data/product_allergen_data.xml @@ -0,0 +1,9 @@ + + + + + Allergens + no_variant + select + + diff --git a/product_ingredient/hooks.py b/product_ingredient/hooks.py new file mode 100644 index 00000000000..85d425fbee4 --- /dev/null +++ b/product_ingredient/hooks.py @@ -0,0 +1,10 @@ +# Copyright 2023 Tecnativa - Carlos Dauden +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). +from openupgradelib import openupgrade + + +def pre_init_hook(cr): + """ + Create product_allergen_attribute used in compute methods with get_allergen_id() + """ + openupgrade.load_data(cr, "product_ingredient", "data/product_allergen_data.xml") diff --git a/product_ingredient/i18n/es.po b/product_ingredient/i18n/es.po new file mode 100644 index 00000000000..0958a604e0c --- /dev/null +++ b/product_ingredient/i18n/es.po @@ -0,0 +1,183 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * product_ingredient +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 15.0\n" +"Report-Msgid-Bugs-To: \n" +"Last-Translator: Carlos Roca Zaragoza \n" +"Language-Team: none\n" +"Language: es\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" +"X-Generator: Weblate 5.15.2\n" + +#. module: product_ingredient +#: model:ir.model.fields,field_description:product_ingredient.field_product_ingredient__allergen_id +#: model:ir.model.fields,field_description:product_ingredient.field_product_ingredient_value__allergen_id +#: model:ir.model.fields,field_description:product_ingredient.field_stock_lot_ingredient_value__allergen_id +msgid "Allergen" +msgstr "Alérgeno" + +#. module: product_ingredient +#: model:ir.model.fields,field_description:product_ingredient.field_product_product__ingredient_allergen_trace_ids +#: model:ir.model.fields,field_description:product_ingredient.field_product_template__ingredient_allergen_trace_ids +msgid "Allergen traces" +msgstr "Trazas alérgenas" + +#. module: product_ingredient +#: model:ir.model.fields,field_description:product_ingredient.field_product_product__allergen_ids +#: model:ir.model.fields,field_description:product_ingredient.field_product_template__allergen_ids +#: model:product.attribute,name:product_ingredient.product_allergen_attribute +msgid "Allergens" +msgstr "Alérgenos" + +#. module: product_ingredient +#: model:ir.model,name:product_ingredient.model_product_attribute_value +msgid "Attribute Value" +msgstr "Valor del Atributo" + +#. module: product_ingredient +#: model:ir.model.fields,field_description:product_ingredient.field_product_ingredient__create_uid +#: model:ir.model.fields,field_description:product_ingredient.field_product_ingredient_value__create_uid +#: model:ir.model.fields,field_description:product_ingredient.field_stock_lot_ingredient_value__create_uid +msgid "Created by" +msgstr "Creado por" + +#. module: product_ingredient +#: model:ir.model.fields,field_description:product_ingredient.field_product_ingredient__create_date +#: model:ir.model.fields,field_description:product_ingredient.field_product_ingredient_value__create_date +#: model:ir.model.fields,field_description:product_ingredient.field_stock_lot_ingredient_value__create_date +msgid "Created on" +msgstr "Creado el" + +#. module: product_ingredient +#: model:ir.model.fields,field_description:product_ingredient.field_product_ingredient__display_name +#: model:ir.model.fields,field_description:product_ingredient.field_product_ingredient_value__display_name +#: model:ir.model.fields,field_description:product_ingredient.field_stock_lot_ingredient_value__display_name +msgid "Display Name" +msgstr "Nombre mostrado" + +#. module: product_ingredient +#: model:ir.model.fields,field_description:product_ingredient.field_product_ingredient__id +#: model:ir.model.fields,field_description:product_ingredient.field_product_ingredient_value__id +#: model:ir.model.fields,field_description:product_ingredient.field_stock_lot_ingredient_value__id +msgid "ID" +msgstr "ID" + +#. module: product_ingredient +#: model:ir.model.fields,field_description:product_ingredient.field_product_ingredient_value__ingredient_id +#: model:ir.model.fields,field_description:product_ingredient.field_stock_lot__ingredient_ids +#: model:ir.model.fields,field_description:product_ingredient.field_stock_lot_ingredient_value__ingredient_id +msgid "Ingredient" +msgstr "Ingrediente" + +#. module: product_ingredient +#: model:ir.model.fields,field_description:product_ingredient.field_product_product__ingredient_additional_info +#: model:ir.model.fields,field_description:product_ingredient.field_product_template__ingredient_additional_info +#: model:ir.model.fields,field_description:product_ingredient.field_stock_lot__ingredient_additional_info +msgid "Ingredient Additional Info" +msgstr "Información adicional del ingrediente" + +#. module: product_ingredient +#: model:ir.model.fields,field_description:product_ingredient.field_stock_lot__ingredient_allergen_trace_ids +msgid "Ingredient Allergen Trace" +msgstr "Traza alérgena del ingrediente" + +#. module: product_ingredient +#: model:ir.model,name:product_ingredient.model_stock_lot_ingredient_value +msgid "Ingredient values for a product lots." +msgstr "Valores de los ingredientes de un lote de producto." + +#. module: product_ingredient +#: model:ir.model,name:product_ingredient.model_product_ingredient_value +msgid "Ingredient values for a product." +msgstr "Valores de los ingredientes de un producto." + +#. module: product_ingredient +#: model:ir.model.fields,field_description:product_ingredient.field_product_product__ingredient_ids +#: model:ir.model.fields,field_description:product_ingredient.field_product_template__ingredient_ids +#: model_terms:ir.ui.view,arch_db:product_ingredient.product_normal_form_view +#: model_terms:ir.ui.view,arch_db:product_ingredient.product_template_only_form_view +#: model_terms:ir.ui.view,arch_db:product_ingredient.view_production_lot_form +msgid "Ingredients" +msgstr "Ingredientes" + +#. module: product_ingredient +#: model:ir.model,name:product_ingredient.model_product_ingredient +msgid "Ingredients of a product." +msgstr "Ingredientes para un producto." + +#. module: product_ingredient +#: model:ir.model.fields,field_description:product_ingredient.field_product_ingredient__is_allergen +#: model:ir.model.fields,field_description:product_ingredient.field_product_ingredient_value__is_allergen +#: model:ir.model.fields,field_description:product_ingredient.field_stock_lot_ingredient_value__is_allergen +msgid "Is Allergen" +msgstr "Es alérgeno" + +#. module: product_ingredient +#: model:ir.model.fields,field_description:product_ingredient.field_product_ingredient__write_uid +#: model:ir.model.fields,field_description:product_ingredient.field_product_ingredient_value__write_uid +#: model:ir.model.fields,field_description:product_ingredient.field_stock_lot_ingredient_value__write_uid +msgid "Last Updated by" +msgstr "Última actualización por" + +#. module: product_ingredient +#: model:ir.model.fields,field_description:product_ingredient.field_product_ingredient__write_date +#: model:ir.model.fields,field_description:product_ingredient.field_product_ingredient_value__write_date +#: model:ir.model.fields,field_description:product_ingredient.field_stock_lot_ingredient_value__write_date +msgid "Last Updated on" +msgstr "Última actualización el" + +#. module: product_ingredient +#: model:ir.model.fields,field_description:product_ingredient.field_stock_lot_ingredient_value__lot_id +msgid "Lot" +msgstr "Lote" + +#. module: product_ingredient +#: model:ir.model,name:product_ingredient.model_stock_lot +msgid "Lot/Serial" +msgstr "Lote/Número de serie" + +#. module: product_ingredient +#: model:ir.model.fields,field_description:product_ingredient.field_product_ingredient__name +msgid "Name" +msgstr "Nombre" + +#. module: product_ingredient +#: model:ir.model.fields,field_description:product_ingredient.field_product_ingredient_value__percentage +#: model:ir.model.fields,field_description:product_ingredient.field_stock_lot_ingredient_value__percentage +msgid "Percentage" +msgstr "Porcentaje" + +#. module: product_ingredient +#: model:ir.model,name:product_ingredient.model_product_template +#: model:ir.model.fields,field_description:product_ingredient.field_product_ingredient_value__product_id +msgid "Product" +msgstr "Producto" + +#. module: product_ingredient +#: model:ir.model,name:product_ingredient.model_product_attribute +msgid "Product Attribute" +msgstr "Atributo de producto" + +#. module: product_ingredient +#: model:ir.model,name:product_ingredient.model_product_product +msgid "Product Variant" +msgstr "Variante de producto" + +#. module: product_ingredient +#: model:ir.model.fields,field_description:product_ingredient.field_product_ingredient__scientific_name +#: model:ir.model.fields,field_description:product_ingredient.field_product_ingredient_value__scientific_name +#: model:ir.model.fields,field_description:product_ingredient.field_stock_lot_ingredient_value__scientific_name +msgid "Scientific Name" +msgstr "Nombre científico" + +#. module: product_ingredient +#: model:ir.model.fields,field_description:product_ingredient.field_product_ingredient_value__sequence +#: model:ir.model.fields,field_description:product_ingredient.field_stock_lot_ingredient_value__sequence +msgid "Sequence" +msgstr "Secuencia" diff --git a/product_ingredient/i18n/it.po b/product_ingredient/i18n/it.po new file mode 100644 index 00000000000..4657f810315 --- /dev/null +++ b/product_ingredient/i18n/it.po @@ -0,0 +1,184 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * product_ingredient +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 18.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2026-04-14 14:45+0000\n" +"Last-Translator: mymage \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" +"X-Generator: Weblate 5.15.2\n" + +#. module: product_ingredient +#: model:ir.model.fields,field_description:product_ingredient.field_product_ingredient__allergen_id +#: model:ir.model.fields,field_description:product_ingredient.field_product_ingredient_value__allergen_id +#: model:ir.model.fields,field_description:product_ingredient.field_stock_lot_ingredient_value__allergen_id +msgid "Allergen" +msgstr "Allergene" + +#. module: product_ingredient +#: model:ir.model.fields,field_description:product_ingredient.field_product_product__ingredient_allergen_trace_ids +#: model:ir.model.fields,field_description:product_ingredient.field_product_template__ingredient_allergen_trace_ids +msgid "Allergen traces" +msgstr "Traccie di allergene" + +#. module: product_ingredient +#: model:ir.model.fields,field_description:product_ingredient.field_product_product__allergen_ids +#: model:ir.model.fields,field_description:product_ingredient.field_product_template__allergen_ids +#: model:product.attribute,name:product_ingredient.product_allergen_attribute +msgid "Allergens" +msgstr "Allergeni" + +#. module: product_ingredient +#: model:ir.model,name:product_ingredient.model_product_attribute_value +msgid "Attribute Value" +msgstr "Valore attributo" + +#. module: product_ingredient +#: model:ir.model.fields,field_description:product_ingredient.field_product_ingredient__create_uid +#: model:ir.model.fields,field_description:product_ingredient.field_product_ingredient_value__create_uid +#: model:ir.model.fields,field_description:product_ingredient.field_stock_lot_ingredient_value__create_uid +msgid "Created by" +msgstr "Creato da" + +#. module: product_ingredient +#: model:ir.model.fields,field_description:product_ingredient.field_product_ingredient__create_date +#: model:ir.model.fields,field_description:product_ingredient.field_product_ingredient_value__create_date +#: model:ir.model.fields,field_description:product_ingredient.field_stock_lot_ingredient_value__create_date +msgid "Created on" +msgstr "Creato il" + +#. module: product_ingredient +#: model:ir.model.fields,field_description:product_ingredient.field_product_ingredient__display_name +#: model:ir.model.fields,field_description:product_ingredient.field_product_ingredient_value__display_name +#: model:ir.model.fields,field_description:product_ingredient.field_stock_lot_ingredient_value__display_name +msgid "Display Name" +msgstr "Nome visualizzato" + +#. module: product_ingredient +#: model:ir.model.fields,field_description:product_ingredient.field_product_ingredient__id +#: model:ir.model.fields,field_description:product_ingredient.field_product_ingredient_value__id +#: model:ir.model.fields,field_description:product_ingredient.field_stock_lot_ingredient_value__id +msgid "ID" +msgstr "ID" + +#. module: product_ingredient +#: model:ir.model.fields,field_description:product_ingredient.field_product_ingredient_value__ingredient_id +#: model:ir.model.fields,field_description:product_ingredient.field_stock_lot__ingredient_ids +#: model:ir.model.fields,field_description:product_ingredient.field_stock_lot_ingredient_value__ingredient_id +msgid "Ingredient" +msgstr "Ingrediente" + +#. module: product_ingredient +#: model:ir.model.fields,field_description:product_ingredient.field_product_product__ingredient_additional_info +#: model:ir.model.fields,field_description:product_ingredient.field_product_template__ingredient_additional_info +#: model:ir.model.fields,field_description:product_ingredient.field_stock_lot__ingredient_additional_info +msgid "Ingredient Additional Info" +msgstr "Informazioni addizionali ingrediente" + +#. module: product_ingredient +#: model:ir.model.fields,field_description:product_ingredient.field_stock_lot__ingredient_allergen_trace_ids +msgid "Ingredient Allergen Trace" +msgstr "Traccia allergene ingrediente" + +#. module: product_ingredient +#: model:ir.model,name:product_ingredient.model_stock_lot_ingredient_value +msgid "Ingredient values for a product lots." +msgstr "Valori ingrediente per i lotti di un prodotto." + +#. module: product_ingredient +#: model:ir.model,name:product_ingredient.model_product_ingredient_value +msgid "Ingredient values for a product." +msgstr "Valori ingrediente per un prodotto." + +#. module: product_ingredient +#: model:ir.model.fields,field_description:product_ingredient.field_product_product__ingredient_ids +#: model:ir.model.fields,field_description:product_ingredient.field_product_template__ingredient_ids +#: model_terms:ir.ui.view,arch_db:product_ingredient.product_normal_form_view +#: model_terms:ir.ui.view,arch_db:product_ingredient.product_template_only_form_view +#: model_terms:ir.ui.view,arch_db:product_ingredient.view_production_lot_form +msgid "Ingredients" +msgstr "Ingredienti" + +#. module: product_ingredient +#: model:ir.model,name:product_ingredient.model_product_ingredient +msgid "Ingredients of a product." +msgstr "Ingredienti di un prodotto." + +#. module: product_ingredient +#: model:ir.model.fields,field_description:product_ingredient.field_product_ingredient__is_allergen +#: model:ir.model.fields,field_description:product_ingredient.field_product_ingredient_value__is_allergen +#: model:ir.model.fields,field_description:product_ingredient.field_stock_lot_ingredient_value__is_allergen +msgid "Is Allergen" +msgstr "È allergene" + +#. module: product_ingredient +#: model:ir.model.fields,field_description:product_ingredient.field_product_ingredient__write_uid +#: model:ir.model.fields,field_description:product_ingredient.field_product_ingredient_value__write_uid +#: model:ir.model.fields,field_description:product_ingredient.field_stock_lot_ingredient_value__write_uid +msgid "Last Updated by" +msgstr "Ultimo aggiornamento di" + +#. module: product_ingredient +#: model:ir.model.fields,field_description:product_ingredient.field_product_ingredient__write_date +#: model:ir.model.fields,field_description:product_ingredient.field_product_ingredient_value__write_date +#: model:ir.model.fields,field_description:product_ingredient.field_stock_lot_ingredient_value__write_date +msgid "Last Updated on" +msgstr "Ultimo aggiornamento il" + +#. module: product_ingredient +#: model:ir.model.fields,field_description:product_ingredient.field_stock_lot_ingredient_value__lot_id +msgid "Lot" +msgstr "Lotto" + +#. module: product_ingredient +#: model:ir.model,name:product_ingredient.model_stock_lot +msgid "Lot/Serial" +msgstr "Lotto/seriale" + +#. module: product_ingredient +#: model:ir.model.fields,field_description:product_ingredient.field_product_ingredient__name +msgid "Name" +msgstr "Nome" + +#. module: product_ingredient +#: model:ir.model.fields,field_description:product_ingredient.field_product_ingredient_value__percentage +#: model:ir.model.fields,field_description:product_ingredient.field_stock_lot_ingredient_value__percentage +msgid "Percentage" +msgstr "Percentuale" + +#. module: product_ingredient +#: model:ir.model,name:product_ingredient.model_product_template +#: model:ir.model.fields,field_description:product_ingredient.field_product_ingredient_value__product_id +msgid "Product" +msgstr "Prodotto" + +#. module: product_ingredient +#: model:ir.model,name:product_ingredient.model_product_attribute +msgid "Product Attribute" +msgstr "Attributo prodotto" + +#. module: product_ingredient +#: model:ir.model,name:product_ingredient.model_product_product +msgid "Product Variant" +msgstr "Variante prodotto" + +#. module: product_ingredient +#: model:ir.model.fields,field_description:product_ingredient.field_product_ingredient__scientific_name +#: model:ir.model.fields,field_description:product_ingredient.field_product_ingredient_value__scientific_name +#: model:ir.model.fields,field_description:product_ingredient.field_stock_lot_ingredient_value__scientific_name +msgid "Scientific Name" +msgstr "Nome scientifico" + +#. module: product_ingredient +#: model:ir.model.fields,field_description:product_ingredient.field_product_ingredient_value__sequence +#: model:ir.model.fields,field_description:product_ingredient.field_stock_lot_ingredient_value__sequence +msgid "Sequence" +msgstr "Sequenza" diff --git a/product_ingredient/i18n/product_ingredient.pot b/product_ingredient/i18n/product_ingredient.pot new file mode 100644 index 00000000000..016beeb136c --- /dev/null +++ b/product_ingredient/i18n/product_ingredient.pot @@ -0,0 +1,181 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * product_ingredient +# +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: product_ingredient +#: model:ir.model.fields,field_description:product_ingredient.field_product_ingredient__allergen_id +#: model:ir.model.fields,field_description:product_ingredient.field_product_ingredient_value__allergen_id +#: model:ir.model.fields,field_description:product_ingredient.field_stock_lot_ingredient_value__allergen_id +msgid "Allergen" +msgstr "" + +#. module: product_ingredient +#: model:ir.model.fields,field_description:product_ingredient.field_product_product__ingredient_allergen_trace_ids +#: model:ir.model.fields,field_description:product_ingredient.field_product_template__ingredient_allergen_trace_ids +msgid "Allergen traces" +msgstr "" + +#. module: product_ingredient +#: model:ir.model.fields,field_description:product_ingredient.field_product_product__allergen_ids +#: model:ir.model.fields,field_description:product_ingredient.field_product_template__allergen_ids +#: model:product.attribute,name:product_ingredient.product_allergen_attribute +msgid "Allergens" +msgstr "" + +#. module: product_ingredient +#: model:ir.model,name:product_ingredient.model_product_attribute_value +msgid "Attribute Value" +msgstr "" + +#. module: product_ingredient +#: model:ir.model.fields,field_description:product_ingredient.field_product_ingredient__create_uid +#: model:ir.model.fields,field_description:product_ingredient.field_product_ingredient_value__create_uid +#: model:ir.model.fields,field_description:product_ingredient.field_stock_lot_ingredient_value__create_uid +msgid "Created by" +msgstr "" + +#. module: product_ingredient +#: model:ir.model.fields,field_description:product_ingredient.field_product_ingredient__create_date +#: model:ir.model.fields,field_description:product_ingredient.field_product_ingredient_value__create_date +#: model:ir.model.fields,field_description:product_ingredient.field_stock_lot_ingredient_value__create_date +msgid "Created on" +msgstr "" + +#. module: product_ingredient +#: model:ir.model.fields,field_description:product_ingredient.field_product_ingredient__display_name +#: model:ir.model.fields,field_description:product_ingredient.field_product_ingredient_value__display_name +#: model:ir.model.fields,field_description:product_ingredient.field_stock_lot_ingredient_value__display_name +msgid "Display Name" +msgstr "" + +#. module: product_ingredient +#: model:ir.model.fields,field_description:product_ingredient.field_product_ingredient__id +#: model:ir.model.fields,field_description:product_ingredient.field_product_ingredient_value__id +#: model:ir.model.fields,field_description:product_ingredient.field_stock_lot_ingredient_value__id +msgid "ID" +msgstr "" + +#. module: product_ingredient +#: model:ir.model.fields,field_description:product_ingredient.field_product_ingredient_value__ingredient_id +#: model:ir.model.fields,field_description:product_ingredient.field_stock_lot__ingredient_ids +#: model:ir.model.fields,field_description:product_ingredient.field_stock_lot_ingredient_value__ingredient_id +msgid "Ingredient" +msgstr "" + +#. module: product_ingredient +#: model:ir.model.fields,field_description:product_ingredient.field_product_product__ingredient_additional_info +#: model:ir.model.fields,field_description:product_ingredient.field_product_template__ingredient_additional_info +#: model:ir.model.fields,field_description:product_ingredient.field_stock_lot__ingredient_additional_info +msgid "Ingredient Additional Info" +msgstr "" + +#. module: product_ingredient +#: model:ir.model.fields,field_description:product_ingredient.field_stock_lot__ingredient_allergen_trace_ids +msgid "Ingredient Allergen Trace" +msgstr "" + +#. module: product_ingredient +#: model:ir.model,name:product_ingredient.model_stock_lot_ingredient_value +msgid "Ingredient values for a product lots." +msgstr "" + +#. module: product_ingredient +#: model:ir.model,name:product_ingredient.model_product_ingredient_value +msgid "Ingredient values for a product." +msgstr "" + +#. module: product_ingredient +#: model:ir.model.fields,field_description:product_ingredient.field_product_product__ingredient_ids +#: model:ir.model.fields,field_description:product_ingredient.field_product_template__ingredient_ids +#: model_terms:ir.ui.view,arch_db:product_ingredient.product_normal_form_view +#: model_terms:ir.ui.view,arch_db:product_ingredient.product_template_only_form_view +#: model_terms:ir.ui.view,arch_db:product_ingredient.view_production_lot_form +msgid "Ingredients" +msgstr "" + +#. module: product_ingredient +#: model:ir.model,name:product_ingredient.model_product_ingredient +msgid "Ingredients of a product." +msgstr "" + +#. module: product_ingredient +#: model:ir.model.fields,field_description:product_ingredient.field_product_ingredient__is_allergen +#: model:ir.model.fields,field_description:product_ingredient.field_product_ingredient_value__is_allergen +#: model:ir.model.fields,field_description:product_ingredient.field_stock_lot_ingredient_value__is_allergen +msgid "Is Allergen" +msgstr "" + +#. module: product_ingredient +#: model:ir.model.fields,field_description:product_ingredient.field_product_ingredient__write_uid +#: model:ir.model.fields,field_description:product_ingredient.field_product_ingredient_value__write_uid +#: model:ir.model.fields,field_description:product_ingredient.field_stock_lot_ingredient_value__write_uid +msgid "Last Updated by" +msgstr "" + +#. module: product_ingredient +#: model:ir.model.fields,field_description:product_ingredient.field_product_ingredient__write_date +#: model:ir.model.fields,field_description:product_ingredient.field_product_ingredient_value__write_date +#: model:ir.model.fields,field_description:product_ingredient.field_stock_lot_ingredient_value__write_date +msgid "Last Updated on" +msgstr "" + +#. module: product_ingredient +#: model:ir.model.fields,field_description:product_ingredient.field_stock_lot_ingredient_value__lot_id +msgid "Lot" +msgstr "" + +#. module: product_ingredient +#: model:ir.model,name:product_ingredient.model_stock_lot +msgid "Lot/Serial" +msgstr "" + +#. module: product_ingredient +#: model:ir.model.fields,field_description:product_ingredient.field_product_ingredient__name +msgid "Name" +msgstr "" + +#. module: product_ingredient +#: model:ir.model.fields,field_description:product_ingredient.field_product_ingredient_value__percentage +#: model:ir.model.fields,field_description:product_ingredient.field_stock_lot_ingredient_value__percentage +msgid "Percentage" +msgstr "" + +#. module: product_ingredient +#: model:ir.model,name:product_ingredient.model_product_template +#: model:ir.model.fields,field_description:product_ingredient.field_product_ingredient_value__product_id +msgid "Product" +msgstr "" + +#. module: product_ingredient +#: model:ir.model,name:product_ingredient.model_product_attribute +msgid "Product Attribute" +msgstr "" + +#. module: product_ingredient +#: model:ir.model,name:product_ingredient.model_product_product +msgid "Product Variant" +msgstr "" + +#. module: product_ingredient +#: model:ir.model.fields,field_description:product_ingredient.field_product_ingredient__scientific_name +#: model:ir.model.fields,field_description:product_ingredient.field_product_ingredient_value__scientific_name +#: model:ir.model.fields,field_description:product_ingredient.field_stock_lot_ingredient_value__scientific_name +msgid "Scientific Name" +msgstr "" + +#. module: product_ingredient +#: model:ir.model.fields,field_description:product_ingredient.field_product_ingredient_value__sequence +#: model:ir.model.fields,field_description:product_ingredient.field_stock_lot_ingredient_value__sequence +msgid "Sequence" +msgstr "" diff --git a/product_ingredient/migrations/16.0.1.0.0/pre-migration.py b/product_ingredient/migrations/16.0.1.0.0/pre-migration.py new file mode 100644 index 00000000000..31b36231899 --- /dev/null +++ b/product_ingredient/migrations/16.0.1.0.0/pre-migration.py @@ -0,0 +1,19 @@ +from openupgradelib import openupgrade + + +@openupgrade.migrate() +def migrate(env, version): + if openupgrade.table_exists( + env.cr, "production_lot_ingredient_value" + ) and not openupgrade.table_exists(env.cr, "stock_lot_ingredient_value"): + openupgrade.rename_models( + env.cr, [("production.lot.ingredient.value", "stock.lot.ingredient.value")] + ) + openupgrade.rename_tables( + env.cr, [("production_lot_ingredient_value", "stock_lot_ingredient_value")] + ) + fields_rename_spec = [ + ("product.product", "product_product", "allergen_id", "allergen_ids"), + ("product.template", "product_template", "allergen_id", "allergen_ids"), + ] + openupgrade.rename_fields(env, fields_rename_spec) diff --git a/product_ingredient/models/__init__.py b/product_ingredient/models/__init__.py new file mode 100644 index 00000000000..97edad52c62 --- /dev/null +++ b/product_ingredient/models/__init__.py @@ -0,0 +1,8 @@ +from . import product_attribute +from . import product_attribute_value +from . import stock_lot +from . import product_ingredient +from . import product_ingredient_value +from . import stock_lot_ingredient_value +from . import product_product +from . import product_template diff --git a/product_ingredient/models/product_attribute.py b/product_ingredient/models/product_attribute.py new file mode 100644 index 00000000000..edacd1a0ba7 --- /dev/null +++ b/product_ingredient/models/product_attribute.py @@ -0,0 +1,14 @@ +# Copyright 2023 Tecnativa - Carlos Dauden +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +from odoo import api, models +from odoo.tools import ormcache + + +class ProductAttribute(models.Model): + _inherit = "product.attribute" + + @api.model + @ormcache() + def get_allergen_id(self): + """Helper to get allergen attribute id""" + return self.env.ref("product_ingredient.product_allergen_attribute").id diff --git a/product_ingredient/models/product_attribute_value.py b/product_ingredient/models/product_attribute_value.py new file mode 100644 index 00000000000..9c00eaad9e5 --- /dev/null +++ b/product_ingredient/models/product_attribute_value.py @@ -0,0 +1,14 @@ +# Copyright 2023 Tecnativa - Carlos Dauden +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +from odoo import api, models + + +class ProductAttributeValue(models.Model): + _inherit = "product.attribute.value" + + @api.model + def default_get(self, fields_list): + res = super().default_get(fields_list) + if self.env.context.get("set_allergen_attribute"): + res["attribute_id"] = self.env["product.attribute"].get_allergen_id() + return res diff --git a/product_ingredient/models/product_ingredient.py b/product_ingredient/models/product_ingredient.py new file mode 100644 index 00000000000..b102dfffa5f --- /dev/null +++ b/product_ingredient/models/product_ingredient.py @@ -0,0 +1,19 @@ +# Copyright 2023 Tecnativa - Sergio Teruel +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +from odoo import fields, models + + +class ProductIngredients(models.Model): + _name = "product.ingredient" + _description = "Ingredients of a product." + + name = fields.Char(translate=True) + scientific_name = fields.Char() + allergen_id = fields.Many2one( + comodel_name="product.attribute.value", + domain=lambda self: [ + ("attribute_id", "=", self.env["product.attribute"].get_allergen_id()) + ], + context={"set_allergen_attribute": True, "show_attribute": False}, + ) + is_allergen = fields.Boolean() diff --git a/product_ingredient/models/product_ingredient_value.py b/product_ingredient/models/product_ingredient_value.py new file mode 100644 index 00000000000..9a295824c9c --- /dev/null +++ b/product_ingredient/models/product_ingredient_value.py @@ -0,0 +1,18 @@ +# Copyright 2023 Tecnativa - Sergio Teruel +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +from odoo import fields, models + + +class ProductIngredientValue(models.Model): + _name = "product.ingredient.value" + _description = "Ingredient values for a product." + _rec_name = "ingredient_id" + _order = "sequence, id" + + sequence = fields.Integer() + product_id = fields.Many2one(comodel_name="product.product") + ingredient_id = fields.Many2one(comodel_name="product.ingredient") + scientific_name = fields.Char(related="ingredient_id.scientific_name") + allergen_id = fields.Many2one(related="ingredient_id.allergen_id") + percentage = fields.Float(digits="Product Unit of Measure") + is_allergen = fields.Boolean(related="ingredient_id.is_allergen") diff --git a/product_ingredient/models/product_product.py b/product_ingredient/models/product_product.py new file mode 100644 index 00000000000..ae74d209c22 --- /dev/null +++ b/product_ingredient/models/product_product.py @@ -0,0 +1,35 @@ +# Copyright 2023 Tecnativa - Sergio Teruel +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +from odoo import api, fields, models + + +class ProductProduct(models.Model): + _inherit = "product.product" + + allergen_ids = fields.Many2many( + comodel_name="product.attribute.value", + compute="_compute_allergen_id", + string="Allergens", + ) + ingredient_ids = fields.One2many( + comodel_name="product.ingredient.value", + inverse_name="product_id", + string="Ingredients", + ) + ingredient_allergen_trace_ids = fields.Many2many( + comodel_name="product.attribute.value", + string="Allergen traces", + domain=lambda self: [ + ("attribute_id", "=", self.env["product.attribute"].get_allergen_id()) + ], + context={"set_allergen_attribute": True, "show_attribute": False}, + ) + ingredient_additional_info = fields.Text(translate=True) + + @api.depends("ingredient_ids", "ingredient_allergen_trace_ids") + def _compute_allergen_id(self): + for product in self: + product.allergen_ids = ( + product.ingredient_ids.mapped("allergen_id") + + product.ingredient_allergen_trace_ids + ) diff --git a/product_ingredient/models/product_template.py b/product_ingredient/models/product_template.py new file mode 100644 index 00000000000..c7da3391398 --- /dev/null +++ b/product_ingredient/models/product_template.py @@ -0,0 +1,19 @@ +# Copyright 2023 Tecnativa - Sergio Teruel +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +from odoo import fields, models + + +class ProductTemplate(models.Model): + _inherit = "product.template" + + allergen_ids = fields.Many2many(related="product_variant_ids.allergen_ids") + ingredient_ids = fields.One2many( + related="product_variant_ids.ingredient_ids", + readonly=False, + ) + ingredient_allergen_trace_ids = fields.Many2many( + related="product_variant_ids.ingredient_allergen_trace_ids", readonly=False + ) + ingredient_additional_info = fields.Text( + related="product_variant_ids.ingredient_additional_info", readonly=False + ) diff --git a/product_ingredient/models/stock_lot.py b/product_ingredient/models/stock_lot.py new file mode 100644 index 00000000000..c611e95ed25 --- /dev/null +++ b/product_ingredient/models/stock_lot.py @@ -0,0 +1,48 @@ +# Copyright 2023 Tecnativa - Sergio Teruel +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +from odoo import Command, api, fields, models + + +class StockLot(models.Model): + _inherit = "stock.lot" + + ingredient_ids = fields.One2many( + comodel_name="stock.lot.ingredient.value", + inverse_name="lot_id", + compute="_compute_ingredient_values", + store=True, + readonly=False, + ) + ingredient_allergen_trace_ids = fields.Many2many( + comodel_name="product.attribute.value", + compute="_compute_ingredient_values", + readonly=False, + domain=lambda self: [ + ("attribute_id", "=", self.env["product.attribute"].get_allergen_id()) + ], + context={"set_allergen_attribute": True, "show_attribute": False}, + store=True, + ) + ingredient_additional_info = fields.Text( + compute="_compute_ingredient_values", readonly=False, store=True, translate=True + ) + + @api.depends("product_id") + def _compute_ingredient_values(self): + for lot in self: + ingredient_list = [Command.clear()] + for ingredient_line in lot.product_id.ingredient_ids: + ingredient_list.append( + Command.create( + { + "sequence": ingredient_line.sequence, + "ingredient_id": ingredient_line.ingredient_id.id, + "percentage": ingredient_line.percentage, + }, + ) + ) + lot.ingredient_ids = ingredient_list + lot.ingredient_allergen_trace_ids = ( + lot.product_id.ingredient_allergen_trace_ids + ) + lot.ingredient_additional_info = lot.product_id.ingredient_additional_info diff --git a/product_ingredient/models/stock_lot_ingredient_value.py b/product_ingredient/models/stock_lot_ingredient_value.py new file mode 100644 index 00000000000..4a38264ca37 --- /dev/null +++ b/product_ingredient/models/stock_lot_ingredient_value.py @@ -0,0 +1,19 @@ +# Copyright 2023 Tecnativa - Sergio Teruel +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +from odoo import fields, models + + +class ProductionLotIngredientValue(models.Model): + _name = "stock.lot.ingredient.value" + _description = "Ingredient values for a product lots." + _rec_name = "ingredient_id" + _order = "sequence, id" + + sequence = fields.Integer() + lot_id = fields.Many2one(comodel_name="stock.lot") + # product_id = fields.Many2one(related='lot_id.product_id') + ingredient_id = fields.Many2one(comodel_name="product.ingredient") + scientific_name = fields.Char(related="ingredient_id.scientific_name") + allergen_id = fields.Many2one(related="ingredient_id.allergen_id") + percentage = fields.Float(digits="Product Unit of Measure") + is_allergen = fields.Boolean(related="ingredient_id.is_allergen") diff --git a/product_ingredient/pyproject.toml b/product_ingredient/pyproject.toml new file mode 100644 index 00000000000..4231d0cccb3 --- /dev/null +++ b/product_ingredient/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["whool"] +build-backend = "whool.buildapi" diff --git a/product_ingredient/readme/CONTRIBUTORS.md b/product_ingredient/readme/CONTRIBUTORS.md new file mode 100644 index 00000000000..ae3658e55ec --- /dev/null +++ b/product_ingredient/readme/CONTRIBUTORS.md @@ -0,0 +1,3 @@ +- [Tecnativa](https://www.tecnativa.com) + - Sergio Teruel + - Carlos Dauden diff --git a/product_ingredient/readme/DESCRIPTION.md b/product_ingredient/readme/DESCRIPTION.md new file mode 100644 index 00000000000..f5490ee8b09 --- /dev/null +++ b/product_ingredient/readme/DESCRIPTION.md @@ -0,0 +1 @@ +This module allows to set ingredients information for a given product. diff --git a/product_ingredient/readme/USAGE.md b/product_ingredient/readme/USAGE.md new file mode 100644 index 00000000000..99226aa7db5 --- /dev/null +++ b/product_ingredient/readme/USAGE.md @@ -0,0 +1,8 @@ +To use this module you have to: + +- Create or edit a product variant or product template with just a + variant. +- Go to ingredients page +- Create some ingredients for the product. + +Now you can print the "Ingredients Info" report label. diff --git a/product_ingredient/security/ir.model.access.csv b/product_ingredient/security/ir.model.access.csv new file mode 100644 index 00000000000..afe1d3e2e27 --- /dev/null +++ b/product_ingredient/security/ir.model.access.csv @@ -0,0 +1,4 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +access_product_ingredient,access_product_ingredient,model_product_ingredient,base.group_user,1,1,1,1 +access_product_ingredient_value,access_product_ingredient_value,model_product_ingredient_value,base.group_user,1,1,1,1 +access_stock_lot_ingredient_value,access_stock_lot_ingredient_value,model_stock_lot_ingredient_value,base.group_user,1,1,1,1 diff --git a/product_ingredient/static/description/icon.png b/product_ingredient/static/description/icon.png new file mode 100644 index 00000000000..3a0328b516c Binary files /dev/null and b/product_ingredient/static/description/icon.png differ diff --git a/product_ingredient/static/description/index.html b/product_ingredient/static/description/index.html new file mode 100644 index 00000000000..da90b5531d0 --- /dev/null +++ b/product_ingredient/static/description/index.html @@ -0,0 +1,447 @@ + + + + + +README.rst + + + +
+ + + +Odoo Community Association + +
+

Product Ingredients

+ +

Beta License: AGPL-3 OCA/product-attribute Translate me on Weblate Try me on Runboat

+

This module allows to set ingredients information for a given product.

+

Table of contents

+ +
+

Usage

+

To use this module you have to:

+
    +
  • Create or edit a product variant or product template with just a +variant.
  • +
  • Go to ingredients page
  • +
  • Create some ingredients for the product.
  • +
+

Now you can print the “Ingredients Info” report label.

+
+
+

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

+
    +
  • Tecnativa
  • +
+
+
+

Contributors

+
    +
  • Tecnativa
      +
    • Sergio Teruel
    • +
    • Carlos Dauden
    • +
    +
  • +
+
+
+

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:

+

sergio-teruel

+

This module is part of the OCA/product-attribute project on GitHub.

+

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

+
+
+
+
+ + diff --git a/product_ingredient/views/product_attribute_value_views.xml b/product_ingredient/views/product_attribute_value_views.xml new file mode 100644 index 00000000000..536b0f78995 --- /dev/null +++ b/product_ingredient/views/product_attribute_value_views.xml @@ -0,0 +1,17 @@ + + + + product.attribute.value.form + product.attribute.value + +
+ + + + + + +
+
+
+
diff --git a/product_ingredient/views/product_ingredient_views.xml b/product_ingredient/views/product_ingredient_views.xml new file mode 100644 index 00000000000..0f466a9128e --- /dev/null +++ b/product_ingredient/views/product_ingredient_views.xml @@ -0,0 +1,19 @@ + + + + product.ingredient.form.view + product.ingredient + +
+ + + + + + + + +
+
+
+
diff --git a/product_ingredient/views/product_views.xml b/product_ingredient/views/product_views.xml new file mode 100644 index 00000000000..4970061a3db --- /dev/null +++ b/product_ingredient/views/product_views.xml @@ -0,0 +1,75 @@ + + + + + product.product + + + + + + + + + + + + + + + + + + + + + + + + + + product.template + + + + + + + + + + + + + + + + + + + + + + + diff --git a/product_ingredient/views/stock_lot_view.xml b/product_ingredient/views/stock_lot_view.xml new file mode 100644 index 00000000000..50ec8e35ab2 --- /dev/null +++ b/product_ingredient/views/stock_lot_view.xml @@ -0,0 +1,34 @@ + + + + + stock.lot + + + + + + + + + + + + + + + + + + + + + + diff --git a/setup/product_ingredient/odoo/addons/product_ingredient b/setup/product_ingredient/odoo/addons/product_ingredient new file mode 120000 index 00000000000..9c706710f93 --- /dev/null +++ b/setup/product_ingredient/odoo/addons/product_ingredient @@ -0,0 +1 @@ +../../../../product_ingredient \ No newline at end of file diff --git a/setup/product_ingredient/setup.py b/setup/product_ingredient/setup.py new file mode 100644 index 00000000000..28c57bb6403 --- /dev/null +++ b/setup/product_ingredient/setup.py @@ -0,0 +1,6 @@ +import setuptools + +setuptools.setup( + setup_requires=['setuptools-odoo'], + odoo_addon=True, +)