diff options
| author | XavierDo <xdo@odoo.com> | 2018-04-27 16:50:03 +0200 |
|---|---|---|
| committer | XavierDo <xdo@odoo.com> | 2018-06-07 11:46:28 +0200 |
| commit | 133eeb1bbf52e9a9ee58f83be8e7f0aba3c6d1ad (patch) | |
| tree | cd7c6b0a3c931705158c9af590206130480426f6 /addons/mail/static/src/js | |
| parent | aa7fb8c72317e330bbeb6ce29b4aace8627ef1d7 (diff) | |
[ADD] mail, mass_mailing: allow a user to resend a mail with failures
When a mail is in failure state, a red envelope appears next to the message
in a thread but it was difficult to send the mail again.
This tasks will allow users to send mail again easily, or mark notification
as cancelled if the user want to ignore this failure.
A notification will appear in sender systray while mail are in failure.
Task: #46158
PR: #24628
Diffstat (limited to 'addons/mail/static/src/js')
| -rw-r--r-- | addons/mail/static/src/js/services/chat_manager.js | 78 | ||||
| -rw-r--r-- | addons/mail/static/src/js/systray.js | 55 | ||||
| -rw-r--r-- | addons/mail/static/src/js/thread.js | 21 |
3 files changed, 138 insertions, 16 deletions
diff --git a/addons/mail/static/src/js/services/chat_manager.js b/addons/mail/static/src/js/services/chat_manager.js index eaedb9cd11e..8a90fc57482 100644 --- a/addons/mail/static/src/js/services/chat_manager.js +++ b/addons/mail/static/src/js/services/chat_manager.js @@ -119,6 +119,7 @@ var ChatManager = AbstractService.extend({ this.messages = []; this.channels = []; + this.messageFailures = []; this.channelsPreviewDef; this.channelDefs = {}; this.unreadConversationCounter = 0; @@ -285,7 +286,8 @@ var ChatManager = AbstractService.extend({ var self = this; var channelsPreview = _.map(channels, function (channel) { var info; - if (channel.channel_ids && _.contains(channel.channel_ids,"channel_inbox")) { + if ((channel.channel_ids && _.contains(channel.channel_ids, "channel_inbox")) || channel.id === "mail_failure") { + // this is a hack to preview messages and mail failure // map inbox(mail_message) data with existing channel/chat template info = _.pick(channel, 'id', 'body', 'avatar_src', 'res_id', 'model', 'module_icon', @@ -299,7 +301,9 @@ var ChatManager = AbstractService.extend({ info.name = info.record_name || info.subject || info.displayed_author; info.image_src = info.module_icon || info.avatar_src; info.message_id = info.id; - info.id = 'channel_inbox'; + if (channel.id !== "mail_failure") { + info.id = 'channel_inbox'; + } return info; } info = _.pick(channel, 'id', 'is_chat', 'name', 'status', 'unread_counter'); @@ -421,6 +425,14 @@ var ChatManager = AbstractService.extend({ return result; }, /** + * Returns a list of mail failures + * + * @return {Object[]} list of channels + */ + getMessageFailures: function () { + return this.messageFailures; + }, + /** * Get all listeners of a channel. * * @param {Object} channel @@ -1215,6 +1227,7 @@ var ChatManager = AbstractService.extend({ _.each(result.channel_slots, function (channels) { _.each(channels, self._addChannel.bind(self)); }); + self.messageFailures = result.mail_failures; self.needactionCounter = result.needaction_inbox_counter || 0; self.starredCounter = result.starred_counter || 0; self.moderationCounter = result.moderation_counter; @@ -1636,6 +1649,42 @@ var ChatManager = AbstractService.extend({ this.chatBus.trigger('update_moderation_counter'); }, /** + * Add or remove failure when receiving a failure update message + * @private + * @param {Object} data + */ + _manageMessageFailureNotification: function (data) { + var self = this; + _.each(data.elements, function (updateMessage) { + + var isAddFailure = _.some(updateMessage.notifications, function(notif) { + return notif[0] === 'exception' || notif[0] === 'bounce'; + }); + var res = _.find(self.messageFailures, {'message_id': updateMessage.message_id}); + if (res) { + var index = _.findIndex(self.messageFailures, res); + if (isAddFailure) { + self.messageFailures[index] = updateMessage; + } else { + self.messageFailures.splice(index, 1); + } + } else if (isAddFailure) { + self.messageFailures.push(updateMessage); + } + var message = _.findWhere(self.messages, { id: updateMessage.message_id }); + if (message) { + if (isAddFailure) { + message.customer_email_status = "exception"; + } else{ + message.customer_email_status = "sent"; + } + self._updateMessageNotificationStatus(updateMessage, message); + self.chatBus.trigger('update_message', message); + } + }); + this.chatBus.trigger('update_needaction', this.needactionCounter); + }, + /** * Updates channel_inbox when a message has marked as read. * * @private @@ -1738,6 +1787,8 @@ var ChatManager = AbstractService.extend({ this._manageTransientMessageNotification(data); } else if (data.type === 'activity_updated') { this._manageActivityUpdateNotification(data); + } else if (data.type === 'mail_failure') { + this._manageMessageFailureNotification(data); } else { this._manageChatSessionNotification(data); } @@ -1883,7 +1934,28 @@ var ChatManager = AbstractService.extend({ channel.unread_counter = counter; this.chatBus.trigger("update_channel_unread_counter", channel); }, - + /** + * Update the message notification status of message based on update_message + * + * @private + * @param {Object} updateMessage + * @param {Object[]} updateMessage.notifications + */ + _updateMessageNotificationStatus: function (updateMessage, message) { + _.each(updateMessage.notifications, function (notif, id, list) { + var partnerName = notif[1]; + var notifStatus = notif[0]; + var res = _.find(message.customer_email_data, function(entry){ + return entry[0] === parseInt(id); + }); + if (res) { + res[2] = notifStatus; + } else { + message.customer_email_data.push([parseInt(id), partnerName, notifStatus]); + } + }); + }, + //-------------------------------------------------------------------------- // Handlers //-------------------------------------------------------------------------- diff --git a/addons/mail/static/src/js/systray.js b/addons/mail/static/src/js/systray.js index c62b964472f..f11531b6eab 100644 --- a/addons/mail/static/src/js/systray.js +++ b/addons/mail/static/src/js/systray.js @@ -5,8 +5,8 @@ var config = require('web.config'); var core = require('web.core'); var session = require('web.session'); var SystrayMenu = require('web.SystrayMenu'); +var time = require('web.time'); var Widget = require('web.Widget'); - var QWeb = core.qweb; /** @@ -34,19 +34,23 @@ var MessagingMenu = Widget.extend({ this.$filter_buttons = this.$('.o_filter_button'); this.$channels_preview = this.$('.o_mail_navbar_dropdown_channels'); this.filter = false; - var chatBus = this.call('chat_manager', 'getChatBus'); - chatBus.on("update_needaction", this, this.update_counter); - chatBus.on("update_channel_unread_counter", this, this.update_counter); - this.call('chat_manager', 'isReady').then(this.update_counter.bind(this)); + var self = this; + this.call('chat_manager', 'isReady').then(function () { + self.update_counter(); + var chatBus = self.call('chat_manager', 'getChatBus'); + chatBus.on('update_needaction', self, self.update_counter); + chatBus.on('update_channel_unread_counter', self, self.update_counter); + }); return this._super(); }, is_open: function () { return this.$el.hasClass('open'); }, update_counter: function () { + var messageFailures = this.call('chat_manager', 'getMessageFailures'); var needactionCounter = this.call('chat_manager', 'getNeedactionCounter'); var unreadConversationCounter = this.call('chat_manager', 'getUnreadConversationCounter'); - var counter = needactionCounter + unreadConversationCounter; + var counter = needactionCounter + unreadConversationCounter + messageFailures.length; this.$('.o_notification_counter').text(counter); this.$el.toggleClass('o_no_notification', !counter); if (this.is_open()) { @@ -55,7 +59,6 @@ var MessagingMenu = Widget.extend({ }, update_channels_preview: function () { var self = this; - // Display spinner while waiting for channels preview this.$channels_preview.html(QWeb.render('Spinner')); this.call('chat_manager', 'isReady').then(function () { @@ -69,6 +72,28 @@ var MessagingMenu = Widget.extend({ return channel.type !== 'static'; } }); + var formatedFailures = []; + var messageFailures = self.call('chat_manager', 'getMessageFailures'); + _.each(messageFailures, function (messageFailure) { + var model = messageFailure.model; + var existingFailure = _.findWhere(formatedFailures, { model: model }); + if (existingFailure) { + if (existingFailure.res_id !== messageFailure.res_id) { + existingFailure.res_id = null; + existingFailure.record_name = messageFailure.model_name;//for display, will be used as subject + } + existingFailure.unread_counter ++; + } else { + messageFailure = _.clone(messageFailure); + messageFailure.unread_counter = 1; + messageFailure.id = "mail_failure"; + messageFailure.body = "An error occured sending an email"; + messageFailure.date = moment(time.str_to_datetime(messageFailure.last_message_date)); + messageFailure.displayed_author = ""; + formatedFailures.push(messageFailure); + } + }); + channels = _.union(channels, formatedFailures); self.call('chat_manager', 'getMessages', {channelID: 'channel_inbox'}) .then(function (messages) { var res = []; @@ -115,8 +140,10 @@ var MessagingMenu = Widget.extend({ this.call('chat_window_manager', 'openChat'); }, - // Handlers + //-------------------------------------------------------------------------- + // Handlers + //-------------------------------------------------------------------------- /** * When a channel is clicked on, we want to open chat/channel window * @@ -126,7 +153,7 @@ var MessagingMenu = Widget.extend({ _onClickChannel: function (event) { var self = this; var channelID = $(event.currentTarget).data('channel_id'); - if (channelID === 'channel_inbox') { + if (channelID === 'channel_inbox' || channelID === 'mail_failure') { var resID = $(event.currentTarget).data('res_id'); var resModel = $(event.currentTarget).data('res_model'); if (resModel && resID) { @@ -136,6 +163,16 @@ var MessagingMenu = Widget.extend({ views: [[false, 'form']], res_id: resID }); + } else if (resModel) { + this.do_action({ + name: "Mail failures", + type: 'ir.actions.act_window', + view_mode: 'kanban,list,form', + views: [[false, 'kanban'], [false, 'list'], [false, 'form']], + target: 'current', + res_model: resModel, + domain: [['message_has_error', '=', true]], + }); } else { this.do_action('mail.mail_channel_action_client_chat', {clear_breadcrumbs: true}) .then(function () { diff --git a/addons/mail/static/src/js/thread.js b/addons/mail/static/src/js/thread.js index 39d179a715a..54a36e169e4 100644 --- a/addons/mail/static/src/js/thread.js +++ b/addons/mail/static/src/js/thread.js @@ -35,15 +35,16 @@ var Thread = Widget.extend({ "click .o_attachment_download": "_onAttachmentDownload", "click .o_attachment_view": "_onAttachmentView", "click .o_thread_message_needaction": function (event) { - var message_id = $(event.currentTarget).data('message-id'); - this.trigger("mark_as_read", message_id); + var messageId = $(event.currentTarget).data('message-id'); + this.trigger("mark_as_read", messageId); }, "click .o_thread_message_moderation": "_onClickMessageModeration", "change .moderation_checkbox": "_onChangeModerationCheckbox", "click .o_thread_message_star": function (event) { - var message_id = $(event.currentTarget).data('message-id'); - this.trigger("toggle_star_status", message_id); + var messageId = $(event.currentTarget).data('message-id'); + this.trigger("toggle_star_status", messageId); }, + "click .o_thread_message_email_exception": "_onClickMailException", "click .o_thread_message_reply": function (event) { this.selected_id = $(event.currentTarget).data('message-id'); this.$('.o_thread_message').removeClass('o_thread_selected_message'); @@ -414,6 +415,18 @@ var Thread = Widget.extend({ var decision = $button.data('decision'); this.trigger_up('message_moderation', { messageID: messageID, decision: decision }); }, + /** + * @private + * @param {MouseEvent} event + */ + _onClickMailException: function (event) { + var messageId = $(event.currentTarget).data('message-id'); + this.do_action('mail.mail_resend_message_action', { + additional_context: { + mail_message_to_resend: messageId + } + }); + }, }); Thread.ORDER = ORDER; |
