[FIX] product: remove digits_precision from uom factor fields

Remove the hardcoded precision of 12 on factor and factor_inv,
to use the complete natural precision of NUMERIC types,
preserving all significant digits.

e.g. a UoM with a factor_inv of 6.0 used to be computed as:
factor_inv: 6.0 -> factor: 0.166666666667 (1.0/6.0, rounded to 12 digits) -> factor_inv: 5.999999999988 (1.0/factor)
which could lead to errors such 12*0.166666666667 = 2.000000000004 instead of 2.0

Slightly changed the way the ORM handles float fields to allow setting `digits=0`
as a way to explicitly require a NUMERIC value but without enforcing/rounding
the values at the ORM level, i.e. a truly full-precision field.

NUMERIC type has unlimited precision but is less efficient so should not be
used as the default behaviour, which is why we keep float8 as an alternative.

Modified the view to display the product UOM factor with a 5 digits value by default.
This value is for usability purpose only, the field still accepts bigger precision, by
setting the `digits` option on the field in the form view.

This change is safe in a stable series, the `digits=0` alternative is
treated the same as the default `digits=None` everywhere in the framework,
except when creating the database field.
This commit is contained in:
Cedric Snauwaert 2014-10-16 17:23:51 +02:00 committed by Olivier Dony
parent 7705f883d2
commit fa2f7b86bf
3 changed files with 10 additions and 5 deletions

View File

@ -132,10 +132,10 @@ class product_uom(osv.osv):
'name': fields.char('Unit of Measure', size=64, required=True, translate=True),
'category_id': fields.many2one('product.uom.categ', 'Category', required=True, ondelete='cascade',
help="Conversion between Units of Measure can only occur if they belong to the same category. The conversion will be made based on the ratios."),
'factor': fields.float('Ratio', required=True,digits=(12, 12),
'factor': fields.float('Ratio', required=True, digits=0, # force NUMERIC with unlimited precision
help='How much bigger or smaller this unit is compared to the reference Unit of Measure for this category:\n'\
'1 * (reference unit) = ratio * (this unit)'),
'factor_inv': fields.function(_factor_inv, digits=(12,12),
'factor_inv': fields.function(_factor_inv, digits=0, # force NUMERIC with unlimited precision
fnct_inv=_factor_inv_write,
string='Ratio',
help='How many times this Unit of Measure is bigger than the reference Unit of Measure in this category:\n'\

View File

@ -421,8 +421,8 @@
<field name="uom_type" on_change="onchange_type(uom_type)"/>
<label for="factor"/>
<div>
<field name="factor" attrs="{'invisible':[('uom_type','!=','smaller')]}"/>
<field name="factor_inv" attrs="{'invisible':[('uom_type','!=','bigger')]}"/>
<field name="factor" digits="[42,5]" attrs="{'invisible':[('uom_type','!=','smaller')]}"/>
<field name="factor_inv" digits="[42,5]" attrs="{'invisible':[('uom_type','!=','bigger')]}"/>
<p attrs="{'invisible':[('uom_type','!=','smaller')]}" class="oe_grey">
e.g: 1 * (reference unit) = ratio * (this unit)
</p>

View File

@ -592,7 +592,12 @@ def get_pg_type(f, type_override=None):
if field_type in FIELDS_TO_PGTYPES:
pg_type = (FIELDS_TO_PGTYPES[field_type], FIELDS_TO_PGTYPES[field_type])
elif issubclass(field_type, fields.float):
if f.digits:
# Explicit support for "falsy" digits (0, False) to indicate a
# NUMERIC field with no fixed precision. The values will be saved
# in the database with all significant digits.
# FLOAT8 type is still the default when there is no precision because
# it is faster for most operations (sums, etc.)
if f.digits is not None:
pg_type = ('numeric', 'NUMERIC')
else:
pg_type = ('float8', 'DOUBLE PRECISION')