diff --git a/stock_location_lockdown/README.rst b/stock_location_lockdown/README.rst new file mode 100644 index 0000000..4f0ef49 --- /dev/null +++ b/stock_location_lockdown/README.rst @@ -0,0 +1,103 @@ +======================= +Stock Location Lockdown +======================= + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:0562a65b8b5bd0d7896019c2960499d5560b9378bb352da7a80f10cf445b7d76 + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png + :target: https://odoo-community.org/page/development-status + :alt: Beta +.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png + :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html + :alt: License: AGPL-3 +.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fstock--logistics--warehouse-lightgray.png?logo=github + :target: https://github.com/OCA/stock-logistics-warehouse/tree/18.0/stock_location_lockdown + :alt: OCA/stock-logistics-warehouse +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/stock-logistics-warehouse-18-0/stock-logistics-warehouse-18-0-stock_location_lockdown + :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-warehouse&target_branch=18.0 + :alt: Try me on Runboat + +|badge1| |badge2| |badge3| |badge4| |badge5| + +The aim of this module is to provide a way to mark internal locations +where product storage is disallowed. This feature is versatile and can +be used in various scenarios, such as: + +- Temporarily blocking stock movement to specific locations. +- Preventing stock from being stored in locations not meant for physical + storage. + +Indeed, in complex warehouse setups, we may have a complicated tree of +internal locations with parent locations only used to create the +hierarchy of the internal locations. We may want to avoid to put stock +on these parent internal locations since they are not physical +locations, they just represent a zone of the warehouse. Theses locations +must have *Location Type* set to *Internal Location* because they belong +to a warehouse (they can't be configured with *Location Type* set to +*View*, cf `Odoo bug +#26679 `__). With this +module, you will be able to enable a new option *Block stock entrance* +for these locations. + +**Table of contents** + +.. contents:: + :local: + +Usage +===== + +- Once the module is installed, select any internal location for which + you want to prevent stock entrance and check the box *Block Stock + Entrance*. Then, you won't be allow to add stock on these locations. + +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 +------- + +* Akretion + +Contributors +------------ + +- Florian da Costa +- David Montull Guasch +- Urvisha Desai + +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/stock-logistics-warehouse `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/stock_location_lockdown/__init__.py b/stock_location_lockdown/__init__.py new file mode 100644 index 0000000..79e06e2 --- /dev/null +++ b/stock_location_lockdown/__init__.py @@ -0,0 +1,4 @@ +# Copyright 2018 Akretion +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from . import models diff --git a/stock_location_lockdown/__manifest__.py b/stock_location_lockdown/__manifest__.py new file mode 100644 index 0000000..b7674d7 --- /dev/null +++ b/stock_location_lockdown/__manifest__.py @@ -0,0 +1,16 @@ +# Copyright 2018 Akretion +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +{ + "name": "Stock Location Lockdown", + "summary": "Prevent to add stock on locked locations", + "author": "Akretion, Odoo Community Association (OCA)", + "website": "https://github.com/OCA/stock-logistics-warehouse", + "category": "Warehouse", + "version": "18.0.1.0.0", + "license": "AGPL-3", + "application": False, + "installable": True, + "depends": ["stock"], + "data": ["views/stock_location.xml"], +} diff --git a/stock_location_lockdown/i18n/es.po b/stock_location_lockdown/i18n/es.po new file mode 100644 index 0000000..6b3fbe7 --- /dev/null +++ b/stock_location_lockdown/i18n/es.po @@ -0,0 +1,64 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * stock_location_lockdown +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 16.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2024-08-22 18:06+0000\n" +"Last-Translator: Florencia Frigieri \n" +"Language-Team: none\n" +"Language: es\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 5.6.2\n" + +#. module: stock_location_lockdown +#: model:ir.model.fields,field_description:stock_location_lockdown.field_stock_location__block_stock_entrance +msgid "Block Stock Entrance" +msgstr "Bloquear la entrada de existencias" + +#. module: stock_location_lockdown +#: model:ir.model,name:stock_location_lockdown.model_stock_location +msgid "Inventory Locations" +msgstr "Ubicaciones" + +#. module: stock_location_lockdown +#. odoo-python +#: code:addons/stock_location_lockdown/models/stock_location.py:0 +#, python-format +msgid "" +"It is impossible to prohibit this location from receiving " +"products as it already contains some." +msgstr "" +"Es imposible prohibir que este lugar " +"reciba productos, puesto que " +"ya contiene algunos." + +#. module: stock_location_lockdown +#: model:ir.model,name:stock_location_lockdown.model_stock_quant +msgid "Quants" +msgstr "Cantidades" + +#. module: stock_location_lockdown +#. odoo-python +#: code:addons/stock_location_lockdown/models/stock_quant.py:0 +#, python-format +msgid "" +"The location %(location)s is blocked and can not be used for moving the " +"product %(product)s" +msgstr "" +"La ubicación %(location)s esta bloqueada, no puede ser usada para mover el " +"producto %(product)s" + +#. module: stock_location_lockdown +#: model:ir.model.fields,help:stock_location_lockdown.field_stock_location__block_stock_entrance +msgid "" +"if this box is checked, putting stock on this location won't be allowed. " +"Usually used for a virtual location that has childrens." +msgstr "" +"si esta casilla está marcada, no se permitirá poner acciones en esta " +"ubicación. Normalmente se utiliza para una ubicación virtual que tiene niños." diff --git a/stock_location_lockdown/i18n/fr.po b/stock_location_lockdown/i18n/fr.po new file mode 100644 index 0000000..aa71f0f --- /dev/null +++ b/stock_location_lockdown/i18n/fr.po @@ -0,0 +1,69 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * stock_location_lockdown +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 9.0c\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2018-09-06 13:10+0000\n" +"PO-Revision-Date: 2018-09-06 13:10+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: stock_location_lockdown +#: model:ir.model.fields,field_description:stock_location_lockdown.field_stock_location__block_stock_entrance +#, fuzzy +msgid "Block Stock Entrance" +msgstr "Bloquer les entrées de stock" + +#. module: stock_location_lockdown +#: model:ir.model,name:stock_location_lockdown.model_stock_location +msgid "Inventory Locations" +msgstr "" + +#. module: stock_location_lockdown +#. odoo-python +#: code:addons/stock_location_lockdown/models/stock_location.py:0 +#, python-format +msgid "" +"It is impossible to prohibit this location from receiving " +"products as it already contains some." +msgstr "" + +#. module: stock_location_lockdown +#: model:ir.model,name:stock_location_lockdown.model_stock_quant +msgid "Quants" +msgstr "" + +#. module: stock_location_lockdown +#. odoo-python +#: code:addons/stock_location_lockdown/models/stock_quant.py:0 +#, python-format +msgid "" +"The location %(location)s is blocked and can not be used for moving the " +"product %(product)s" +msgstr "" + +#. module: stock_location_lockdown +#: model:ir.model.fields,help:stock_location_lockdown.field_stock_location__block_stock_entrance +#, fuzzy +msgid "" +"if this box is checked, putting stock on this location won't be allowed. " +"Usually used for a virtual location that has childrens." +msgstr "" +"Si cette case est cochée, il ne sera pas possible d'ajouter du stock dans " +"cette emplacement. Habituellement utilisée pour les emplacements virtuels " +"ayant des enfants." + +#, fuzzy +#~ msgid "The location '%s' is not configured to receive stock." +#~ msgstr "L'emplacement %s n'est pas configuré pour recevoir du stock." + +#~ msgid "Location" +#~ msgstr "Emplacement" diff --git a/stock_location_lockdown/i18n/it.po b/stock_location_lockdown/i18n/it.po new file mode 100644 index 0000000..60e98cf --- /dev/null +++ b/stock_location_lockdown/i18n/it.po @@ -0,0 +1,63 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * stock_location_lockdown +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 16.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2025-11-24 12:14+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.10.4\n" + +#. module: stock_location_lockdown +#: model:ir.model.fields,field_description:stock_location_lockdown.field_stock_location__block_stock_entrance +msgid "Block Stock Entrance" +msgstr "Blocco entrata magazzino" + +#. module: stock_location_lockdown +#: model:ir.model,name:stock_location_lockdown.model_stock_location +msgid "Inventory Locations" +msgstr "Ubicazioni di inventario" + +#. module: stock_location_lockdown +#. odoo-python +#: code:addons/stock_location_lockdown/models/stock_location.py:0 +#, python-format +msgid "" +"It is impossible to prohibit this location from receiving " +"products as it already contains some." +msgstr "" +"Non è possibile bloccare la ricezione di prodotti in " +"questa ubicazione perché ha già giacenze." + +#. module: stock_location_lockdown +#: model:ir.model,name:stock_location_lockdown.model_stock_quant +msgid "Quants" +msgstr "Quanti" + +#. module: stock_location_lockdown +#. odoo-python +#: code:addons/stock_location_lockdown/models/stock_quant.py:0 +#, python-format +msgid "" +"The location %(location)s is blocked and can not be used for moving the " +"product %(product)s" +msgstr "" +"L'ubicazione %(location)s è bloccata e non può essere utilizzata per " +"movimentare il prodotto %(product)s" + +#. module: stock_location_lockdown +#: model:ir.model.fields,help:stock_location_lockdown.field_stock_location__block_stock_entrance +msgid "" +"if this box is checked, putting stock on this location won't be allowed. " +"Usually used for a virtual location that has childrens." +msgstr "" +"Se selezionato, non è possibile caricare merce in questa ubicazione. " +"Normalmente utilizzato per una ubicazione virtuale con elementi figli." diff --git a/stock_location_lockdown/i18n/ja.po b/stock_location_lockdown/i18n/ja.po new file mode 100644 index 0000000..18c7e08 --- /dev/null +++ b/stock_location_lockdown/i18n/ja.po @@ -0,0 +1,64 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * stock_location_lockdown +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 18.0+e\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2026-04-27 03:37+0000\n" +"PO-Revision-Date: 2026-04-27 03:37+0000\n" +"Last-Translator: \n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" + +#. module: stock_location_lockdown +#: model:ir.model.fields,field_description:stock_location_lockdown.field_stock_location__block_stock_entrance +msgid "Block Stock Entrance" +msgstr "在庫禁止" + +#. module: stock_location_lockdown +#: model:ir.model.fields,help:stock_location_lockdown.field_stock_location__block_stock_entrance +msgid "" +"If this box is checked, putting stock on this location won't be allowed. Use" +" this to temporarily block stock movements or to enforce restrictions in " +"both physical and virtual locations." +msgstr "" +"このボックスにチェックを入れると、このロケーションへの在庫が禁止されます。在庫移動を一時的にブロックしたり、物理ロケーションおよび仮想ロケーションの両方に制限を適用するために使用します。" + +#. module: stock_location_lockdown +#: model:ir.model,name:stock_location_lockdown.model_stock_location +msgid "Inventory Locations" +msgstr "在庫ロケーション" + +#. module: stock_location_lockdown +#. odoo-python +#: code:addons/stock_location_lockdown/models/stock_location.py:0 +msgid "" +"It is impossible to prohibit this location from receiving" +" products as it already contains some." +msgstr "" +"このロケーションにはすでに在庫があるため、プロダクトの在庫を禁止することはできません。" + +#. module: stock_location_lockdown +#: model:ir.model,name:stock_location_lockdown.model_stock_quant +msgid "Quants" +msgstr "保管ロット" + +#. module: stock_location_lockdown +#: model:ir.model.fields,field_description:stock_location_lockdown.field_stock_location__smart_search +#: model:ir.model.fields,field_description:stock_location_lockdown.field_stock_quant__smart_search +msgid "Smart Search" +msgstr "スマート検索" + +#. module: stock_location_lockdown +#. odoo-python +#: code:addons/stock_location_lockdown/models/stock_quant.py:0 +msgid "" +"The location %(location)s is blocked and can not be used for moving the " +"product %(product)s" +msgstr "" +"ロケーション %(location)s はブロックされており、プロダクト %(product)s の移動には使用できません。" \ No newline at end of file diff --git a/stock_location_lockdown/i18n/pt.po b/stock_location_lockdown/i18n/pt.po new file mode 100644 index 0000000..0b549c4 --- /dev/null +++ b/stock_location_lockdown/i18n/pt.po @@ -0,0 +1,64 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * stock_location_lockdown +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 10.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2018-12-28 01:41+0000\n" +"Last-Translator: Pedro Castro Silva \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" +"X-Generator: Weblate 3.3\n" + +#. module: stock_location_lockdown +#: model:ir.model.fields,field_description:stock_location_lockdown.field_stock_location__block_stock_entrance +#, fuzzy +msgid "Block Stock Entrance" +msgstr "Bloquear entradas de stock" + +#. module: stock_location_lockdown +#: model:ir.model,name:stock_location_lockdown.model_stock_location +msgid "Inventory Locations" +msgstr "Localizações de Inventário" + +#. module: stock_location_lockdown +#. odoo-python +#: code:addons/stock_location_lockdown/models/stock_location.py:0 +#, python-format +msgid "" +"It is impossible to prohibit this location from receiving " +"products as it already contains some." +msgstr "" + +#. module: stock_location_lockdown +#: model:ir.model,name:stock_location_lockdown.model_stock_quant +msgid "Quants" +msgstr "" + +#. module: stock_location_lockdown +#. odoo-python +#: code:addons/stock_location_lockdown/models/stock_quant.py:0 +#, python-format +msgid "" +"The location %(location)s is blocked and can not be used for moving the " +"product %(product)s" +msgstr "" + +#. module: stock_location_lockdown +#: model:ir.model.fields,help:stock_location_lockdown.field_stock_location__block_stock_entrance +msgid "" +"if this box is checked, putting stock on this location won't be allowed. " +"Usually used for a virtual location that has childrens." +msgstr "" +"Se esta caixa estiver selecionada, não será permitido colocar stock nesta " +"localização. É geralmente utilizada em localizações virtuais com " +"descendentes." + +#~ msgid "The location '%s' is not configured to receive stock." +#~ msgstr "A localização '%s' não está configurada para receber stock." diff --git a/stock_location_lockdown/i18n/stock_location_lockdown.pot b/stock_location_lockdown/i18n/stock_location_lockdown.pot new file mode 100644 index 0000000..ed41edc --- /dev/null +++ b/stock_location_lockdown/i18n/stock_location_lockdown.pot @@ -0,0 +1,53 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * stock_location_lockdown +# +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_location_lockdown +#: model:ir.model.fields,field_description:stock_location_lockdown.field_stock_location__block_stock_entrance +msgid "Block Stock Entrance" +msgstr "" + +#. module: stock_location_lockdown +#: model:ir.model.fields,help:stock_location_lockdown.field_stock_location__block_stock_entrance +msgid "" +"If this box is checked, putting stock on this location won't be allowed. Use" +" this to temporarily block stock movements or to enforce restrictions in " +"both physical and virtual locations." +msgstr "" + +#. module: stock_location_lockdown +#: model:ir.model,name:stock_location_lockdown.model_stock_location +msgid "Inventory Locations" +msgstr "" + +#. module: stock_location_lockdown +#. odoo-python +#: code:addons/stock_location_lockdown/models/stock_location.py:0 +msgid "" +"It is impossible to prohibit this location from receiving" +" products as it already contains some." +msgstr "" + +#. module: stock_location_lockdown +#: model:ir.model,name:stock_location_lockdown.model_stock_quant +msgid "Quants" +msgstr "" + +#. module: stock_location_lockdown +#. odoo-python +#: code:addons/stock_location_lockdown/models/stock_quant.py:0 +msgid "" +"The location %(location)s is blocked and can not be used for moving the " +"product %(product)s" +msgstr "" diff --git a/stock_location_lockdown/i18n/zh_CN.po b/stock_location_lockdown/i18n/zh_CN.po new file mode 100644 index 0000000..8de7ef6 --- /dev/null +++ b/stock_location_lockdown/i18n/zh_CN.po @@ -0,0 +1,62 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * stock_location_lockdown +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 12.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2019-10-16 16:05+0000\n" +"Last-Translator: 黎伟杰 <674416404@qq.com>\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.8\n" + +#. module: stock_location_lockdown +#: model:ir.model.fields,field_description:stock_location_lockdown.field_stock_location__block_stock_entrance +msgid "Block Stock Entrance" +msgstr "阻止入库" + +#. module: stock_location_lockdown +#: model:ir.model,name:stock_location_lockdown.model_stock_location +msgid "Inventory Locations" +msgstr "库存位置" + +#. module: stock_location_lockdown +#. odoo-python +#: code:addons/stock_location_lockdown/models/stock_location.py:0 +#, python-format +msgid "" +"It is impossible to prohibit this location from receiving " +"products as it already contains some." +msgstr "因为已经包含一些产品,所以无法禁止此位置接收产品。" + +#. module: stock_location_lockdown +#: model:ir.model,name:stock_location_lockdown.model_stock_quant +msgid "Quants" +msgstr "数量分析" + +#. module: stock_location_lockdown +#. odoo-python +#: code:addons/stock_location_lockdown/models/stock_quant.py:0 +#, python-format +msgid "" +"The location %(location)s is blocked and can not be used for moving the " +"product %(product)s" +msgstr "" + +#. module: stock_location_lockdown +#: model:ir.model.fields,help:stock_location_lockdown.field_stock_location__block_stock_entrance +msgid "" +"if this box is checked, putting stock on this location won't be allowed. " +"Usually used for a virtual location that has childrens." +msgstr "如果选中此框,则不允许在此位置放货。通常用于有子位置的虚拟位置。" + +#, python-format +#~ msgid "" +#~ "The location %s is blocked and can not be used for moving the product %s" +#~ msgstr "位置%s被阻止,无法用于移动产品%s" diff --git a/stock_location_lockdown/models/__init__.py b/stock_location_lockdown/models/__init__.py new file mode 100644 index 0000000..d081518 --- /dev/null +++ b/stock_location_lockdown/models/__init__.py @@ -0,0 +1,5 @@ +# Copyright 2019 Akretion +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from . import stock_location +from . import stock_quant diff --git a/stock_location_lockdown/models/stock_location.py b/stock_location_lockdown/models/stock_location.py new file mode 100644 index 0000000..8e49663 --- /dev/null +++ b/stock_location_lockdown/models/stock_location.py @@ -0,0 +1,33 @@ +# Copyright 2019 Akretion +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import fields, models +from odoo.exceptions import UserError + + +class StockLocation(models.Model): + _inherit = "stock.location" + + block_stock_entrance = fields.Boolean( + help="If this box is checked, putting stock on this location won't be " + "allowed. Use this to temporarily block stock movements or to enforce " + "restrictions in both physical and virtual locations." + ) + + # Raise error if the location that you're trying to block + # has already got quants + def write(self, values): + res = super().write(values) + + if "block_stock_entrance" in values and values["block_stock_entrance"]: + # Unlink zero quants before checking + # if there are quants on the location + self.env["stock.quant"]._unlink_zero_quants() + if self.mapped("quant_ids"): + raise UserError( + self.env._( + "It is impossible to prohibit this location from\ + receiving products as it already contains some." + ) + ) + return res diff --git a/stock_location_lockdown/models/stock_quant.py b/stock_location_lockdown/models/stock_quant.py new file mode 100644 index 0000000..2d89040 --- /dev/null +++ b/stock_location_lockdown/models/stock_quant.py @@ -0,0 +1,26 @@ +# Copyright 2019 Akretion +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import api, models +from odoo.exceptions import ValidationError + + +class StockQuant(models.Model): + _inherit = "stock.quant" + + # Raise an error when trying to change a quant + # which corresponding stock location is blocked + @api.constrains("location_id") + def check_location_blocked(self): + for record in self: + if record.location_id.block_stock_entrance: + raise ValidationError( + self.env._( + "The location %(location)s is blocked and can " + "not be used for moving the product %(product)s" + ) + % { + "location": record.location_id.display_name, + "product": record.product_id.display_name, + } + ) diff --git a/stock_location_lockdown/pyproject.toml b/stock_location_lockdown/pyproject.toml new file mode 100644 index 0000000..4231d0c --- /dev/null +++ b/stock_location_lockdown/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["whool"] +build-backend = "whool.buildapi" diff --git a/stock_location_lockdown/readme/CONTRIBUTORS.md b/stock_location_lockdown/readme/CONTRIBUTORS.md new file mode 100644 index 0000000..32e2ef5 --- /dev/null +++ b/stock_location_lockdown/readme/CONTRIBUTORS.md @@ -0,0 +1,3 @@ +- Florian da Costa \<\> +- David Montull Guasch \<\> +- Urvisha Desai \<\> diff --git a/stock_location_lockdown/readme/DESCRIPTION.md b/stock_location_lockdown/readme/DESCRIPTION.md new file mode 100644 index 0000000..faf9278 --- /dev/null +++ b/stock_location_lockdown/readme/DESCRIPTION.md @@ -0,0 +1,17 @@ +The aim of this module is to provide a way to mark internal locations where product storage is disallowed. +This feature is versatile and can be used in various scenarios, such as: + +- Temporarily blocking stock movement to specific locations. +- Preventing stock from being stored in locations not meant for physical storage. + +Indeed, in complex warehouse setups, we may have a +complicated tree of internal locations with parent locations only used +to create the hierarchy of the internal locations. We may want to avoid +to put stock on these parent internal locations since they are not +physical locations, they just represent a zone of the warehouse. Theses +locations must have *Location Type* set to *Internal Location* because +they belong to a warehouse (they can't be configured with *Location +Type* set to *View*, cf [Odoo bug +\#26679](https://github.com/odoo/odoo/issues/26679)). With this module, +you will be able to enable a new option *Block stock entrance* for these +locations. diff --git a/stock_location_lockdown/readme/USAGE.md b/stock_location_lockdown/readme/USAGE.md new file mode 100644 index 0000000..96634d8 --- /dev/null +++ b/stock_location_lockdown/readme/USAGE.md @@ -0,0 +1,3 @@ +- Once the module is installed, select any internal location for which + you want to prevent stock entrance and check the box *Block Stock + Entrance*. Then, you won't be allow to add stock on these locations. diff --git a/stock_location_lockdown/static/description/icon.png b/stock_location_lockdown/static/description/icon.png new file mode 100644 index 0000000..3a0328b Binary files /dev/null and b/stock_location_lockdown/static/description/icon.png differ diff --git a/stock_location_lockdown/static/description/index.html b/stock_location_lockdown/static/description/index.html new file mode 100644 index 0000000..05475d1 --- /dev/null +++ b/stock_location_lockdown/static/description/index.html @@ -0,0 +1,452 @@ + + + + + +Stock Location Lockdown + + + +
+

Stock Location Lockdown

+ + +

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

+

The aim of this module is to provide a way to mark internal locations +where product storage is disallowed. This feature is versatile and can +be used in various scenarios, such as:

+
    +
  • Temporarily blocking stock movement to specific locations.
  • +
  • Preventing stock from being stored in locations not meant for physical +storage.
  • +
+

Indeed, in complex warehouse setups, we may have a complicated tree of +internal locations with parent locations only used to create the +hierarchy of the internal locations. We may want to avoid to put stock +on these parent internal locations since they are not physical +locations, they just represent a zone of the warehouse. Theses locations +must have Location Type set to Internal Location because they belong +to a warehouse (they can’t be configured with Location Type set to +View, cf Odoo bug +#26679). With this +module, you will be able to enable a new option Block stock entrance +for these locations.

+

Table of contents

+ +
+

Usage

+
    +
  • Once the module is installed, select any internal location for which +you want to prevent stock entrance and check the box Block Stock +Entrance. Then, you won’t be allow to add stock on these locations.
  • +
+
+
+

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

+
    +
  • Akretion
  • +
+
+
+

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/stock-logistics-warehouse project on GitHub.

+

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

+
+
+
+ + diff --git a/stock_location_lockdown/tests/__init__.py b/stock_location_lockdown/tests/__init__.py new file mode 100644 index 0000000..2f0a9ad --- /dev/null +++ b/stock_location_lockdown/tests/__init__.py @@ -0,0 +1,4 @@ +# Copyright 2019 Akretion +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from . import test_block_stock_location_entrance diff --git a/stock_location_lockdown/tests/test_block_stock_location_entrance.py b/stock_location_lockdown/tests/test_block_stock_location_entrance.py new file mode 100644 index 0000000..4310359 --- /dev/null +++ b/stock_location_lockdown/tests/test_block_stock_location_entrance.py @@ -0,0 +1,98 @@ +# Copyright 2019 Akretion France +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo.exceptions import UserError, ValidationError +from odoo.tests.common import TransactionCase + + +class TestStockLocationLockdown(TransactionCase): + @classmethod + def setUpClass(cls): + super().setUpClass() + + # Create a new stock location with no quants and blocked stock entrance + new_loc = {"name": "location_test", "usage": "internal"} + cls.new_stock_location = cls.env["stock.location"].create(new_loc) + cls.new_stock_location.block_stock_entrance = True + + cls.supplier_location = cls.env.ref("stock.stock_location_suppliers") + cls.customer_location = cls.env.ref("stock.stock_location_customers") + + # Call an existing product and force no Lot/Serial Number tracking + cls.product = cls.env.ref("product.product_product_27") + cls.product.tracking = "none" + + # Catch the first quant's stock location + cls.stock_location = cls.env["stock.quant"].search([])[0].location_id + + def test_transfer_stock_in_locked_location(self): + """ + Test to move stock within a location that should not accept + stock entrance. + """ + move_vals = { + "location_id": self.supplier_location.id, + "location_dest_id": self.new_stock_location.id, + "product_id": self.product.id, + "product_uom_qty": self.product.qty_available + 1, + "quantity": self.product.qty_available + 1, + "picked": True, + "product_uom": self.product.uom_id.id, + "name": "test", + "move_line_ids": [ + ( + 0, + 0, + { + "product_id": self.product.id, + "product_uom_id": self.product.uom_id.id, + "quantity": self.product.qty_available + 1, + "location_id": self.supplier_location.id, + "location_dest_id": self.new_stock_location.id, + }, + ) + ], + } + stock_move = self.env["stock.move"].create(move_vals) + + with self.assertRaises(ValidationError): + stock_move._action_done() + + def test_transfer_stock_out_locked_location(self): + """ + Test to move stock out from a location that should not accept + stock removal. + """ + move_vals = { + "location_id": self.new_stock_location.id, + "location_dest_id": self.customer_location.id, + "product_id": self.product.id, + "product_uom_qty": self.product.qty_available + 1, + "quantity": self.product.qty_available + 1, + "picked": True, + "product_uom": self.product.uom_id.id, + "name": "test", + "move_line_ids": [ + ( + 0, + 0, + { + "product_id": self.product.id, + "product_uom_id": self.product.uom_id.id, + "quantity": self.product.qty_available + 1, + "location_id": self.new_stock_location.id, + "location_dest_id": self.customer_location.id, + }, + ) + ], + } + with self.assertRaises(ValidationError): + self.env["stock.move"].create(move_vals) + + def test_block_location_with_quants(self): + """ + Test to click on block_stock_entrance checkbox in a location + that should not be blocked because it has already got quants + """ + with self.assertRaises(UserError): + self.stock_location.write({"block_stock_entrance": True}) diff --git a/stock_location_lockdown/views/stock_location.xml b/stock_location_lockdown/views/stock_location.xml new file mode 100644 index 0000000..c685ac1 --- /dev/null +++ b/stock_location_lockdown/views/stock_location.xml @@ -0,0 +1,14 @@ + + + + + stock.location + + + + + + + +