[FIX] product: when converting unit of mesures, use ceiling instead of rounding method

This avoids flows to be stucked when a convertion would move/reserve/buy less pieces than the number required (eg: MTO product where supplier has a UoM bigger than the one on the sale order)

lp bug: https://launchpad.net/bugs/1280463 fixed

bzr revid: mat@openerp.com-20140306162033-yqoc22lo37x06cfh
This commit is contained in:
Martin Trigaux
2014-03-06 17:20:33 +01:00
8 changed files with 62 additions and 27 deletions
+4 -1
View File
@@ -30,6 +30,7 @@ from openerp.tools.translate import _
from openerp import netsvc
from openerp import tools
from openerp import SUPERUSER_ID
from openerp.addons.product import _common
#----------------------------------------------------------
# Work Centers
@@ -324,7 +325,7 @@ class mrp_bom(osv.osv):
"""
routing_obj = self.pool.get('mrp.routing')
factor = factor / (bom.product_efficiency or 1.0)
factor = rounding(factor, bom.product_rounding)
factor = _common.ceiling(factor, bom.product_rounding)
if factor < bom.product_rounding:
factor = bom.product_rounding
result = []
@@ -380,6 +381,8 @@ class mrp_bom(osv.osv):
def rounding(f, r):
# TODO for trunk: log deprecation warning
# _logger.warning("Deprecated rounding method, please use tools.float_round to round floats.")
import math
if not r:
return f
-1
View File
@@ -61,7 +61,6 @@ Print product labels with barcode.
],
'test': [
'product_pricelist_demo.yml',
'test/product_uom.yml',
'test/product_pricelist.yml',
],
'installable': True,
+12 -6
View File
@@ -18,12 +18,18 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
from openerp import tools
import math
def rounding(f, r):
# TODO for trunk: log deprecation warning
# _logger.warning("Deprecated rounding method, please use tools.float_round to round floats.")
return tools.float_round(f, precision_rounding=r)
# TODO for trunk: add rounding method parameter to tools.float_round and use this method as hook
def ceiling(f, r):
if not r:
return f
return round(f / r) * r
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
return math.ceil(f / r) * r
+2 -2
View File
@@ -21,7 +21,7 @@
import time
from _common import rounding
from _common import ceiling
from openerp.osv import fields, osv
from openerp.tools.translate import _
@@ -296,7 +296,7 @@ class product_pricelist(osv.osv):
if price is not False:
price_limit = price
price = price * (1.0+(res['price_discount'] or 0.0))
price = rounding(price, res['price_round']) #TOFIX: rounding with tools.float_rouding
price = ceiling(price, res['price_round'])
price += (res['price_surcharge'] or 0.0)
if res['price_min_margin']:
price = max(price, price_limit+res['price_min_margin'])
+2 -2
View File
@@ -22,7 +22,7 @@
import math
import re
from _common import rounding
from _common import ceiling
from openerp import tools
from openerp.osv import osv, fields
@@ -178,7 +178,7 @@ class product_uom(osv.osv):
return qty
amount = qty / from_unit.factor
if to_unit:
amount = rounding(amount * to_unit.factor, to_unit.rounding)
amount = ceiling(amount * to_unit.factor, to_unit.rounding)
return amount
def _compute_price(self, cr, uid, from_uom_id, price, to_uom_id=False):
-15
View File
@@ -1,15 +0,0 @@
-
In order to test conversation of UOM,
-
I convert Grams into TON with price.
-
!python {model: product.uom}: |
from_uom_id = ref("product_uom_gram")
to_uom_id = ref("product_uom_ton")
price = 2
qty = 1020000
price = self._compute_price(cr, uid, from_uom_id, price, to_uom_id)
qty = self._compute_qty(cr, uid, from_uom_id, qty, to_uom_id)
assert qty == 1.02, "Qty is not correspond."
assert price == 2000000.0, "Price is not correspond."
+5
View File
@@ -0,0 +1,5 @@
from . import test_uom
fast_suite = [
test_uom,
]
+37
View File
@@ -0,0 +1,37 @@
from openerp.tests.common import TransactionCase
class TestUom(TransactionCase):
"""Tests for unit of measure conversion"""
def setUp(self):
super(TestUom, self).setUp()
self.product = self.registry('product.product')
self.uom = self.registry('product.uom')
self.imd = self.registry('ir.model.data')
def test_10_conversion(self):
cr, uid = self.cr, self.uid
gram_id = self.imd.get_object_reference(cr, uid, 'product', 'product_uom_gram')[1]
tonne_id = self.imd.get_object_reference(cr, uid, 'product', 'product_uom_ton')[1]
qty = self.uom._compute_qty(cr, uid, gram_id, 1020000, tonne_id)
self.assertEquals(qty, 1.02, "Converted quantity does not correspond.")
price = self.uom._compute_price(cr, uid, gram_id, 2, tonne_id)
self.assertEquals(price, 2000000.0, "Converted price does not correspond.")
def test_20_rounding(self):
cr, uid = self.cr, self.uid
unit_id = self.imd.get_object_reference(cr, uid, 'product', 'product_uom_unit')[1]
categ_unit_id = self.imd.get_object_reference(cr, uid, 'product', 'product_uom_categ_unit')[1]
score_id = self.uom.create(cr, uid, {
'name': 'Score',
'factor_inv': 20,
'uom_type': 'bigger',
'rounding': 1.0,
'category_id': categ_unit_id
})
qty = self.uom._compute_qty(cr, uid, unit_id, 2, score_id)
self.assertEquals(qty, 1, "Converted quantity should be rounded up.")