diff --git a/CHANGELOG b/CHANGELOG
index 60fdc69178..7cb0841933 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,3 +1,4 @@
+* Forbid to decrease digits of unit of measure
* Add support for Python 3.10
* Remove support for Python 3.6
diff --git a/exceptions.py b/exceptions.py
index 609f13efbc..607e69d214 100644
--- a/exceptions.py
+++ b/exceptions.py
@@ -1,7 +1,7 @@
# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
-from trytond.model.exceptions import ValidationError
+from trytond.model.exceptions import AccessError, ValidationError
class TemplateValidationError(ValidationError):
@@ -16,5 +16,9 @@ class UOMValidationError(ValidationError):
pass
+class UOMAccessError(AccessError):
+ pass
+
+
class InvalidIdentifierCode(ValidationError):
pass
diff --git a/message.xml b/message.xml
index d8b1f2f10e..340ec37af8 100644
--- a/message.xml
+++ b/message.xml
@@ -12,6 +12,9 @@ this repository contains the full copyright notices and license terms. -->
You cannot modify the category of UOM "%(uom)s".
+
+ You cannot decrease the digits of UOM "%(uom)s".
+
If the UOM is still not used, you can delete it otherwise you can deactivate it and create a new one.
diff --git a/tests/test_product.py b/tests/test_product.py
index 27d4bc8021..78b8ac473d 100644
--- a/tests/test_product.py
+++ b/tests/test_product.py
@@ -11,6 +11,7 @@ from trytond.tests.test_tryton import (
ModuleTestCase, doctest_checker, doctest_teardown, with_transaction)
from trytond.transaction import Transaction
+from ..exceptions import UOMAccessError
from ..product import round_price
@@ -261,6 +262,57 @@ class ProductTestCase(CompanyTestMixin, ModuleTestCase):
Uom.compute_price(g, price, m3, **keys), result,
msg=msg)
+ @with_transaction()
+ def test_uom_modify_factor_rate(self):
+ "Test can not modify factor or rate of uom"
+ pool = Pool()
+ Uom = pool.get('product.uom')
+ g, = Uom.search([('name', '=', "Gram")])
+
+ g.factor = 1
+ g.rate = 1
+
+ with self.assertRaises(UOMAccessError):
+ g.save()
+
+ @with_transaction()
+ def test_uom_modify_category(self):
+ "Test can not modify category of uom"
+ pool = Pool()
+ Uom = pool.get('product.uom')
+ Category = pool.get('product.uom.category')
+ g, = Uom.search([('name', '=', "Gram")])
+ units, = Category.search([('name', '=', "Units")])
+
+ g.category = units
+
+ with self.assertRaises(UOMAccessError):
+ g.save()
+
+ @with_transaction()
+ def test_uom_increase_digits(self):
+ "Test can increase digits of uom"
+ pool = Pool()
+ Uom = pool.get('product.uom')
+ g, = Uom.search([('name', '=', "Gram")])
+
+ g.digits += 1
+
+ g.save()
+
+ @with_transaction()
+ def test_uom_decrease_digits(self):
+ "Test can not decrease digits of uom"
+ pool = Pool()
+ Uom = pool.get('product.uom')
+ g, = Uom.search([('name', '=', "Gram")])
+
+ g.digits -= 1
+ g.rounding = 1
+
+ with self.assertRaises(UOMAccessError):
+ g.save()
+
@with_transaction()
def test_product_search_domain(self):
'Test product.product search_domain function'
diff --git a/uom.py b/uom.py
index 74ee707a79..b636a6567e 100644
--- a/uom.py
+++ b/uom.py
@@ -9,11 +9,10 @@ from trytond.i18n import gettext
from trytond.model import (
Check, DeactivableMixin, DigitsMixin, ModelSQL, ModelView, SymbolMixin,
fields)
-from trytond.model.exceptions import AccessError
from trytond.pyson import Eval
from trytond.transaction import Transaction
-from .exceptions import UOMValidationError
+from .exceptions import UOMAccessError, UOMValidationError
__all__ = ['uom_conversion_digits']
@@ -153,26 +152,25 @@ class Uom(SymbolMixin, DigitsMixin, DeactivableMixin, ModelSQL, ModelView):
super(Uom, cls).write(*args)
return
- actions = iter(args)
- all_uoms = []
- for uoms, values in zip(actions, actions):
- if 'rate' not in values and 'factor' not in values \
- and 'category' not in values:
- continue
- all_uoms += uoms
-
- old_uom = dict((uom.id, (uom.factor, uom.rate, uom.category))
- for uom in all_uoms)
+ all_uoms = sum(args[0:None:2], [])
+ old_uom = {
+ uom.id: (uom.factor, uom.rate, uom.category) for uom in all_uoms}
+ old_digits = {uom.id: uom.digits for uom in all_uoms}
super(Uom, cls).write(*args)
for uom in all_uoms:
for i, field in enumerate(['factor', 'rate', 'category']):
if getattr(uom, field) != old_uom[uom.id][i]:
- raise AccessError(
+ raise UOMAccessError(
gettext('product.msg_uom_modify_%s' % field,
uom=uom.rec_name),
gettext('product.msg_uom_modify_options'))
+ if uom.digits < old_digits[uom.id]:
+ raise UOMAccessError(
+ gettext('product.msg_uom_decrease_digits',
+ uom=uom.rec_name),
+ gettext('product.msg_uom_modify_options'))
@property
def accurate_field(self):