diff --git a/product_lot_sequence/README.rst b/product_lot_sequence/README.rst new file mode 100644 index 00000000000..33f2d237ff8 --- /dev/null +++ b/product_lot_sequence/README.rst @@ -0,0 +1,149 @@ +==================== +Product Lot Sequence +==================== + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:c7d3bbb8df78fdcebb50d639bc04f7e6672298712d63116547a9bd08dcfff441 + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |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%2Fproduct--attribute-lightgray.png?logo=github + :target: https://github.com/OCA/product-attribute/tree/17.0/product_lot_sequence + :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-17-0/product-attribute-17-0-product_lot_sequence + :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=17.0 + :alt: Try me on Runboat + +|badge1| |badge2| |badge3| |badge4| |badge5| + +Adds ability to define a lot sequence from the product which will be +proposed upon creating new lots. + +**Table of contents** + +.. contents:: + :local: + +Configuration +============= + +Lot Sequence policy +------------------- + +There are two ways you can configure this module through the use of +System Parameter \`product_lot_sequence.policy\`: + +- "product": This is the default behaviour once you install this + module. It's the same than in previous Odoo versions with this module + installed, i.e. it allows to define a dedicated sequence on each + product. +- "global": This was the default behaviour from previous Odoo versions + when this module was not installed, i.e it will always use the same + global sequence for every product. + +If any other value is used for this System Parameter, then you will get +the default behaviour from odoo 15.0 which will look for the last lot +number for each product and will increment it. + +Default Number of Digits for Product Sequence Generation +-------------------------------------------------------- + +The default is 7 digits. To change that to something else, go to the +inventory configuration, find "Sequence Number of Digits" and change the +number. + +Usage +===== + +To use this module: + +- Go to Inventory > Products +- Under the inventory tab when tracking set to lots 4 new fields will + be displayed +- If a sequence is not selected, a new one using the prefix, padding + and next number fields, will be created +- Go to Inventory > Lot/Serial Numbers +- Create new Lot/Serial number +- Select the product and the next number of the product sequence will + be automatically proposed + +Known issues / Roadmap +====================== + +- There is an issue with the use of ir.sequence with the newer version + of Odoo. + +Mostly, when opening the detailed operations of an assigned picking for +a product tracked by serial numbers, Odoo systematically calls +\_get_next_serial even if there is not any serial number to generate. +Moreover, the widget allowing to generate the serial numbers will not +call the sequence but only increment the number according to the next +serial, potentially leading to a sequence that is not in sync anymore +with the created serial numbers. + +cf https://github.com/OCA/product-attribute/issues/1326 + +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 +------- + +* ForgeFlow S.L. + +Contributors +------------ + +- Adria Gil Sorribes +- Domantas Girdžiūnas +- `Camptocamp `__: + + - Akim Juillerat + - Vincent Van Rossem + +- `Quartile `__: + + - Yoshi Tashiro + +- `Apik `__: + + - Frederic Grall + +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. + +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_lot_sequence/__init__.py b/product_lot_sequence/__init__.py new file mode 100644 index 00000000000..0650744f6bc --- /dev/null +++ b/product_lot_sequence/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/product_lot_sequence/__manifest__.py b/product_lot_sequence/__manifest__.py new file mode 100644 index 00000000000..36e4d3e6192 --- /dev/null +++ b/product_lot_sequence/__manifest__.py @@ -0,0 +1,18 @@ +# Copyright 2020 ForgeFlow S.L. +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +{ + "name": "Product Lot Sequence", + "summary": """ + Adds ability to define a lot sequence from the product""", + "version": "17.0.1.0.0", + "license": "AGPL-3", + "author": "ForgeFlow S.L., Odoo Community Association (OCA)", + "website": "https://github.com/OCA/product-attribute", + "depends": ["stock"], + "data": [ + "data/ir_config_parameter.xml", + "views/product_views.xml", + "views/res_config_settings_views.xml", + ], +} diff --git a/product_lot_sequence/data/ir_config_parameter.xml b/product_lot_sequence/data/ir_config_parameter.xml new file mode 100644 index 00000000000..ec50a63018d --- /dev/null +++ b/product_lot_sequence/data/ir_config_parameter.xml @@ -0,0 +1,7 @@ + + + + product_lot_sequence.policy + product + + diff --git a/product_lot_sequence/i18n/ca.po b/product_lot_sequence/i18n/ca.po new file mode 100644 index 00000000000..ae5e647c933 --- /dev/null +++ b/product_lot_sequence/i18n/ca.po @@ -0,0 +1,131 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * product_lot_sequence +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 13.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2021-02-23 18:45+0000\n" +"Last-Translator: claudiagn \n" +"Language-Team: none\n" +"Language: ca\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 4.3.2\n" + +#. module: product_lot_sequence +#: model_terms:ir.ui.view,arch_db:product_lot_sequence.res_config_settings_view_form +msgid "" +"" +msgstr "" + +#. module: product_lot_sequence +#: model:ir.model,name:product_lot_sequence.model_res_company +msgid "Companies" +msgstr "" + +#. module: product_lot_sequence +#: model:ir.model,name:product_lot_sequence.model_res_config_settings +msgid "Config Settings" +msgstr "" + +#. module: product_lot_sequence +#: model_terms:ir.ui.view,arch_db:product_lot_sequence.res_config_settings_view_form +msgid "" +"Default number of digits to be set on products for product lot/serial " +"sequence generation." +msgstr "" + +#. module: product_lot_sequence +#: model:ir.model.fields,field_description:product_lot_sequence.field_product_product__display_lot_sequence_fields +#: model:ir.model.fields,field_description:product_lot_sequence.field_product_template__display_lot_sequence_fields +msgid "Display Lot Sequence Fields" +msgstr "" + +#. module: product_lot_sequence +#: model:ir.model.fields,field_description:product_lot_sequence.field_product_product__lot_sequence_id +#: model:ir.model.fields,field_description:product_lot_sequence.field_product_template__lot_sequence_id +msgid "Entry Sequence" +msgstr "Seqüència d’entrada" + +#. module: product_lot_sequence +#: model:ir.model,name:product_lot_sequence.model_stock_lot +msgid "Lot/Serial" +msgstr "Lot/Sèrie" + +#. module: product_lot_sequence +#: model:ir.model.fields,field_description:product_lot_sequence.field_stock_lot__name +msgid "Lot/Serial Number" +msgstr "" + +#. module: product_lot_sequence +#: model:ir.model.fields,field_description:product_lot_sequence.field_product_product__lot_sequence_number_next +#: model:ir.model.fields,field_description:product_lot_sequence.field_product_template__lot_sequence_number_next +msgid "Next Number" +msgstr "Següent Número" + +#. module: product_lot_sequence +#: model:ir.model,name:product_lot_sequence.model_product_template +msgid "Product" +msgstr "" + +#. module: product_lot_sequence +#: model:ir.model.fields,field_description:product_lot_sequence.field_product_product__lot_sequence_padding +#: model:ir.model.fields,field_description:product_lot_sequence.field_product_template__lot_sequence_padding +#: model:ir.model.fields,field_description:product_lot_sequence.field_res_company__lot_sequence_padding +#: model:ir.model.fields,field_description:product_lot_sequence.field_res_config_settings__lot_sequence_padding +msgid "Sequence Number of Digits" +msgstr "Seqüència Nombre de dígits" + +#. module: product_lot_sequence +#: model:ir.model.fields,field_description:product_lot_sequence.field_product_product__lot_sequence_prefix +#: model:ir.model.fields,field_description:product_lot_sequence.field_product_template__lot_sequence_prefix +msgid "Sequence Prefix" +msgstr "Prefix de seqüència" + +#. module: product_lot_sequence +#: model:ir.model,name:product_lot_sequence.model_stock_move +msgid "Stock Move" +msgstr "" + +#. module: product_lot_sequence +#: model:ir.model.fields,help:product_lot_sequence.field_product_product__lot_sequence_prefix +#: model:ir.model.fields,help:product_lot_sequence.field_product_template__lot_sequence_prefix +msgid "The lot's sequence will be created using this prefix." +msgstr "La seqüència del lot es crearà mitjançant aquest prefix." + +#. module: product_lot_sequence +#: model:ir.model.fields,help:product_lot_sequence.field_product_product__lot_sequence_padding +#: model:ir.model.fields,help:product_lot_sequence.field_product_template__lot_sequence_padding +msgid "The lots' sequence will be created using this number of digits." +msgstr "La seqüència dels lots es crearà utilitzant aquest nombre de dígits." + +#. module: product_lot_sequence +#: model:ir.model.fields,help:product_lot_sequence.field_product_product__lot_sequence_number_next +#: model:ir.model.fields,help:product_lot_sequence.field_product_template__lot_sequence_number_next +msgid "The next sequence number will be used for the next lot." +msgstr "El següent número de seqüència s'utilitzarà per al següent lot." + +#. module: product_lot_sequence +#: model:ir.model.fields,help:product_lot_sequence.field_product_product__lot_sequence_id +#: model:ir.model.fields,help:product_lot_sequence.field_product_template__lot_sequence_id +msgid "This field contains the information related to the numbering of lots." +msgstr "Aquest camp conté la informació relacionada amb la numeració de lots." + +#. module: product_lot_sequence +#: model:ir.model.fields,help:product_lot_sequence.field_stock_lot__name +msgid "Unique Lot/Serial Number" +msgstr "" + +#. module: product_lot_sequence +#: model_terms:ir.ui.view,arch_db:product_lot_sequence.res_config_settings_view_form +msgid "digits" +msgstr "" + +#~ msgid "Product Template" +#~ msgstr "Plantilla de producte" diff --git a/product_lot_sequence/i18n/es.po b/product_lot_sequence/i18n/es.po new file mode 100644 index 00000000000..48fa2ba317b --- /dev/null +++ b/product_lot_sequence/i18n/es.po @@ -0,0 +1,139 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * product_lot_sequence +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 12.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2023-12-07 18:33+0000\n" +"Last-Translator: Ivorra78 \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 4.17\n" + +#. module: product_lot_sequence +#: model_terms:ir.ui.view,arch_db:product_lot_sequence.res_config_settings_view_form +msgid "" +"" +msgstr "" +"" + +#. module: product_lot_sequence +#: model:ir.model,name:product_lot_sequence.model_res_company +msgid "Companies" +msgstr "Compañías" + +#. module: product_lot_sequence +#: model:ir.model,name:product_lot_sequence.model_res_config_settings +msgid "Config Settings" +msgstr "Ajustes de Config" + +#. module: product_lot_sequence +#: model_terms:ir.ui.view,arch_db:product_lot_sequence.res_config_settings_view_form +msgid "" +"Default number of digits to be set on products for product lot/serial " +"sequence generation." +msgstr "" +"Número predeterminado de dígitos que se establecerán en los productos para " +"la generación de la secuencia de lote/serie del producto." + +#. module: product_lot_sequence +#: model:ir.model.fields,field_description:product_lot_sequence.field_product_product__display_lot_sequence_fields +#: model:ir.model.fields,field_description:product_lot_sequence.field_product_template__display_lot_sequence_fields +msgid "Display Lot Sequence Fields" +msgstr "Visualizar Campos de Secuencia de Lote" + +#. module: product_lot_sequence +#: model:ir.model.fields,field_description:product_lot_sequence.field_product_product__lot_sequence_id +#: model:ir.model.fields,field_description:product_lot_sequence.field_product_template__lot_sequence_id +msgid "Entry Sequence" +msgstr "Entrar secuencia" + +#. module: product_lot_sequence +#: model:ir.model,name:product_lot_sequence.model_stock_lot +msgid "Lot/Serial" +msgstr "Lote/Serie" + +#. module: product_lot_sequence +#: model:ir.model.fields,field_description:product_lot_sequence.field_stock_lot__name +msgid "Lot/Serial Number" +msgstr "Lote/Número de Serie" + +#. module: product_lot_sequence +#: model:ir.model.fields,field_description:product_lot_sequence.field_product_product__lot_sequence_number_next +#: model:ir.model.fields,field_description:product_lot_sequence.field_product_template__lot_sequence_number_next +msgid "Next Number" +msgstr "Siguiente número" + +#. module: product_lot_sequence +#: model:ir.model,name:product_lot_sequence.model_product_template +msgid "Product" +msgstr "Producto" + +#. module: product_lot_sequence +#: model:ir.model.fields,field_description:product_lot_sequence.field_product_product__lot_sequence_padding +#: model:ir.model.fields,field_description:product_lot_sequence.field_product_template__lot_sequence_padding +#: model:ir.model.fields,field_description:product_lot_sequence.field_res_company__lot_sequence_padding +#: model:ir.model.fields,field_description:product_lot_sequence.field_res_config_settings__lot_sequence_padding +msgid "Sequence Number of Digits" +msgstr "Número de secuencia de dígitos" + +#. module: product_lot_sequence +#: model:ir.model.fields,field_description:product_lot_sequence.field_product_product__lot_sequence_prefix +#: model:ir.model.fields,field_description:product_lot_sequence.field_product_template__lot_sequence_prefix +msgid "Sequence Prefix" +msgstr "Prefijo de secuencia" + +#. module: product_lot_sequence +#: model:ir.model,name:product_lot_sequence.model_stock_move +msgid "Stock Move" +msgstr "" + +#. module: product_lot_sequence +#: model:ir.model.fields,help:product_lot_sequence.field_product_product__lot_sequence_prefix +#: model:ir.model.fields,help:product_lot_sequence.field_product_template__lot_sequence_prefix +msgid "The lot's sequence will be created using this prefix." +msgstr "La secuencia del lote será creada utilizando este prefijo." + +#. module: product_lot_sequence +#: model:ir.model.fields,help:product_lot_sequence.field_product_product__lot_sequence_padding +#: model:ir.model.fields,help:product_lot_sequence.field_product_template__lot_sequence_padding +msgid "The lots' sequence will be created using this number of digits." +msgstr "" +"La secuencia del los lotes será creada utilizando este número de dígitos." + +#. module: product_lot_sequence +#: model:ir.model.fields,help:product_lot_sequence.field_product_product__lot_sequence_number_next +#: model:ir.model.fields,help:product_lot_sequence.field_product_template__lot_sequence_number_next +msgid "The next sequence number will be used for the next lot." +msgstr "" +"El siguiente número de secuencia será utilizado para el siguiente lote." + +#. module: product_lot_sequence +#: model:ir.model.fields,help:product_lot_sequence.field_product_product__lot_sequence_id +#: model:ir.model.fields,help:product_lot_sequence.field_product_template__lot_sequence_id +msgid "This field contains the information related to the numbering of lots." +msgstr "" +"Este campo contiene la información relacionada con la numeración de lotes." + +#. module: product_lot_sequence +#: model:ir.model.fields,help:product_lot_sequence.field_stock_lot__name +msgid "Unique Lot/Serial Number" +msgstr "Número Único de Lote/Serie" + +#. module: product_lot_sequence +#: model_terms:ir.ui.view,arch_db:product_lot_sequence.res_config_settings_view_form +msgid "digits" +msgstr "dígitos" + +#~ msgid "Product Template" +#~ msgstr "Plantilla de producto" diff --git a/product_lot_sequence/i18n/fr.po b/product_lot_sequence/i18n/fr.po new file mode 100644 index 00000000000..ed5eb46e0bb --- /dev/null +++ b/product_lot_sequence/i18n/fr.po @@ -0,0 +1,137 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * product_lot_sequence +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 14.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2021-07-21 13:09+0000\n" +"PO-Revision-Date: 2021-07-21 13:09+0000\n" +"Last-Translator: \n" +"Language-Team: \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" + +#. module: product_lot_sequence +#: model_terms:ir.ui.view,arch_db:product_lot_sequence.res_config_settings_view_form +msgid "" +"" +msgstr "" + +#. module: product_lot_sequence +#: model:ir.model,name:product_lot_sequence.model_res_company +msgid "Companies" +msgstr "" + +#. module: product_lot_sequence +#: model:ir.model,name:product_lot_sequence.model_res_config_settings +msgid "Config Settings" +msgstr "" + +#. module: product_lot_sequence +#: model_terms:ir.ui.view,arch_db:product_lot_sequence.res_config_settings_view_form +msgid "" +"Default number of digits to be set on products for product lot/serial " +"sequence generation." +msgstr "" + +#. module: product_lot_sequence +#: model:ir.model.fields,field_description:product_lot_sequence.field_product_product__display_lot_sequence_fields +#: model:ir.model.fields,field_description:product_lot_sequence.field_product_template__display_lot_sequence_fields +msgid "Display Lot Sequence Fields" +msgstr "" + +#. module: product_lot_sequence +#: model:ir.model.fields,field_description:product_lot_sequence.field_product_product__lot_sequence_id +#: model:ir.model.fields,field_description:product_lot_sequence.field_product_template__lot_sequence_id +msgid "Entry Sequence" +msgstr "Référence de séquence" + +#. module: product_lot_sequence +#: model:ir.model,name:product_lot_sequence.model_stock_lot +msgid "Lot/Serial" +msgstr "Lot/N° série" + +#. module: product_lot_sequence +#: model:ir.model.fields,field_description:product_lot_sequence.field_stock_lot__name +msgid "Lot/Serial Number" +msgstr "" + +#. module: product_lot_sequence +#: model:ir.model.fields,field_description:product_lot_sequence.field_product_product__lot_sequence_number_next +#: model:ir.model.fields,field_description:product_lot_sequence.field_product_template__lot_sequence_number_next +msgid "Next Number" +msgstr "Prochain numéro" + +#. module: product_lot_sequence +#: model:ir.model,name:product_lot_sequence.model_product_template +msgid "Product" +msgstr "" + +#. module: product_lot_sequence +#: model:ir.model.fields,field_description:product_lot_sequence.field_product_product__lot_sequence_padding +#: model:ir.model.fields,field_description:product_lot_sequence.field_product_template__lot_sequence_padding +#: model:ir.model.fields,field_description:product_lot_sequence.field_res_company__lot_sequence_padding +#: model:ir.model.fields,field_description:product_lot_sequence.field_res_config_settings__lot_sequence_padding +msgid "Sequence Number of Digits" +msgstr "Nombre de chiffres dans la séquence" + +#. module: product_lot_sequence +#: model:ir.model.fields,field_description:product_lot_sequence.field_product_product__lot_sequence_prefix +#: model:ir.model.fields,field_description:product_lot_sequence.field_product_template__lot_sequence_prefix +msgid "Sequence Prefix" +msgstr "Préfixe de séquence" + +#. module: product_lot_sequence +#: model:ir.model,name:product_lot_sequence.model_stock_move +msgid "Stock Move" +msgstr "" + +#. module: product_lot_sequence +#: model:ir.model.fields,help:product_lot_sequence.field_product_product__lot_sequence_prefix +#: model:ir.model.fields,help:product_lot_sequence.field_product_template__lot_sequence_prefix +msgid "The lot's sequence will be created using this prefix." +msgstr "La séquence sera créée avec ce préfixe." + +#. module: product_lot_sequence +#: model:ir.model.fields,help:product_lot_sequence.field_product_product__lot_sequence_padding +#: model:ir.model.fields,help:product_lot_sequence.field_product_template__lot_sequence_padding +msgid "The lots' sequence will be created using this number of digits." +msgstr "La séquence sera créée avec ce nombre de chiffres" + +#. module: product_lot_sequence +#: model:ir.model.fields,help:product_lot_sequence.field_product_product__lot_sequence_number_next +#: model:ir.model.fields,help:product_lot_sequence.field_product_template__lot_sequence_number_next +msgid "The next sequence number will be used for the next lot." +msgstr "Le prochain numéro à utiliser" + +#. module: product_lot_sequence +#: model:ir.model.fields,help:product_lot_sequence.field_product_product__lot_sequence_id +#: model:ir.model.fields,help:product_lot_sequence.field_product_template__lot_sequence_id +msgid "This field contains the information related to the numbering of lots." +msgstr "Ce champ contient le lien vers la séquence de lot/numéro de série" + +#. module: product_lot_sequence +#: model:ir.model.fields,help:product_lot_sequence.field_stock_lot__name +msgid "Unique Lot/Serial Number" +msgstr "" + +#. module: product_lot_sequence +#: model_terms:ir.ui.view,arch_db:product_lot_sequence.res_config_settings_view_form +msgid "digits" +msgstr "" + +#~ msgid "Product Template" +#~ msgstr "Modèle d'article" + +#~ msgid "Display Name" +#~ msgstr "Nom affiché" + +#~ msgid "Last Modified on" +#~ msgstr "Dernière modification le" diff --git a/product_lot_sequence/i18n/it.po b/product_lot_sequence/i18n/it.po new file mode 100644 index 00000000000..138d0ce0c2e --- /dev/null +++ b/product_lot_sequence/i18n/it.po @@ -0,0 +1,134 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * product_lot_sequence +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 16.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2024-05-08 09:36+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 4.17\n" + +#. module: product_lot_sequence +#: model_terms:ir.ui.view,arch_db:product_lot_sequence.res_config_settings_view_form +msgid "" +"" +msgstr "" +"" + +#. module: product_lot_sequence +#: model:ir.model,name:product_lot_sequence.model_res_company +msgid "Companies" +msgstr "Aziende" + +#. module: product_lot_sequence +#: model:ir.model,name:product_lot_sequence.model_res_config_settings +msgid "Config Settings" +msgstr "Impostazioni configurazione" + +#. module: product_lot_sequence +#: model_terms:ir.ui.view,arch_db:product_lot_sequence.res_config_settings_view_form +msgid "" +"Default number of digits to be set on products for product lot/serial " +"sequence generation." +msgstr "" +"Numero predefinito di cifre da impostare nei prodotti per la generazione del " +"numero di lotto/ serie." + +#. module: product_lot_sequence +#: model:ir.model.fields,field_description:product_lot_sequence.field_product_product__display_lot_sequence_fields +#: model:ir.model.fields,field_description:product_lot_sequence.field_product_template__display_lot_sequence_fields +msgid "Display Lot Sequence Fields" +msgstr "Visualizza campi sequenza lotto" + +#. module: product_lot_sequence +#: model:ir.model.fields,field_description:product_lot_sequence.field_product_product__lot_sequence_id +#: model:ir.model.fields,field_description:product_lot_sequence.field_product_template__lot_sequence_id +msgid "Entry Sequence" +msgstr "Sequenza iniziale" + +#. module: product_lot_sequence +#: model:ir.model,name:product_lot_sequence.model_stock_lot +msgid "Lot/Serial" +msgstr "Lotto/seriale" + +#. module: product_lot_sequence +#: model:ir.model.fields,field_description:product_lot_sequence.field_stock_lot__name +msgid "Lot/Serial Number" +msgstr "Numero di lotto/serie" + +#. module: product_lot_sequence +#: model:ir.model.fields,field_description:product_lot_sequence.field_product_product__lot_sequence_number_next +#: model:ir.model.fields,field_description:product_lot_sequence.field_product_template__lot_sequence_number_next +msgid "Next Number" +msgstr "Numero successivo" + +#. module: product_lot_sequence +#: model:ir.model,name:product_lot_sequence.model_product_template +msgid "Product" +msgstr "Prodotto" + +#. module: product_lot_sequence +#: model:ir.model.fields,field_description:product_lot_sequence.field_product_product__lot_sequence_padding +#: model:ir.model.fields,field_description:product_lot_sequence.field_product_template__lot_sequence_padding +#: model:ir.model.fields,field_description:product_lot_sequence.field_res_company__lot_sequence_padding +#: model:ir.model.fields,field_description:product_lot_sequence.field_res_config_settings__lot_sequence_padding +msgid "Sequence Number of Digits" +msgstr "Numero cifre sequenza" + +#. module: product_lot_sequence +#: model:ir.model.fields,field_description:product_lot_sequence.field_product_product__lot_sequence_prefix +#: model:ir.model.fields,field_description:product_lot_sequence.field_product_template__lot_sequence_prefix +msgid "Sequence Prefix" +msgstr "Prefisso sequenza" + +#. module: product_lot_sequence +#: model:ir.model,name:product_lot_sequence.model_stock_move +msgid "Stock Move" +msgstr "Movimento di magazzino" + +#. module: product_lot_sequence +#: model:ir.model.fields,help:product_lot_sequence.field_product_product__lot_sequence_prefix +#: model:ir.model.fields,help:product_lot_sequence.field_product_template__lot_sequence_prefix +msgid "The lot's sequence will be created using this prefix." +msgstr "La sequenza del lotto verrà creata utilizzando questo prefisso." + +#. module: product_lot_sequence +#: model:ir.model.fields,help:product_lot_sequence.field_product_product__lot_sequence_padding +#: model:ir.model.fields,help:product_lot_sequence.field_product_template__lot_sequence_padding +msgid "The lots' sequence will be created using this number of digits." +msgstr "La sequenza del lotto verrà creata utilizzando questo numero di cifre." + +#. module: product_lot_sequence +#: model:ir.model.fields,help:product_lot_sequence.field_product_product__lot_sequence_number_next +#: model:ir.model.fields,help:product_lot_sequence.field_product_template__lot_sequence_number_next +msgid "The next sequence number will be used for the next lot." +msgstr "" +"Il numero di sequenza successivo verrà utilizzato per il prossimo lotto." + +#. module: product_lot_sequence +#: model:ir.model.fields,help:product_lot_sequence.field_product_product__lot_sequence_id +#: model:ir.model.fields,help:product_lot_sequence.field_product_template__lot_sequence_id +msgid "This field contains the information related to the numbering of lots." +msgstr "Il campo contiene l'informazione relativa alla numerazone dei lotti." + +#. module: product_lot_sequence +#: model:ir.model.fields,help:product_lot_sequence.field_stock_lot__name +msgid "Unique Lot/Serial Number" +msgstr "Numero di lotto/serie univoco" + +#. module: product_lot_sequence +#: model_terms:ir.ui.view,arch_db:product_lot_sequence.res_config_settings_view_form +msgid "digits" +msgstr "cifre" diff --git a/product_lot_sequence/i18n/product_lot_sequence.pot b/product_lot_sequence/i18n/product_lot_sequence.pot new file mode 100644 index 00000000000..48587e358f1 --- /dev/null +++ b/product_lot_sequence/i18n/product_lot_sequence.pot @@ -0,0 +1,125 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * product_lot_sequence +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 16.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_lot_sequence +#: model_terms:ir.ui.view,arch_db:product_lot_sequence.res_config_settings_view_form +msgid "" +"" +msgstr "" + +#. module: product_lot_sequence +#: model:ir.model,name:product_lot_sequence.model_res_company +msgid "Companies" +msgstr "" + +#. module: product_lot_sequence +#: model:ir.model,name:product_lot_sequence.model_res_config_settings +msgid "Config Settings" +msgstr "" + +#. module: product_lot_sequence +#: model_terms:ir.ui.view,arch_db:product_lot_sequence.res_config_settings_view_form +msgid "" +"Default number of digits to be set on products for product lot/serial " +"sequence generation." +msgstr "" + +#. module: product_lot_sequence +#: model:ir.model.fields,field_description:product_lot_sequence.field_product_product__display_lot_sequence_fields +#: model:ir.model.fields,field_description:product_lot_sequence.field_product_template__display_lot_sequence_fields +msgid "Display Lot Sequence Fields" +msgstr "" + +#. module: product_lot_sequence +#: model:ir.model.fields,field_description:product_lot_sequence.field_product_product__lot_sequence_id +#: model:ir.model.fields,field_description:product_lot_sequence.field_product_template__lot_sequence_id +msgid "Entry Sequence" +msgstr "" + +#. module: product_lot_sequence +#: model:ir.model,name:product_lot_sequence.model_stock_lot +msgid "Lot/Serial" +msgstr "" + +#. module: product_lot_sequence +#: model:ir.model.fields,field_description:product_lot_sequence.field_stock_lot__name +msgid "Lot/Serial Number" +msgstr "" + +#. module: product_lot_sequence +#: model:ir.model.fields,field_description:product_lot_sequence.field_product_product__lot_sequence_number_next +#: model:ir.model.fields,field_description:product_lot_sequence.field_product_template__lot_sequence_number_next +msgid "Next Number" +msgstr "" + +#. module: product_lot_sequence +#: model:ir.model,name:product_lot_sequence.model_product_template +msgid "Product" +msgstr "" + +#. module: product_lot_sequence +#: model:ir.model.fields,field_description:product_lot_sequence.field_product_product__lot_sequence_padding +#: model:ir.model.fields,field_description:product_lot_sequence.field_product_template__lot_sequence_padding +#: model:ir.model.fields,field_description:product_lot_sequence.field_res_company__lot_sequence_padding +#: model:ir.model.fields,field_description:product_lot_sequence.field_res_config_settings__lot_sequence_padding +msgid "Sequence Number of Digits" +msgstr "" + +#. module: product_lot_sequence +#: model:ir.model.fields,field_description:product_lot_sequence.field_product_product__lot_sequence_prefix +#: model:ir.model.fields,field_description:product_lot_sequence.field_product_template__lot_sequence_prefix +msgid "Sequence Prefix" +msgstr "" + +#. module: product_lot_sequence +#: model:ir.model,name:product_lot_sequence.model_stock_move +msgid "Stock Move" +msgstr "" + +#. module: product_lot_sequence +#: model:ir.model.fields,help:product_lot_sequence.field_product_product__lot_sequence_prefix +#: model:ir.model.fields,help:product_lot_sequence.field_product_template__lot_sequence_prefix +msgid "The lot's sequence will be created using this prefix." +msgstr "" + +#. module: product_lot_sequence +#: model:ir.model.fields,help:product_lot_sequence.field_product_product__lot_sequence_padding +#: model:ir.model.fields,help:product_lot_sequence.field_product_template__lot_sequence_padding +msgid "The lots' sequence will be created using this number of digits." +msgstr "" + +#. module: product_lot_sequence +#: model:ir.model.fields,help:product_lot_sequence.field_product_product__lot_sequence_number_next +#: model:ir.model.fields,help:product_lot_sequence.field_product_template__lot_sequence_number_next +msgid "The next sequence number will be used for the next lot." +msgstr "" + +#. module: product_lot_sequence +#: model:ir.model.fields,help:product_lot_sequence.field_product_product__lot_sequence_id +#: model:ir.model.fields,help:product_lot_sequence.field_product_template__lot_sequence_id +msgid "This field contains the information related to the numbering of lots." +msgstr "" + +#. module: product_lot_sequence +#: model:ir.model.fields,help:product_lot_sequence.field_stock_lot__name +msgid "Unique Lot/Serial Number" +msgstr "" + +#. module: product_lot_sequence +#: model_terms:ir.ui.view,arch_db:product_lot_sequence.res_config_settings_view_form +msgid "digits" +msgstr "" diff --git a/product_lot_sequence/models/__init__.py b/product_lot_sequence/models/__init__.py new file mode 100644 index 00000000000..3dceccb802b --- /dev/null +++ b/product_lot_sequence/models/__init__.py @@ -0,0 +1,5 @@ +from . import res_company +from . import product +from . import res_config_settings +from . import stock_lot +from . import stock_move diff --git a/product_lot_sequence/models/product.py b/product_lot_sequence/models/product.py new file mode 100644 index 00000000000..46215bde637 --- /dev/null +++ b/product_lot_sequence/models/product.py @@ -0,0 +1,124 @@ +# Copyright 2020 ForgeFlow S.L. +# Copyright 2024 Tecnativa - Carolina Fernandez +# 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" + + lot_sequence_id = fields.Many2one( + "ir.sequence", + string="Entry Sequence", + help="This field contains the information related to the numbering of lots.", + copy=False, + ) + lot_sequence_prefix = fields.Char( + string="Sequence Prefix", + help="The lot's sequence will be created using this prefix.", + ) + lot_sequence_padding = fields.Integer( + string="Sequence Number of Digits", + default=lambda self: self.env.company.lot_sequence_padding, + help="The lots' sequence will be created using this number of digits.", + ) + lot_sequence_number_next = fields.Integer( + string="Next Number", + help="The next sequence number will be used for the next lot.", + compute="_compute_lot_seq_number_next", + inverse="_inverse_lot_seq_number_next", + ) + display_lot_sequence_fields = fields.Boolean( + compute="_compute_display_lot_sequence_fields" + ) + + @api.depends("tracking") # For products being created (before saved). + def _compute_display_lot_sequence_fields(self): + self.display_lot_sequence_fields = ( + self.env["stock.lot"]._get_sequence_policy() == "product" + ) + + @api.model + def _create_lot_sequence(self, vals): + """Create new no_gap entry sequence""" + name = vals.get("name", False) or self.name + prefix = vals.get("lot_sequence_prefix", False) or self.lot_sequence_prefix + padding = vals.get("lot_sequence_padding") or self.lot_sequence_padding + seq = { + "name": name, + "implementation": "no_gap", + "prefix": prefix, + "padding": padding, + "number_increment": 1, + "use_date_range": False, + } + seq = self.env["ir.sequence"].create(seq) + seq_date_range = seq._get_current_sequence() + seq_date_range.number_next = self.lot_sequence_number_next or vals.get( + "lot_sequence_number_next", 1 + ) + return seq + + # do not depend on 'lot_sequence_id.date_range_ids', because + # lot_sequence_id._get_current_sequence() may invalidate it! + @api.depends("lot_sequence_id.use_date_range", "lot_sequence_id.number_next_actual") + def _compute_lot_seq_number_next(self): + """ + Compute 'lot_sequence_number_next' according to the current sequence in use, an + ir.sequence or an ir.sequence.date_range. + """ + for template in self: + if template.lot_sequence_id: + sequence = template.lot_sequence_id._get_current_sequence() + template.lot_sequence_number_next = sequence.number_next_actual + else: + template.lot_sequence_number_next = 1 + + def _inverse_lot_seq_number_next(self): + """ + Inverse 'lot_sequence_number_next' to edit the current sequence next number + """ + for template in self: + if template.lot_sequence_id and template.lot_sequence_number_next: + sequence = template.lot_sequence_id._get_current_sequence() + sequence.sudo().number_next = template.lot_sequence_number_next + + def write(self, vals): + seq_policy = self.env["stock.lot"]._get_sequence_policy() + if seq_policy == "product": + for template in self: + tracking = vals.get("tracking", False) or template.tracking + if tracking in ["lot", "serial"]: + if ( + not vals.get("lot_sequence_id", False) + and not template.lot_sequence_id + ): + vals["lot_sequence_id"] = ( + template.sudo()._create_lot_sequence(vals).id + ) + elif vals.get("lot_sequence_id", False): + lot_sequence_id = self.env["ir.sequence"].browse( + vals["lot_sequence_id"] + ) + vals["lot_sequence_prefix"] = lot_sequence_id.prefix + vals["lot_sequence_padding"] = lot_sequence_id.padding + return super().write(vals) + + @api.model_create_multi + def create(self, vals_list): + seq_policy = self.env["stock.lot"]._get_sequence_policy() + for vals in vals_list: + if seq_policy == "product" and vals.get("tracking", False) in [ + "lot", + "serial", + ]: + if not vals.get("lot_sequence_id", False): + vals["lot_sequence_id"] = self.sudo()._create_lot_sequence(vals).id + else: + lot_sequence_id = self.env["ir.sequence"].browse( + vals["lot_sequence_id"] + ) + vals["lot_sequence_prefix"] = lot_sequence_id.prefix + vals["lot_sequence_padding"] = lot_sequence_id.padding + return super().create(vals_list) diff --git a/product_lot_sequence/models/res_company.py b/product_lot_sequence/models/res_company.py new file mode 100644 index 00000000000..906a104f88d --- /dev/null +++ b/product_lot_sequence/models/res_company.py @@ -0,0 +1,10 @@ +# Copyright 2023 Quartile Limited +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import fields, models + + +class ResCompany(models.Model): + _inherit = "res.company" + + lot_sequence_padding = fields.Integer("Sequence Number of Digits", default=7) diff --git a/product_lot_sequence/models/res_config_settings.py b/product_lot_sequence/models/res_config_settings.py new file mode 100644 index 00000000000..ad33ee2d448 --- /dev/null +++ b/product_lot_sequence/models/res_config_settings.py @@ -0,0 +1,13 @@ +# Copyright 2023 Quartile Limited +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import fields, models + + +class ResConfigSettings(models.TransientModel): + _inherit = "res.config.settings" + + lot_sequence_padding = fields.Integer( + related="company_id.lot_sequence_padding", + readonly=False, + ) diff --git a/product_lot_sequence/models/stock_lot.py b/product_lot_sequence/models/stock_lot.py new file mode 100644 index 00000000000..a2ca7eeee3b --- /dev/null +++ b/product_lot_sequence/models/stock_lot.py @@ -0,0 +1,68 @@ +# Copyright 2020 ForgeFlow S.L. +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import api, fields, models + + +class StockLot(models.Model): + _inherit = "stock.lot" + + name = fields.Char(default=lambda self: self._default_name()) + + @api.model + def _get_sequence_policy(self): + return ( + self.env["ir.config_parameter"] + .sudo() + .get_param("product_lot_sequence.policy") + ) + + @api.model + def _default_name(self): + seq_policy = self._get_sequence_policy() + if seq_policy != "product": + return self.env["ir.sequence"].next_by_code("stock.lot.serial") + return "" + + @api.onchange("product_id") + def onchange_product_id(self): + seq_policy = self._get_sequence_policy() + if ( + seq_policy == "product" + and self.product_id + and self.product_id.product_tmpl_id.lot_sequence_id + ): + self.name = self.product_id.product_tmpl_id.lot_sequence_id._next() + + @api.model_create_multi + def create(self, vals_list): + seq_policy = self._get_sequence_policy() + if seq_policy in ["product", "global"]: + for lot_vals in vals_list: + if "name" not in lot_vals: + if seq_policy == "product": + product = self.env["product.product"].browse( + lot_vals["product_id"] + ) + if product and product.product_tmpl_id.lot_sequence_id: + lot_vals[ + "name" + ] = product.product_tmpl_id.lot_sequence_id._next() + else: + lot_vals["name"] = self.env["ir.sequence"].next_by_code( + "stock.lot.serial" + ) + return super().create(vals_list) + + @api.model + def _get_next_serial(self, company, product): + if "force_next_serial" in self.env.context: + return self.env.context.get("force_next_serial") + seq_policy = self._get_sequence_policy() + if seq_policy == "product": + seq = product.product_tmpl_id.lot_sequence_id + if seq: + return seq._next() + elif seq_policy == "global": + return self.env["ir.sequence"].next_by_code("stock.lot.serial") + return super()._get_next_serial(company, product) diff --git a/product_lot_sequence/models/stock_move.py b/product_lot_sequence/models/stock_move.py new file mode 100644 index 00000000000..7ff13145be1 --- /dev/null +++ b/product_lot_sequence/models/stock_move.py @@ -0,0 +1,24 @@ +# Copyright 2023 Camptocamp SA +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl) +from odoo import models + + +class StockMove(models.Model): + _inherit = "stock.move" + + def action_show_details(self): + """Avoid calling and incrementing the sequence if not needed or already done""" + seq_policy = self.env["stock.lot"]._get_sequence_policy() + + if seq_policy in ("product", "global"): + # If move is not supposed to assign serial pass empty string for next serial + if not self.display_assign_serial: + self = self.with_context(force_next_serial="") + # If the sequence was already called once, avoid calling it another time + elif self.next_serial: + self = self.with_context(force_next_serial=self.next_serial) + elif self.product_id.tracking == "serial" and self.state == "assigned": + self.next_serial = self.env["stock.lot"]._get_next_serial( + self.company_id, self.product_id + ) + return super().action_show_details() diff --git a/product_lot_sequence/pyproject.toml b/product_lot_sequence/pyproject.toml new file mode 100644 index 00000000000..4231d0cccb3 --- /dev/null +++ b/product_lot_sequence/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["whool"] +build-backend = "whool.buildapi" diff --git a/product_lot_sequence/readme/CONFIGURE.md b/product_lot_sequence/readme/CONFIGURE.md new file mode 100644 index 00000000000..18a13fedebc --- /dev/null +++ b/product_lot_sequence/readme/CONFIGURE.md @@ -0,0 +1,22 @@ +## Lot Sequence policy + +There are two ways you can configure this module through the use of +System Parameter \`product_lot_sequence.policy\`: + +- "product": This is the default behaviour once you install this module. + It's the same than in previous Odoo versions with this module + installed, i.e. it allows to define a dedicated sequence on each + product. +- "global": This was the default behaviour from previous Odoo versions + when this module was not installed, i.e it will always use the same + global sequence for every product. + +If any other value is used for this System Parameter, then you will get +the default behaviour from odoo 15.0 which will look for the last lot +number for each product and will increment it. + +## Default Number of Digits for Product Sequence Generation + +The default is 7 digits. To change that to something else, go to the +inventory configuration, find "Sequence Number of Digits" and change the +number. diff --git a/product_lot_sequence/readme/CONTRIBUTORS.md b/product_lot_sequence/readme/CONTRIBUTORS.md new file mode 100644 index 00000000000..8034a23f6e7 --- /dev/null +++ b/product_lot_sequence/readme/CONTRIBUTORS.md @@ -0,0 +1,9 @@ +- Adria Gil Sorribes \<\> +- Domantas Girdžiūnas \<\> +- [Camptocamp](https://www.camptocamp.com): + - Akim Juillerat \<\> + - Vincent Van Rossem \<\> +- [Quartile](https://www.quartile.co): + - Yoshi Tashiro +- [Apik](https://www.apik.cloud): + - Frederic Grall diff --git a/product_lot_sequence/readme/DESCRIPTION.md b/product_lot_sequence/readme/DESCRIPTION.md new file mode 100644 index 00000000000..bd64f4b1541 --- /dev/null +++ b/product_lot_sequence/readme/DESCRIPTION.md @@ -0,0 +1,2 @@ +Adds ability to define a lot sequence from the product which will be +proposed upon creating new lots. diff --git a/product_lot_sequence/readme/ROADMAP.md b/product_lot_sequence/readme/ROADMAP.md new file mode 100644 index 00000000000..f2a60b94455 --- /dev/null +++ b/product_lot_sequence/readme/ROADMAP.md @@ -0,0 +1,12 @@ +- There is an issue with the use of ir.sequence with the newer version + of Odoo. + +Mostly, when opening the detailed operations of an assigned picking for +a product tracked by serial numbers, Odoo systematically calls +\_get_next_serial even if there is not any serial number to generate. +Moreover, the widget allowing to generate the serial numbers will not +call the sequence but only increment the number according to the next +serial, potentially leading to a sequence that is not in sync anymore +with the created serial numbers. + +cf diff --git a/product_lot_sequence/readme/USAGE.md b/product_lot_sequence/readme/USAGE.md new file mode 100644 index 00000000000..bdf7897683e --- /dev/null +++ b/product_lot_sequence/readme/USAGE.md @@ -0,0 +1,11 @@ +To use this module: + +- Go to Inventory \> Products +- Under the inventory tab when tracking set to lots 4 new fields will be + displayed +- If a sequence is not selected, a new one using the prefix, padding and + next number fields, will be created +- Go to Inventory \> Lot/Serial Numbers +- Create new Lot/Serial number +- Select the product and the next number of the product sequence will be + automatically proposed diff --git a/product_lot_sequence/static/description/icon.png b/product_lot_sequence/static/description/icon.png new file mode 100644 index 00000000000..3a0328b516c Binary files /dev/null and b/product_lot_sequence/static/description/icon.png differ diff --git a/product_lot_sequence/static/description/index.html b/product_lot_sequence/static/description/index.html new file mode 100644 index 00000000000..dfb1be79715 --- /dev/null +++ b/product_lot_sequence/static/description/index.html @@ -0,0 +1,501 @@ + + + + + +Product Lot Sequence + + + +
+

Product Lot Sequence

+ + +

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

+

Adds ability to define a lot sequence from the product which will be +proposed upon creating new lots.

+

Table of contents

+ +
+

Configuration

+
+

Lot Sequence policy

+

There are two ways you can configure this module through the use of +System Parameter `product_lot_sequence.policy`:

+
    +
  • “product”: This is the default behaviour once you install this +module. It’s the same than in previous Odoo versions with this module +installed, i.e. it allows to define a dedicated sequence on each +product.
  • +
  • “global”: This was the default behaviour from previous Odoo versions +when this module was not installed, i.e it will always use the same +global sequence for every product.
  • +
+

If any other value is used for this System Parameter, then you will get +the default behaviour from odoo 15.0 which will look for the last lot +number for each product and will increment it.

+
+
+

Default Number of Digits for Product Sequence Generation

+

The default is 7 digits. To change that to something else, go to the +inventory configuration, find “Sequence Number of Digits” and change the +number.

+
+
+
+

Usage

+

To use this module:

+
    +
  • Go to Inventory > Products
  • +
  • Under the inventory tab when tracking set to lots 4 new fields will +be displayed
  • +
  • If a sequence is not selected, a new one using the prefix, padding +and next number fields, will be created
  • +
  • Go to Inventory > Lot/Serial Numbers
  • +
  • Create new Lot/Serial number
  • +
  • Select the product and the next number of the product sequence will +be automatically proposed
  • +
+
+
+

Known issues / Roadmap

+
    +
  • There is an issue with the use of ir.sequence with the newer version +of Odoo.
  • +
+

Mostly, when opening the detailed operations of an assigned picking for +a product tracked by serial numbers, Odoo systematically calls +_get_next_serial even if there is not any serial number to generate. +Moreover, the widget allowing to generate the serial numbers will not +call the sequence but only increment the number according to the next +serial, potentially leading to a sequence that is not in sync anymore +with the created serial numbers.

+

cf https://github.com/OCA/product-attribute/issues/1326

+
+
+

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

+
    +
  • ForgeFlow S.L.
  • +
+
+
+

Contributors

+ +
+
+

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.

+

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_lot_sequence/tests/__init__.py b/product_lot_sequence/tests/__init__.py new file mode 100644 index 00000000000..70cfe192521 --- /dev/null +++ b/product_lot_sequence/tests/__init__.py @@ -0,0 +1 @@ +from . import test_product_lot_sequence diff --git a/product_lot_sequence/tests/test_product_lot_sequence.py b/product_lot_sequence/tests/test_product_lot_sequence.py new file mode 100644 index 00000000000..957880de74c --- /dev/null +++ b/product_lot_sequence/tests/test_product_lot_sequence.py @@ -0,0 +1,141 @@ +from odoo.tests import Form +from odoo.tests.common import TransactionCase + + +class TestProductLotSequence(TransactionCase): + """Test product lot sequence.""" + + @classmethod + def setUpClass(self): + super().setUpClass() + self.product_product = self.env["product.product"] + self.stock_production_lot = self.env["stock.lot"] + self.receipt_type = self.env.ref("stock.picking_type_in") + self.delivery_type = self.env.ref("stock.picking_type_out") + + def _create_picking(self, picking_type, move_vals_list): + picking_form = Form(self.env["stock.picking"]) + picking_form.picking_type_id = picking_type + for move_vals in move_vals_list: + with picking_form.move_ids_without_package.new() as move_form: + move_form.product_id = move_vals.get("product_id") + move_form.product_uom_qty = move_vals.get("product_uom_qty", 1.0) + move_form.product_uom = move_vals.get( + "product_uom", self.env.ref("uom.product_uom_unit") + ) + picking = picking_form.save() + picking.action_confirm() + return picking + + def test_product_sequence(self): + self.assertEqual(self.stock_production_lot._get_sequence_policy(), "product") + product = self.product_product.create( + dict(name="The bar of foo", tracking="serial") + ) + self.assertTrue(product.lot_sequence_id) + product.lot_sequence_id.write( + dict( + prefix="foo/", + padding=5, + number_increment=1, + number_next_actual=1, + suffix="/bar", + ) + ) + next_serial = self.env["stock.lot"]._get_next_serial(self.env.company, product) + self.assertRegex(next_serial, r"foo/\d{5}/bar") + + def test_lot_onchange_product_id(self): + self.assertEqual(self.stock_production_lot._get_sequence_policy(), "product") + product = self.product_product.create(dict(name="Shiba plush", tracking="lot")) + self.assertTrue(product.lot_sequence_id) + product.lot_sequence_id.write( + dict(prefix="shiba/", padding=4, number_increment=1, number_next_actual=1) + ) + lot_form = Form(self.stock_production_lot) + lot_form.product_id = product + lot_form.company_id = self.env.company + lot = lot_form.save() + self.assertRegex(lot.name, r"shiba/\d{4}$") + + def test_global_sequence(self): + self.env["ir.config_parameter"].set_param( + "product_lot_sequence.policy", "global" + ) + product_1 = self.product_product.create( + {"name": "Test global 1", "tracking": "serial"} + ) + self.assertFalse(product_1.lot_sequence_id) + product_2 = self.product_product.create( + {"name": "Test global 2", "tracking": "lot"} + ) + self.assertFalse(product_2.lot_sequence_id) + seq = self.env["ir.sequence"].search([("code", "=", "stock.lot.serial")]) + next_sequence_number = seq.get_next_char(seq.number_next_actual) + next_serial = self.env["stock.lot"]._get_next_serial( + self.env.company, product_1 + ) + self.assertEqual(next_serial, next_sequence_number) + seq._get_number_next_actual() + next_sequence_number_2 = seq.get_next_char(seq.number_next_actual) + next_serial_2 = self.env["stock.lot"]._get_next_serial( + self.env.company, product_2 + ) + self.assertEqual(next_serial_2, next_sequence_number_2) + + def test_lot_onchange_product_id_global(self): + self.env["ir.config_parameter"].set_param( + "product_lot_sequence.policy", "global" + ) + product = self.product_product.create( + {"name": "Test global", "tracking": "serial"} + ) + self.assertFalse(product.lot_sequence_id) + seq = self.env["ir.sequence"].search([("code", "=", "stock.lot.serial")]) + next_sequence_number = seq.get_next_char(seq.number_next_actual) + lot_form = Form( + self.stock_production_lot.with_context( + default_company_id=self.env.company.id + ) + ) + self.assertEqual(lot_form.name, next_sequence_number) + self.assertEqual(lot_form.company_id, self.env.company) + lot_form.product_id = product + lot = lot_form.save() + self.assertEqual(lot.name, next_sequence_number) + + def test_open_detailed_operations(self): + # Required for `product_uom` to be visible in the view + self.env.user.groups_id += self.env.ref("uom.group_uom") + + self.env["ir.config_parameter"].set_param( + "product_lot_sequence.policy", "global" + ) + seq = self.env["ir.sequence"].search([("code", "=", "stock.lot.serial")]) + first_next_sequence_number = seq.get_next_char(seq.number_next_actual) + product = self.product_product.create( + {"name": "Test global", "tracking": "serial"} + ) + delivery_picking = self._create_picking( + self.delivery_type, [{"product_id": product}] + ) + delivery_move = delivery_picking.move_ids + self.assertFalse(delivery_move.next_serial) + delivery_move.action_show_details() + self.assertFalse(delivery_move.next_serial) + self.assertEqual( + seq.get_next_char(seq.number_next_actual), first_next_sequence_number + ) + receipt_picking = self._create_picking( + self.receipt_type, [{"product_id": product}] + ) + receipt_move = receipt_picking.move_ids + self.assertFalse(receipt_move.next_serial) + receipt_move.action_show_details() + self.assertEqual(receipt_move.next_serial, first_next_sequence_number) + new_next_sequence_number = seq.get_next_char(seq.number_next_actual) + self.assertNotEqual(new_next_sequence_number, first_next_sequence_number) + receipt_move.action_show_details() + self.assertEqual( + new_next_sequence_number, seq.get_next_char(seq.number_next_actual) + ) diff --git a/product_lot_sequence/views/product_views.xml b/product_lot_sequence/views/product_views.xml new file mode 100644 index 00000000000..3ba26798949 --- /dev/null +++ b/product_lot_sequence/views/product_views.xml @@ -0,0 +1,31 @@ + + + + + product.template.stock.property.form.inherit + product.template + + + + + + + + + + + + diff --git a/product_lot_sequence/views/res_config_settings_views.xml b/product_lot_sequence/views/res_config_settings_views.xml new file mode 100644 index 00000000000..a6db3b4c189 --- /dev/null +++ b/product_lot_sequence/views/res_config_settings_views.xml @@ -0,0 +1,32 @@ + + + + res.config.settings.view.form.inherit.stock + res.config.settings + + + +
+
+
+
+
+