details: https://code.tryton.org/tryton/commit/0e3f9c26b751
branch: default
user: Cédric Krier <[email protected]>
date: Wed Mar 11 10:01:51 2026 +0100
description:
Add notify_user to ModelStorage
Closes #14667
diffstat:
trytond/CHANGELOG | 1 +
trytond/doc/ref/models.rst | 5 +++++
trytond/doc/ref/transaction.rst | 2 ++
trytond/trytond/model/modelstorage.py | 20 ++++++++++++++++++++
trytond/trytond/res/notification.py | 2 +-
trytond/trytond/tests/test_modelstorage.py | 24 ++++++++++++++++++++++++
trytond/trytond/transaction.py | 18 ++++++++++++++++++
7 files changed, 71 insertions(+), 1 deletions(-)
diffs (181 lines):
diff -r db7cbffa9536 -r 0e3f9c26b751 trytond/CHANGELOG
--- a/trytond/CHANGELOG Wed Mar 11 10:01:22 2026 +0100
+++ b/trytond/CHANGELOG Wed Mar 11 10:01:51 2026 +0100
@@ -1,3 +1,4 @@
+* Add notify_user to ModelStorage
* Check button states when testing access
* Remove the files of Binary fields from the Filestore
* Add delete and delete_many to Filestore
diff -r db7cbffa9536 -r 0e3f9c26b751 trytond/doc/ref/models.rst
--- a/trytond/doc/ref/models.rst Wed Mar 11 10:01:22 2026 +0100
+++ b/trytond/doc/ref/models.rst Wed Mar 11 10:01:51 2026 +0100
@@ -356,6 +356,11 @@
Log event for records.
+
+.. classmethod:: ModelStorage.notify_user(records, icon, label[, description[,
user[, \**extra]]])
+
+ Notify user about records.
+
.. classmethod:: ModelStorage.preprocess_values(cls, mode, values)
Returns a copy of ``values`` to be used for :meth:`~ModelStorage.create` and
diff -r db7cbffa9536 -r 0e3f9c26b751 trytond/doc/ref/transaction.rst
--- a/trytond/doc/ref/transaction.rst Wed Mar 11 10:01:22 2026 +0100
+++ b/trytond/doc/ref/transaction.rst Wed Mar 11 10:01:51 2026 +0100
@@ -54,6 +54,8 @@
.. attribute:: Transaction.log_records
+.. attribute:: Transaction.user_notifications
+
.. attribute:: Transaction.check_warnings
The dictionary of warnings already checked with user and warning
diff -r db7cbffa9536 -r 0e3f9c26b751 trytond/trytond/model/modelstorage.py
--- a/trytond/trytond/model/modelstorage.py Wed Mar 11 10:01:22 2026 +0100
+++ b/trytond/trytond/model/modelstorage.py Wed Mar 11 10:01:51 2026 +0100
@@ -5,6 +5,7 @@
import csv
import datetime
import decimal
+import json
import math
import random
import time
@@ -245,6 +246,25 @@
resource=record, event=event, target=target,
user=user, **extra))
+ @dualmethod
+ def notify_user(
+ cls, records, icon, label, description=None, user=None, **extra):
+ pool = Pool()
+ Notification = pool.get('res.notification')
+ for transaction, sub_records in groupby(
+ records, lambda r: r._transaction):
+ with Transaction().set_current_transaction(transaction):
+ if user is None:
+ user = transaction.user
+ transaction.user_notifications.append(Notification(
+ user=user,
+ icon=icon,
+ label=label,
+ description=description,
+ model=cls.__name__,
+ records=json.dumps([r.id for r in records]),
+ **extra))
+
@classmethod
def preprocess_values(cls, mode, values):
assert mode in {'create', 'write'}
diff -r db7cbffa9536 -r 0e3f9c26b751 trytond/trytond/res/notification.py
--- a/trytond/trytond/res/notification.py Wed Mar 11 10:01:22 2026 +0100
+++ b/trytond/trytond/res/notification.py Wed Mar 11 10:01:51 2026 +0100
@@ -54,7 +54,7 @@
@classmethod
def __setup__(cls):
super().__setup__()
-
+ cls._order = [('id', 'DESC')]
cls.__rpc__.update({
'get': RPC(),
'get_count': RPC(),
diff -r db7cbffa9536 -r 0e3f9c26b751 trytond/trytond/tests/test_modelstorage.py
--- a/trytond/trytond/tests/test_modelstorage.py Wed Mar 11 10:01:22
2026 +0100
+++ b/trytond/trytond/tests/test_modelstorage.py Wed Mar 11 10:01:51
2026 +0100
@@ -743,6 +743,30 @@
Model.delete([record])
+ @with_transaction()
+ def test_notify_user(self):
+ "Test notify user"
+ pool = Pool()
+ Model = pool.get('test.modelstorage')
+ Notification = pool.get('res.notification')
+ transaction = Transaction()
+
+ record = Model(name="Foo")
+ record.save()
+
+ record.notify_user(
+ 'tryton-notification',
+ "Test notification",
+ "Long description")
+ transaction._store_user_notifications()
+
+ notification, = Notification.search([])
+
+ self.assertEqual(notification.user.id, transaction.user)
+ self.assertEqual(notification.icon, 'tryton-notification')
+ self.assertEqual(notification.label, "Test notification")
+ self.assertEqual(notification.description, "Long description")
+
class EvalEnvironmentTestCase(TestCase):
"Test EvalEnvironment"
diff -r db7cbffa9536 -r 0e3f9c26b751 trytond/trytond/transaction.py
--- a/trytond/trytond/transaction.py Wed Mar 11 10:01:22 2026 +0100
+++ b/trytond/trytond/transaction.py Wed Mar 11 10:01:51 2026 +0100
@@ -130,6 +130,7 @@
instance.delete_records = None
instance.trigger_records = None
instance.log_records = None
+ instance.user_notifications = None
instance.check_warnings = None
instance.timestamp = None
instance.started_at = None
@@ -198,6 +199,7 @@
self.delete_records = defaultdict(set)
self.trigger_records = defaultdict(set)
self.log_records = []
+ self.user_notifications = []
self.check_warnings = defaultdict(set)
self.timestamp = {}
self.counter = 0
@@ -265,6 +267,7 @@
self.delete_records = None
self.trigger_records = None
self.log_records = None
+ self.user_notifications = None
self.timestamp = None
self._datamanagers = []
@@ -340,6 +343,19 @@
if self.log_records:
self.log_records.clear()
+ def _store_user_notifications(self):
+ from trytond.pool import Pool
+ if self.user_notifications:
+ pool = Pool()
+ Notification = pool.get('res.notification')
+ with without_check_access():
+ Notification.save(self.user_notifications)
+ self._clear_user_notifications()
+
+ def _clear_user_notifications(self):
+ if self.user_notifications:
+ self.user_notifications.clear()
+
def _remove_warnings(self):
from trytond.pool import Pool
if self.check_warnings:
@@ -358,6 +374,7 @@
from trytond.cache import Cache
try:
self._store_log_records()
+ self._store_user_notifications()
self._remove_warnings()
if self._datamanagers:
for datamanager in self._datamanagers:
@@ -391,6 +408,7 @@
datamanager.tpc_abort(self)
Cache.rollback(self)
self._clear_log_records()
+ self._clear_user_notifications()
self._clear_warnings()
if self.connection:
self.connection.rollback()