Skip to content

Commit 7ae238b

Browse files
committed
Add a sticky notification in the webclient
1 parent 2eafb6a commit 7ae238b

File tree

6 files changed

+94
-19
lines changed

6 files changed

+94
-19
lines changed

base_notification/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
1-
# from . import models
1+
from . import models
2+
23
# from .hooks import post_init_hook

base_notification/__manifest__.py

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,21 @@
55
"version": "16.0.1.0.0",
66
"author": "Kencove, Odoo Community Association (OCA)",
77
"website": "https://github.com/OCA/server-tools",
8-
# "category": "Tools",
8+
"category": "Tools",
99
"license": "LGPL-3",
10-
# "depends": ["base", "mail"],
11-
# "data": [
12-
# "security/ir.model.access.csv",
13-
# "data/base_notification_data.xml",
14-
# "views/base_notification_rule_views.xml",
15-
# ],
10+
"depends": ["base", "mail"],
11+
"data": [
12+
"security/ir.model.access.csv",
13+
"views/base_notification_rule_views.xml",
14+
],
15+
"demo": [
16+
"demo/base_notification_data.xml",
17+
],
18+
"assets": {
19+
"web.assets_backend": [
20+
"base_notification/static/src/js/base_notification_service.esm.js",
21+
],
22+
},
1623
# "post_init_hook": "post_init_hook",
1724
# "installable": True,
1825
# "application": False,

base_notification/data/base_notification_data.xml renamed to base_notification/demo/base_notification_data.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<odoo>
1+
<odoo noupdate="1">
22
<record id="base_notification_rule_demo" model="base.notification.rule">
33
<field name="name">Demo: Notify on Partner Create</field>
44
<field name="model_id" ref="base.model_res_partner" />

base_notification/models/base_notification_rule.py

Lines changed: 39 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import logging
22

3-
from odoo import fields, models
3+
from odoo import _, api, fields, models
44
from odoo.tools.safe_eval import safe_eval
55

66
_logger = logging.getLogger(__name__)
@@ -18,6 +18,9 @@ class BaseNotificationRule(models.Model):
1818
required=True,
1919
ondelete="cascade",
2020
)
21+
model = fields.Char(
22+
related="model_id.model",
23+
)
2124
trigger = fields.Selection(
2225
[
2326
("on_create", "On Create"),
@@ -41,11 +44,23 @@ class BaseNotificationRule(models.Model):
4144
partner_ids = fields.Many2many("res.partner", string="Recipients")
4245
template_id = fields.Many2one("mail.template", string="Mail Template")
4346

44-
def _execute_notification(self, records):
47+
@api.model
48+
def notify_changes(self, partner_ids, message):
49+
"""Send notification to partner_ids."""
50+
channel = "base_notification_updates"
51+
for partner_id in partner_ids:
52+
self.env["bus.bus"]._sendone(
53+
partner_id,
54+
channel,
55+
{
56+
"message": message,
57+
},
58+
)
59+
60+
def _execute_notification(self, records, message):
4561
"""Send the configured notification."""
4662
if not self.active or not records:
4763
return
48-
4964
if self.domain:
5065
try:
5166
domain = safe_eval(self.domain)
@@ -54,18 +69,32 @@ def _execute_notification(self, records):
5469
_logger.warning(
5570
f"Invalid domain in rule {self.name}: {self.domain} ({e})"
5671
)
57-
5872
for rec in records:
5973
if not rec.exists():
6074
continue
61-
6275
if self.template_id:
63-
self.template_id.send_mail(rec.id, force_send=True)
76+
self.template_id.with_context(
77+
mail_post_autofollow=False,
78+
mail_create_nosubscribe=True,
79+
).send_mail(rec.id, force_send=True)
6480
else:
65-
rec.message_post(
66-
body=f"🔔 Notification: {self.name}",
81+
rec.with_context(mail_post_autofollow=False).message_post(
82+
body=message,
6783
partner_ids=self.partner_ids.ids,
6884
)
85+
self.notify_changes(self.partner_ids, message)
86+
87+
def _get_notification_message(self):
88+
self.ensure_one()
89+
model = self.env["ir.model"].search([("model", "=", self.model)])
90+
message = _(
91+
"Event: %(trigger)s for model: %(model_name)s with ID: %(id)d was triggered"
92+
) % {
93+
"trigger": self.trigger,
94+
"model_name": model.name,
95+
"id": self.id,
96+
}
97+
return message
6998

7099
def _apply_trigger(self, event_type, records):
71100
"""Called by create/write/unlink hooks."""
@@ -77,4 +106,5 @@ def _apply_trigger(self, event_type, records):
77106
]
78107
)
79108
for rule in rules:
80-
rule._execute_notification(records)
109+
message = rule._get_notification_message()
110+
rule._execute_notification(records, message)
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/** @odoo-module **/
2+
/* Copyright 2025 Kencove - Mohamed Alkobrosli
3+
* License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). */
4+
5+
import {registry} from "@web/core/registry";
6+
7+
export const watchBaseNotificationsService = {
8+
dependencies: ["bus_service", "notification"],
9+
async start(env, {bus_service, notification}) {
10+
bus_service.addEventListener("notification", ({detail: notifications}) => {
11+
for (const notif of notifications) {
12+
if (notif.type === "base_notification_updates") {
13+
const message =
14+
notif.payload && notif.payload.message
15+
? notif.payload.message
16+
: notif.payload;
17+
notification.add(message, {
18+
title: env._t("Notification"),
19+
type: "info",
20+
sticky: true,
21+
});
22+
}
23+
}
24+
});
25+
await bus_service.addChannel("base_notification_updates");
26+
await bus_service.start();
27+
},
28+
};
29+
30+
registry
31+
.category("services")
32+
.add("watchBaseNotifications", watchBaseNotificationsService);

base_notification/views/base_notification_rule_views.xml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,14 +48,19 @@
4848
</group>
4949
<group>
5050
<field name="model_id" />
51+
<field name="model" invisible="1" />
5152
<field name="trigger" />
5253
<field
5354
name="method_name"
5455
attrs="{'invisible': [('trigger', '!=', 'on_method_call')]}"
5556
/>
5657
</group>
5758
<group>
58-
<field name="domain" />
59+
<field
60+
name="domain"
61+
widget="domain"
62+
options="{'model': 'model'}"
63+
/>
5964
<field name="notify_mode" />
6065
</group>
6166
<group>

0 commit comments

Comments
 (0)