details: https://code.tryton.org/tryton/commit/8f2189c7f348
branch: 7.6
user: Cédric Krier <[email protected]>
date: Thu Jan 15 17:20:32 2026 +0100
description:
Do not convert input when converting between the same unit
Applying the factor/rate twice may loose precision if one of the number
is a
rational with recurring decimal.
Closes #14501
(grafted from 09e3674f3ffe90f74cf2bc8a9884e885b28c93b8)
diffstat:
modules/product/tests/test_module.py | 2 +
modules/product/uom.py | 72 +++++++++++++++++++----------------
2 files changed, 41 insertions(+), 33 deletions(-)
diffs (115 lines):
diff -r 8d0862f093c7 -r 8f2189c7f348 modules/product/tests/test_module.py
--- a/modules/product/tests/test_module.py Thu Jan 15 17:28:20 2026 +0100
+++ b/modules/product/tests/test_module.py Thu Jan 15 17:20:32 2026 +0100
@@ -130,6 +130,7 @@
tests = [
('Kilogram', 100, 'Gram', 100000, 100000),
('Gram', 1, 'Pound', 0.0022046226218487759, 0.0),
+ ('Ounce', 1 / 7, 'Ounce', 1 / 7, 0.14),
('Second', 5, 'Minute', 0.083333333333333343, 0.08),
('Second', 25, 'Hour', 0.0069444444444444441, 0.01),
('Millimeter', 3, 'Inch', 0.11811023622047245, 0.12),
@@ -201,6 +202,7 @@
tests = [
('Kilogram', Decimal('100'), 'Gram', Decimal('0.1')),
('Gram', Decimal('1'), 'Pound', Decimal('453.59237')),
+ ('Ounce', Decimal(1 / 7), 'Ounce', Decimal(1 / 7)),
('Second', Decimal('5'), 'Minute', Decimal('300')),
('Second', Decimal('25'), 'Hour', Decimal('90000')),
('Millimeter', Decimal('3'), 'Inch', Decimal('76.2')),
diff -r 8d0862f093c7 -r 8f2189c7f348 modules/product/uom.py
--- a/modules/product/uom.py Thu Jan 15 17:28:20 2026 +0100
+++ b/modules/product/uom.py Thu Jan 15 17:20:32 2026 +0100
@@ -206,25 +206,28 @@
elif factor or rate:
raise ValueError("factor and rate not allowed for same category")
- if from_uom.accurate_field == 'factor':
- amount = qty * from_uom.factor
- else:
- amount = qty / from_uom.rate
-
- if factor and rate:
- if _accurate_operator(factor, rate) == 'rate':
- factor = None
+ if from_uom != to_uom:
+ if from_uom.accurate_field == 'factor':
+ amount = qty * from_uom.factor
else:
- rate = None
- if factor:
- amount *= factor
- elif rate:
- amount /= rate
+ amount = qty / from_uom.rate
- if to_uom.accurate_field == 'factor':
- amount = amount / to_uom.factor
+ if factor and rate:
+ if _accurate_operator(factor, rate) == 'rate':
+ factor = None
+ else:
+ rate = None
+ if factor:
+ amount *= factor
+ elif rate:
+ amount /= rate
+
+ if to_uom.accurate_field == 'factor':
+ amount = amount / to_uom.factor
+ else:
+ amount = amount * to_uom.rate
else:
- amount = amount * to_uom.rate
+ amount = qty
if round:
amount = to_uom.round(amount)
@@ -254,27 +257,30 @@
elif factor or rate:
raise ValueError("factor and rate not allow for same category")
- format_ = '%%.%df' % uom_conversion_digits[1]
+ if from_uom != to_uom:
+ format_ = '%%.%df' % uom_conversion_digits[1]
- if from_uom.accurate_field == 'factor':
- new_price = price / Decimal(format_ % from_uom.factor)
- else:
- new_price = price * Decimal(format_ % from_uom.rate)
-
- if factor and rate:
- if _accurate_operator(factor, rate) == 'rate':
- factor = None
+ if from_uom.accurate_field == 'factor':
+ new_price = price / Decimal(format_ % from_uom.factor)
else:
- rate = None
- if factor:
- new_price /= Decimal(factor)
- elif rate:
- new_price *= Decimal(rate)
+ new_price = price * Decimal(format_ % from_uom.rate)
- if to_uom.accurate_field == 'factor':
- new_price = new_price * Decimal(format_ % to_uom.factor)
+ if factor and rate:
+ if _accurate_operator(factor, rate) == 'rate':
+ factor = None
+ else:
+ rate = None
+ if factor:
+ new_price /= Decimal(factor)
+ elif rate:
+ new_price *= Decimal(rate)
+
+ if to_uom.accurate_field == 'factor':
+ new_price = new_price * Decimal(format_ % to_uom.factor)
+ else:
+ new_price = new_price / Decimal(format_ % to_uom.rate)
else:
- new_price = new_price / Decimal(format_ % to_uom.rate)
+ new_price = price
return new_price