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
This commit is contained in:
Cédric Krier
2026-01-15 17:20:32 +01:00
parent 212d6e5a45
commit ededbdb3c9
2 changed files with 41 additions and 33 deletions
+2
View File
@@ -130,6 +130,7 @@ class ProductTestCase(CompanyTestMixin, ModuleTestCase):
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 @@ class ProductTestCase(CompanyTestMixin, ModuleTestCase):
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')),
+39 -33
View File
@@ -206,25 +206,28 @@ class Uom(SymbolMixin, DigitsMixin, DeactivableMixin, ModelSQL, ModelView):
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 @@ class Uom(SymbolMixin, DigitsMixin, DeactivableMixin, ModelSQL, ModelView):
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