forked from Vauxoo/stock-logistics-warehouse
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request Vauxoo#1 from numerigraphe/8.0-stock_available_imm…
…ediately2 Thank you @clonedagain for your help.
- Loading branch information
Showing
45 changed files
with
1,412 additions
and
155 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
# -*- 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 <http://www.gnu.org/licenses/>. | ||
# | ||
############################################################################## | ||
|
||
from . import product |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
# -*- 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 <http://www.gnu.org/licenses/>. | ||
# | ||
############################################################################## | ||
|
||
{ | ||
'name': 'Consider the production potential is available to promise', | ||
'version': '2.0', | ||
"author": u"Numérigraphe,Odoo Community Association (OCA)", | ||
'category': 'Hidden', | ||
'depends': ['stock_available', 'mrp'], | ||
'data': [ | ||
'product_view.xml', | ||
], | ||
'test': [ | ||
'test/potential_qty.yml', | ||
], | ||
'license': 'AGPL-3', | ||
'installable': False | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
# Translation of OpenERP Server. | ||
# This file contains the translation of the following modules: | ||
# * stock_available_mrp | ||
# | ||
msgid "" | ||
msgstr "" | ||
"Project-Id-Version: OpenERP Server 7.0\n" | ||
"Report-Msgid-Bugs-To: \n" | ||
"POT-Creation-Date: 2014-07-30 19:29+0000\n" | ||
"PO-Revision-Date: 2014-07-30 19:29+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_mrp | ||
#: field:product.product,potential_qty:0 | ||
msgid "Potential" | ||
msgstr "Potentiel" | ||
|
||
#. module: stock_available_mrp | ||
#: code:_description:0 | ||
#: model:ir.model,name:stock_available_mrp.model_product_product | ||
#, python-format | ||
msgid "Product" | ||
msgstr "Article" | ||
|
||
#. module: stock_available_mrp | ||
#: help:product.product,potential_qty:0 | ||
msgid "Quantity of this Product that could be produced using the materials already at hand, following a single level of the Bills of Materials." | ||
msgstr "Quantité de cet article que l'on pourrait produire en utilisant les produits déjà disponibles, en suivant un seul niveau de nomenclature." | ||
|
34 changes: 34 additions & 0 deletions
34
__unported__/stock_available_mrp/i18n/stock_available_mrp.pot
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
# Translation of OpenERP Server. | ||
# This file contains the translation of the following modules: | ||
# * stock_available_mrp | ||
# | ||
msgid "" | ||
msgstr "" | ||
"Project-Id-Version: OpenERP Server 7.0\n" | ||
"Report-Msgid-Bugs-To: \n" | ||
"POT-Creation-Date: 2014-07-30 19:41+0000\n" | ||
"PO-Revision-Date: 2014-07-30 19:41+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_mrp | ||
#: field:product.product,potential_qty:0 | ||
msgid "Potential" | ||
msgstr "" | ||
|
||
#. module: stock_available_mrp | ||
#: code:_description:0 | ||
#: model:ir.model,name:stock_available_mrp.model_product_product | ||
#, python-format | ||
msgid "Product" | ||
msgstr "" | ||
|
||
#. module: stock_available_mrp | ||
#: help:product.product,potential_qty:0 | ||
msgid "Quantity of this Product that could be produced using the materials already at hand, following a single level of the Bills of Materials." | ||
msgstr "" | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,126 @@ | ||
# -*- 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 <http://www.gnu.org/licenses/>. | ||
# | ||
############################################################################## | ||
|
||
from openerp import SUPERUSER_ID | ||
from openerp.osv import orm, fields | ||
import openerp.addons.decimal_precision as dp | ||
|
||
|
||
class product_product(orm.Model): | ||
"""Add the computation for the stock available to promise""" | ||
_inherit = 'product.product' | ||
|
||
def _product_available(self, cr, uid, ids, field_names=None, arg=False, | ||
context=None): | ||
"""Quantity available to promise based on components at hand.""" | ||
# Compute the core quantities | ||
res = super(product_product, self)._product_available( | ||
cr, uid, ids, field_names=field_names, arg=arg, context=context) | ||
# If we didn't get a field_names list, there's nothing to do | ||
if field_names is None: | ||
return res | ||
|
||
if context is None: | ||
context = {} | ||
# Prepare an alternative context without 'uom', to avoid cross-category | ||
# conversions when reading the available stock of components | ||
if 'uom' in context: | ||
context_wo_uom = context.copy() | ||
del context_wo_uom['uom'] | ||
else: | ||
context_wo_uom = context | ||
|
||
# Compute the production capacity | ||
if any([f in field_names | ||
for f in ['potential_qty', 'immediately_usable_qty']]): | ||
# Compute the potential qty from BoMs with components available | ||
bom_obj = self.pool['mrp.bom'] | ||
to_uom = 'uom' in context and self.pool['product.uom'].browse( | ||
cr, SUPERUSER_ID, context['uom'], context=context) | ||
|
||
for product in self.browse(cr, uid, ids, context=context): | ||
# _bom_find() returns a single BoM id. | ||
# We will not check any other BoM for this product | ||
bom_id = bom_obj._bom_find(cr, SUPERUSER_ID, product.id, | ||
product.uom_id.id) | ||
if bom_id: | ||
min_qty = self._compute_potential_qty_from_bom( | ||
cr, uid, bom_id, to_uom or product.uom_id, | ||
context=context) | ||
|
||
if 'potential_qty' in field_names: | ||
res[product.id]['potential_qty'] += min_qty | ||
if 'immediately_usable_qty' in field_names: | ||
res[product.id]['immediately_usable_qty'] += min_qty | ||
|
||
return res | ||
|
||
def _compute_potential_qty_from_bom(self, cr, uid, bom_id, to_uom, | ||
context=None): | ||
"""Compute the potential qty from BoMs with components available""" | ||
bom_obj = self.pool['mrp.bom'] | ||
uom_obj = self.pool['product.uom'] | ||
if context is None: | ||
context = {} | ||
if 'uom' in context: | ||
context_wo_uom = context.copy() | ||
del context_wo_uom['uom'] | ||
else: | ||
context_wo_uom = context | ||
min_qty = False | ||
# Browse ignoring the UoM context to avoid cross-category conversions | ||
bom = bom_obj.browse( | ||
cr, uid, [bom_id], context=context_wo_uom)[0] | ||
|
||
# store id of final product uom | ||
|
||
for component in bom.bom_lines: | ||
# qty available in BOM line's UoM | ||
# XXX use context['uom'] instead? | ||
stock_component_qty = uom_obj._compute_qty_obj( | ||
cr, uid, | ||
component.product_id.uom_id, | ||
component.product_id.virtual_available, | ||
component.product_uom) | ||
# qty we can produce with this component, in the BoM's UoM | ||
bom_uom_qty = (stock_component_qty // component.product_qty | ||
) * bom.product_qty | ||
# Convert back to the reporting default UoM | ||
stock_product_uom_qty = uom_obj._compute_qty_obj( | ||
cr, uid, bom.product_uom, bom_uom_qty, | ||
to_uom) | ||
if min_qty is False: | ||
min_qty = stock_product_uom_qty | ||
elif stock_product_uom_qty < min_qty: | ||
min_qty = stock_product_uom_qty | ||
if min_qty < 0.0: | ||
min_qty = 0.0 | ||
return min_qty | ||
|
||
_columns = { | ||
'potential_qty': fields.function( | ||
_product_available, method=True, multi='qty_available', | ||
type='float', | ||
digits_compute=dp.get_precision('Product Unit of Measure'), | ||
string='Potential', | ||
help="Quantity of this Product that could be produced using " | ||
"the materials already at hand, following a single level " | ||
"of the Bills of Materials."), | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<openerp> | ||
<data> | ||
<!-- Add the quantity available to promise in the product form --> | ||
<record id="view_product_form_potential_qty" model="ir.ui.view"> | ||
<field name="name">product.form.potential_qty</field> | ||
<field name="model">product.product</field> | ||
<field name="type">form</field> | ||
<field name="inherit_id" ref="stock.view_normal_procurement_locations_form" /> | ||
<field name="arch" type="xml"> | ||
<data> | ||
<xpath expr="//field[@name='virtual_available']" position="after"> | ||
<field name="potential_qty"/> | ||
</xpath> | ||
</data> | ||
</field> | ||
</record> | ||
</data> | ||
</openerp> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
- Test the computation of the potential quantity on product_product_16, a product with several multi-line BoMs | ||
|
||
- Create a UoM in the category of PCE | ||
- !record {model: product.uom, id: thousand}: | ||
name: Thousand | ||
factor: 0.001 | ||
rounding: 0.0001 | ||
uom_type: bigger | ||
category_id: product.product_uom_categ_unit | ||
|
||
- Receive enough of the first component to run the BoM 1000x, and check that the potential is unchanged | ||
- !python {model: mrp.bom}: | | ||
bom = self.browse( | ||
cr, uid, | ||
self._bom_find( | ||
cr, uid, ref('product.product_product_16'), | ||
ref('product.product_uom_unit'))) | ||
assert len(bom.bom_lines)>1, "The test BoM has a single line, two or more are needed for the test" | ||
initial_qty = bom.product_id.potential_qty | ||
component = bom.bom_lines[0] | ||
assert component.product_uom.category_id.id == ref('product.product_uom_categ_unit'), "The first component's UoM is in the wrong category can't test" | ||
self.pool['stock.move'].create( | ||
cr, uid, | ||
{ | ||
'name': 'Receive first component', | ||
'product_id': component.product_id.id, | ||
'product_qty': component.product_qty * 1000.0, | ||
'product_uom': component.product_id.uom_id.id, | ||
'location_id': ref('stock.stock_location_suppliers'), | ||
'location_dest_id': ref('stock.stock_location_stock'), | ||
'state': 'done', | ||
}) | ||
# Re-read the potential quantity | ||
bom.refresh() | ||
new_qty = bom.product_id.potential_qty | ||
assert new_qty == initial_qty, "Receiving a single component should not change the potential qty (%s instead of %s)" % (new_qty, initial_qty) | ||
|
||
- Receive enough of all the components to run the BoM 1000x and check that the potential is correct | ||
- !python {model: mrp.bom}: | | ||
# Select a BoM for product_product_16 | ||
bom = self.browse( | ||
cr, uid, | ||
self._bom_find( | ||
cr, uid, ref('product.product_product_16'), | ||
ref('product.product_uom_unit'))) | ||
assert len(bom.bom_lines)>1, "The test BoM has a single line, two or more are needed for the test" | ||
initial_qty = bom.product_id.potential_qty | ||
for component in bom.bom_lines: | ||
assert component.product_uom.category_id.id == ref('product.product_uom_categ_unit'), "The first component's UoM is in the wrong category, can't test" | ||
self.pool['stock.move'].create( | ||
cr, uid, | ||
{ | ||
'name': 'Receive all components', | ||
'product_id': component.product_id.id, | ||
'product_qty': component.product_qty * 1000.0, | ||
'product_uom': component.product_id.uom_id.id, | ||
'location_id': ref('stock.stock_location_suppliers'), | ||
'location_dest_id': ref('stock.stock_location_stock'), | ||
'state': 'done', | ||
}) | ||
# Re-read the potential quantity | ||
bom.refresh() | ||
new_qty = bom.product_id.potential_qty | ||
right_qty = initial_qty + bom.product_qty * 1000.0 | ||
assert new_qty == right_qty, "The potential qty is incorrect after receiveing all the components (%s instead of %s)" % (new_qty, right_qty) | ||
# Re-read the potential quantity with a different UoM in the context | ||
new_qty = self.browse( | ||
cr, uid, bom.id, context={'uom': ref('thousand')}).product_id.potential_qty | ||
right_qty = initial_qty / 1000.0 + bom.product_qty | ||
assert abs(new_qty - right_qty) < 0.0001, "The potential qty is incorrect with another UoM in the context (%s instead of %s)" % (new_qty, right_qty) |
Oops, something went wrong.