[IMP] mail: display scheduled_datetime of delayed notify in chatter

Followup of odoo/odoo#95623 (introduce scheduled message notification) as well
as odoo/odoo#99482 (support scheduled datetime from template to composer in
both comment and mailing modes).

Task-3093257 (Mail: The Composer Update)

Part-of: odoo/odoo#107356
This commit is contained in:
Thibault Delavallée
2023-01-27 19:56:09 +01:00
parent 40456d7445
commit 8a66cc7db0
11 changed files with 99 additions and 13 deletions
+3
View File
@@ -15,6 +15,9 @@ You can track your vendors, customers and other contacts.
'data': [
'views/contact_views.xml',
],
'demo': [
'data/mail_demo.xml',
],
'application': True,
'license': 'LGPL-3',
'assets': {
+19
View File
@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo><data noupdate="1">
<!-- Message with scheduled notification -->
<record id="message_demo_partner_2_0" model="mail.message">
<field name="author_id" ref="base.partner_demo"/>
<field name="body" type="html"><p>Hello! Could you send us your address ?</p></field>
<field name="date" eval="(DateTime.today() - timedelta(days=1)).strftime('%Y-%m-%d %H:%M:00')"/>
<field name="model">res.partner</field>
<field name="res_id" ref="base.res_partner_2"/>
<field name="message_type">email</field>
<field name="subtype_id" ref="mail.mt_comment"/>
</record>
<record id="message_demo_partner_1_5_notif_0" model="mail.message.schedule">
<field name="mail_message_id" ref="message_demo_partner_2_0"/>
<field name="scheduled_datetime" eval="(DateTime.today() + timedelta(days=2)).strftime('%Y-%m-%d %H:%M:00')"/>
</record>
</data></odoo>
+1
View File
@@ -73,6 +73,7 @@ class TestImLivechatMessage(TransactionCase):
'recipients': [],
'record_name': "test1 Ernest Employee",
'res_id': channel_livechat_1.id,
'scheduledDatetime': False,
'sms_ids': [],
'starred_partner_ids': [],
'subject': False,
+25 -4
View File
@@ -904,10 +904,17 @@ class Message(models.Model):
domain = expression.AND([domain, [('id', '>', min_id)]])
return self.search(domain, limit=limit)
def message_format(self, format_reply=True):
""" Get the message values in the format for web client. Since message values can be broadcasted,
computed fields MUST NOT BE READ and broadcasted.
:returns list(dict).
def message_format(self, format_reply=True, msg_vals=None):
""" Get the message values in the format for web client. Since message
values can be broadcasted, computed fields MUST NOT BE READ and
broadcasted.
:param msg_vals: dictionary of values used to create the message. If
given it may be used to access values related to ``message`` without
accessing it directly. It lessens query count in some optimized use
cases by avoiding access message content in db;
:returns list(dict).
Example :
{
'body': HTML content of the message
@@ -958,6 +965,19 @@ class Message(models.Model):
com_id = self.env['ir.model.data']._xmlid_to_res_id('mail.mt_comment')
note_id = self.env['ir.model.data']._xmlid_to_res_id('mail.mt_note')
# fetch scheduled notifications once, only if msg_vals is not given to
# avoid useless queries when notifying Inbox right after a message_post
scheduled_dt_by_msg_id = {}
if msg_vals:
scheduled_dt_by_msg_id = {msg.id: msg_vals.get('scheduled_date') for msg in self}
elif self:
schedulers = self.env['mail.message.schedule'].sudo().search([
('mail_message_id', 'in', self.ids)
])
for scheduler in schedulers:
scheduled_dt_by_msg_id[scheduler.mail_message_id.id] = scheduler.scheduled_datetime
for vals in vals_list:
message_sudo = self.browse(vals['id']).sudo().with_prefetch(self.ids)
notifs = message_sudo.notification_ids.filtered(lambda n: n.res_partner_id)
@@ -969,6 +989,7 @@ class Message(models.Model):
'subtype_description': message_sudo.subtype_id.description,
'is_notification': vals['message_type'] == 'user_notification',
'recipients': [{'id': p.id, 'name': p.name} for p in message_sudo.partner_ids],
'scheduledDatetime': scheduled_dt_by_msg_id.get(vals['id'], False),
})
if vals['model'] and self.env[vals['model']]._original_module:
vals['module_icon'] = modules.module.get_module_icon(self.env[vals['model']]._original_module)
+1 -1
View File
@@ -2857,7 +2857,7 @@ class MailThread(models.AbstractModel):
} for pid in inbox_pids]
self.env['mail.notification'].sudo().create(notif_create_values)
message_format_values = message.message_format()[0]
message_format_values = message.message_format(msg_vals=msg_vals)[0]
for partner_id in inbox_pids:
bus_notifications.append((self.env['res.partner'].browse(partner_id), 'mail.message/inbox', dict(message_format_values)))
self.env['bus.bus'].sudo()._sendmany(bus_notifications)
@@ -76,6 +76,11 @@
on <a class="o_MessageView_originThreadLink fs-6" t-att-href="message.originThread.url" t-on-click="onClickOriginThread"><t t-if="message.originThread.displayName"><t t-esc="message.originThread.displayName"/></t><t t-else="">document</t></a>
</t>
</small>
<div t-if="message.scheduledDatetime" class="o_MessageView_headerScheduledDatetime" t-att-class="{ 'ms-2': isInChatWindowAndIsAlignedRight }" t-att-title="scheduledFromNow">
<span class="text-600 cursor-pointer">
<i class="fa fa-calendar-o"></i>
</span>
</div>
<div t-if="messageListViewItemOwner and message.originThread and message.originThread === messageListViewItemOwner.messageListViewOwner.threadViewOwner.thread and message.notifications.length > 0" t-att-class="{ 'ms-2': isInChatWindowAndIsAlignedRight }">
<span t-if="message.failureNotifications.length > 0" class="o_MessageView_notificationIconClickable o-error cursor-pointer text-danger" role="button" tabindex="0" t-on-click="onClickFailure">
<i class="o_MessageView_notificationIcon" t-att-class="failureNotificationIconClassName" role="img" aria-label="Delivery failure"/> <span t-if="failureNotificationIconLabel" t-out="failureNotificationIconLabel"/>
+20
View File
@@ -99,6 +99,9 @@ Model({
if ("recipients" in data) {
data2.recipients = data.recipients;
}
if ("scheduledDatetime" in data) {
data2.scheduledDatetime = data.scheduledDatetime;
}
if ("starred_partner_ids" in data && this.messaging.currentPartner) {
data2.isStarred = data.starred_partner_ids.includes(
this.messaging.currentPartner.id
@@ -698,6 +701,23 @@ Model({
},
}),
recipients: many("Partner"),
/**
* In case of delayed notification, a scheduled datetime linked to the
* message scheduler is given in order to display it new to the post
* datetime.
*/
scheduledDatetime: attr(),
scheduledMomentDate: attr({
compute() {
if (!this.scheduledDatetime) {
return clear();
}
if (!moment.isMoment(this.scheduledDatetime)) {
return moment(str_to_datetime(this.scheduledDatetime));
}
return this.scheduledDatetime;
},
}),
shortTime: attr({
compute() {
if (!this.momentDate) {
@@ -713,5 +713,22 @@ Model({
return this.env._t("Read More");
},
}),
/**
* Scheduled for sending
*/
scheduledFromNow: attr({
compute() {
if (!this.message) {
return clear();
}
if (!this.message.scheduledMomentDate) {
return clear();
}
if (!this.clockWatcher.clock.date) {
return clear();
}
return this.message.scheduledMomentDate.fromNow();
},
}),
},
});
+2 -2
View File
@@ -26,8 +26,8 @@ class MailMessage(models.Model):
])
return [('id', 'in', ratings.mapped('message_id').ids)]
def message_format(self, format_reply=True):
message_values = super().message_format(format_reply=format_reply)
def message_format(self, format_reply=True, msg_vals=None):
message_values = super().message_format(format_reply=format_reply, msg_vals=msg_vals)
rating_mixin_messages = self.filtered(lambda message:
message.model
and message.res_id
+2 -2
View File
@@ -33,13 +33,13 @@ class MailMessage(models.Model):
return ['&', ('notification_ids.notification_status', '=', 'exception'), ('notification_ids.notification_type', '=', 'sms')]
raise NotImplementedError()
def message_format(self, format_reply=True):
def message_format(self, format_reply=True, msg_vals=None):
""" Override in order to retrieves data about SMS (recipient name and
SMS status)
TDE FIXME: clean the overall message_format thingy
"""
message_values = super(MailMessage, self).message_format(format_reply=format_reply)
message_values = super(MailMessage, self).message_format(format_reply=format_reply, msg_vals=msg_vals)
all_sms_notifications = self.env['mail.notification'].sudo().search([
('mail_message_id', 'in', [r['id'] for r in message_values]),
('notification_type', '=', 'sms')
+4 -4
View File
@@ -1187,7 +1187,7 @@ class TestMailComplexPerformance(BaseMailPerformance):
]
}])
with self.assertQueryCount(employee=6):
with self.assertQueryCount(employee=7):
res = messages.message_format()
self.assertEqual(len(res), 2)
for message in res:
@@ -1196,7 +1196,7 @@ class TestMailComplexPerformance(BaseMailPerformance):
self.env.flush_all()
self.env.invalidate_all()
with self.assertQueryCount(employee=19):
with self.assertQueryCount(employee=20):
res = messages.message_format()
self.assertEqual(len(res), 2)
for message in res:
@@ -1217,14 +1217,14 @@ class TestMailComplexPerformance(BaseMailPerformance):
'res_id': record.id
} for record in records])
with self.assertQueryCount(employee=5):
with self.assertQueryCount(employee=6):
res = messages.message_format()
self.assertEqual(len(res), 6)
self.env.flush_all()
self.env.invalidate_all()
with self.assertQueryCount(employee=14):
with self.assertQueryCount(employee=15):
res = messages.message_format()
self.assertEqual(len(res), 6)