summaryrefslogtreecommitdiff
path: root/addons/mail/static/src
diff options
context:
space:
mode:
authorXavierDo <xdo@odoo.com>2018-04-27 16:50:03 +0200
committerXavierDo <xdo@odoo.com>2018-06-07 11:46:28 +0200
commit133eeb1bbf52e9a9ee58f83be8e7f0aba3c6d1ad (patch)
treecd7c6b0a3c931705158c9af590206130480426f6 /addons/mail/static/src
parentaa7fb8c72317e330bbeb6ce29b4aace8627ef1d7 (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')
-rw-r--r--addons/mail/static/src/img/smiley/mailfailure.jpgbin0 -> 10498 bytes
-rw-r--r--addons/mail/static/src/js/services/chat_manager.js78
-rw-r--r--addons/mail/static/src/js/systray.js55
-rw-r--r--addons/mail/static/src/js/thread.js21
-rw-r--r--addons/mail/static/src/scss/thread.scss1
-rw-r--r--addons/mail/static/src/xml/discuss.xml4
-rw-r--r--addons/mail/static/src/xml/thread.xml15
7 files changed, 152 insertions, 22 deletions
diff --git a/addons/mail/static/src/img/smiley/mailfailure.jpg b/addons/mail/static/src/img/smiley/mailfailure.jpg
new file mode 100644
index 00000000000..6f0ec91ad80
--- /dev/null
+++ b/addons/mail/static/src/img/smiley/mailfailure.jpg
Binary files differ
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;
diff --git a/addons/mail/static/src/scss/thread.scss b/addons/mail/static/src/scss/thread.scss
index 0529238a36e..6d8eb8b8254 100644
--- a/addons/mail/static/src/scss/thread.scss
+++ b/addons/mail/static/src/scss/thread.scss
@@ -161,6 +161,7 @@
&.o_thread_message_email_exception {
color: red;
opacity: 1;
+ cursor: pointer;
}
&.o_thread_message_email_bounce {
color: red;
diff --git a/addons/mail/static/src/xml/discuss.xml b/addons/mail/static/src/xml/discuss.xml
index 1ec08a23635..1eda1dfec1b 100644
--- a/addons/mail/static/src/xml/discuss.xml
+++ b/addons/mail/static/src/xml/discuss.xml
@@ -231,7 +231,9 @@
<span class="fa fa-mail-reply"/> You:
</t>
<t t-else="">
- <t t-esc="channel.last_message.displayed_author"/>:
+ <t t-if="channel.last_message.displayed_author">
+ <t t-esc="channel.last_message.displayed_author"/>:
+ </t>
</t>
<t t-raw="channel.last_message_preview"/>
</div>
diff --git a/addons/mail/static/src/xml/thread.xml b/addons/mail/static/src/xml/thread.xml
index 20049e89cf6..ca8ae9b8319 100644
--- a/addons/mail/static/src/xml/thread.xml
+++ b/addons/mail/static/src/xml/thread.xml
@@ -175,14 +175,19 @@
(from <a t-att-data-oe-id="message.origin_id" href="#">#<t t-esc="message.origin_name"/></a>)
</t>
<span t-if="options.display_email_icon and message.customer_email_data and message.customer_email_data.length" class="o_thread_tooltip_container">
- <i t-att-class="'o_thread_tooltip o_thread_message_email o_thread_message_email_' + message.customer_email_status + ' fa fa-envelope-o'"/>
+ <t t-set="fatype" t-value="''"/>
+ <t t-if="message.customer_email_status === 'sent' or message.customer_email_status === 'ready'">
+ <t t-set="fatype" t-value="'-o'"/>
+ </t>
+ <i t-att-class="'o_thread_tooltip o_thread_message_email o_thread_message_email_' + message.customer_email_status + ' fa fa-envelope'+ fatype" t-att-data-message-id="message.id"/>
<span class="o_thread_tooltip_content">
<t t-foreach="message.customer_email_data" t-as="customer">
<span>
- <t t-if="customer[2] == 'sent'"><i class='fa fa-check'/></t>
- <t t-if="customer[2] == 'bounce'"><i class='fa fa-exclamation'/></t>
- <t t-if="customer[2] == 'exception'"><i class='fa fa-exclamation'/></t>
- <t t-if="customer[2] == 'ready'"><i class='fa fa-send-o'/></t>
+ <t t-if="customer[2] === 'sent'"><i class='fa fa-check'/></t>
+ <t t-if="customer[2] === 'bounce'"><i class='fa fa-exclamation'/></t>
+ <t t-if="customer[2] === 'exception'"><i class='fa fa-exclamation'/></t>
+ <t t-if="customer[2] === 'ready'"><i class='fa fa-send-o'/></t>
+ <t t-if="customer[2] === 'canceled'"><i class='fa fa-trash-o'/></t>
<t t-esc="customer[1]"/>
</span>
<br />