diff --git a/mail_tracking/__manifest__.py b/mail_tracking/__manifest__.py index 6e81b83ee..f33f1d9a9 100644 --- a/mail_tracking/__manifest__.py +++ b/mail_tracking/__manifest__.py @@ -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', diff --git a/mail_tracking/static/src/js/failed_message.js b/mail_tracking/static/src/js/failed_message.js deleted file mode 100644 index e827ef60d..000000000 --- a/mail_tracking/static/src/js/failed_message.js +++ /dev/null @@ -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; - -}); diff --git a/mail_tracking/static/src/js/failed_message/discuss.js b/mail_tracking/static/src/js/failed_message/discuss.js new file mode 100644 index 000000000..313041947 --- /dev/null +++ b/mail_tracking/static/src/js/failed_message/discuss.js @@ -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); + }, + }); + +}); diff --git a/mail_tracking/static/src/js/failed_message/widget.js b/mail_tracking/static/src/js/failed_message/widget.js new file mode 100644 index 000000000..00d2a5e3e --- /dev/null +++ b/mail_tracking/static/src/js/failed_message/widget.js @@ -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; + +}); diff --git a/mail_tracking/static/src/xml/failed_message/common.xml b/mail_tracking/static/src/xml/failed_message/common.xml new file mode 100644 index 000000000..05124577f --- /dev/null +++ b/mail_tracking/static/src/xml/failed_message/common.xml @@ -0,0 +1,15 @@ + + + + + + + Set as Reviewed + + + Retry + + + + + diff --git a/mail_tracking/static/src/xml/discuss.xml b/mail_tracking/static/src/xml/failed_message/discuss.xml similarity index 60% rename from mail_tracking/static/src/xml/discuss.xml rename to mail_tracking/static/src/xml/failed_message/discuss.xml index 786d57ed7..fb84da01e 100644 --- a/mail_tracking/static/src/xml/discuss.xml +++ b/mail_tracking/static/src/xml/failed_message/discuss.xml @@ -25,15 +25,4 @@ - - - - Set as Reviewed - - - Retry - - - - diff --git a/mail_tracking/static/src/xml/failed_message.xml b/mail_tracking/static/src/xml/failed_message/widget.xml similarity index 93% rename from mail_tracking/static/src/xml/failed_message.xml rename to mail_tracking/static/src/xml/failed_message/widget.xml index d47d13b4c..cafe38d9d 100644 --- a/mail_tracking/static/src/xml/failed_message.xml +++ b/mail_tracking/static/src/xml/failed_message/widget.xml @@ -28,10 +28,10 @@ - - + Set as Reviewed - + Retry diff --git a/mail_tracking/views/assets.xml b/mail_tracking/views/assets.xml index 9f88fbef1..5858e841a 100644 --- a/mail_tracking/views/assets.xml +++ b/mail_tracking/views/assets.xml @@ -13,7 +13,9 @@