Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
111 changes: 111 additions & 0 deletions uom_rounding_coherence/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
======================
UoM Rounding Coherence
======================

..
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:d646eddf3ef1d6ff89719e1651d153ab196194e731190ebbcaa2e135d9ff4a8e
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png
:target: https://odoo-community.org/page/development-status
:alt: Beta
.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
:alt: License: AGPL-3
.. |badge3| image:: https://img.shields.io/badge/github-NuoBiT%2Fodoo--addons-lightgray.png?logo=github
:target: https://github.com/NuoBiT/odoo-addons/tree/18.0/uom_rounding_coherence
:alt: NuoBiT/odoo-addons

|badge1| |badge2| |badge3|

This module adds validation to ensure that Unit of Measure (UoM)
rounding precision is coherent with the conversion ratio to the
reference unit, preventing precision loss during conversions.

When converting quantities between UoMs in the same category, a
non-reference UoM whose rounding is too coarse relative to its
conversion factor will lose precision beyond the reference UoM's
rounding.

**Example Problem:**

If the reference UoM has rounding 0.001 and a secondary UoM with ratio
1.141 has rounding 0.01, each conversion can introduce up to ±0.004
error in reference units — enough to accumulate visible discrepancies
over multiple transactions.

**The Validation:**

The module checks that converting the UoM's rounding step to reference
units (rounding / factor) does not exceed the reference UoM's rounding.
This ensures data consistency and prevents precision-related errors.

**Table of contents**

.. contents::
:local:

Configuration
=============

No configuration is needed. The module automatically validates UoM
rounding coherence when you create or modify UoMs.

Usage
=====

When creating or modifying Units of Measure:

1. Go to *Inventory > Configuration > UoM Categories*
2. Create or edit a UoM
3. If the rounding precision is too coarse for the conversion ratio, the
system will show a validation error
4. The error message will indicate:

- The UoM with the problem
- Its current rounding value
- The conversion factor
- The effective rounding in reference units
- The reference unit and its rounding

5. To fix the error, either:

- Decrease the rounding of the problematic UoM, or
- Increase the rounding of the reference UoM (if appropriate)

Bug Tracker
===========

Bugs are tracked on `GitHub Issues <https://github.com/NuoBiT/odoo-addons/issues>`_.
In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us to smash it by providing a detailed and welcomed
`feedback <https://github.com/NuoBiT/odoo-addons/issues/new?body=module:%20uom_rounding_coherence%0Aversion:%2018.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.

Do not contact contributors directly about support or help with technical issues.

Credits
=======

Authors
-------

* NuoBiT Solutions SL

Contributors
------------

- `NuoBiT <https://www.nuobit.com>`__:

- Eric Antones eantones@nuobit.com
- Deniz Gallo dgallo@nuobit.com

Maintainers
-----------

This module is part of the `NuoBiT/odoo-addons <https://github.com/NuoBiT/odoo-addons/tree/18.0/uom_rounding_coherence>`_ project on GitHub.

You are welcome to contribute.
1 change: 1 addition & 0 deletions uom_rounding_coherence/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import models
15 changes: 15 additions & 0 deletions uom_rounding_coherence/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Copyright 2026 NuoBiT Solutions SL - Eric Antones <eantones@nuobit.com>
# Copyright 2026 NuoBiT Solutions SL - Deniz Gallo <dgallo@nuobit.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl)

{
"name": "UoM Rounding Coherence",
"summary": "Validates that UoM rounding precision is coherent"
" with the conversion ratio to prevent precision loss",
"version": "18.0.1.0.0",
"author": "NuoBiT Solutions SL",
"website": "https://github.com/NuoBiT/odoo-addons",
"category": "Product",
"depends": ["uom"],
"license": "AGPL-3",
}
47 changes: 47 additions & 0 deletions uom_rounding_coherence/i18n/ca.po
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * uom_rounding_coherence
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 18.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-02-17 00:00+0000\n"
"PO-Revision-Date: 2026-02-17 00:00+0000\n"
"Last-Translator: \n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: \n"

#. module: uom_rounding_coherence
#: code:addons/uom_rounding_coherence/models/uom_uom.py:0
#, python-format
msgid ""
"Cannot validate rounding coherence for category '%(category)s': expected "
"exactly one active reference unit of measure but found %(count)s."
msgstr ""
"No es pot validar la coherència d'arrodoniment per a la categoria "
"'%(category)s': s'esperava exactament una unitat de mesura de referència "
"activa però se n'han trobat %(count)s."

#. module: uom_rounding_coherence
#: code:addons/uom_rounding_coherence/models/uom_uom.py:0
#, python-format
msgid ""
"The rounding precision of '%(uom)s' (%(uom_rounding)s) is too coarse for "
"its conversion ratio (%(factor)s). When converted to the reference unit "
"'%(ref)s', the effective rounding becomes %(effective)s, which exceeds the "
"reference rounding of %(ref_rounding)s.\n"
"\n"
"To fix this, either decrease the rounding of '%(uom)s' or increase the "
"rounding of '%(ref)s'."
msgstr ""
"La precisió d'arrodoniment de '%(uom)s' (%(uom_rounding)s) és massa "
"gruixuda per al seu ràtio de conversió (%(factor)s). En convertir a la "
"unitat de referència '%(ref)s', l'arrodoniment efectiu és %(effective)s, "
"que excedeix l'arrodoniment de referència de %(ref_rounding)s.\n"
"\n"
"Per solucionar-ho, disminuïu l'arrodoniment de '%(uom)s' o augmenteu "
"l'arrodoniment de '%(ref)s'."
47 changes: 47 additions & 0 deletions uom_rounding_coherence/i18n/es.po
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * uom_rounding_coherence
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 18.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-02-17 00:00+0000\n"
"PO-Revision-Date: 2026-02-17 00:00+0000\n"
"Last-Translator: \n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: \n"

#. module: uom_rounding_coherence
#: code:addons/uom_rounding_coherence/models/uom_uom.py:0
#, python-format
msgid ""
"Cannot validate rounding coherence for category '%(category)s': expected "
"exactly one active reference unit of measure but found %(count)s."
msgstr ""
"No se puede validar la coherencia de redondeo para la categoría "
"'%(category)s': se esperaba exactamente una unidad de medida de referencia "
"activa pero se encontraron %(count)s."

#. module: uom_rounding_coherence
#: code:addons/uom_rounding_coherence/models/uom_uom.py:0
#, python-format
msgid ""
"The rounding precision of '%(uom)s' (%(uom_rounding)s) is too coarse for "
"its conversion ratio (%(factor)s). When converted to the reference unit "
"'%(ref)s', the effective rounding becomes %(effective)s, which exceeds the "
"reference rounding of %(ref_rounding)s.\n"
"\n"
"To fix this, either decrease the rounding of '%(uom)s' or increase the "
"rounding of '%(ref)s'."
msgstr ""
"La precisión de redondeo de '%(uom)s' (%(uom_rounding)s) es demasiado "
"gruesa para su ratio de conversión (%(factor)s). Al convertir a la unidad "
"de referencia '%(ref)s', el redondeo efectivo es %(effective)s, que excede "
"el redondeo de referencia de %(ref_rounding)s.\n"
"\n"
"Para solucionarlo, disminuya el redondeo de '%(uom)s' o aumente el "
"redondeo de '%(ref)s'."
1 change: 1 addition & 0 deletions uom_rounding_coherence/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import uom_uom
83 changes: 83 additions & 0 deletions uom_rounding_coherence/models/uom_uom.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
# Copyright 2026 NuoBiT Solutions SL - Eric Antones <eantones@nuobit.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl)

from odoo import _, api, models, tools
from odoo.exceptions import ValidationError


class UoM(models.Model):
_inherit = "uom.uom"

@api.constrains("rounding", "factor", "uom_type", "category_id")
def _check_rounding_factor_coherence(self):
"""Ensure UoM rounding is fine enough relative to the conversion ratio.

When converting quantities between UoMs in the same category,
a non-reference UoM whose rounding is too coarse relative to
its conversion factor will lose precision beyond the reference
UoM's rounding. For example, if the reference UoM has rounding
0.001 and a secondary UoM with ratio 1.141 has rounding 0.01,
each conversion can introduce up to ±0.004 error in reference
units — enough to accumulate visible discrepancies over
multiple transactions.

The check: converting the UoM's rounding step to reference units
(rounding / factor) must not exceed the reference UoM's rounding.
"""
categories = self.mapped("category_id")
for category in categories:
uoms = self.env["uom.uom"].search(
[
("category_id", "=", category.id),
("active", "=", True),
]
)
ref_uom = uoms.filtered(lambda u: u.uom_type == "reference")
if len(ref_uom) != 1:
raise ValidationError(
_(
"Cannot validate rounding coherence for "
"category '%(category)s': expected exactly one "
"active reference unit of measure but found "
"%(count)s."
)
% {
"category": category.name,
"count": len(ref_uom),
}
)
for uom in uoms - ref_uom:
# Convert this UoM's rounding to reference units
# Using the same formula as _compute_quantity:
# amount = qty / self.factor * to_unit.factor
# Since ref_uom.factor = 1.0:
# rounding_in_ref = uom.rounding / uom.factor
rounding_in_ref = uom.rounding / uom.factor
if (
tools.float_compare(
rounding_in_ref,
ref_uom.rounding,
precision_rounding=ref_uom.rounding,
)
> 0
):
raise ValidationError(
_(
"The rounding precision of '%(uom)s' (%(uom_rounding)s) "
"is too coarse for its conversion ratio (%(factor)s). "
"When converted to the reference unit '%(ref)s', "
"the effective rounding becomes %(effective)s, "
"which exceeds the reference rounding of "
"%(ref_rounding)s.\n\n"
"To fix this, either decrease the rounding of "
"'%(uom)s' or increase the rounding of '%(ref)s'."
)
% {
"uom": uom.name,
"uom_rounding": uom.rounding,
"factor": uom.factor,
"ref": ref_uom.name,
"effective": rounding_in_ref,
"ref_rounding": ref_uom.rounding,
}
)
3 changes: 3 additions & 0 deletions uom_rounding_coherence/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[build-system]
requires = ["whool"]
build-backend = "whool.buildapi"
2 changes: 2 additions & 0 deletions uom_rounding_coherence/readme/CONFIGURE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
No configuration is needed. The module automatically validates UoM
rounding coherence when you create or modify UoMs.
3 changes: 3 additions & 0 deletions uom_rounding_coherence/readme/CONTRIBUTORS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
- [NuoBiT](https://www.nuobit.com):
- Eric Antones <eantones@nuobit.com>
- Deniz Gallo <dgallo@nuobit.com>
21 changes: 21 additions & 0 deletions uom_rounding_coherence/readme/DESCRIPTION.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
This module adds validation to ensure that Unit of Measure (UoM)
rounding precision is coherent with the conversion ratio to the
reference unit, preventing precision loss during conversions.

When converting quantities between UoMs in the same category, a
non-reference UoM whose rounding is too coarse relative to its
conversion factor will lose precision beyond the reference UoM's
rounding.

**Example Problem:**

If the reference UoM has rounding 0.001 and a secondary UoM with ratio
1.141 has rounding 0.01, each conversion can introduce up to ±0.004
error in reference units — enough to accumulate visible discrepancies
over multiple transactions.

**The Validation:**

The module checks that converting the UoM's rounding step to reference
units (rounding / factor) does not exceed the reference UoM's rounding.
This ensures data consistency and prevents precision-related errors.
15 changes: 15 additions & 0 deletions uom_rounding_coherence/readme/USAGE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
When creating or modifying Units of Measure:

1. Go to *Inventory \> Configuration \> UoM Categories*
2. Create or edit a UoM
3. If the rounding precision is too coarse for the conversion ratio,
the system will show a validation error
4. The error message will indicate:
- The UoM with the problem
- Its current rounding value
- The conversion factor
- The effective rounding in reference units
- The reference unit and its rounding
5. To fix the error, either:
- Decrease the rounding of the problematic UoM, or
- Increase the rounding of the reference UoM (if appropriate)
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Loading