diff --git a/stock_available/__init__.py b/stock_available/__init__.py
new file mode 100644
index 000000000..6755b49d2
--- /dev/null
+++ b/stock_available/__init__.py
@@ -0,0 +1,24 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# This module is copyright (C) 2014 Numérigraphe SARL. All Rights Reserved.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+#
+##############################################################################
+
+from . import product
+from . import res_config
+
+from .product import _product_available_fnct
diff --git a/stock_available/__openerp__.py b/stock_available/__openerp__.py
new file mode 100644
index 000000000..16ea5f8ab
--- /dev/null
+++ b/stock_available/__openerp__.py
@@ -0,0 +1,42 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# This module is copyright (C) 2014 Numérigraphe SARL. All Rights Reserved.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+#
+##############################################################################
+
+{
+ 'name': 'Stock available to promise',
+ 'version': '2.0',
+ 'author': u'Numérigraphe',
+ 'category': 'Warehouse',
+ 'depends': ['stock'],
+ 'description': """
+Stock available to promise
+==========================
+This module proposes several options to compute the quantity available to
+promise for each product.
+This quantity is based on the projected stock and, depending on the
+configuration, it can account for various data such as sales quotations or
+immediate production capacity.
+This can be configured in the menu Settings > Configuration > Warehouse.
+""",
+ 'license': 'AGPL-3',
+ 'data': [
+ 'product_view.xml',
+ 'res_config_view.xml',
+ ]
+}
diff --git a/stock_available/i18n/fr.po b/stock_available/i18n/fr.po
new file mode 100644
index 000000000..6c8e4c244
--- /dev/null
+++ b/stock_available/i18n/fr.po
@@ -0,0 +1,98 @@
+# Translation of OpenERP Server.
+# This file contains the translation of the following modules:
+# * stock_available
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: OpenERP Server 7.0\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2014-07-30 16:42+0000\n"
+"PO-Revision-Date: 2014-07-30 16:42+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_available
+#: field:product.product,immediately_usable_qty:0
+msgid "Available to promise"
+msgstr "Disponible à la vente"
+
+#. module: stock_available
+#: view:product.product:0
+msgid "Available to promise:"
+msgstr "Disponible à la vente:"
+
+#. module: stock_available
+#: field:stock.config.settings,module_stock_available_sale:0
+msgid "Exclude goods already in sale quotations"
+msgstr "Exclure les marchandises qui sont déjà dans les devis"
+
+#. module: stock_available
+#: field:stock.config.settings,module_stock_available_immediately:0
+msgid "Exclude incoming goods"
+msgstr "Exclure les receptions attendues"
+
+#. module: stock_available
+#: field:stock.config.settings,module_stock_available_mrp:0
+msgid "Include the production potential"
+msgstr "Inclure la production potentielle"
+
+#. module: stock_available
+#: code:_description:0
+#: model:ir.model,name:stock_available.model_product_product
+#, python-format
+msgid "Product"
+msgstr "Article"
+
+#. module: stock_available
+#: view:stock.config.settings:0
+msgid "Stock available to promise"
+msgstr "Stock disponible à la vente"
+
+#. module: stock_available
+#: help:product.product,immediately_usable_qty:0
+msgid "Stock for this Product that can be safely proposed for sale to Customers.\n"
+"The definition of this value can be configured to suit your needs"
+msgstr "Stock de cet article qui peut sans risque être proposé à la vente aux clients.\n"
+"La définition de cette valeur est paramétrable selon vos besoins"
+
+#. module: stock_available
+#: help:stock.config.settings,module_stock_available_mrp:0
+msgid "This will add the quantities of goods that can be immediately manufactured, to the quantities available to promise.\n"
+"This installs the module stock_available_mrp.\n"
+"If the module mrp is not installed, this will install it too"
+msgstr "Ceci ajoute les quantités de marchandises qui peuvent être immédiatement fabriquées, aux quantitiés disponibles à la vente.\n"
+"Ceci installe le module stock_available_mrp.\n"
+"Si le module mrp n'est pas encore installé, il le sera aussi"
+
+#. module: stock_available
+#: help:stock.config.settings,module_stock_available_immediately:0
+msgid "This will subtract incoming quantities from the quantities available to promise.\n"
+"This installs the module stock_available_immediately."
+msgstr "Ceci soustrait les réceptions attendues des quantitiés disponibles à la vente.\n"
+"Ceci installe le module stock_available_immediately."
+
+#. module: stock_available
+#: help:stock.config.settings,module_stock_available_sale:0
+msgid "This will subtract quantities from the sale quotations from the quantities available to promise.\n"
+"This installs the modules stock_available_sale.\n"
+"If the modules sale and sale_delivery_date are not installed, this will install them too"
+msgstr "Ceci soustrait les quantités des devis de vente des quantitiés disponibles à la vente.\n"
+"Ceci installe le modules stock_available_sale.\n"
+"Si les modules sale et sale_delivery_date ne sont pas encore installés, ils le seront également"
+
+#. module: stock_available
+#: view:product.product:0
+msgid "red:immediately_usable_qty<0;blue:immediately_usable_qty>=0 and state in ('draft', 'end', 'obsolete');black:immediately_usable_qty>=0 and state not in ('draft', 'end', 'obsolete')"
+msgstr "red:immediately_usable_qty<0;blue:immediately_usable_qty>=0 and state in ('draft', 'end', 'obsolete');black:immediately_usable_qty>=0 and state not in ('draft', 'end', 'obsolete')"
+
+#. module: stock_available
+#: code:_description:0
+#: model:ir.model,name:stock_available.model_stock_config_settings
+#, python-format
+msgid "stock.config.settings"
+msgstr "stock.config.settings"
+
diff --git a/stock_available/i18n/stock_available.pot b/stock_available/i18n/stock_available.pot
new file mode 100644
index 000000000..6eed1c952
--- /dev/null
+++ b/stock_available/i18n/stock_available.pot
@@ -0,0 +1,92 @@
+# Translation of OpenERP Server.
+# This file contains the translation of the following modules:
+# * stock_available
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: OpenERP Server 7.0\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2014-07-30 16:48+0000\n"
+"PO-Revision-Date: 2014-07-30 16:48+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_available
+#: field:product.product,immediately_usable_qty:0
+msgid "Available to promise"
+msgstr ""
+
+#. module: stock_available
+#: view:product.product:0
+msgid "Available to promise:"
+msgstr ""
+
+#. module: stock_available
+#: field:stock.config.settings,module_stock_available_sale:0
+msgid "Exclude goods already in sale quotations"
+msgstr ""
+
+#. module: stock_available
+#: field:stock.config.settings,module_stock_available_immediately:0
+msgid "Exclude incoming goods"
+msgstr ""
+
+#. module: stock_available
+#: field:stock.config.settings,module_stock_available_mrp:0
+msgid "Include the production potential"
+msgstr ""
+
+#. module: stock_available
+#: code:_description:0
+#: model:ir.model,name:stock_available.model_product_product
+#, python-format
+msgid "Product"
+msgstr ""
+
+#. module: stock_available
+#: view:stock.config.settings:0
+msgid "Stock available to promise"
+msgstr ""
+
+#. module: stock_available
+#: help:product.product,immediately_usable_qty:0
+msgid "Stock for this Product that can be safely proposed for sale to Customers.\n"
+"The definition of this value can be configured to suit your needs"
+msgstr ""
+
+#. module: stock_available
+#: help:stock.config.settings,module_stock_available_mrp:0
+msgid "This will add the quantities of goods that can be immediately manufactured, to the quantities available to promise.\n"
+"This installs the module stock_available_mrp.\n"
+"If the module mrp is not installed, this will install it too"
+msgstr ""
+
+#. module: stock_available
+#: help:stock.config.settings,module_stock_available_immediately:0
+msgid "This will subtract incoming quantities from the quantities available to promise.\n"
+"This installs the module stock_available_immediately."
+msgstr ""
+
+#. module: stock_available
+#: help:stock.config.settings,module_stock_available_sale:0
+msgid "This will subtract quantities from the sale quotations from the quantities available to promise.\n"
+"This installs the modules stock_available_sale.\n"
+"If the modules sale and sale_delivery_date are not installed, this will install them too"
+msgstr ""
+
+#. module: stock_available
+#: view:product.product:0
+msgid "red:immediately_usable_qty<0;blue:immediately_usable_qty>=0 and state in ('draft', 'end', 'obsolete');black:immediately_usable_qty>=0 and state not in ('draft', 'end', 'obsolete')"
+msgstr ""
+
+#. module: stock_available
+#: code:_description:0
+#: model:ir.model,name:stock_available.model_stock_config_settings
+#, python-format
+msgid "stock.config.settings"
+msgstr ""
+
diff --git a/stock_available/product.py b/stock_available/product.py
new file mode 100644
index 000000000..a4a528eb7
--- /dev/null
+++ b/stock_available/product.py
@@ -0,0 +1,100 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# This module is copyright (C) 2014 Numérigraphe SARL. All Rights Reserved.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+#
+##############################################################################
+
+from openerp.osv import orm, fields
+import openerp.addons.decimal_precision as dp
+
+
+# Expose the method as a function, like when the fields are defined,
+# and use the pool to call the method from the other modules too.
+def _product_available_fnct(self, cr, uid, ids, field_names=None, arg=False,
+ context=None):
+ return self.pool['product.product']._product_available(
+ cr, uid, ids, field_names=field_names, arg=arg, context=context)
+
+
+class ProductProduct(orm.Model):
+ """Add a field for the stock available to promise.
+
+ Useful implementations need to be installed through the Settings menu or by
+ installing one of the modules stock_available_*
+ """
+ _inherit = 'product.product'
+
+ def __init__(self, pool, cr):
+ """Use _product_available_fnct to compute all the quantities."""
+ # Doing this lets us change the function and not redefine fields
+ super(ProductProduct, self).__init__(pool, cr)
+ for coldef in self._columns.values():
+ if (isinstance(coldef, fields.function)
+ and coldef._multi == 'qty_available'):
+ coldef._fnct = _product_available_fnct
+
+ def _product_available(self, cr, uid, ids, field_names=None, arg=False,
+ context=None):
+ """No-op implementation of the stock available to promise.
+
+ Must be overridden by another module that actually implement
+ computations.
+ The sub-modules MUST call super()._product_available BEFORE their own
+ computations
+
+ Side-effect warning: This method may change the list passed as the
+ field_names parameter, which will then alter the caller's state."""
+ # If we didn't get a field_names list, there's nothing to do
+ if field_names is None:
+ return super(ProductProduct, self)._product_available(
+ cr, uid, ids, field_names=field_names, arg=arg,
+ context=context)
+
+ if context is None:
+ context = {}
+
+ # Load virtual_available if it's not already asked for
+ # We need it to compute immediately_usable_qty
+ # We DO want to change the caller's list so we're NOT going to
+ # work on a copy of field_names.
+ if ('virtual_available' not in field_names
+ and 'immediately_usable_qty' in field_names):
+ field_names.append('virtual_available')
+
+ # Compute the core quantities
+ res = super(ProductProduct, self)._product_available(
+ cr, uid, ids, field_names=field_names, arg=arg, context=context)
+
+ # By default, available to promise = forecasted quantity
+ if ('immediately_usable_qty' in field_names):
+ for stock_qty in res.itervalues():
+ stock_qty['immediately_usable_qty'] = \
+ stock_qty['virtual_available']
+
+ return res
+
+ _columns = {
+ 'immediately_usable_qty': fields.function(
+ _product_available_fnct, multi='qty_available',
+ type='float',
+ digits_compute=dp.get_precision('Product Unit of Measure'),
+ string='Available to promise',
+ help="Stock for this Product that can be safely proposed "
+ "for sale to Customers.\n"
+ "The definition of this value can be configured to suit "
+ "your needs"),
+ }
diff --git a/stock_available_immediately/product_view.xml b/stock_available/product_view.xml
similarity index 54%
rename from stock_available_immediately/product_view.xml
rename to stock_available/product_view.xml
index bdd7873f9..d05270f75 100644
--- a/stock_available_immediately/product_view.xml
+++ b/stock_available/product_view.xml
@@ -1,32 +1,20 @@
-
-
-
-
- product.normal.stock.active.qty.form.inherit
+
+ Quantity available to promise (form)product.template
-
-
-
-
-
-
- product_immediately_usable.product_product_tree_view
+
+
+ Quantity available to promise (tree)product.template
@@ -34,12 +22,22 @@
red:immediately_usable_qty<0;blue:immediately_usable_qty>=0 and state in ('draft', 'end', 'obsolete');black:immediately_usable_qty>=0 and state not in ('draft', 'end', 'obsolete')
-
+
+
+ Quantity available to promise (kanban)
+ product.template
+
+
+
+
Available to promise:
+
+
+
diff --git a/stock_available/res_config.py b/stock_available/res_config.py
new file mode 100644
index 000000000..535f58460
--- /dev/null
+++ b/stock_available/res_config.py
@@ -0,0 +1,34 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# This module is copyright (C) 2014 Numérigraphe SARL. All Rights Reserved.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+#
+##############################################################################
+
+from openerp.osv import orm, fields
+
+
+class StockConfig(orm.TransientModel):
+ """Add options to easily install the submodules"""
+ _inherit = 'stock.config.settings'
+
+ _columns = {
+ 'module_stock_available_immediately': fields.boolean(
+ 'Exclude incoming goods',
+ help="This will subtract incoming quantities from the quantities "
+ "available to promise.\n"
+ "This installs the module stock_available_immediately."),
+ }
diff --git a/stock_available/res_config_view.xml b/stock_available/res_config_view.xml
new file mode 100644
index 000000000..15e45c031
--- /dev/null
+++ b/stock_available/res_config_view.xml
@@ -0,0 +1,25 @@
+
+
+
+
+ Stock settings: quantity available to promise
+ stock.config.settings
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/stock_available_immediately/__openerp__.py b/stock_available_immediately/__openerp__.py
index 1cedaa84f..838f9db4c 100644
--- a/stock_available_immediately/__openerp__.py
+++ b/stock_available_immediately/__openerp__.py
@@ -20,21 +20,27 @@
#
#
-
{
- "name": "Immediately Usable Stock Quantity",
- "version": "1.0",
- "depends": ["product", "stock", ],
+ "name": "Ignore planned receptions in quantity available to promise",
+ "version": "2.0",
+ "depends": ["stock_available"],
"author": "Camptocamp",
"license": "AGPL-3",
- "description": """
-Compute the immediately usable stock.
-Immediately usable is computed : Quantity on Hand - Outgoing Stock.
+ "description": u"""
+Ignore planned receptions in quantity available to promise
+----------------------------------------------------------
+
+Normally the quantity available to promise is based on the virtual stock,
+which includes both planned outgoing and incoming goods.
+This module will subtract the planned receptions from the quantity available to
+promise.
+
+Contributors
+------------
+ * Author: Guewen Baconnier (Camptocamp SA)
+ * Sébastien BEAU (Akretion)
+ * Lionel Sausin (Numérigraphe)
""",
- "website": "http://tinyerp.com/module_account.html",
- "category": "Generic Modules/Stock",
- "data": ["product_view.xml",
- ],
- "active": False,
+ "category": "Hidden",
'installable': True
}
diff --git a/stock_available_immediately/product.py b/stock_available_immediately/product.py
index 8e6a7dc95..939bbbb9d 100644
--- a/stock_available_immediately/product.py
+++ b/stock_available_immediately/product.py
@@ -19,106 +19,41 @@
#
##############################################################################
-from openerp.addons import decimal_precision as dp
+from openerp.osv import orm
+
from openerp.osv import orm, fields
+class product_immediately_usable(orm.Model):
+ """Subtract incoming qty from immediately_usable_qty
-class ProductTemplate(orm.Model):
- """
- Immediately usable quantity is : real stock - outgoing qty
- """
- _inherit = 'product.template'
+ We don't need to override the function fields, the module stock_available
+ takes of it for us.
+
+ Side-effect warning: This method may change the list passed as the
+ field_names parameter, which will then alter the caller's state."""
+ _inherit = 'product.product'
def _product_available(self, cr, uid, ids, field_names=None,
arg=False, context=None):
- res = super(ProductTemplate, self)._product_available(
- cr, uid, ids, field_names, arg, context)
+ """Ignore the incoming goods in the quantity available to promise"""
+ # If we didn't get a field_names list, there's nothing to do
+ if field_names is None or 'immediately_usable_qty' not in field_names:
+ return super(product_immediately_usable, self)._product_available(
+ cr, uid, ids, field_names=field_names, arg=arg,
+ context=context)
- if 'immediately_usable_qty' in field_names:
- for product_id, stock_qty in res.iteritems():
- res[product_id]['immediately_usable_qty'] = \
- stock_qty['qty_available'] - stock_qty['outgoing_qty']
+ # We need available and incoming quantities to compute
+ # immediately usable quantity.
+ # We DO want to change the caller's list so we're NOT going to
+ # work on a copy of field_names.
+ field_names.append('qty_available')
+ field_names.append('incoming_qty')
+
+ res = super(product_immediately_usable, self)._product_available(
+ cr, uid, ids, field_names=field_names, arg=arg, context=context)
+
+ for stock_qty in res.itervalues():
+ stock_qty['immediately_usable_qty'] -= \
+ stock_qty['incoming_qty']
return res
-
- _columns = {
- 'qty_available': fields.function(
- _product_available,
- multi='qty_available',
- type='float',
- digits_compute=dp.get_precision('Product UoM'),
- string='Quantity On Hand',
- help="Current quantity of products.\n"
- "In a context with a single Stock Location, this includes "
- "goods stored at this Location, or any of its children.\n"
- "In a context with a single Warehouse, this includes "
- "goods stored in the Stock Location of this Warehouse, "
- "or any "
- "of its children.\n"
- "In a context with a single Shop, this includes goods "
- "stored in the Stock Location of the Warehouse of this Shop, "
- "or any of its children.\n"
- "Otherwise, this includes goods stored in any Stock Location "
- "typed as 'internal'."),
- 'virtual_available': fields.function(
- _product_available,
- multi='qty_available',
- type='float',
- digits_compute=dp.get_precision('Product UoM'),
- string='Quantity Available',
- help="Forecast quantity (computed as Quantity On Hand "
- "- Outgoing + Incoming)\n"
- "In a context with a single Stock Location, this includes "
- "goods stored at this Location, or any of its children.\n"
- "In a context with a single Warehouse, this includes "
- "goods stored in the Stock Location of this Warehouse, "
- "or any "
- "of its children.\n"
- "In a context with a single Shop, this includes goods "
- "stored in the Stock Location of the Warehouse of this Shop, "
- "or any of its children.\n"
- "Otherwise, this includes goods stored in any Stock Location "
- "typed as 'internal'."),
- 'incoming_qty': fields.function(
- _product_available,
- multi='qty_available',
- type='float',
- digits_compute=dp.get_precision('Product UoM'),
- string='Incoming',
- help="Quantity of products that are planned to arrive.\n"
- "In a context with a single Stock Location, this includes "
- "goods arriving to this Location, or any of its children.\n"
- "In a context with a single Warehouse, this includes "
- "goods arriving to the Stock Location of this Warehouse, or "
- "any of its children.\n"
- "In a context with a single Shop, this includes goods "
- "arriving to the Stock Location of the Warehouse of this "
- "Shop, or any of its children.\n"
- "Otherwise, this includes goods arriving to any Stock "
- "Location typed as 'internal'."),
- 'outgoing_qty': fields.function(
- _product_available,
- multi='qty_available',
- type='float',
- digits_compute=dp.get_precision('Product UoM'),
- string='Outgoing',
- help="Quantity of products that are planned to leave.\n"
- "In a context with a single Stock Location, this includes "
- "goods leaving from this Location, or any of its children.\n"
- "In a context with a single Warehouse, this includes "
- "goods leaving from the Stock Location of this Warehouse, or "
- "any of its children.\n"
- "In a context with a single Shop, this includes goods "
- "leaving from the Stock Location of the Warehouse of this "
- "Shop, or any of its children.\n"
- "Otherwise, this includes goods leaving from any Stock "
- "Location typed as 'internal'."),
- 'immediately_usable_qty': fields.function(
- _product_available,
- digits_compute=dp.get_precision('Product UoM'),
- type='float',
- string='Immediately Usable',
- multi='qty_available',
- help="Quantity of products really available for sale."
- "Computed as: Quantity On Hand - Outgoing."),
- }