From 8881e61ec8512e504fcf798519745d73b68b5656 Mon Sep 17 00:00:00 2001 From: Martin Geubelle Date: Tue, 11 Jul 2017 17:18:19 +0200 Subject: [FIX] mail: make many2many_tags_email widget work This widget hasn't been rewritten with the new views. The purpose of this widget is to open a popup for each invalid partners (without email) in a many2many to fill the email. If the email is not set, the partner will not appear in the tags and its id will not be sent (which should not be the role of a widget but that's the way it is). --- addons/mail/static/src/js/many2many_tags_email.js | 144 +++++++++++++++++----- 1 file changed, 111 insertions(+), 33 deletions(-) (limited to 'addons/mail/static/src/js') diff --git a/addons/mail/static/src/js/many2many_tags_email.js b/addons/mail/static/src/js/many2many_tags_email.js index 52e213ddb7d..d266147bcc7 100644 --- a/addons/mail/static/src/js/many2many_tags_email.js +++ b/addons/mail/static/src/js/many2many_tags_email.js @@ -1,53 +1,131 @@ odoo.define('mail.many2manytags', function (require) { "use strict"; -// FIXME: apply https://github.com/odoo/odoo/commit/1217ae914b313df7fe8511c138871e585bb21c81 - +var BasicModel = require('web.BasicModel'); var core = require('web.core'); var form_common = require('web.view_dialogs'); var field_registry = require('web.field_registry'); var relational_fields = require('web.relational_fields'); +var M2MTags = relational_fields.FieldMany2ManyTags; var _t = core._t; -var FieldMany2ManyTags = relational_fields.FieldMany2ManyTags; +BasicModel.include({ + + //-------------------------------------------------------------------------- + // Private + //-------------------------------------------------------------------------- -var FieldMany2ManyTagsEmail = FieldMany2ManyTags.extend({ - init: function() { - this.values_checking = []; - this._super.apply(this, arguments); + /** + * @private + * @param {Object} record - an element from the localData + * @param {string} fieldName + * @return {Deferred} the deferred is resolved with the + * invalidPartnerIds + */ + _setInvalidMany2ManyTagsEmail: function (record, fieldName) { + var self = this; + var localID = (record._changes && fieldName in record._changes) ? + record._changes[fieldName] : + record.data[fieldName]; + var list = this.localData[localID]; + var invalidPartnerIds = []; + _.each(list.data, function (id) { + var record = self.localData[id]; + if (!record.data.email) { + invalidPartnerIds.push(record); + } + }); + var def; + if (invalidPartnerIds) { + // remove invalid partners + var changes = {operation: 'REMOVE', ids: _.pluck(invalidPartnerIds, 'id')}; + def = this._applyX2ManyChange(record, fieldName, changes); + } + return $.when(def).then(function () { + return $.when({ + invalidPartnerIds: _.pluck(invalidPartnerIds, 'res_id'), + }); + }); }, +}); + +var FieldMany2ManyTagsEmail = M2MTags.extend({ + fieldsToFetch: _.extend({}, M2MTags.prototype.fieldsToFetch, { + email: {type: 'char'}, + }), + specialData: "_setInvalidMany2ManyTagsEmail", + + //-------------------------------------------------------------------------- + // Private + //-------------------------------------------------------------------------- - add_id: function (id) { + /** + * Open a popup for each invalid partners (without email) to fill the email. + * + * @private + * @returns {Deferred} + */ + _checkEmailPopup: function () { var self = this; - var _super = this._super.bind(this); - // check partner has email - this.trigger_up('perform_model_rpc', { - model: 'res.partner', - method: 'search', - args: [[ - ["id", "=", id], - ["email", "=", false], - ]], - on_success: function(partner_id) { - if (partner_id.length) { - // invalid partner - var pop = new form_common.FormViewDialog(self, { - res_model: 'res.partner', - res_id: partner_id[0], - title: _t("Please complete partner's informations and Email"), - }).open(); - pop.on('write_completed', self, function () { - // self.values_checking = _.without(self.values_checking, id); - _super.apply(self, [id]); - }); - } else { - // valid partner - _super.apply(self, [id]); - } + + var popupDefs = []; + var validPartners = []; + + // propose the user to correct invalid partners + _.each(this.record.specialData[this.name].invalidPartnerIds, function (resID) { + var def = $.Deferred(); + popupDefs.push(def); + + var pop = new form_common.FormViewDialog(self, { + res_model: self.field.relation, + res_id: resID, + title: _t("Please complete partner's informations and Email"), + on_saved: function (record) { + if (record.data.email) { + validPartners.push(record.res_id); + } + }, + }).open(); + pop.on('closed', self, function () { + def.resolve(); + }); + }); + return $.when.apply($, popupDefs).then(function() { + // All popups have been processed for the given ids + // It is now time to set the final value with valid partners ids. + validPartners = _.uniq(validPartners); + if (validPartners.length) { + var values = _.map(validPartners, function (id) { + return {id: id}; + }); + self._setValue({ + operation: 'ADD_M2M', + ids: values, + }); } }); }, + /** + * Override to check if all many2many values have an email set before + * rendering the widget. + * + * @override + * @private + */ + _render: function () { + var self = this; + var def = $.Deferred(); + var _super = this._super.bind(this); + if (this.record.specialData[this.name].invalidPartnerIds.length) { + def = this._checkEmailPopup(); + } else { + def.resolve(); + } + return def.then(function () { + return _super.apply(self, arguments); + }); + }, }); field_registry.add('many2many_tags_email', FieldMany2ManyTagsEmail); -- cgit v1.2.3 From 9ee00dd265457948e0cfc8bdcca2a34064191d0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A9ry=20Debongnie?= Date: Tue, 11 Jul 2017 15:53:36 +0200 Subject: [FIX] mail: prevent crash when chat system is not ready When a chatter is created, appended, and destroyed before being ready, bad things could happen. This is because the code in start/other deferred was executed regardless if the widget was still alive. And, some mechanisms, such as _getBus, depends on the event system. If the widget is destroyed, it will be remove from the component tree and such functions will then return undefined. To protect agains those issues, we simply make sure that the deferred are only resolved when the widget is still alive. --- addons/mail/static/src/js/thread_field.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'addons/mail/static/src/js') diff --git a/addons/mail/static/src/js/thread_field.js b/addons/mail/static/src/js/thread_field.js index 481dc49af36..0d7635cae8b 100644 --- a/addons/mail/static/src/js/thread_field.js +++ b/addons/mail/static/src/js/thread_field.js @@ -21,7 +21,7 @@ var ThreadField = AbstractField.extend(chat_mixin, { this.msgIDs = this.value.res_ids; }, willStart: function () { - return this._chatReady(); + return this.alive(this._chatReady()); }, start: function () { var self = this; @@ -43,7 +43,7 @@ var ThreadField = AbstractField.extend(chat_mixin, { var def1 = this.thread.appendTo(this.$el); var def2 = this._super.apply(this, arguments); - return $.when(def1, def2).then(function () { + return this.alive($.when(def1, def2)).then(function () { // unwrap the thread to remove an unnecessary level on div self.setElement(self.thread.$el); -- cgit v1.2.3