diff --git a/stock_no_negative/README.rst b/stock_no_negative/README.rst new file mode 100644 index 00000000000..7f94547779d --- /dev/null +++ b/stock_no_negative/README.rst @@ -0,0 +1,134 @@ +======================= +Stock Disallow Negative +======================= + +.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |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--workflow-lightgray.png?logo=github + :target: https://github.com/OCA/stock-logistics-workflow/tree/12.0/stock_no_negative + :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-12-0/stock-logistics-workflow-12-0-stock_no_negative + :alt: Translate me on Weblate +.. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png + :target: https://runbot.odoo-community.org/runbot/154/12.0 + :alt: Try me on Runbot + +|badge1| |badge2| |badge3| |badge4| |badge5| + +By default, Odoo allows negative stock. The advantage of negative stock +is that, if some stock levels are wrong in the ERP, you will not be blocked +when validating the picking for a customer... so you will still be able to +ship the products on time (it's an example !). The problem is that, after you +forced the stock level to negative, you are supposed to fix the stock level +later via an inventory ; but this action is often forgotten by users, +so you end up with negative stock levels in your ERP and it can stay like +this forever (or at least until the next full inventory). + +If you disallow negative stock in Odoo with this module, you will be blocked +when trying to validate a stock operation that will set the stock level of +a product and/or location as negative. So you will have to fix the +wrong stock level of that product without delay, in order to validate the +stock operation in Odoo...you can't forget it anymore ! + + +**Table of contents** + +.. contents:: + :local: + +Configuration +============= + +By default, the stockable products will not be allowed to have a negative +stock. If you want to make some exceptions for some products, product +categories or locations, you can activate the option *Allow Negative Stock*: + +For products: + +#. Go to *Inventory / Master Data / Products* and in the + tab *General Information* activate this option. + +For product categories: + +#. Go to *Inventory / Configuration / Products / Product Categories* + and activate this option. + +For individual locations: + +#. Go to *Inventory / Configuration / Settings* and activate + the option *Storage Locations*. +#. Go to *Inventory / Configuration / Warehouse Management / Locations* and + activate the option the option *Allow Negative Stock* for the locations you + choose. + + +Usage +===== + +When you validate a stock operation (a stock move, a picking, +a manufacturing order, etc.) that will set the stock level of a +stockable product as negative, you will be blocked by an error message. +The consumable products can still have a negative stock level. + +Changelog +========= + +11.0.1.1.0 (2018-12-13) +~~~~~~~~~~~~~~~~~~~~~~~ + +* Add the ability to allow negative stock for individual stock 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 smashing it by providing a detailed and welcomed +`feedback `_. + +Do not contact contributors directly about support or help with technical issues. + +Credits +======= + +Authors +~~~~~~~ + +* Akretion + +Contributors +~~~~~~~~~~~~ + +* Alexis de Lattre +* Eficent Business and IT Consulting Services S.L. + * Jordi Ballester +* Serpent Consulting Services Pvt. Ltd. +* Tecnativa + * Pedro M. Baeza + +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-workflow `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/stock_no_negative/__init__.py b/stock_no_negative/__init__.py new file mode 100644 index 00000000000..31c46882374 --- /dev/null +++ b/stock_no_negative/__init__.py @@ -0,0 +1,5 @@ +# ?? 2015-2016 Akretion (http://www.akretion.com) +# @author Alexis de Lattre +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from . import models diff --git a/stock_no_negative/__manifest__.py b/stock_no_negative/__manifest__.py new file mode 100644 index 00000000000..517157cd614 --- /dev/null +++ b/stock_no_negative/__manifest__.py @@ -0,0 +1,20 @@ +# ?? 2015-2016 Akretion (http://www.akretion.com) +# @author Alexis de Lattre +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + + +{ + 'name': 'Stock Disallow Negative', + 'version': '12.0.1.0.0', + 'category': 'Inventory, Logistic, Storage', + 'license': 'AGPL-3', + 'summary': 'Disallow negative stock levels by default', + 'author': 'Akretion,Odoo Community Association (OCA)', + 'website': 'https://github.com/OCA/stock-logistics-workflow', + 'depends': ['stock'], + 'data': [ + 'views/product_product_views.xml', + 'views/stock_location_views.xml', + ], + 'installable': True, +} diff --git a/stock_no_negative/i18n/ar.po b/stock_no_negative/i18n/ar.po new file mode 100644 index 00000000000..b4c323f87ea --- /dev/null +++ b/stock_no_negative/i18n/ar.po @@ -0,0 +1,73 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * stock_no_negative +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 12.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2019-02-26 09:53+0000\n" +"PO-Revision-Date: 2019-02-26 09:53+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_no_negative +#: code:addons/stock_no_negative/models/stock_quant.py:39 +#, python-format +msgid " lot '%s'" +msgstr " lote '%s'" + +#. module: stock_no_negative +#: model:ir.model.fields,field_description:stock_no_negative.field_product_category__allow_negative_stock +#: model:ir.model.fields,field_description:stock_no_negative.field_product_product__allow_negative_stock +#: model:ir.model.fields,field_description:stock_no_negative.field_product_template__allow_negative_stock +#: model:ir.model.fields,field_description:stock_no_negative.field_stock_location__allow_negative_stock +msgid "Allow Negative Stock" +msgstr "Permitir Stock Negativo" + +#. module: stock_no_negative +#: model:ir.model.fields,help:stock_no_negative.field_product_category__allow_negative_stock +msgid "Allow negative stock levels for the stockable products attached to this category. The options doesn't apply to products attached to sub-categories of this category." +msgstr "Permitir niveles de stock negativos para los productos en stock adjuntos a esta categoría. Las opciones no se aplican a los productos adjuntos a subcategorías de esta categoría." + +#. module: stock_no_negative +#: model:ir.model.fields,help:stock_no_negative.field_stock_location__allow_negative_stock +msgid "Allow negative stock levels for the stockable products attached to this location." +msgstr "Permitir niveles de stock negativos para los productos en stock ubicados en esta ubicación." + +#. module: stock_no_negative +#: model:ir.model.fields,help:stock_no_negative.field_product_product__allow_negative_stock +#: model:ir.model.fields,help:stock_no_negative.field_product_template__allow_negative_stock +msgid "If this option is not active on this product nor on its product category and that this product is a stockable product, then the validation of the related stock moves will be blocked if the stock level becomes negative with the stock move." +msgstr "Si esta opción no está activa en este producto ni en su categoría de producto y este producto es un producto almacenable, entonces la validación de los movimientos de stock relacionados se bloqueará si el nivel de stock se vuelve negativo con el movimiento de stock." + +#. module: stock_no_negative +#: model:ir.model,name:stock_no_negative.model_stock_location +msgid "Inventory Locations" +msgstr "Ubicaciones de inventario" + +#. module: stock_no_negative +#: model:ir.model,name:stock_no_negative.model_product_category +msgid "Product Category" +msgstr "Categoría de producto" + +#. module: stock_no_negative +#: model:ir.model,name:stock_no_negative.model_product_template +msgid "Product Template" +msgstr "Plantilla de producto" + +#. module: stock_no_negative +#: model:ir.model,name:stock_no_negative.model_stock_quant +msgid "Quants" +msgstr "Quants" + +#. module: stock_no_negative +#: code:addons/stock_no_negative/models/stock_quant.py:40 +#, python-format +msgid "You cannot validate this stock operation because the stock level of the product '%s'%s would become negative (%s) on the stock location '%s' and negative stock is not allowed for this product and/or location." +msgstr "No se puede validar esta operación de stock porque el nivel de stock del producto '%s'%s se volvería negativo (%s) en la ubicación de stock '%s' y no se permite stock negativo para este producto y/o ubicación." + diff --git a/stock_no_negative/i18n/es.po b/stock_no_negative/i18n/es.po new file mode 100644 index 00000000000..b4c323f87ea --- /dev/null +++ b/stock_no_negative/i18n/es.po @@ -0,0 +1,73 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * stock_no_negative +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 12.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2019-02-26 09:53+0000\n" +"PO-Revision-Date: 2019-02-26 09:53+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_no_negative +#: code:addons/stock_no_negative/models/stock_quant.py:39 +#, python-format +msgid " lot '%s'" +msgstr " lote '%s'" + +#. module: stock_no_negative +#: model:ir.model.fields,field_description:stock_no_negative.field_product_category__allow_negative_stock +#: model:ir.model.fields,field_description:stock_no_negative.field_product_product__allow_negative_stock +#: model:ir.model.fields,field_description:stock_no_negative.field_product_template__allow_negative_stock +#: model:ir.model.fields,field_description:stock_no_negative.field_stock_location__allow_negative_stock +msgid "Allow Negative Stock" +msgstr "Permitir Stock Negativo" + +#. module: stock_no_negative +#: model:ir.model.fields,help:stock_no_negative.field_product_category__allow_negative_stock +msgid "Allow negative stock levels for the stockable products attached to this category. The options doesn't apply to products attached to sub-categories of this category." +msgstr "Permitir niveles de stock negativos para los productos en stock adjuntos a esta categoría. Las opciones no se aplican a los productos adjuntos a subcategorías de esta categoría." + +#. module: stock_no_negative +#: model:ir.model.fields,help:stock_no_negative.field_stock_location__allow_negative_stock +msgid "Allow negative stock levels for the stockable products attached to this location." +msgstr "Permitir niveles de stock negativos para los productos en stock ubicados en esta ubicación." + +#. module: stock_no_negative +#: model:ir.model.fields,help:stock_no_negative.field_product_product__allow_negative_stock +#: model:ir.model.fields,help:stock_no_negative.field_product_template__allow_negative_stock +msgid "If this option is not active on this product nor on its product category and that this product is a stockable product, then the validation of the related stock moves will be blocked if the stock level becomes negative with the stock move." +msgstr "Si esta opción no está activa en este producto ni en su categoría de producto y este producto es un producto almacenable, entonces la validación de los movimientos de stock relacionados se bloqueará si el nivel de stock se vuelve negativo con el movimiento de stock." + +#. module: stock_no_negative +#: model:ir.model,name:stock_no_negative.model_stock_location +msgid "Inventory Locations" +msgstr "Ubicaciones de inventario" + +#. module: stock_no_negative +#: model:ir.model,name:stock_no_negative.model_product_category +msgid "Product Category" +msgstr "Categoría de producto" + +#. module: stock_no_negative +#: model:ir.model,name:stock_no_negative.model_product_template +msgid "Product Template" +msgstr "Plantilla de producto" + +#. module: stock_no_negative +#: model:ir.model,name:stock_no_negative.model_stock_quant +msgid "Quants" +msgstr "Quants" + +#. module: stock_no_negative +#: code:addons/stock_no_negative/models/stock_quant.py:40 +#, python-format +msgid "You cannot validate this stock operation because the stock level of the product '%s'%s would become negative (%s) on the stock location '%s' and negative stock is not allowed for this product and/or location." +msgstr "No se puede validar esta operación de stock porque el nivel de stock del producto '%s'%s se volvería negativo (%s) en la ubicación de stock '%s' y no se permite stock negativo para este producto y/o ubicación." + diff --git a/stock_no_negative/i18n/fr.po b/stock_no_negative/i18n/fr.po new file mode 100644 index 00000000000..abbcdda4fd1 --- /dev/null +++ b/stock_no_negative/i18n/fr.po @@ -0,0 +1,102 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * stock_no_negative +# +# Translators: +# OCA Transbot , 2017 +# guillaume bauer , 2017 +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 11.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2018-02-28 08:51+0000\n" +"PO-Revision-Date: 2018-02-28 08:51+0000\n" +"Last-Translator: guillaume bauer , 2017\n" +"Language-Team: French (https://www.transifex.com/oca/teams/23907/fr/)\n" +"Language: fr\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_no_negative +#: code:addons/stock_no_negative/models/stock_quant.py:39 +#, python-format +msgid " lot '%s'" +msgstr "lot%s" + +#. module: stock_no_negative +#: model:ir.model.fields,field_description:stock_no_negative.field_product_category_allow_negative_stock +#: model:ir.model.fields,field_description:stock_no_negative.field_product_product_allow_negative_stock +#: model:ir.model.fields,field_description:stock_no_negative.field_product_template_allow_negative_stock +#: model:ir.model.fields,field_description:stock_no_negative.field_stock_location_allow_negative_stock +msgid "Allow Negative Stock" +msgstr "Autoriser le stock n??gatif" + +#. module: stock_no_negative +#: model:ir.model.fields,help:stock_no_negative.field_product_category_allow_negative_stock +msgid "" +"Allow negative stock levels for the stockable products attached to this " +"category. The options doesn't apply to products attached to sub-categories " +"of this category." +msgstr "" +"Autorise les niveaux de stock n??gatif pour les articles stockables attach??s " +"?? cette cat??gorie. Cette option ne s'applique pas aux articles attach??s ?? " +"des sous-cat??gories de cette cat??gorie." + +#. module: stock_no_negative +#: model:ir.model.fields,help:stock_no_negative.field_stock_location_allow_negative_stock +#, fuzzy +msgid "" +"Allow negative stock levels for the stockable products attached to this " +"location." +msgstr "" +"Autorise les niveaux de stock n??gatif pour les articles stockables attach??s " +"?? cette cat??gorie. Cette option ne s'applique pas aux articles attach??s ?? " +"des sous-cat??gories de cette cat??gorie." + +#. module: stock_no_negative +#: model:ir.model.fields,help:stock_no_negative.field_product_product_allow_negative_stock +#: model:ir.model.fields,help:stock_no_negative.field_product_template_allow_negative_stock +msgid "" +"If this option is not active on this product nor on its product category and " +"that this product is a stockable product, then the validation of the related " +"stock moves will be blocked if the stock level becomes negative with the " +"stock move." +msgstr "" +"Si cette option n'est pas activ??e sur cet article ni sur la cat??gorie ?? " +"laquelle il est rattach?? et que cet article est un produit stockable, alors " +"la validation des mouvements de stock sera bloqu??e si le niveau de stock " +"devient n??gatif avec ce mouvement de stock." + +#. module: stock_no_negative +#: model:ir.model,name:stock_no_negative.model_stock_location +msgid "Inventory Locations" +msgstr "" + +#. module: stock_no_negative +#: model:ir.model,name:stock_no_negative.model_product_category +msgid "Product Category" +msgstr "Cat??gorie d'articles" + +#. module: stock_no_negative +#: model:ir.model,name:stock_no_negative.model_product_template +msgid "Product Template" +msgstr "Mod??le d'article" + +#. module: stock_no_negative +#: model:ir.model,name:stock_no_negative.model_stock_quant +msgid "Quants" +msgstr "Quants" + +#. module: stock_no_negative +#: code:addons/stock_no_negative/models/stock_quant.py:40 +#, fuzzy, python-format +msgid "" +"You cannot validate this stock operation because the stock level of the " +"product '%s'%s would become negative (%s) on the stock location '%s' and " +"negative stock is not allowed for this product and/or location." +msgstr "" +"Impossible de valider cette op??ration car le niveau de stock de ce produit " +"%s'%s deviendrait n??gative(%s) dans l'emplacement du stock '%s'. Un stock " +"n??gatif n'est pas permis pour ce produit." diff --git a/stock_no_negative/i18n/stock_no_negative.pot b/stock_no_negative/i18n/stock_no_negative.pot new file mode 100644 index 00000000000..610742fb476 --- /dev/null +++ b/stock_no_negative/i18n/stock_no_negative.pot @@ -0,0 +1,72 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * stock_no_negative +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 12.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2019-02-26 09:52+0000\n" +"PO-Revision-Date: 2019-02-26 09:52+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_no_negative +#: code:addons/stock_no_negative/models/stock_quant.py:39 +#, python-format +msgid " lot '%s'" +msgstr "" + +#. module: stock_no_negative +#: model:ir.model.fields,field_description:stock_no_negative.field_product_category__allow_negative_stock +#: model:ir.model.fields,field_description:stock_no_negative.field_product_product__allow_negative_stock +#: model:ir.model.fields,field_description:stock_no_negative.field_product_template__allow_negative_stock +#: model:ir.model.fields,field_description:stock_no_negative.field_stock_location__allow_negative_stock +msgid "Allow Negative Stock" +msgstr "" + +#. module: stock_no_negative +#: model:ir.model.fields,help:stock_no_negative.field_product_category__allow_negative_stock +msgid "Allow negative stock levels for the stockable products attached to this category. The options doesn't apply to products attached to sub-categories of this category." +msgstr "" + +#. module: stock_no_negative +#: model:ir.model.fields,help:stock_no_negative.field_stock_location__allow_negative_stock +msgid "Allow negative stock levels for the stockable products attached to this location." +msgstr "" + +#. module: stock_no_negative +#: model:ir.model.fields,help:stock_no_negative.field_product_product__allow_negative_stock +#: model:ir.model.fields,help:stock_no_negative.field_product_template__allow_negative_stock +msgid "If this option is not active on this product nor on its product category and that this product is a stockable product, then the validation of the related stock moves will be blocked if the stock level becomes negative with the stock move." +msgstr "" + +#. module: stock_no_negative +#: model:ir.model,name:stock_no_negative.model_stock_location +msgid "Inventory Locations" +msgstr "" + +#. module: stock_no_negative +#: model:ir.model,name:stock_no_negative.model_product_category +msgid "Product Category" +msgstr "" + +#. module: stock_no_negative +#: model:ir.model,name:stock_no_negative.model_product_template +msgid "Product Template" +msgstr "" + +#. module: stock_no_negative +#: model:ir.model,name:stock_no_negative.model_stock_quant +msgid "Quants" +msgstr "" + +#. module: stock_no_negative +#: code:addons/stock_no_negative/models/stock_quant.py:40 +#, python-format +msgid "You cannot validate this stock operation because the stock level of the product '%s'%s would become negative (%s) on the stock location '%s' and negative stock is not allowed for this product and/or location." +msgstr "" \ No newline at end of file diff --git a/stock_no_negative/models/__init__.py b/stock_no_negative/models/__init__.py new file mode 100644 index 00000000000..8d84cb14878 --- /dev/null +++ b/stock_no_negative/models/__init__.py @@ -0,0 +1,7 @@ +# ?? 2015-2016 Akretion (http://www.akretion.com) +# @author Alexis de Lattre +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from . import product +from . import stock_quant +from . import stock_location diff --git a/stock_no_negative/models/product.py b/stock_no_negative/models/product.py new file mode 100644 index 00000000000..41ba5bfdb83 --- /dev/null +++ b/stock_no_negative/models/product.py @@ -0,0 +1,26 @@ +# ?? 2015-2016 Akretion (http://www.akretion.com) +# @author Alexis de Lattre +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import models, fields + + +class ProductCategory(models.Model): + _inherit = 'product.category' + + allow_negative_stock = fields.Boolean( + string='Allow Negative Stock', + help="Allow negative stock levels for the stockable products " + "attached to this category. The options doesn't apply to products " + "attached to sub-categories of this category.") + + +class ProductTemplate(models.Model): + _inherit = "product.template" + + allow_negative_stock = fields.Boolean( + string='Allow Negative Stock', + help="If this option is not active on this product nor on its " + "product category and that this product is a stockable product, " + "then the validation of the related stock moves will be blocked if " + "the stock level becomes negative with the stock move.") diff --git a/stock_no_negative/models/stock_location.py b/stock_no_negative/models/stock_location.py new file mode 100644 index 00000000000..c304d066e9c --- /dev/null +++ b/stock_no_negative/models/stock_location.py @@ -0,0 +1,14 @@ +# ?? 2018 Eficent (https://www.eficent.com) +# @author Jordi Ballester +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import models, fields + + +class StockLocation(models.Model): + _inherit = 'stock.location' + + allow_negative_stock = fields.Boolean( + string='Allow Negative Stock', + help="Allow negative stock levels for the stockable products " + "attached to this location.") diff --git a/stock_no_negative/models/stock_quant.py b/stock_no_negative/models/stock_quant.py new file mode 100644 index 00000000000..6ef4a201fe0 --- /dev/null +++ b/stock_no_negative/models/stock_quant.py @@ -0,0 +1,46 @@ +# ?? 2015-2017 Akretion (http://www.akretion.com) +# @author Alexis de Lattre +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import models, api, _ +from odoo.exceptions import ValidationError +from odoo.tools import config, float_compare + + +class StockQuant(models.Model): + _inherit = 'stock.quant' + + @api.multi + @api.constrains('product_id', 'quantity') + def check_negative_qty(self): + p = self.env['decimal.precision'].precision_get( + 'Product Unit of Measure') + check_negative_qty = ( + (config['test_enable'] and + self.env.context.get('test_stock_no_negative')) or + not config['test_enable'] + ) + if not check_negative_qty: + return + + for quant in self: + disallowed_by_product = \ + not quant.product_id.allow_negative_stock \ + and not quant.product_id.categ_id.allow_negative_stock + disallowed_by_location = not quant.location_id.allow_negative_stock + if ( + float_compare(quant.quantity, 0, precision_digits=p) == -1 and + quant.product_id.type == 'product' and + quant.location_id.usage in ['internal', 'transit'] and + disallowed_by_product and disallowed_by_location + ): + msg_add = '' + if quant.lot_id: + msg_add = _(" lot '%s'") % quant.lot_id.name_get()[0][1] + raise ValidationError(_( + "You cannot validate this stock operation because the " + "stock level of the product '%s'%s would become negative " + "(%s) on the stock location '%s' and negative stock is " + "not allowed for this product and/or location.") % ( + quant.product_id.name, msg_add, quant.quantity, + quant.location_id.complete_name)) diff --git a/stock_no_negative/readme/CONFIGURE.rst b/stock_no_negative/readme/CONFIGURE.rst new file mode 100644 index 00000000000..af12e7673fd --- /dev/null +++ b/stock_no_negative/readme/CONFIGURE.rst @@ -0,0 +1,22 @@ +By default, the stockable products will not be allowed to have a negative +stock. If you want to make some exceptions for some products, product +categories or locations, you can activate the option *Allow Negative Stock*: + +For products: + +#. Go to *Inventory / Master Data / Products* and in the + tab *General Information* activate this option. + +For product categories: + +#. Go to *Inventory / Configuration / Products / Product Categories* + and activate this option. + +For individual locations: + +#. Go to *Inventory / Configuration / Settings* and activate + the option *Storage Locations*. +#. Go to *Inventory / Configuration / Warehouse Management / Locations* and + activate the option the option *Allow Negative Stock* for the locations you + choose. + diff --git a/stock_no_negative/readme/CONTRIBUTORS.rst b/stock_no_negative/readme/CONTRIBUTORS.rst new file mode 100644 index 00000000000..553d62f979a --- /dev/null +++ b/stock_no_negative/readme/CONTRIBUTORS.rst @@ -0,0 +1,6 @@ +* Alexis de Lattre +* Eficent Business and IT Consulting Services S.L. + * Jordi Ballester +* Serpent Consulting Services Pvt. Ltd. +* Tecnativa + * Pedro M. Baeza diff --git a/stock_no_negative/readme/DESCRIPTION.rst b/stock_no_negative/readme/DESCRIPTION.rst new file mode 100644 index 00000000000..a2772af003d --- /dev/null +++ b/stock_no_negative/readme/DESCRIPTION.rst @@ -0,0 +1,15 @@ +By default, Odoo allows negative stock. The advantage of negative stock +is that, if some stock levels are wrong in the ERP, you will not be blocked +when validating the picking for a customer... so you will still be able to +ship the products on time (it's an example !). The problem is that, after you +forced the stock level to negative, you are supposed to fix the stock level +later via an inventory ; but this action is often forgotten by users, +so you end up with negative stock levels in your ERP and it can stay like +this forever (or at least until the next full inventory). + +If you disallow negative stock in Odoo with this module, you will be blocked +when trying to validate a stock operation that will set the stock level of +a product and/or location as negative. So you will have to fix the +wrong stock level of that product without delay, in order to validate the +stock operation in Odoo...you can't forget it anymore ! + diff --git a/stock_no_negative/readme/HISTORY.rst b/stock_no_negative/readme/HISTORY.rst new file mode 100644 index 00000000000..c9e7e47f9c4 --- /dev/null +++ b/stock_no_negative/readme/HISTORY.rst @@ -0,0 +1,4 @@ +11.0.1.1.0 (2018-12-13) +~~~~~~~~~~~~~~~~~~~~~~~ + +* Add the ability to allow negative stock for individual stock locations. diff --git a/stock_no_negative/readme/USAGE.rst b/stock_no_negative/readme/USAGE.rst new file mode 100644 index 00000000000..004f5169f9c --- /dev/null +++ b/stock_no_negative/readme/USAGE.rst @@ -0,0 +1,4 @@ +When you validate a stock operation (a stock move, a picking, +a manufacturing order, etc.) that will set the stock level of a +stockable product as negative, you will be blocked by an error message. +The consumable products can still have a negative stock level. diff --git a/stock_no_negative/static/description/index.html b/stock_no_negative/static/description/index.html new file mode 100644 index 00000000000..88960b382d0 --- /dev/null +++ b/stock_no_negative/static/description/index.html @@ -0,0 +1,482 @@ + + + + + + +Stock Disallow Negative + + + +
+

Stock Disallow Negative

+ + +

Beta License: AGPL-3 OCA/stock-logistics-workflow Translate me on Weblate Try me on Runbot

+

By default, Odoo allows negative stock. The advantage of negative stock +is that, if some stock levels are wrong in the ERP, you will not be blocked +when validating the picking for a customer… so you will still be able to +ship the products on time (it’s an example !). The problem is that, after you +forced the stock level to negative, you are supposed to fix the stock level +later via an inventory ; but this action is often forgotten by users, +so you end up with negative stock levels in your ERP and it can stay like +this forever (or at least until the next full inventory).

+

If you disallow negative stock in Odoo with this module, you will be blocked +when trying to validate a stock operation that will set the stock level of +a product and/or location as negative. So you will have to fix the +wrong stock level of that product without delay, in order to validate the +stock operation in Odoo…you can’t forget it anymore !

+

Table of contents

+ +
+

Configuration

+

By default, the stockable products will not be allowed to have a negative +stock. If you want to make some exceptions for some products, product +categories or locations, you can activate the option Allow Negative Stock:

+

For products:

+
    +
  1. Go to Inventory / Master Data / Products and in the +tab General Information activate this option.
  2. +
+

For product categories:

+
    +
  1. Go to Inventory / Configuration / Products / Product Categories +and activate this option.
  2. +
+

For individual locations:

+
    +
  1. Go to Inventory / Configuration / Settings and activate +the option Storage Locations.
  2. +
  3. Go to Inventory / Configuration / Warehouse Management / Locations and +activate the option the option Allow Negative Stock for the locations you +choose.
  4. +
+
+
+

Usage

+

When you validate a stock operation (a stock move, a picking, +a manufacturing order, etc.) that will set the stock level of a +stockable product as negative, you will be blocked by an error message. +The consumable products can still have a negative stock level.

+
+
+

Changelog

+
+

11.0.1.1.0 (2018-12-13)

+
    +
  • Add the ability to allow negative stock for individual stock 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 smashing 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-workflow project on GitHub.

+

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

+
+
+
+ + diff --git a/stock_no_negative/tests/__init__.py b/stock_no_negative/tests/__init__.py new file mode 100644 index 00000000000..629aec36e55 --- /dev/null +++ b/stock_no_negative/tests/__init__.py @@ -0,0 +1,8 @@ +# ?? 2015-2016 Akretion (http://www.akretion.com) +# @author Alexis de Lattre +# ?? 2016 Eficent Business and IT Consulting Services S.L. +# (http://www.eficent.com) +# ?? 2016 Serpent Consulting Services Pvt. Ltd. () +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from . import test_stock_no_negative diff --git a/stock_no_negative/tests/test_stock_no_negative.py b/stock_no_negative/tests/test_stock_no_negative.py new file mode 100644 index 00000000000..c617cdb54da --- /dev/null +++ b/stock_no_negative/tests/test_stock_no_negative.py @@ -0,0 +1,96 @@ +# Copyright 2015-2016 Akretion (http://www.akretion.com) - Alexis de Lattre +# Copyright 2016 Eficent (http://www.eficent.com) +# Copyright 2016 Serpent Consulting Services () +# Copyright 2018 Tecnativa - Pedro M. Baeza +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + + +from odoo.tests.common import TransactionCase +from odoo.exceptions import ValidationError + + +class TestStockNoNegative(TransactionCase): + at_install = False + post_install = True + + def setUp(self): + super(TestStockNoNegative, self).setUp() + self.product_model = self.env['product.product'] + self.product_ctg_model = self.env['product.category'] + self.picking_type_id = self.env.ref('stock.picking_type_out') + self.location_id = self.env.ref('stock.stock_location_stock') + self.location_dest_id = self.env.ref('stock.stock_location_customers') + # Create product category + self.product_ctg = self._create_product_category() + # Create a Product + self.product = self._create_product('test_product1') + self._create_picking() + + def _create_product_category(self): + product_ctg = self.product_ctg_model.create({ + 'name': 'test_product_ctg', + 'allow_negative_stock': False, + }) + return product_ctg + + def _create_product(self, name): + product = self.product_model.create({ + 'name': name, + 'categ_id': self.product_ctg.id, + 'type': 'product', + 'allow_negative_stock': False, + }) + return product + + def _create_picking(self): + self.stock_picking = self.env['stock.picking'].with_context( + test_stock_no_negative=True, + ).create({ + 'picking_type_id': self.picking_type_id.id, + 'move_type': 'direct', + 'location_id': self.location_id.id, + 'location_dest_id': self.location_dest_id.id + }) + + self.stock_move = self.env['stock.move'].create({ + 'name': 'Test Move', + 'product_id': self.product.id, + 'product_uom_qty': 100.0, + 'product_uom': self.product.uom_id.id, + 'picking_id': self.stock_picking.id, + 'state': 'draft', + 'location_id': self.location_id.id, + 'location_dest_id': self.location_dest_id.id, + 'quantity_done': 100.0, + }) + + def test_check_constrains(self): + """Assert that constraint is raised when user + tries to validate the stock operation which would + make the stock level of the product negative """ + self.stock_picking.action_confirm() + with self.assertRaises(ValidationError): + self.stock_picking.button_validate() + + def test_true_allow_negative_stock_product(self): + """Assert that negative stock levels are allowed when + the allow_negative_stock is set active in the product""" + self.product.allow_negative_stock = True + self.stock_picking.action_confirm() + self.stock_picking.button_validate() + quant = self.env['stock.quant'].search([ + ('product_id', '=', self.product.id), + ('location_id', '=', self.location_id.id)]) + self.assertEqual(quant.quantity, -100) + + def test_true_allow_negative_stock_location(self): + """Assert that negative stock levels are allowed when + the allow_negative_stock is set active in the product""" + self.product.allow_negative_stock = False + self.location_id.allow_negative_stock = True + self.stock_picking.action_confirm() + self.stock_picking.button_validate() + quant = self.env['stock.quant'].search([ + ('product_id', '=', self.product.id), + ('location_id', '=', self.location_id.id)]) + self.assertEqual(quant.quantity, -100) diff --git a/stock_no_negative/views/product_product_views.xml b/stock_no_negative/views/product_product_views.xml new file mode 100644 index 00000000000..252fbdf9837 --- /dev/null +++ b/stock_no_negative/views/product_product_views.xml @@ -0,0 +1,33 @@ + + + + + + + stock_no_negative.product.template.form + product.template + + + + + + + + + + stock_no_negative.product.category.form + product.category + + + + + + + + + diff --git a/stock_no_negative/views/stock_location_views.xml b/stock_no_negative/views/stock_location_views.xml new file mode 100644 index 00000000000..dfb555389f0 --- /dev/null +++ b/stock_no_negative/views/stock_location_views.xml @@ -0,0 +1,22 @@ + + + + + + + stock.location.form.allow_negative_stock + stock.location + + + + + + + + +