diff --git a/stock_picking_auto_create_lot/README.rst b/stock_picking_auto_create_lot/README.rst new file mode 100644 index 000000000000..6c0bb6cbcadd --- /dev/null +++ b/stock_picking_auto_create_lot/README.rst @@ -0,0 +1,118 @@ +.. image:: https://odoo-community.org/readme-banner-image + :target: https://odoo-community.org/get-involved?utm_source=readme + :alt: Odoo Community Association + +============================= +Stock Picking Auto Create Lot +============================= + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:cc73ba4adce3d0c3e78373c600d4776ee891529cb5b7a54d7db2194244620a5e + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |badge1| image:: https://img.shields.io/badge/maturity-Production%2FStable-green.png + :target: https://odoo-community.org/page/development-status + :alt: Production/Stable +.. |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%2Fstock--logistics--workflow-lightgray.png?logo=github + :target: https://github.com/OCA/stock-logistics-workflow/tree/19.0/stock_picking_auto_create_lot + :alt: OCA/stock-logistics-workflow +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/stock-logistics-workflow-19-0/stock-logistics-workflow-19-0-stock_picking_auto_create_lot + :alt: Translate me on Weblate +.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png + :target: https://runboat.odoo-community.org/builds?repo=OCA/stock-logistics-workflow&target_branch=19.0 + :alt: Try me on Runboat + +|badge1| |badge2| |badge3| |badge4| |badge5| + +This module extends the functionality of stock module to allow auto +create lots for incoming pickings. + +**Table of contents** + +.. contents:: + :local: + +Configuration +============= + +To configure this module, you need to: + +1. Go to a *Inventory > Configuration > Operation Types*. +2. Set 'auto create lot' option for this operation type. +3. Go to a *Inventory > Master Data > Products*. +4. Set 'auto create lot' option for the products you need. + +Usage +===== + +To use this module you need to: + +1. Go to a *Product > General Information tab*. +2. Set a tracking option for this product. +3. Set auto create lot. +4. Go to *Inventory > Incoming* and create one. +5. Validate picking without lot. + +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 +------- + +* ACSONE SA/NV +* Tecnativa + +Contributors +------------ + +- Carlos Dauden +- Sergio Teruel +- Pimolnat Suntian +- Denis Roussel +- Valentin Vinagre +- `Quartile `__: + + - Aung Ko Ko Lin + +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/stock-logistics-workflow `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/stock_picking_auto_create_lot/__init__.py b/stock_picking_auto_create_lot/__init__.py new file mode 100644 index 000000000000..3275ac2adf3d --- /dev/null +++ b/stock_picking_auto_create_lot/__init__.py @@ -0,0 +1,2 @@ +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +from . import models diff --git a/stock_picking_auto_create_lot/__manifest__.py b/stock_picking_auto_create_lot/__manifest__.py new file mode 100644 index 000000000000..5166be10d08d --- /dev/null +++ b/stock_picking_auto_create_lot/__manifest__.py @@ -0,0 +1,17 @@ +# Copyright 2018 Tecnativa - Sergio Teruel +# Copyright 2020 ACSONE SA/NV +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +{ + "name": "Stock Picking Auto Create Lot", + "summary": "Auto create lots for incoming pickings", + "version": "19.0.1.0.0", + "development_status": "Production/Stable", + "category": "stock", + "website": "https://github.com/OCA/stock-logistics-workflow", + "author": "ACSONE SA/NV, Tecnativa, Odoo Community Association (OCA)", + "license": "AGPL-3", + "installable": True, + "depends": ["stock"], + "data": ["views/product_views.xml", "views/stock_picking_type_views.xml"], + "maintainers": ["sergio-teruel"], +} diff --git a/stock_picking_auto_create_lot/i18n/es.po b/stock_picking_auto_create_lot/i18n/es.po new file mode 100644 index 000000000000..b555eb33b117 --- /dev/null +++ b/stock_picking_auto_create_lot/i18n/es.po @@ -0,0 +1,53 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * stock_picking_auto_create_lot +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 12.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2019-02-25 13:29+0000\n" +"PO-Revision-Date: 2023-03-21 12:12+0000\n" +"Last-Translator: FranciscoFactorLibre \n" +"Language-Team: \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.14.1\n" + +#. module: stock_picking_auto_create_lot +#: model:ir.model.fields,field_description:stock_picking_auto_create_lot.field_product_product__auto_create_lot +#: model:ir.model.fields,field_description:stock_picking_auto_create_lot.field_product_template__auto_create_lot +#: model:ir.model.fields,field_description:stock_picking_auto_create_lot.field_stock_picking_type__auto_create_lot +msgid "Auto Create Lot" +msgstr "Auto crear lote" + +#. module: stock_picking_auto_create_lot +#: model:ir.model,name:stock_picking_auto_create_lot.model_stock_picking_type +msgid "Picking Type" +msgstr "Tipo de albarán" + +#. module: stock_picking_auto_create_lot +#: model:ir.model,name:stock_picking_auto_create_lot.model_product_template +msgid "Product" +msgstr "Producto" + +#. module: stock_picking_auto_create_lot +#: model:ir.model,name:stock_picking_auto_create_lot.model_stock_move_line +msgid "Product Moves (Stock Move Line)" +msgstr "Movimientos de producto (Movimiento de stock)" + +#. module: stock_picking_auto_create_lot +#: model:ir.model,name:stock_picking_auto_create_lot.model_stock_move +msgid "Stock Move" +msgstr "Movimiento de existencias" + +#. module: stock_picking_auto_create_lot +#: model:ir.model,name:stock_picking_auto_create_lot.model_stock_picking +msgid "Transfer" +msgstr "Transferir" + +#~ msgid "Product Template" +#~ msgstr "Plantilla de producto" diff --git a/stock_picking_auto_create_lot/i18n/it.po b/stock_picking_auto_create_lot/i18n/it.po new file mode 100644 index 000000000000..8600ae3b4e1d --- /dev/null +++ b/stock_picking_auto_create_lot/i18n/it.po @@ -0,0 +1,49 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * stock_picking_auto_create_lot +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 16.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2024-08-22 10:06+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.6.2\n" + +#. module: stock_picking_auto_create_lot +#: model:ir.model.fields,field_description:stock_picking_auto_create_lot.field_product_product__auto_create_lot +#: model:ir.model.fields,field_description:stock_picking_auto_create_lot.field_product_template__auto_create_lot +#: model:ir.model.fields,field_description:stock_picking_auto_create_lot.field_stock_picking_type__auto_create_lot +msgid "Auto Create Lot" +msgstr "Creazione automatica lotto" + +#. module: stock_picking_auto_create_lot +#: model:ir.model,name:stock_picking_auto_create_lot.model_stock_picking_type +msgid "Picking Type" +msgstr "Tipo prelievo" + +#. module: stock_picking_auto_create_lot +#: model:ir.model,name:stock_picking_auto_create_lot.model_product_template +msgid "Product" +msgstr "Prodotto" + +#. module: stock_picking_auto_create_lot +#: model:ir.model,name:stock_picking_auto_create_lot.model_stock_move_line +msgid "Product Moves (Stock Move Line)" +msgstr "Movimenti prodotto (riga movimento di magazzino)" + +#. module: stock_picking_auto_create_lot +#: model:ir.model,name:stock_picking_auto_create_lot.model_stock_move +msgid "Stock Move" +msgstr "Movimento di magazzino" + +#. module: stock_picking_auto_create_lot +#: model:ir.model,name:stock_picking_auto_create_lot.model_stock_picking +msgid "Transfer" +msgstr "Trasferimento" diff --git a/stock_picking_auto_create_lot/i18n/nl.po b/stock_picking_auto_create_lot/i18n/nl.po new file mode 100644 index 000000000000..121cc4dbd6ed --- /dev/null +++ b/stock_picking_auto_create_lot/i18n/nl.po @@ -0,0 +1,49 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * stock_picking_auto_create_lot +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 16.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2023-10-14 00:45+0000\n" +"Last-Translator: Bosd \n" +"Language-Team: none\n" +"Language: nl\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: stock_picking_auto_create_lot +#: model:ir.model.fields,field_description:stock_picking_auto_create_lot.field_product_product__auto_create_lot +#: model:ir.model.fields,field_description:stock_picking_auto_create_lot.field_product_template__auto_create_lot +#: model:ir.model.fields,field_description:stock_picking_auto_create_lot.field_stock_picking_type__auto_create_lot +msgid "Auto Create Lot" +msgstr "Automatisch een partij aanmaken" + +#. module: stock_picking_auto_create_lot +#: model:ir.model,name:stock_picking_auto_create_lot.model_stock_picking_type +msgid "Picking Type" +msgstr "" + +#. module: stock_picking_auto_create_lot +#: model:ir.model,name:stock_picking_auto_create_lot.model_product_template +msgid "Product" +msgstr "Product" + +#. module: stock_picking_auto_create_lot +#: model:ir.model,name:stock_picking_auto_create_lot.model_stock_move_line +msgid "Product Moves (Stock Move Line)" +msgstr "Voorraadverplaatsingen (Voorraadverplaatsingsregels)" + +#. module: stock_picking_auto_create_lot +#: model:ir.model,name:stock_picking_auto_create_lot.model_stock_move +msgid "Stock Move" +msgstr "Voorraadverplaatsing" + +#. module: stock_picking_auto_create_lot +#: model:ir.model,name:stock_picking_auto_create_lot.model_stock_picking +msgid "Transfer" +msgstr "transfer" diff --git a/stock_picking_auto_create_lot/i18n/pt.po b/stock_picking_auto_create_lot/i18n/pt.po new file mode 100644 index 000000000000..4dd8504a3bff --- /dev/null +++ b/stock_picking_auto_create_lot/i18n/pt.po @@ -0,0 +1,47 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * stock_picking_auto_create_lot +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 18.0\n" +"Report-Msgid-Bugs-To: \n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: pt\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n > 1;\n" + +#. module: stock_picking_auto_create_lot +#: model:ir.model.fields,field_description:stock_picking_auto_create_lot.field_product_product__auto_create_lot +#: model:ir.model.fields,field_description:stock_picking_auto_create_lot.field_product_template__auto_create_lot +#: model:ir.model.fields,field_description:stock_picking_auto_create_lot.field_stock_picking_type__auto_create_lot +msgid "Auto Create Lot" +msgstr "" + +#. module: stock_picking_auto_create_lot +#: model:ir.model,name:stock_picking_auto_create_lot.model_stock_picking_type +msgid "Picking Type" +msgstr "" + +#. module: stock_picking_auto_create_lot +#: model:ir.model,name:stock_picking_auto_create_lot.model_product_template +msgid "Product" +msgstr "" + +#. module: stock_picking_auto_create_lot +#: model:ir.model,name:stock_picking_auto_create_lot.model_stock_move_line +msgid "Product Moves (Stock Move Line)" +msgstr "" + +#. module: stock_picking_auto_create_lot +#: model:ir.model,name:stock_picking_auto_create_lot.model_stock_move +msgid "Stock Move" +msgstr "" + +#. module: stock_picking_auto_create_lot +#: model:ir.model,name:stock_picking_auto_create_lot.model_stock_picking +msgid "Transfer" +msgstr "" diff --git a/stock_picking_auto_create_lot/i18n/pt_BR.po b/stock_picking_auto_create_lot/i18n/pt_BR.po new file mode 100644 index 000000000000..9c0f46e53818 --- /dev/null +++ b/stock_picking_auto_create_lot/i18n/pt_BR.po @@ -0,0 +1,47 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * stock_picking_auto_create_lot +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 18.0\n" +"Report-Msgid-Bugs-To: \n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: pt_BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n > 1;\n" + +#. module: stock_picking_auto_create_lot +#: model:ir.model.fields,field_description:stock_picking_auto_create_lot.field_product_product__auto_create_lot +#: model:ir.model.fields,field_description:stock_picking_auto_create_lot.field_product_template__auto_create_lot +#: model:ir.model.fields,field_description:stock_picking_auto_create_lot.field_stock_picking_type__auto_create_lot +msgid "Auto Create Lot" +msgstr "" + +#. module: stock_picking_auto_create_lot +#: model:ir.model,name:stock_picking_auto_create_lot.model_stock_picking_type +msgid "Picking Type" +msgstr "" + +#. module: stock_picking_auto_create_lot +#: model:ir.model,name:stock_picking_auto_create_lot.model_product_template +msgid "Product" +msgstr "" + +#. module: stock_picking_auto_create_lot +#: model:ir.model,name:stock_picking_auto_create_lot.model_stock_move_line +msgid "Product Moves (Stock Move Line)" +msgstr "" + +#. module: stock_picking_auto_create_lot +#: model:ir.model,name:stock_picking_auto_create_lot.model_stock_move +msgid "Stock Move" +msgstr "" + +#. module: stock_picking_auto_create_lot +#: model:ir.model,name:stock_picking_auto_create_lot.model_stock_picking +msgid "Transfer" +msgstr "" diff --git a/stock_picking_auto_create_lot/i18n/stock_picking_auto_create_lot.pot b/stock_picking_auto_create_lot/i18n/stock_picking_auto_create_lot.pot new file mode 100644 index 000000000000..aa8b9642bbec --- /dev/null +++ b/stock_picking_auto_create_lot/i18n/stock_picking_auto_create_lot.pot @@ -0,0 +1,46 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * stock_picking_auto_create_lot +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 18.0\n" +"Report-Msgid-Bugs-To: \n" +"Last-Translator: \n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" + +#. module: stock_picking_auto_create_lot +#: model:ir.model.fields,field_description:stock_picking_auto_create_lot.field_product_product__auto_create_lot +#: model:ir.model.fields,field_description:stock_picking_auto_create_lot.field_product_template__auto_create_lot +#: model:ir.model.fields,field_description:stock_picking_auto_create_lot.field_stock_picking_type__auto_create_lot +msgid "Auto Create Lot" +msgstr "" + +#. module: stock_picking_auto_create_lot +#: model:ir.model,name:stock_picking_auto_create_lot.model_stock_picking_type +msgid "Picking Type" +msgstr "" + +#. module: stock_picking_auto_create_lot +#: model:ir.model,name:stock_picking_auto_create_lot.model_product_template +msgid "Product" +msgstr "" + +#. module: stock_picking_auto_create_lot +#: model:ir.model,name:stock_picking_auto_create_lot.model_stock_move_line +msgid "Product Moves (Stock Move Line)" +msgstr "" + +#. module: stock_picking_auto_create_lot +#: model:ir.model,name:stock_picking_auto_create_lot.model_stock_move +msgid "Stock Move" +msgstr "" + +#. module: stock_picking_auto_create_lot +#: model:ir.model,name:stock_picking_auto_create_lot.model_stock_picking +msgid "Transfer" +msgstr "" diff --git a/stock_picking_auto_create_lot/i18n/zh_CN.po b/stock_picking_auto_create_lot/i18n/zh_CN.po new file mode 100644 index 000000000000..b0ff98ca53f9 --- /dev/null +++ b/stock_picking_auto_create_lot/i18n/zh_CN.po @@ -0,0 +1,52 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * stock_picking_auto_create_lot +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 13.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2020-03-21 15:13+0000\n" +"Last-Translator: Dong \n" +"Language-Team: none\n" +"Language: zh_CN\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=1; plural=0;\n" +"X-Generator: Weblate 3.10\n" + +#. module: stock_picking_auto_create_lot +#: model:ir.model.fields,field_description:stock_picking_auto_create_lot.field_product_product__auto_create_lot +#: model:ir.model.fields,field_description:stock_picking_auto_create_lot.field_product_template__auto_create_lot +#: model:ir.model.fields,field_description:stock_picking_auto_create_lot.field_stock_picking_type__auto_create_lot +msgid "Auto Create Lot" +msgstr "自动创建批次" + +#. module: stock_picking_auto_create_lot +#: model:ir.model,name:stock_picking_auto_create_lot.model_stock_picking_type +msgid "Picking Type" +msgstr "作业类型" + +#. module: stock_picking_auto_create_lot +#: model:ir.model,name:stock_picking_auto_create_lot.model_product_template +msgid "Product" +msgstr "" + +#. module: stock_picking_auto_create_lot +#: model:ir.model,name:stock_picking_auto_create_lot.model_stock_move_line +msgid "Product Moves (Stock Move Line)" +msgstr "" + +#. module: stock_picking_auto_create_lot +#: model:ir.model,name:stock_picking_auto_create_lot.model_stock_move +msgid "Stock Move" +msgstr "" + +#. module: stock_picking_auto_create_lot +#: model:ir.model,name:stock_picking_auto_create_lot.model_stock_picking +msgid "Transfer" +msgstr "调拨" + +#~ msgid "Product Template" +#~ msgstr "产品模版" diff --git a/stock_picking_auto_create_lot/models/__init__.py b/stock_picking_auto_create_lot/models/__init__.py new file mode 100644 index 000000000000..d873a374c657 --- /dev/null +++ b/stock_picking_auto_create_lot/models/__init__.py @@ -0,0 +1,6 @@ +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +from . import product +from . import stock_picking +from . import stock_picking_type +from . import stock_move +from . import stock_move_line diff --git a/stock_picking_auto_create_lot/models/product.py b/stock_picking_auto_create_lot/models/product.py new file mode 100644 index 000000000000..00282b56e75e --- /dev/null +++ b/stock_picking_auto_create_lot/models/product.py @@ -0,0 +1,9 @@ +# Copyright 2018 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" + + auto_create_lot = fields.Boolean() diff --git a/stock_picking_auto_create_lot/models/stock_move.py b/stock_picking_auto_create_lot/models/stock_move.py new file mode 100644 index 000000000000..af6594d4d368 --- /dev/null +++ b/stock_picking_auto_create_lot/models/stock_move.py @@ -0,0 +1,40 @@ +# Copyright 2020 ACSONE SA/NV +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +from odoo import api, models + + +class StockMove(models.Model): + _inherit = "stock.move" + + @api.depends( + "has_tracking", + "picking_type_id.auto_create_lot", + "product_id.auto_create_lot", + "picking_type_id.use_existing_lots", + "state", + ) + def _compute_display_assign_serial(self): + super()._compute_display_assign_serial() + moves_not_display = self.filtered( + lambda m: m.picking_type_id.auto_create_lot and m.product_id.auto_create_lot + ) + for move in moves_not_display: + move.display_assign_serial = False + return + + # pylint: disable=missing-return + def _set_quantities_to_reservation(self): + super()._set_quantities_to_reservation() + for move in self: + if move.state not in ("partially_available", "assigned"): + continue + if ( + move.product_id.tracking == "none" + or not move.product_id.auto_create_lot + or not move.picking_type_id.auto_create_lot + ): + continue + for move_line in move.move_line_ids: + if move_line.lot_id: + # Create-backorder wizard would open without this. + move_line.quantity = move_line.quantity_product_uom diff --git a/stock_picking_auto_create_lot/models/stock_move_line.py b/stock_picking_auto_create_lot/models/stock_move_line.py new file mode 100644 index 000000000000..5fb9dd267f06 --- /dev/null +++ b/stock_picking_auto_create_lot/models/stock_move_line.py @@ -0,0 +1,12 @@ +# Copyright 2024 Quartile Limited +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import models + + +class StockMoveLine(models.Model): + _inherit = "stock.move.line" + + def _get_lot_sequence(self): + self.ensure_one() + return self.env["ir.sequence"].next_by_code("stock.lot.serial") diff --git a/stock_picking_auto_create_lot/models/stock_picking.py b/stock_picking_auto_create_lot/models/stock_picking.py new file mode 100644 index 000000000000..777e8fbe62eb --- /dev/null +++ b/stock_picking_auto_create_lot/models/stock_picking.py @@ -0,0 +1,32 @@ +# Copyright 2018 Tecnativa - Sergio Teruel +# Copyright 2020 ACSONE SA/NV +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +from odoo import models + + +class StockPicking(models.Model): + _inherit = "stock.picking" + + def _set_auto_lot(self): + """ + Allows to be called either by button or through code + """ + pickings = self.filtered(lambda p: p.picking_type_id.auto_create_lot) + lines = pickings.mapped("move_line_ids").filtered( + lambda x: ( + not x.lot_id + and not x.lot_name + and x.product_id.tracking != "none" + and x.product_id.auto_create_lot + ) + ) + for line in lines: + line.lot_name = line._get_lot_sequence() + + def _action_done(self): + self._set_auto_lot() + return super()._action_done() + + def button_validate(self): + self._set_auto_lot() + return super().button_validate() diff --git a/stock_picking_auto_create_lot/models/stock_picking_type.py b/stock_picking_auto_create_lot/models/stock_picking_type.py new file mode 100644 index 000000000000..e4dc27e5c9c8 --- /dev/null +++ b/stock_picking_auto_create_lot/models/stock_picking_type.py @@ -0,0 +1,9 @@ +# Copyright 2018 Tecnativa - Sergio Teruel +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +from odoo import fields, models + + +class StockPickingType(models.Model): + _inherit = "stock.picking.type" + + auto_create_lot = fields.Boolean() diff --git a/stock_picking_auto_create_lot/pyproject.toml b/stock_picking_auto_create_lot/pyproject.toml new file mode 100644 index 000000000000..4231d0cccb3d --- /dev/null +++ b/stock_picking_auto_create_lot/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["whool"] +build-backend = "whool.buildapi" diff --git a/stock_picking_auto_create_lot/readme/CONFIGURE.md b/stock_picking_auto_create_lot/readme/CONFIGURE.md new file mode 100644 index 000000000000..cafa7606df94 --- /dev/null +++ b/stock_picking_auto_create_lot/readme/CONFIGURE.md @@ -0,0 +1,6 @@ +To configure this module, you need to: + +1. Go to a *Inventory \> Configuration \> Operation Types*. +2. Set 'auto create lot' option for this operation type. +3. Go to a *Inventory \> Master Data \> Products*. +4. Set 'auto create lot' option for the products you need. diff --git a/stock_picking_auto_create_lot/readme/CONTRIBUTORS.md b/stock_picking_auto_create_lot/readme/CONTRIBUTORS.md new file mode 100644 index 000000000000..7f919404503f --- /dev/null +++ b/stock_picking_auto_create_lot/readme/CONTRIBUTORS.md @@ -0,0 +1,7 @@ +- Carlos Dauden \<\> +- Sergio Teruel \<\> +- Pimolnat Suntian \<\> +- Denis Roussel \<\> +- Valentin Vinagre \<\> +- [Quartile](https://www.quartile.co): + - Aung Ko Ko Lin diff --git a/stock_picking_auto_create_lot/readme/DESCRIPTION.md b/stock_picking_auto_create_lot/readme/DESCRIPTION.md new file mode 100644 index 000000000000..4c8d98f8115c --- /dev/null +++ b/stock_picking_auto_create_lot/readme/DESCRIPTION.md @@ -0,0 +1,2 @@ +This module extends the functionality of stock module to allow auto +create lots for incoming pickings. diff --git a/stock_picking_auto_create_lot/readme/USAGE.md b/stock_picking_auto_create_lot/readme/USAGE.md new file mode 100644 index 000000000000..dbbcfebf2fbb --- /dev/null +++ b/stock_picking_auto_create_lot/readme/USAGE.md @@ -0,0 +1,7 @@ +To use this module you need to: + +1. Go to a *Product \> General Information tab*. +2. Set a tracking option for this product. +3. Set auto create lot. +4. Go to *Inventory \> Incoming* and create one. +5. Validate picking without lot. diff --git a/stock_picking_auto_create_lot/static/description/icon.png b/stock_picking_auto_create_lot/static/description/icon.png new file mode 100644 index 000000000000..3a0328b516c4 Binary files /dev/null and b/stock_picking_auto_create_lot/static/description/icon.png differ diff --git a/stock_picking_auto_create_lot/static/description/index.html b/stock_picking_auto_create_lot/static/description/index.html new file mode 100644 index 000000000000..141ab5e0f908 --- /dev/null +++ b/stock_picking_auto_create_lot/static/description/index.html @@ -0,0 +1,464 @@ + + + + + +README.rst + + + +
+ + + +Odoo Community Association + +
+

Stock Picking Auto Create Lot

+ +

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

+

This module extends the functionality of stock module to allow auto +create lots for incoming pickings.

+

Table of contents

+ +
+

Configuration

+

To configure this module, you need to:

+
    +
  1. Go to a Inventory > Configuration > Operation Types.
  2. +
  3. Set ‘auto create lot’ option for this operation type.
  4. +
  5. Go to a Inventory > Master Data > Products.
  6. +
  7. Set ‘auto create lot’ option for the products you need.
  8. +
+
+
+

Usage

+

To use this module you need to:

+
    +
  1. Go to a Product > General Information tab.
  2. +
  3. Set a tracking option for this product.
  4. +
  5. Set auto create lot.
  6. +
  7. Go to Inventory > Incoming and create one.
  8. +
  9. Validate picking without lot.
  10. +
+
+
+

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

+
    +
  • ACSONE SA/NV
  • +
  • Tecnativa
  • +
+
+
+

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.

+

Current maintainer:

+

sergio-teruel

+

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

+

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

+
+
+
+
+ + diff --git a/stock_picking_auto_create_lot/tests/__init__.py b/stock_picking_auto_create_lot/tests/__init__.py new file mode 100644 index 000000000000..59ff2aaf0a3f --- /dev/null +++ b/stock_picking_auto_create_lot/tests/__init__.py @@ -0,0 +1,3 @@ +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +from . import common +from . import test_stock_picking_auto_create_lot diff --git a/stock_picking_auto_create_lot/tests/common.py b/stock_picking_auto_create_lot/tests/common.py new file mode 100644 index 000000000000..1fdc8e4917fc --- /dev/null +++ b/stock_picking_auto_create_lot/tests/common.py @@ -0,0 +1,64 @@ +# Copyright 2018 Tecnativa - Sergio Teruel +# Copyright 2020 ACSONE SA/NV +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + + +class CommonStockPickingAutoCreateLot: + def assertUniqueIn(self, element_list): + elements = [] + for element in element_list: + if element in elements: + raise Exception(f"Element {element} is not unique in list") + elements.append(element) + + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.env = cls.env(context=dict(cls.env.context, tracking_disable=True)) + cls.lot_obj = cls.env["stock.lot"] + cls.warehouse = cls.env.ref("stock.warehouse0") + cls.picking_type_in = cls.env.ref("stock.picking_type_in") + cls.supplier_location = cls.env.ref("stock.stock_location_suppliers") + cls.supplier = cls.env["res.partner"].create({"name": "Supplier - test"}) + + @classmethod + def _create_product(cls, tracking="lot", auto=True): + name = f"{tracking} - {auto}" + return cls.env["product.product"].create( + { + "name": name, + "type": "consu", + "tracking": tracking, + "auto_create_lot": auto, + "is_storable": True, + } + ) + + @classmethod + def _create_picking(cls): + cls.picking = ( + cls.env["stock.picking"] + .with_context(default_picking_type_id=cls.picking_type_in.id) + .create( + { + "partner_id": cls.supplier.id, + "picking_type_id": cls.picking_type_in.id, + "location_id": cls.supplier_location.id, + } + ) + ) + + @classmethod + def _create_move(cls, product=None, qty=1.0): + location_dest = cls.picking.picking_type_id.default_location_dest_id + cls.move = cls.env["stock.move"].create( + { + "product_id": product.id, + "picking_id": cls.picking.id, + "picking_type_id": cls.picking.picking_type_id.id, + "product_uom_qty": qty, + "product_uom": product.uom_id.id, + "location_id": cls.supplier_location.id, + "location_dest_id": location_dest.id, + } + ) diff --git a/stock_picking_auto_create_lot/tests/test_stock_picking_auto_create_lot.py b/stock_picking_auto_create_lot/tests/test_stock_picking_auto_create_lot.py new file mode 100644 index 000000000000..4a9430713ea9 --- /dev/null +++ b/stock_picking_auto_create_lot/tests/test_stock_picking_auto_create_lot.py @@ -0,0 +1,173 @@ +# Copyright 2018 Tecnativa - Sergio Teruel +# Copyright 2020 ACSONE SA/NV +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +from odoo.exceptions import UserError +from odoo.tests import TransactionCase + +from .common import CommonStockPickingAutoCreateLot + + +class TestStockPickingAutoCreateLot(CommonStockPickingAutoCreateLot, TransactionCase): + @classmethod + def setUpClass(cls): + super().setUpClass() + # Create 3 products with lot/serial and auto_create True/False + cls.product = cls._create_product() + cls.product_serial = cls._create_product(tracking="serial") + cls.product_serial_not_auto = cls._create_product(tracking="serial", auto=False) + cls.picking_type_in.auto_create_lot = True + + cls._create_picking() + cls._create_move(product=cls.product, qty=2.0) + cls._create_move(product=cls.product_serial, qty=3.0) + cls._create_move(product=cls.product_serial_not_auto, qty=4.0) + + def test_manual_lot(self): + self.picking.action_assign() + # Check the display field + move = self.picking.move_ids.filtered( + lambda m: m.product_id == self.product_serial + ) + self.assertFalse(move.display_assign_serial) + + move = self.picking.move_ids.filtered( + lambda m: m.product_id == self.product_serial_not_auto + ) + self.assertTrue(move.display_assign_serial) + # Assign manual serials + self._assign_manual_serials(move) + self.picking.move_ids.picked = True + self.picking.button_validate() + lot = self.env["stock.lot"].search([("product_id", "=", self.product.id)]) + self.assertEqual(len(lot), 1) + # Search for serials + lot = self.env["stock.lot"].search( + [("product_id", "=", self.product_serial.id)] + ) + self.assertEqual(len(lot), 3) + + def test_auto_create_lot(self): + self.picking.action_assign() + # Check the display field + move = self.picking.move_ids.filtered( + lambda m: m.product_id == self.product_serial + ) + self.assertFalse(move.display_assign_serial) + + move = self.picking.move_ids.filtered( + lambda m: m.product_id == self.product_serial_not_auto + ) + self.assertTrue(move.display_assign_serial) + # Assign manual serials + self._assign_manual_serials(move) + self.picking.move_ids.picked = True + + self.picking._action_done() + lot = self.env["stock.lot"].search([("product_id", "=", self.product.id)]) + self.assertEqual(len(lot), 1) + # Search for serials + lot = self.env["stock.lot"].search( + [("product_id", "=", self.product_serial.id)] + ) + self.assertEqual(len(lot), 3) + + def test_auto_create_transfer_lot(self): + self.picking.action_assign() + moves = self.picking.move_ids.filtered( + lambda m: m.product_id == self.product_serial + ) + for line in moves.mapped("move_line_ids"): + self.assertFalse(line.lot_name) + + # Test the exception if manual serials are not filled in + with self.assertRaises(UserError), self.cr.savepoint(): + self.picking.button_validate() + + # Assign manual serial for product that need it + moves = self.picking.move_ids.filtered( + lambda m: m.product_id == self.product_serial_not_auto + ) + # Assign manual serials + self._assign_manual_serials(moves) + self.picking.move_ids.picked = True + + self.picking.button_validate() + for line in moves.mapped("move_line_ids"): + self.assertTrue(line.lot_id) + + lot = self.env["stock.lot"].search([("product_id", "=", self.product.id)]) + self.assertEqual(len(lot), 1) + # Search for serials + lot = self.env["stock.lot"].search( + [("product_id", "=", self.product_serial.id)] + ) + self.assertEqual(len(lot), 3) + + # Check if lots are unique per move and per product if managed + # per serial + move_lines_serial = self.picking.move_line_ids.filtered( + lambda m: m.product_id.tracking == "serial" and m.product_id.auto_create_lot + ) + serials = [] + for move in move_lines_serial: + serials.append(move.lot_id.name) + self.assertUniqueIn(serials) + + def test_multi_auto_create_lot(self): + """ + Create two pickings + Try to validate them together + Check if lots have been assigned to each move + """ + self.picking.action_assign() + picking_1 = self.picking + self._create_picking() + picking_2 = self.picking + self._create_move(product=self.product_serial, qty=3.0) + picking_2.action_assign() + pickings = picking_1 | picking_2 + + moves = pickings.mapped("move_ids").filtered( + lambda m: m.product_id == self.product_serial + and m.product_id.auto_create_lot + ) + for line in moves.mapped("move_line_ids"): + self.assertFalse(line.lot_name) + + pickings._action_done() + for line in moves.mapped("move_line_ids"): + self.assertTrue(line.lot_name) + + def test_immediate_validate_tracked_move_with_auto_create_lot(self): + # Clear existing move if not the picking will open backorder wizard because + # when we manually assign lot for serial_not_auto product, other products still + # have 0 done qty. + self.picking.move_ids = False + self._create_move(product=self.product_serial, qty=4.0) + self.picking.action_assign() + self.picking.button_validate() + # Confirm that validation is not blocked, for example, by create-backorder + # wizard. + self.assertEqual(self.picking.state, "done") + + def test_multiple_sml_for_one_stock_move(self): + """ + Create a picking and we receive goods from supplier with different features so + we want different lots by each stock move line. + """ + self._create_picking() + self._create_move(product=self.product, qty=50.0) + self.picking.action_assign() + self.picking.move_line_ids.quantity = 25.0 + # new sml with 25.0 units + self.picking.move_line_ids.copy({"quantity": 25.0}) + self.picking.button_validate() + lots = self.picking.move_line_ids.lot_id + self.assertEqual(len(lots), 2) + + def _assign_manual_serials(self, moves): + # Assign manual serials + moves.picking_id._set_auto_lot() + moves.move_line_ids.quantity = 1.0 + for line in moves.move_line_ids: + line.lot_name = self.env["ir.sequence"].next_by_code("stock.lot.serial") diff --git a/stock_picking_auto_create_lot/views/product_views.xml b/stock_picking_auto_create_lot/views/product_views.xml new file mode 100644 index 000000000000..b9441b2c1f5d --- /dev/null +++ b/stock_picking_auto_create_lot/views/product_views.xml @@ -0,0 +1,15 @@ + + + + + Product template Secondary Unit + product.template + + + + + + + + diff --git a/stock_picking_auto_create_lot/views/stock_picking_type_views.xml b/stock_picking_auto_create_lot/views/stock_picking_type_views.xml new file mode 100644 index 000000000000..345efb36bf5b --- /dev/null +++ b/stock_picking_auto_create_lot/views/stock_picking_type_views.xml @@ -0,0 +1,15 @@ + + + + + stock.picking.type.auto.lot + stock.picking.type + + + + + + + +