From 476065cf11c4298ed58aa72b57ff59c59e49bef3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Thu, 27 Nov 2025 16:26:20 +0100 Subject: [PATCH] Use creation position to format warning key for new records The opposite position in the creation order is used instead of the id (which is not stable over transaction retries) to format the warning key when the record has been created during the transaction. This ensures that the formatting of the warning key is stable over transaction retries. Closes #10591 --- trytond/doc/ref/transaction.rst | 8 ++++++++ trytond/trytond/model/modelsql.py | 2 +- trytond/trytond/model/modelstorage.py | 2 +- trytond/trytond/res/user.py | 12 +++++++++++- trytond/trytond/tests/test_res.py | 15 +++++++++++++++ trytond/trytond/transaction.py | 2 +- 6 files changed, 37 insertions(+), 4 deletions(-) diff --git a/trytond/doc/ref/transaction.rst b/trytond/doc/ref/transaction.rst index 693a88d0a8..6008a66141 100644 --- a/trytond/doc/ref/transaction.rst +++ b/trytond/doc/ref/transaction.rst @@ -40,8 +40,16 @@ Transaction .. attribute:: Transaction.create_records + A :py:class:`defaultdict ` storing for each + :attr:`~trytond.model.Model.__name__` a :py:class:`list` of ids created + during the transaction. + .. attribute:: Transaction.delete_records + A :py:class:`defaultdict ` storing for each + :attr:`~trytond.model.Model.__name__` a :py:class:`set` of ids deleted + during the transaction. + .. attribute:: Transaction.trigger_records .. attribute:: Transaction.check_warnings diff --git a/trytond/trytond/model/modelsql.py b/trytond/trytond/model/modelsql.py index a2777c84e1..d2f64f2433 100644 --- a/trytond/trytond/model/modelsql.py +++ b/trytond/trytond/model/modelsql.py @@ -2312,7 +2312,7 @@ class ModelSQL(ModelStorage): def lock(cls, records=None): transaction = Transaction() if records is not None: - new_ids = transaction.create_records[cls.__name__] + new_ids = set(transaction.create_records[cls.__name__]) ids = [id_ for id_ in map(int, records) if id_ not in new_ids] transaction.lock_records(cls._table, ids) else: diff --git a/trytond/trytond/model/modelstorage.py b/trytond/trytond/model/modelstorage.py index e4891ebf6b..669cfbb4e0 100644 --- a/trytond/trytond/model/modelstorage.py +++ b/trytond/trytond/model/modelstorage.py @@ -299,7 +299,7 @@ class ModelStorage(Model): for trigger in triggers: trigger.queue_trigger_action(records) - transaction.create_records[cls.__name__].update(ids) + transaction.create_records[cls.__name__].extend(ids) return ids @classmethod diff --git a/trytond/trytond/res/user.py b/trytond/trytond/res/user.py index 8dbfb2be60..2c3aaf0bfe 100644 --- a/trytond/trytond/res/user.py +++ b/trytond/trytond/res/user.py @@ -964,7 +964,17 @@ class Warning_(ModelSQL, ModelView): @classmethod def format(cls, name, records): - key = '|'.join(map(str, records)).encode('utf-8') + create_records = Transaction().create_records + + def str_(record): + name = record.__name__ + try: + # start from 1 to avoid 0 == -0 + i = create_records[name].index(record.id) + 1 + return '%s,%s' % (name, -i) + except ValueError: + return str(record) + key = '|'.join(map(str_, records)).encode('utf-8') return '%s.%s' % (hashlib.md5(key).hexdigest(), name) @classmethod diff --git a/trytond/trytond/tests/test_res.py b/trytond/trytond/tests/test_res.py index 266129bcdc..70ececa945 100644 --- a/trytond/trytond/tests/test_res.py +++ b/trytond/trytond/tests/test_res.py @@ -82,5 +82,20 @@ class ResTestCase(ModuleTestCase): self.assertFalse(Warning_.check('test')) self.assertFalse(Warning_.check('test')) + @with_transaction() + def test_user_warning_format(self): + "Test format of user warning" + pool = Pool() + Warning_ = pool.get('res.user.warning') + Record = pool.get('res.user') + transaction = Transaction() + + key1 = Warning_.format('test', [Record(1)]) + + transaction.create_records[Record.__name__].append(1) + key2 = Warning_.format('test', [Record(1)]) + + self.assertNotEqual(key1, key2) + del ModuleTestCase diff --git a/trytond/trytond/transaction.py b/trytond/trytond/transaction.py index bf73401ec0..fb539d565e 100644 --- a/trytond/trytond/transaction.py +++ b/trytond/trytond/transaction.py @@ -197,7 +197,7 @@ class Transaction(object): self.readonly = readonly self.close = close self.context = ImmutableDict(context or {}) - self.create_records = defaultdict(set) + self.create_records = defaultdict(list) self.delete_records = defaultdict(set) self.trigger_records = defaultdict(set) self.log_records = []