details: https://code.tryton.org/tryton/commit/3aa32252dcb8
branch: default
user: Cédric Krier <[email protected]>
date: Tue Dec 02 19:24:36 2025 +0100
description:
Allow users to subscribe to notification cron jobs
Closes #13988
diffstat:
trytond/CHANGELOG | 1 +
trytond/doc/modules/ir/design/cron.inc.rst | 2 +
trytond/doc/modules/res/design.rst | 5 +-
trytond/trytond/ir/cron.py | 54 +++++++++++++++++++++-
trytond/trytond/res/user.py | 11 ++++
trytond/trytond/res/view/user_form.xml | 3 +
trytond/trytond/res/view/user_form_preferences.xml | 3 +
7 files changed, 76 insertions(+), 3 deletions(-)
diffs (195 lines):
diff -r 773f7f1ba3d5 -r 3aa32252dcb8 trytond/CHANGELOG
--- a/trytond/CHANGELOG Tue Dec 02 16:01:39 2025 +0100
+++ b/trytond/CHANGELOG Tue Dec 02 19:24:36 2025 +0100
@@ -1,3 +1,4 @@
+* Allow users to subscribe to notification cron jobs
* Add user notification
* Add support for materializing ModelSQL based on a table query
* Add an option to trytond-console to run a script file
diff -r 773f7f1ba3d5 -r 3aa32252dcb8 trytond/doc/modules/ir/design/cron.inc.rst
--- a/trytond/doc/modules/ir/design/cron.inc.rst Tue Dec 02 16:01:39
2025 +0100
+++ b/trytond/doc/modules/ir/design/cron.inc.rst Tue Dec 02 19:24:36
2025 +0100
@@ -4,6 +4,8 @@
====
The *Cron* stores the configuration for `scheduled actions <topics-cron>`.
+Some jobs can be set up to notify `Users <model-res.user>`, if so they will
+appear in the user preferences.
.. seealso::
diff -r 773f7f1ba3d5 -r 3aa32252dcb8 trytond/doc/modules/res/design.rst
--- a/trytond/doc/modules/res/design.rst Tue Dec 02 16:01:39 2025 +0100
+++ b/trytond/doc/modules/res/design.rst Tue Dec 02 19:24:36 2025 +0100
@@ -19,8 +19,9 @@
The login name is used when logging in to Tryton, along with other
authentication data, such as their password.
-It also contains a set of other properties that let you store additional
-information about the user, such as their name, email address, and language.
+It also contains a number of other properties that allow you to store
+additional information about the user, such as their name, email address,
+language and notifications to subscribe to.
Users can belong to `Groups <model-res.group>` which define, amongst other
things, their access rights.
diff -r 773f7f1ba3d5 -r 3aa32252dcb8 trytond/trytond/ir/cron.py
--- a/trytond/trytond/ir/cron.py Tue Dec 02 16:01:39 2025 +0100
+++ b/trytond/trytond/ir/cron.py Tue Dec 02 19:24:36 2025 +0100
@@ -6,6 +6,7 @@
import random
import time
from collections import defaultdict
+from itertools import groupby
from dateutil.relativedelta import relativedelta
from sql import Literal
@@ -14,6 +15,7 @@
from trytond import backend, config
from trytond.exceptions import UserError, UserWarning
+from trytond.i18n import gettext, ngettext
from trytond.model import (
DeactivableMixin, Index, ModelSQL, ModelView, dualmethod, fields)
from trytond.pool import Pool
@@ -113,6 +115,7 @@
},
})
cls._sql_indexes.add(Index(table, (table.next_call, Index.Range())))
+ cls._notifications = set()
@classmethod
def default_timezone(cls):
@@ -147,6 +150,17 @@
return running
@classmethod
+ def notifications(cls):
+ "Yield method and label which support user notification"
+ pool = Pool()
+ ModelAccess = pool.get('ir.model.access')
+ for method, label in cls.fields_get(['method'])['method']['selection']:
+ if method in cls._notifications:
+ model_name, _ = method.split('|')
+ if ModelAccess.check(model_name, raise_exception=False):
+ yield method, label
+
+ @classmethod
def view_attributes(cls):
return [(
'//label[@id="time_label"]', 'states', {
@@ -246,7 +260,8 @@
try:
if not database.has_select_for():
task.lock()
- with processing(name):
+ with processing(name), \
+ transaction.set_context(_cron=task.method):
task.run_once()
task.next_call = task.compute_next_call(now)
task.save()
@@ -293,6 +308,43 @@
transaction.rollback()
logger.info('cron finished for "%s"', db_name)
+ @classmethod
+ def notify(
+ cls, icon, action_id, action_value,
+ message_id, n=None, **variables):
+ "Notify subscribed users to the current cron task"
+ pool = Pool()
+ User = pool.get('res.user')
+ Notification = pool.get('res.notification')
+ ModelData = pool.get('ir.model.data')
+ transaction = Transaction()
+ if method := transaction.context.get('_cron'):
+ notifications = []
+ if action_id is not None:
+ action_id = ModelData.get_id(action_id)
+ users = User.search([
+ ('notifications', 'in', method),
+ ])
+ for language, users in groupby(
+ users, key=lambda u: u.language):
+ language = language.code if language else None
+ with transaction.set_context(language=language):
+ label = dict(cls.notifications()).get(method, method)
+ if n is None:
+ msg = gettext(message_id, **variables)
+ else:
+ msg = ngettext(message_id, n, **variables)
+ for user in users:
+ notifications.append(Notification(
+ user=user,
+ label=label,
+ description=msg,
+ icon=icon,
+ action=action_id,
+ action_value=action_value,
+ ))
+ Notification.save(notifications)
+
class Log(ModelSQL, ModelView):
__name__ = 'ir.cron.log'
diff -r 773f7f1ba3d5 -r 3aa32252dcb8 trytond/trytond/res/user.py
--- a/trytond/trytond/res/user.py Tue Dec 02 16:01:39 2025 +0100
+++ b/trytond/trytond/res/user.py Tue Dec 02 19:24:36 2025 +0100
@@ -142,6 +142,10 @@
language_direction = fields.Function(fields.Char('Language Direction'),
'get_language_direction')
email = fields.Char('Email')
+ notifications = fields.MultiSelection(
+ 'get_notifications', "Notifications",
+ help="Notifications to subscribe to.")
+
status_bar = fields.Function(fields.Char('Status Bar'), 'get_status_bar')
avatar_badge_url = fields.Function(
fields.Char("Avatar Badge URL"), 'get_avatar_badge_url')
@@ -183,6 +187,7 @@
'avatar_badge_url',
'warnings',
'applications',
+ 'notifications',
]
cls._context_fields = [
'language',
@@ -329,6 +334,12 @@
return result
@classmethod
+ def get_notifications(cls):
+ pool = Pool()
+ Cron = pool.get('ir.cron')
+ return list(Cron.notifications())
+
+ @classmethod
def preprocess_values(cls, mode, values):
pool = Pool()
Action = pool.get('ir.action')
diff -r 773f7f1ba3d5 -r 3aa32252dcb8 trytond/trytond/res/view/user_form.xml
--- a/trytond/trytond/res/view/user_form.xml Tue Dec 02 16:01:39 2025 +0100
+++ b/trytond/trytond/res/view/user_form.xml Tue Dec 02 19:24:36 2025 +0100
@@ -37,6 +37,9 @@
<page string="Preferences" col="2" id="preferences">
<label name="language"/>
<field name="language" widget="selection"/>
+
+ <label name="notifications"/>
+ <field name="notifications"/>
</page>
</notebook>
</form>
diff -r 773f7f1ba3d5 -r 3aa32252dcb8
trytond/trytond/res/view/user_form_preferences.xml
--- a/trytond/trytond/res/view/user_form_preferences.xml Tue Dec 02
16:01:39 2025 +0100
+++ b/trytond/trytond/res/view/user_form_preferences.xml Tue Dec 02
19:24:36 2025 +0100
@@ -32,6 +32,9 @@
<page string="Preferences" col="2" id="preferences">
<label name="language"/>
<field name="language" widget="selection"/>
+
+ <label name="notifications"/>
+ <field name="notifications"/>
</page>
</notebook>
</form>