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>

Reply via email to