fixup! [IMP] mail_tracking: Failed Messages to 12.0

pull/447/head
Alexandre Díaz 2019-10-30 19:24:47 +01:00
parent 9a18de6229
commit 322a3e0437
8 changed files with 646 additions and 591 deletions

View File

@ -31,8 +31,9 @@
],
"qweb": [
"static/src/xml/mail_tracking.xml",
"static/src/xml/failed_message.xml",
"static/src/xml/discuss.xml",
"static/src/xml/failed_message/common.xml",
"static/src/xml/failed_message/widget.xml",
"static/src/xml/failed_message/discuss.xml",
],
'demo': [
'demo/demo.xml',

View File

@ -1,575 +0,0 @@
/* Copyright 2019 Alexandre Díaz
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). */
odoo.define('mail_tracking.FailedMessage', function (require) {
"use strict";
var AbstractField = require('web.AbstractField');
var BasicModel = require('web.BasicModel');
var BasicView = require('web.BasicView');
var Chatter = require('mail.Chatter');
var Discuss = require('mail.Discuss');
var MailManager = require('mail.Manager');
var Mailbox = require('mail.model.Mailbox');
var MailManagerNotif = require('mail.Manager.Notification');
var AbstractMessage = require('mail.model.AbstractMessage');
var Message = require('mail.model.Message');
var utils = require('mail.utils');
var core = require('web.core');
var field_registry = require('web.field_registry');
var time = require('web.time');
var QWeb = core.qweb;
var _t = core._t;
var FAILED_STATES = [
'error', 'rejected', 'spam', 'bounced', 'soft-bounced',
];
/* COMMON */
AbstractMessage.include({
/**
* Abstract method to be implemented
*
* @returns {Boolean}
*/
isFailed: function () {
return false;
},
});
Message.include({
/**
* Init
*
* @param {Widget} parent
* @param {Object} data
*/
init: function (parent, data) {
this._isFailedMessage = data.is_failed_message;
this._super.apply(this, arguments);
},
/**
* Implementation of the abstract method
*
* @returns {Boolean}
*/
isFailed: function () {
return _.contains(this._threadIDs, 'mailbox_failed');
},
/**
* Adds/Remove message to/from failed thread
*
* @param {Boolean} failed
*/
setFailed: function (failed) {
if (failed) {
this._addThread('mailbox_failed');
} else {
this.removeThread('mailbox_failed');
}
},
/**
* Process message mailbox
*/
_processMailboxes: function () {
this.setFailed(this._isFailedMessage);
this._super.apply(this, arguments);
},
});
MailManagerNotif.include({
/**
* Handle partner notification
*
* @private
* @param {Object} data
*/
_handlePartnerNotification: function (data) {
if (data.type === 'toggle_tracking_status') {
this._handlePartnerToggleFailedNotification(data);
} else {
this._super.apply(this, arguments);
}
},
/**
* Handle partner toggle failed notification
*
* @private
* @param {Object} data
*/
_handlePartnerToggleFailedNotification: function (data) {
var self = this;
var failed = this.getMailbox('failed');
_.each(data.message_ids, function (messageID) {
var message = _.find(self._messages, function (msg) {
return msg.getID() === messageID;
});
if (message) {
message.setFailed(data.needs_actions);
if (message.isFailed() === false) {
self._removeMessageFromThread(
'mailbox_failed', message);
} else {
self._addMessageToThreads(message, []);
var channelFailed = self.getMailbox('failed');
channelFailed.invalidateCaches();
}
self._mailBus.trigger('update_message', message);
}
});
if (data.needs_actions) {
// Increase failed counter if message is marked as failed
failed.incrementMailboxCounter(data.message_ids.length);
} else {
// Decrease failed counter if message is remove from failed
failed.decrementMailboxCounter(data.message_ids.length);
}
this._mailBus.trigger('update_failed', failed.getMailboxCounter());
},
});
/* DISCUSS */
Discuss.include({
events: _.extend({}, Discuss.prototype.events, {
'click .o_failed_message_retry': '_onRetryFailedMessage',
'click .o_failed_message_reviewed': '_onMarkFailedMessageReviewed',
}),
/**
* Sidebar QWeb button params
*
* @private
* @returns {Object}
*/
_sidebarQWebParams: function () {
var failed = this.call('mail_service', 'getMailbox', 'failed');
return {
activeThreadID: this._thread ? this._thread.getID() : undefined,
failedCounter: failed.getMailboxCounter(),
};
},
/**
* Render sidebar failed button
*
* @private
* @returns {jQueryElementt}
*/
_renderSidebar: function () {
var $sidebar = this._super.apply(this, arguments);
// Because Odoo implementation isn't designed to be inherited
// properly we inject failed button using jQuery.
var $failed_item = $(QWeb.render('mail_tracking.SidebarFailed',
this._sidebarQWebParams()));
$failed_item.insertAfter(
$sidebar.find(".o_mail_discuss_title_main").filter(":last"));
return $sidebar;
},
/**
* Message Updated
*
* @private
* @param {Object} message
* @param {String} type
*/
_onMessageUpdated: function (message, type) {
var self = this;
var currentThreadID = this._thread.getID();
if (currentThreadID === 'mailbox_failed' && !message.isFailed()) {
this._thread.fetchMessages(this.domain)
.then(function () {
var options = self._getThreadRenderingOptions();
self._threadWidget.removeMessageAndRender(
message.getID(), self._thread, options)
.then(function () {
self._updateButtonStatus(
!self._thread.hasMessages(), type);
});
});
} else {
// Workaround to avoid calling '_fetchAndRenderThread' when
// it's not really needed.
this._super.apply(this, arguments);
}
},
/**
* Get thread rendering options
*
* @private
* @returns {Object}
*/
_getThreadRenderingOptions: function () {
var values = this._super.apply(this, arguments);
if (this._thread.getID() === 'mailbox_failed') {
values.displayEmailIcons = true;
values.displayReplyIcons = false;
values.displayRetryButton = true;
values.displayReviewedButton = true;
}
return values;
},
/**
* Start listening events
*
* @private
*/
_startListening: function () {
this._super.apply(this, arguments);
this.call('mail_service', 'getMailBus')
.on('update_failed', this, this._throttledUpdateThreads);
},
// Handlers
/**
* @private
* @param {Event} event
*/
_onRetryFailedMessage: function (event) {
event.preventDefault();
var messageID = $(event.currentTarget).data('message-id');
this.do_action('mail.mail_resend_message_action', {
additional_context: {
mail_message_to_resend: messageID,
},
});
},
/**
* @private
* @param {Event} event
* @returns {Promise}
*/
_onMarkFailedMessageReviewed: function (event) {
event.preventDefault();
var messageID = $(event.currentTarget).data('message-id');
return this._rpc({
model: 'mail.message',
method: 'toggle_tracking_status',
args: [[messageID]],
context: this.getSession().user_context,
});
},
});
MailManager.include({
/**
* Create mailbox entry
*
* @private
* @param {Object} data
*/
_updateMailboxesFromServer: function (data) {
this._super.apply(this, arguments);
this._addMailbox({
id: 'failed',
name: _t("Failed"),
mailboxCounter: data.failed_counter || 0,
});
},
});
Mailbox.include({
/**
* Get thread domain
*
* @private
* @returns {Array}
*/
_getThreadDomain: function () {
if (this._id === 'mailbox_failed') {
// Workaround to avoid throw an exception
return [
['mail_tracking_ids.state', 'in', FAILED_STATES],
['mail_tracking_needs_action', '=', true],
];
}
return this._super.apply(this, arguments);
},
});
/* FAILED MESSAGES CHATTER WIDGET */
/**
* Get messages with selected ids
*
* @private
* @param {Object} self
* @param {Array} ids
* @returns {Array}
*/
function _readMessages (self, ids) {
if (!ids.length) {
return $.when([]);
}
var context = self.record && self.record.getContext();
return self._rpc({
model: 'mail.message',
method: 'get_failed_messages',
args: [ids],
context: context || self.getSession().user_context,
}).then(function (messages) {
// Convert date to moment
_.each(messages, function (msg) {
msg.date = moment(time.auto_str_to_date(msg.date));
msg.hour = utils.timeFromNow(msg.date);
});
return messages;
});
}
BasicModel.include({
/**
* Fetch special failed messages
*
* @private
* @param {Object} record
* @param {String} fieldName
* @returns {Array}
*/
_fetchSpecialFailedMessages: function (record, fieldName) {
var localID = record._changes && fieldName in record._changes
? record._changes[fieldName] : record.data[fieldName];
return _readMessages(this, this.localData[localID].res_ids);
},
});
var AbstractFailedMessagesField = AbstractField.extend({
/**
* Abstract method to be implemented
*
* @returns {Boolean}
*/
_markFailedMessageReviewed: function () {
return false;
},
});
var FailedMessage = AbstractFailedMessagesField.extend({
className: 'o_mail_failed_message',
events: {
'click .o_failed_message_retry': '_onRetryFailedMessage',
'click .o_failed_message_reviewed': '_onMarkFailedMessageReviewed',
},
specialData: '_fetchSpecialFailedMessages',
init: function () {
this._super.apply(this, arguments);
this.failed_messages = this.record.specialData[this.name];
this.call(
'bus_service', 'onNotification', this, this._onNotification);
},
/**
* Get message qweb parameters
*
* @private
* @returns {Object}
*/
_failedItemsQWebParams: function () {
return {
failed_messages: this.failed_messages,
nbFailedMessages: this.failed_messages.length,
date_format: time.getLangDateFormat(),
datetime_format: time.getLangDatetimeFormat(),
};
},
/**
* Render failed message
*
* @private
*/
_render: function () {
if (this.failed_messages.length) {
this.$el.html(QWeb.render(
'mail_tracking.failed_message_items',
this._failedItemsQWebParams()));
} else {
this.$el.empty();
}
},
/**
* Reset
*
* @private
* @param {Object} record
*/
_reset: function (record) {
this._super.apply(this, arguments);
this.failed_messages = this.record.specialData[this.name];
this.res_id = record.res_id;
},
/**
* Reload
*
* @private
* @param {Array} fieldsToReload
*/
_reload: function (fieldsToReload) {
this.trigger_up('reload_mail_fields', fieldsToReload);
},
/**
* Mark failed message as reviewed
*
* @private
* @param {Int} id
* @returns {Promise}
*/
_markFailedMessageReviewed: function (id) {
return this._rpc({
model: 'mail.message',
method: 'toggle_tracking_status',
args: [[id]],
context: this.record.getContext(),
});
},
// Handlers
/**
* Listen notification to launch reload process
*
* @private
* @param {Array} notifs
*/
_onNotification: function (notifs) {
var self = this;
_.each(notifs, function (notif) {
var model = notif[0][1];
if (model === 'res.partner') {
var data = notif[1];
if (data.type === 'update_failed_messages') {
// Update failed messages
self._reload({failed_message: true});
}
}
});
},
/**
* Handle retry failed message event
*
* @private
* @param {Event} event
*/
_onRetryFailedMessage: function (event) {
event.preventDefault();
var messageID = $(event.currentTarget).data('message-id');
this.do_action('mail.mail_resend_message_action', {
additional_context: {
mail_message_to_resend: messageID,
},
});
},
/**
* Handle mark message as reviewed event
*
* @private
* @param {Event} event
*/
_onMarkFailedMessageReviewed: function (event) {
event.preventDefault();
var messageID = $(event.currentTarget).data('message-id');
this._markFailedMessageReviewed(messageID).then(
this._reload.bind(this, {failed_message: true}));
},
});
field_registry.add('mail_failed_message', FailedMessage);
var mailWidgets = ['mail_failed_message'];
BasicView.include({
init: function () {
this._super.apply(this, arguments);
// Adds mail_failed_message as valid mail widget
var fieldsInfo = this.fieldsInfo[this.viewType];
for (var fieldName in fieldsInfo) {
var fieldInfo = fieldsInfo[fieldName];
if (_.contains(mailWidgets, fieldInfo.widget)) {
this.mailFields[fieldInfo.widget] = fieldName;
fieldInfo.__no_fetch = true;
}
}
Object.assign(this.rendererParams.mailFields, this.mailFields);
},
});
Chatter.include({
/**
* Init
*
* @private
* @param {Widget} parent
* @param {Object} record
* @param {Object} mailFields
* @param {Object} options
*/
init: function (parent, record, mailFields, options) {
this._super.apply(this, arguments);
// Initialize mail_failed_message widget
if (mailFields.mail_failed_message) {
this.fields.failed_message = new FailedMessage(
this, mailFields.mail_failed_message, record, options);
}
},
/**
* Render
*
* @private
* @returns {Promise}
*/
_render: function () {
var self = this;
return this._super.apply(this, arguments).then(function () {
if (self.fields.failed_message) {
self.fields.failed_message.$el.insertBefore(
self.$el.find('.o_mail_thread'));
}
});
},
/**
* Handle reload fields event
*
* @private
* @param {Event} event
*/
_onReloadMailFields: function (event) {
if (this.fields.failed_message && event.data.failed_message) {
this.trigger_up('reload', {
fieldNames: [this.fields.failed_message.name],
keepChanges: true,
});
} else {
// Workarround to avoid trigger reload event two times.
this._super.apply(this, arguments);
}
},
});
return FailedMessage;
});

View File

@ -0,0 +1,312 @@
/* Copyright 2019 Alexandre Díaz
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). */
odoo.define('mail_tracking.FailedMessageDiscuss', function (require) {
"use strict";
// To be considered:
// - One message can be displayed in many threads
// - A thread can be a mailbox, channel, ...
// - A mailbox it's a type of thread that it's displayed on top of
// the discuss menu, has a counter, etc...
var MailManagerNotif = require('mail.Manager.Notification');
var AbstractMessage = require('mail.model.AbstractMessage');
var Message = require('mail.model.Message');
var Discuss = require('mail.Discuss');
var MailManager = require('mail.Manager');
var Mailbox = require('mail.model.Mailbox');
var core = require('web.core');
var QWeb = core.qweb;
var _t = core._t;
/* The states to consider a message as failed message */
var FAILED_STATES = [
'error', 'rejected', 'spam', 'bounced', 'soft-bounced',
];
AbstractMessage.include({
/**
* Abstract declaration to know if a message its included on the
* failed mailbox. By default should be false.
*
* @returns {Boolean}
*/
isFailed: function () {
return false;
},
});
Message.include({
/**
* Overrides to store information from server
*
* @Override
*/
init: function (parent, data) {
this._isFailedMessage = data.is_failed_message;
this._super.apply(this, arguments);
},
/**
* Implementation to know if a message its included on the
* failed mailbox.
*
* @Override
*/
isFailed: function () {
return _.contains(this._threadIDs, 'mailbox_failed');
},
/**
* Adds/Remove message to/from failed mailbox
*
* @param {Boolean} failed
*/
setFailed: function (failed) {
if (failed) {
this._addThread('mailbox_failed');
} else {
this.removeThread('mailbox_failed');
}
},
/**
* Overrides to update if the message need be show in 'failed' mailbox
* thread
* @Override
*/
_processMailboxes: function () {
this.setFailed(this._isFailedMessage);
this._super.apply(this, arguments);
},
});
MailManagerNotif.include({
/**
* Overrides to handle changes in the 'mail_tracking_needs_action' flag
*
* @Override
*/
_handlePartnerNotification: function (data) {
if (data.type === 'toggle_tracking_status') {
this._handlePartnerToggleFailedNotification(data);
} else {
// Workaround to avoid call '_handlePartnerChannelNotification'
// because this is related with the failed mailbox, not a
// channel.
this._super.apply(this, arguments);
}
},
/**
* This method update messages in the failed mailbox when the flag
* 'mail_tracking_needs_action' is toggled. This can remove/add
* the message from/to failed mailbox and update mailbox counter.
*
* @private
* @param {Object} data
*/
_handlePartnerToggleFailedNotification: function (data) {
var self = this;
var failed = this.getMailbox('failed');
_.each(data.message_ids, function (messageID) {
var message = _.find(self._messages, function (msg) {
return msg.getID() === messageID;
});
if (message) {
message.setFailed(data.needs_actions);
if (message.isFailed() === false) {
self._removeMessageFromThread(
'mailbox_failed', message);
} else {
self._addMessageToThreads(message, []);
var channelFailed = self.getMailbox('failed');
channelFailed.invalidateCaches();
}
self._mailBus.trigger('update_message', message);
}
});
if (data.needs_actions) {
// Increase failed counter if message is marked as failed
failed.incrementMailboxCounter(data.message_ids.length);
} else {
// Decrease failed counter if message is remove from failed
failed.decrementMailboxCounter(data.message_ids.length);
}
// Trigger event to refresh threads
this._mailBus.trigger('update_failed', failed.getMailboxCounter());
},
});
Discuss.include({
events: _.extend({}, Discuss.prototype.events, {
'click .o_failed_message_retry': '_onRetryFailedMessage',
'click .o_failed_message_reviewed': '_onMarkFailedMessageReviewed',
}),
/**
* Paramaters used to render 'failed' mailbox entry in Discuss
*
* @private
* @returns {Object}
*/
_sidebarQWebParams: function () {
var failed = this.call('mail_service', 'getMailbox', 'failed');
return {
activeThreadID: this._thread ? this._thread.getID() : undefined,
failedCounter: failed.getMailboxCounter(),
};
},
/**
* Render 'failed' mailbox menu entry in Discuss
*
* @private
* @returns {jQueryElementt}
*/
_renderSidebar: function () {
var $sidebar = this._super.apply(this, arguments);
// Because Odoo implementation isn't designed to be inherited
// properly, we inject 'failed' button using jQuery.
var $failed_item = $(QWeb.render('mail_tracking.SidebarFailed',
this._sidebarQWebParams()));
$failed_item.insertAfter(
$sidebar.find(".o_mail_discuss_title_main").filter(":last"));
return $sidebar;
},
/**
* Overrides to update messages in 'failed' mailbox thread
*
* @Override
*/
_onMessageUpdated: function (message, type) {
var self = this;
var currentThreadID = this._thread.getID();
if (currentThreadID === 'mailbox_failed' && !message.isFailed()) {
this._thread.fetchMessages(this.domain)
.then(function () {
var options = self._getThreadRenderingOptions();
self._threadWidget.removeMessageAndRender(
message.getID(), self._thread, options)
.then(function () {
self._updateButtonStatus(
!self._thread.hasMessages(), type);
});
});
} else {
// Workaround to avoid call '_fetchAndRenderThread' and refetch
// thread messages.
this._super.apply(this, arguments);
}
},
/**
* Overrides to hide reply in the 'failed' mailbox, as this feature does
* not necessary in that channel. It also show retry and
* 'set as reviewed'.
*
* @Override
*/
_getThreadRenderingOptions: function () {
var values = this._super.apply(this, arguments);
if (this._thread.getID() === 'mailbox_failed') {
values.displayEmailIcons = true;
values.displayReplyIcons = false;
values.displayRetryButton = true;
values.displayReviewedButton = true;
}
return values;
},
/**
* Overrides to listen event that refresh thread messages
*
* @Override
*/
_startListening: function () {
this._super.apply(this, arguments);
this.call('mail_service', 'getMailBus')
.on('update_failed', this, this._throttledUpdateThreads);
},
// Handlers
/**
* Open the resend mail.resend.message wizard
*
* @private
* @param {Event} event
*/
_onRetryFailedMessage: function (event) {
event.preventDefault();
var messageID = $(event.currentTarget).data('message-id');
this.do_action('mail.mail_resend_message_action', {
additional_context: {
mail_message_to_resend: messageID,
},
});
},
/**
* Toggle 'mail_tracking_needs_action' flag
*
* @private
* @param {Event} event
* @returns {Promise}
*/
_onMarkFailedMessageReviewed: function (event) {
event.preventDefault();
var messageID = $(event.currentTarget).data('message-id');
return this._rpc({
model: 'mail.message',
method: 'toggle_tracking_status',
args: [[messageID]],
context: this.getSession().user_context,
});
},
});
MailManager.include({
/**
* Overrides to add the 'failed' mailbox
*
* @Override
*/
_updateMailboxesFromServer: function (data) {
this._super.apply(this, arguments);
this._addMailbox({
id: 'failed',
name: _t("Failed"),
mailboxCounter: data.failed_counter || 0,
});
},
});
Mailbox.include({
/**
* Overrides to add domain for 'failed' mailbox thread
*
* @Override
*/
_getThreadDomain: function () {
if (this._id === 'mailbox_failed') {
return [
['mail_tracking_ids.state', 'in', FAILED_STATES],
['mail_tracking_needs_action', '=', true],
];
}
// Workaround to avoid throw 'Missing domain' exception
return this._super.apply(this, arguments);
},
});
});

View File

@ -0,0 +1,311 @@
/* Copyright 2019 Alexandre Díaz
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). */
odoo.define('mail_tracking.FailedMessage', function (require) {
"use strict";
var AbstractField = require('web.AbstractField');
var BasicModel = require('web.BasicModel');
var BasicView = require('web.BasicView');
var Chatter = require('mail.Chatter');
var MailThread = require('mail.widget.Thread');
var utils = require('mail.utils');
var core = require('web.core');
var field_registry = require('web.field_registry');
var time = require('web.time');
var QWeb = core.qweb;
/**
* Helper method to fetch failed messages
*
* @private
* @param {Object} self
* @param {Array} ids
* @returns {Array}
*/
function _readMessages (self, ids) {
if (!ids.length) {
return $.when([]);
}
var context = self.record && self.record.getContext();
return self._rpc({
model: 'mail.message',
method: 'get_failed_messages',
args: [ids],
context: context || self.getSession().user_context,
}).then(function (messages) {
// Convert date to moment
_.each(messages, function (msg) {
msg.date = moment(time.auto_str_to_date(msg.date));
msg.hour = utils.timeFromNow(msg.date);
});
return messages;
});
}
BasicModel.include({
/**
* Fetches the failed messages displayed by the 'mail_failed_message'
* field widget in form views.
*
* @private
* @param {Object} record
* @param {String} fieldName
* @returns {Array}
*/
_fetchSpecialFailedMessages: function (record, fieldName) {
var localID = record._changes && fieldName in record._changes
? record._changes[fieldName] : record.data[fieldName];
return _readMessages(this, this.localData[localID].res_ids);
},
});
var AbstractFailedMessagesField = AbstractField.extend({
/**
* Mark failed message as reviewed. By default should be don't reviewed.
*
* @returns {Boolean}
*/
_markFailedMessageReviewed: function () {
return false;
},
});
var FailedMessage = AbstractFailedMessagesField.extend({
className: 'o_mail_failed_message',
events: {
'click .o_failed_message_retry': '_onRetryFailedMessage',
'click .o_failed_message_reviewed': '_onMarkFailedMessageReviewed',
},
specialData: '_fetchSpecialFailedMessages',
/**
* Overrides to listen bus notifications
*
* @Override
*/
init: function () {
this._super.apply(this, arguments);
this.failed_messages = this.record.specialData[this.name];
this.call(
'bus_service', 'onNotification', this, this._onNotification);
},
/**
* Paremeters used to render widget
*
* @private
* @returns {Object}
*/
_failedItemsQWebParams: function () {
return {
failed_messages: this.failed_messages,
nbFailedMessages: this.failed_messages.length,
date_format: time.getLangDateFormat(),
datetime_format: time.getLangDatetimeFormat(),
};
},
/**
* @private
*/
_render: function () {
if (this.failed_messages.length) {
this.$el.html(QWeb.render(
'mail_tracking.failed_message_items',
this._failedItemsQWebParams()));
} else {
this.$el.empty();
}
},
/**
* Reset widget data using selected record
*
* @private
* @param {Object} record
*/
_reset: function (record) {
this._super.apply(this, arguments);
this.failed_messages = this.record.specialData[this.name];
this.res_id = record.res_id;
},
/**
* Trigger event to reload mail widgets
*
* @private
* @param {Array} fieldsToReload
*/
_reload: function (fieldsToReload) {
this.trigger_up('reload_mail_fields', fieldsToReload);
},
/**
* Mark failed message as reviewed
*
* @private
* @param {Int} id
* @returns {Promise}
*/
_markFailedMessageReviewed: function (id) {
return this._rpc({
model: 'mail.message',
method: 'toggle_tracking_status',
args: [[id]],
context: this.record.getContext(),
});
},
// Handlers
/**
* Listen bus notification to launch reload process.
* This bus notification is received when the user uses
* 'mail.resend.message' wizard.
*
* @private
* @param {Array} notifs
*/
_onNotification: function (notifs) {
var self = this;
_.each(notifs, function (notif) {
var model = notif[0][1];
if (model === 'res.partner') {
var data = notif[1];
if (data.type === 'update_failed_messages') {
// Reload 'mail_failed_message' widget
self._reload({failed_message: true});
}
}
});
},
/**
* Handle retry failed message event to open the mail.resend.message
* wizard.
*
* @private
* @param {Event} event
*/
_onRetryFailedMessage: function (event) {
event.preventDefault();
var messageID = $(event.currentTarget).data('message-id');
this.do_action('mail.mail_resend_message_action', {
additional_context: {
mail_message_to_resend: messageID,
},
});
},
/**
* Handle mark message as reviewed event
*
* @private
* @param {Event} event
*/
_onMarkFailedMessageReviewed: function (event) {
event.preventDefault();
var messageID = $(event.currentTarget).data('message-id');
this._markFailedMessageReviewed(messageID).then(
this._reload.bind(this, {failed_message: true}));
},
});
field_registry.add('mail_failed_message', FailedMessage);
var mailWidgets = ['mail_failed_message'];
BasicView.include({
/**
* Overrides to add 'mail_failed_message' widget as "mail widget" used
* in Chatter.
*
* @Override
*/
init: function () {
this._super.apply(this, arguments);
var fieldsInfo = this.fieldsInfo[this.viewType];
for (var fieldName in fieldsInfo) {
var fieldInfo = fieldsInfo[fieldName];
if (_.contains(mailWidgets, fieldInfo.widget)) {
this.mailFields[fieldInfo.widget] = fieldName;
fieldInfo.__no_fetch = true;
}
}
Object.assign(this.rendererParams.mailFields, this.mailFields);
},
});
Chatter.include({
/**
* Overrides to initialize 'mail_failed_message' widget.
*
* @Override
*/
init: function (parent, record, mailFields, options) {
this._super.apply(this, arguments);
// Initialize mail_failed_message widget
if (mailFields.mail_failed_message) {
this.fields.failed_message = new FailedMessage(
this, mailFields.mail_failed_message, record, options);
}
},
/**
* Injects widget before the chatter
*
* @private
* @returns {Promise}
*/
_render: function () {
var self = this;
return this._super.apply(this, arguments).then(function () {
if (self.fields.failed_message) {
self.fields.failed_message.$el.insertBefore(
self.$el.find('.o_mail_thread'));
}
});
},
/**
* Overrides to reload 'mail_failed_message' widget
*
* @Override
*/
_onReloadMailFields: function (event) {
if (this.fields.failed_message && event.data.failed_message) {
this.trigger_up('reload', {
fieldNames: [this.fields.failed_message.name],
keepChanges: true,
});
} else {
// Workarround to avoid trigger reload event two times (one for
// mail_failed_message and other with empty 'fieldNames'.
this._super.apply(this, arguments);
}
},
});
MailThread.include({
/**
* Overrides to show 'retry' & 'Set as reviewed' buttons in the Chatter
*
* @Override
*/
init: function () {
this._super.apply(this, arguments);
this._enabledOptions.displayRetryButton = true;
this._enabledOptions.displayReviewedButton = true;
this._disabledOptions.displayRetryButton = true;
this._disabledOptions.displayReviewedButton = true;
},
});
return FailedMessage;
});

View File

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<templates>
<t t-extend="mail.widget.Thread.Message">
<t t-jquery="span[t-attf-class=o_thread_icons]" t-operation="append">
<a t-if="message.isFailed() &amp;&amp; options.displayRetryButton" class="btn btn-link o_thread_icon btn-success text-success btn-sm o_failed_message_reviewed o_activity_link mr8" t-att-data-message-id="message.getID()">
<i class="fa fa-check"/> Set as Reviewed
</a>
<a t-if="message.isFailed() &amp;&amp; options.displayReviewedButton" class="btn btn-link o_thread_icon btn-default text-warning btn-sm o_failed_message_retry" t-att-data-message-id="message.getID()">
<i class="fa fa-retweet"/> Retry
</a>
</t>
</t>
</templates>

View File

@ -25,15 +25,4 @@
</t>
</t>
<t t-extend="mail.widget.Thread.Message">
<t t-jquery="span[t-attf-class=o_thread_icons]" t-operation="append">
<a t-if="message.isFailed() &amp;&amp; options.displayRetryButton" class="btn btn-link btn-success text-success btn-sm o_failed_message_reviewed o_activity_link mr8" t-att-data-message-id="message.getID()">
<i class="fa fa-check"/> Set as Reviewed
</a>
<a t-if="message.isFailed() &amp;&amp; options.displayReviewedButton" class="btn btn-link btn-default text-warning btn-sm o_failed_message_retry" t-att-data-message-id="message.getID()">
<i class="fa fa-retweet"/> Retry
</a>
</t>
</t>
</templates>

View File

@ -28,10 +28,10 @@
</strong>
- <small class="o_mail_timestamp" t-att-title="message.date.format(date_format)"><t t-esc="message.hour"/></small>
<span t-attf-class="o_thread_icons">
<a href="#" class="btn btn-link btn-success text-success btn-sm o_failed_message_reviewed o_activity_link" t-att-data-message-id="message.id">
<a href="#" class="btn btn-link btn-success o_thread_icon text-success btn-sm o_failed_message_reviewed o_activity_link" t-att-data-message-id="message.id">
<i class="fa fa-check"/> Set as Reviewed
</a>
<a href="#" class="btn btn-link btn-default text-warning btn-sm o_failed_message_retry" t-att-data-message-id="message.id">
<a href="#" class="btn btn-link btn-default o_thread_icon text-warning btn-sm o_failed_message_retry" t-att-data-message-id="message.id">
<i class="fa fa-retweet"/> Retry
</a>
</span>

View File

@ -13,7 +13,9 @@
<script type="text/javascript"
src="/mail_tracking/static/src/js/mail_tracking.js"/>
<script type="text/javascript"
src="/mail_tracking/static/src/js/failed_message.js"/>
src="/mail_tracking/static/src/js/failed_message/discuss.js"/>
<script type="text/javascript"
src="/mail_tracking/static/src/js/failed_message/widget.js"/>
</xpath>
</template>
</odoo>