[MERGE] forward port of branch 7.0 up to 5f6d324

This commit is contained in:
Denis Ledoux 2014-09-25 15:10:37 +02:00
commit 76067367b2
6 changed files with 48 additions and 14 deletions

View File

@ -622,6 +622,13 @@ class crm_lead(format_address, osv.osv):
attachment.write(values) attachment.write(values)
return True return True
def _merge_opportunity_phonecalls(self, cr, uid, opportunity_id, opportunities, context=None):
phonecall_obj = self.pool['crm.phonecall']
for opportunity in opportunities:
for phonecall_id in phonecall_obj.search(cr, uid, [('opportunity_id', '=', opportunity.id)], context=context):
phonecall_obj.write(cr, uid, phonecall_id, {'opportunity_id': opportunity_id}, context=context)
return True
def merge_opportunity(self, cr, uid, ids, user_id=False, section_id=False, context=None): def merge_opportunity(self, cr, uid, ids, user_id=False, section_id=False, context=None):
""" """
Different cases of merge: Different cases of merge:
@ -667,6 +674,7 @@ class crm_lead(format_address, osv.osv):
# Merge messages and attachements into the first opportunity # Merge messages and attachements into the first opportunity
self._merge_opportunity_history(cr, uid, highest.id, tail_opportunities, context=context) self._merge_opportunity_history(cr, uid, highest.id, tail_opportunities, context=context)
self._merge_opportunity_attachments(cr, uid, highest.id, tail_opportunities, context=context) self._merge_opportunity_attachments(cr, uid, highest.id, tail_opportunities, context=context)
self._merge_opportunity_phonecalls(cr, uid, highest.id, tail_opportunities, context=context)
# Merge notifications about loss of information # Merge notifications about loss of information
opportunities = [highest] opportunities = [highest]

View File

@ -64,6 +64,7 @@
<field name="res_model">account.invoice</field> <field name="res_model">account.invoice</field>
<field name="view_mode">tree,form</field> <field name="view_mode">tree,form</field>
<field name="domain">[('type','in',['out_invoice','out_refund'])]</field> <field name="domain">[('type','in',['out_invoice','out_refund'])]</field>
<field name="context">{}</field>
<field name="search_view_id" ref="account.view_account_invoice_filter"/> <field name="search_view_id" ref="account.view_account_invoice_filter"/>
<field name="help">We haven't sent you any invoice.</field> <field name="help">We haven't sent you any invoice.</field>
</record> </record>

View File

@ -20,9 +20,6 @@
############################################################################## ##############################################################################
from openerp import tools from openerp import tools
import math
def rounding(f, r): def rounding(f, r):
# TODO for trunk: log deprecation warning # TODO for trunk: log deprecation warning
# _logger.warning("Deprecated rounding method, please use tools.float_round to round floats.") # _logger.warning("Deprecated rounding method, please use tools.float_round to round floats.")
@ -32,4 +29,4 @@ def rounding(f, r):
def ceiling(f, r): def ceiling(f, r):
if not r: if not r:
return f return f
return math.ceil(f / r) * r return tools.float_round(f, precision_rounding=r, rounding_method='UP')

View File

@ -30,6 +30,7 @@ from openerp.osv import osv, orm, fields
from openerp.tools.translate import _ from openerp.tools.translate import _
import openerp.addons.decimal_precision as dp import openerp.addons.decimal_precision as dp
from openerp.tools.float_utils import float_round
def ean_checksum(eancode): def ean_checksum(eancode):
"""returns the checksum of an ean string of length 13, returns -1 if the string has the wrong length""" """returns the checksum of an ean string of length 13, returns -1 if the string has the wrong length"""
@ -176,7 +177,10 @@ class product_uom(osv.osv):
raise osv.except_osv(_('Error!'), _('Conversion from Product UoM %s to Default UoM %s is not possible as they both belong to different Category!.') % (from_unit.name,to_unit.name,)) raise osv.except_osv(_('Error!'), _('Conversion from Product UoM %s to Default UoM %s is not possible as they both belong to different Category!.') % (from_unit.name,to_unit.name,))
else: else:
return qty return qty
amount = qty / from_unit.factor # First round to the precision of the original unit, so that
# float representation errors do not bias the following ceil()
# e.g. with 1 / (1/12) we could get 12.0000048, ceiling to 13!
amount = float_round(qty/from_unit.factor, precision_rounding=from_unit.rounding)
if to_unit: if to_unit:
amount = ceiling(amount * to_unit.factor, to_unit.rounding) amount = ceiling(amount * to_unit.factor, to_unit.rounding)
return amount return amount

View File

@ -198,8 +198,8 @@
- -
!python {model: res.currency}: | !python {model: res.currency}: |
from openerp.tools import float_compare, float_is_zero, float_round, float_repr from openerp.tools import float_compare, float_is_zero, float_round, float_repr
def try_round(amount, expected, precision_digits=3, float_round=float_round, float_repr=float_repr): def try_round(amount, expected, precision_digits=3, float_round=float_round, float_repr=float_repr, rounding_method='HALF-UP'):
result = float_repr(float_round(amount, precision_digits=precision_digits), result = float_repr(float_round(amount, precision_digits=precision_digits, rounding_method=rounding_method),
precision_digits=precision_digits) precision_digits=precision_digits)
assert result == expected, 'Rounding error: got %s, expected %s' % (result, expected) assert result == expected, 'Rounding error: got %s, expected %s' % (result, expected)
try_round(2.6745, '2.675') try_round(2.6745, '2.675')
@ -213,6 +213,15 @@
try_round(457.4554, '457.455') try_round(457.4554, '457.455')
try_round(-457.4554, '-457.455') try_round(-457.4554, '-457.455')
# Try some rounding value with rounding method UP instead of HALF-UP
# We use 8.175 because when normalizing 8.175 with precision_digits=3 it gives
# us 8175,0000000001234 as value, and if not handle correctly the rounding UP
# value will be incorrect (should be 8,175 and not 8,176)
try_round(8.175, '8.175', rounding_method='UP')
try_round(8.1751, '8.176', rounding_method='UP')
try_round(-8.175, '-8.175', rounding_method='UP')
try_round(-8.1751, '-8.175', rounding_method='UP')
# Extended float range test, inspired by Cloves Almeida's test on bug #882036. # Extended float range test, inspired by Cloves Almeida's test on bug #882036.
fractions = [.0, .015, .01499, .675, .67499, .4555, .4555, .45555] fractions = [.0, .015, .01499, .675, .67499, .4555, .4555, .45555]
expecteds = ['.00', '.02', '.01', '.68', '.67', '.46', '.456', '.4556'] expecteds = ['.00', '.02', '.01', '.68', '.67', '.46', '.456', '.4556']

View File

@ -29,10 +29,11 @@ def _float_check_precision(precision_digits=None, precision_rounding=None):
return 10 ** -precision_digits return 10 ** -precision_digits
return precision_rounding return precision_rounding
def float_round(value, precision_digits=None, precision_rounding=None): def float_round(value, precision_digits=None, precision_rounding=None, rounding_method='HALF-UP'):
"""Return ``value`` rounded to ``precision_digits`` """Return ``value`` rounded to ``precision_digits`` decimal digits,
decimal digits, minimizing IEEE-754 floating point representation minimizing IEEE-754 floating point representation errors, and applying
errors, and applying HALF-UP (away from zero) tie-breaking rule. the tie-breaking rule selected with ``rounding_method``, by default
HALF-UP (away from zero).
Precision must be given by ``precision_digits`` or ``precision_rounding``, Precision must be given by ``precision_digits`` or ``precision_rounding``,
not both! not both!
@ -41,6 +42,9 @@ def float_round(value, precision_digits=None, precision_rounding=None):
:param float precision_rounding: decimal number representing the minimum :param float precision_rounding: decimal number representing the minimum
non-zero value at the desired precision (for example, 0.01 for a non-zero value at the desired precision (for example, 0.01 for a
2-digit precision). 2-digit precision).
:param rounding_method: the rounding method used: 'HALF-UP' or 'UP', the first
one rounding up to the closest number with the rule that number>=0.5 is
rounded up to 1, and the latest one always rounding up.
:return: rounded float :return: rounded float
""" """
rounding_factor = _float_check_precision(precision_digits=precision_digits, rounding_factor = _float_check_precision(precision_digits=precision_digits,
@ -52,7 +56,7 @@ def float_round(value, precision_digits=None, precision_rounding=None):
# we normalize the value before rounding it as an integer, and de-normalize # we normalize the value before rounding it as an integer, and de-normalize
# after rounding: e.g. float_round(1.3, precision_rounding=.5) == 1.5 # after rounding: e.g. float_round(1.3, precision_rounding=.5) == 1.5
# TIE-BREAKING: HALF-UP # TIE-BREAKING: HALF-UP (for normal rounding)
# We want to apply HALF-UP tie-breaking rules, i.e. 0.5 rounds away from 0. # We want to apply HALF-UP tie-breaking rules, i.e. 0.5 rounds away from 0.
# Due to IEE754 float/double representation limits, the approximation of the # Due to IEE754 float/double representation limits, the approximation of the
# real value may be slightly below the tie limit, resulting in an error of # real value may be slightly below the tie limit, resulting in an error of
@ -66,8 +70,19 @@ def float_round(value, precision_digits=None, precision_rounding=None):
normalized_value = value / rounding_factor # normalize normalized_value = value / rounding_factor # normalize
epsilon_magnitude = math.log(abs(normalized_value), 2) epsilon_magnitude = math.log(abs(normalized_value), 2)
epsilon = 2**(epsilon_magnitude-53) epsilon = 2**(epsilon_magnitude-53)
normalized_value += cmp(normalized_value,0) * epsilon if rounding_method == 'HALF-UP':
rounded_value = round(normalized_value) # round to integer normalized_value += cmp(normalized_value,0) * epsilon
rounded_value = round(normalized_value) # round to integer
# TIE-BREAKING: UP (for ceiling operations)
# When rounding the value up, we instead subtract the epsilon value
# as the the approximation of the real value may be slightly *above* the
# tie limit, this would result in incorrectly rounding up to the next number
elif rounding_method == 'UP':
normalized_value -= cmp(normalized_value,0) * epsilon
rounded_value = math.ceil(normalized_value) # ceil to integer
result = rounded_value * rounding_factor # de-normalize result = rounded_value * rounding_factor # de-normalize
return result return result