diff --git a/mail_base/static/lib/base.js b/mail_base/static/lib/base.js
index 3971c9f..67bb4b5 100644
--- a/mail_base/static/lib/base.js
+++ b/mail_base/static/lib/base.js
@@ -11,6 +11,11 @@ var session = require('web.session');
var time = require('web.time');
var web_client = require('web.web_client');
+var composer = require('mail.composer');
+var config = require('web.config');
+var Chatter = require('mail.Chatter');
+var form_common = require('web.form_common');
+
var _t = core._t;
var _lt = core._lt;
var LIMIT = 100;
@@ -125,6 +130,288 @@ ChatAction.include({
}
});
+var MailComposer = composer.BasicComposer.extend({
+ template: 'mail.chatter.ChatComposer',
+
+ init: function (parent, dataset, options) {
+ this._super(parent, options);
+ this.thread_dataset = dataset;
+ this.suggested_partners = [];
+ this.options = _.defaults(this.options, {
+ display_mode: 'textarea',
+ record_name: false,
+ is_log: false,
+ });
+ if (this.options.is_log) {
+ this.options.send_text = _t('Log');
+ }
+ this.events = _.extend(this.events, {
+ 'click .o_composer_button_full_composer': 'on_open_full_composer',
+ });
+ },
+
+ willStart: function () {
+ if (this.options.is_log) {
+ return this._super.apply(this, arguments);
+ }
+ return $.when(this._super.apply(this, arguments), this.message_get_suggested_recipients());
+ },
+
+ should_send: function () {
+ return false;
+ },
+
+ preprocess_message: function () {
+ var self = this;
+ var def = $.Deferred();
+ this._super().then(function (message) {
+ message = _.extend(message, {
+ subtype: 'mail.mt_comment',
+ message_type: 'comment',
+ content_subtype: 'html',
+ context: self.context,
+ });
+
+ // Subtype
+ if (self.options.is_log) {
+ message.subtype = 'mail.mt_note';
+ }
+
+ // Partner_ids
+ if (!self.options.is_log) {
+ var checked_suggested_partners = self.get_checked_suggested_partners();
+ self.check_suggested_partners(checked_suggested_partners).done(function (partner_ids) {
+ message.partner_ids = (message.partner_ids || []).concat(partner_ids);
+ // update context
+ message.context = _.defaults({}, message.context, {
+ mail_post_autofollow: true,
+ });
+ def.resolve(message);
+ });
+ } else {
+ def.resolve(message);
+ }
+
+ });
+
+ return def;
+ },
+
+ /**
+ * Send the message on SHIFT+ENTER, but go to new line on ENTER
+ */
+ prevent_send: function (event) {
+ return !event.shiftKey;
+ },
+
+ message_get_suggested_recipients: function () {
+ var self = this;
+ var email_addresses = _.pluck(this.suggested_partners, 'email_address');
+ return this.thread_dataset
+ .call('message_get_suggested_recipients', [[this.context.default_res_id], this.context])
+ .done(function (suggested_recipients) {
+ var thread_recipients = suggested_recipients[self.context.default_res_id];
+ _.each(thread_recipients, function (recipient) {
+ var parsed_email = utils.parse_email(recipient[1]);
+ if (_.indexOf(email_addresses, parsed_email[1]) === -1) {
+ self.suggested_partners.push({
+ checked: true,
+ partner_id: recipient[0],
+ full_name: recipient[1],
+ name: parsed_email[0],
+ email_address: parsed_email[1],
+ reason: recipient[2],
+ });
+ }
+ });
+ });
+ },
+
+ /**
+ * Get the list of selected suggested partners
+ * @returns Array() : list of 'recipient' selected partners (may not be created in db)
+ **/
+ get_checked_suggested_partners: function () {
+ var self = this;
+ var checked_partners = [];
+ this.$('.o_composer_suggested_partners input:checked').each(function() {
+ var full_name = $(this).data('fullname');
+ checked_partners = checked_partners.concat(_.filter(self.suggested_partners, function(item) {
+ return full_name === item.full_name;
+ }));
+ });
+ return checked_partners;
+ },
+
+ /**
+ * Check the additional partners (not necessary registered partners), and open a popup form view
+ * for the ones who informations is missing.
+ * @param Array : list of 'recipient' partners to complete informations or validate
+ * @returns Deferred resolved with the list of checked suggested partners (real partner)
+ **/
+ check_suggested_partners: function (checked_suggested_partners) {
+ var self = this;
+ var check_done = $.Deferred();
+
+ var recipients = _.filter(checked_suggested_partners, function (recipient) { return recipient.checked; });
+ var recipients_to_find = _.filter(recipients, function (recipient) { return (! recipient.partner_id); });
+ var names_to_find = _.pluck(recipients_to_find, 'full_name');
+ var recipients_to_check = _.filter(recipients, function (recipient) { return (recipient.partner_id && ! recipient.email_address); });
+ var recipient_ids = _.pluck(_.filter(recipients, function (recipient) { return recipient.partner_id && recipient.email_address; }), 'partner_id');
+
+ var names_to_remove = [];
+ var recipient_ids_to_remove = [];
+
+ // have unknown names -> call message_get_partner_info_from_emails to try to find partner_id
+ var find_done = $.Deferred();
+ if (names_to_find.length > 0) {
+ find_done = self.thread_dataset.call('message_partner_info_from_emails', [[this.context.default_res_id], names_to_find]);
+ } else {
+ find_done.resolve([]);
+ }
+
+ // for unknown names + incomplete partners -> open popup - cancel = remove from recipients
+ $.when(find_done).pipe(function (result) {
+ var emails_deferred = [];
+ var recipient_popups = result.concat(recipients_to_check);
+
+ _.each(recipient_popups, function (partner_info) {
+ var deferred = $.Deferred();
+ emails_deferred.push(deferred);
+
+ var partner_name = partner_info.full_name;
+ var partner_id = partner_info.partner_id;
+ var parsed_email = utils.parse_email(partner_name);
+
+ var dialog = new form_common.FormViewDialog(self, {
+ res_model: 'res.partner',
+ res_id: partner_id,
+ context: {
+ force_email: true,
+ ref: "compound_context",
+ default_name: parsed_email[0],
+ default_email: parsed_email[1],
+ },
+ title: _t("Please complete partner's informations"),
+ disable_multiple_selection: true,
+ }).open();
+ dialog.on('closed', self, function () {
+ deferred.resolve();
+ });
+ dialog.opened().then(function () {
+ dialog.view_form.on('on_button_cancel', self, function () {
+ names_to_remove.push(partner_name);
+ if (partner_id) {
+ recipient_ids_to_remove.push(partner_id);
+ }
+ });
+ });
+ });
+ $.when.apply($, emails_deferred).then(function () {
+ var new_names_to_find = _.difference(names_to_find, names_to_remove);
+ find_done = $.Deferred();
+ if (new_names_to_find.length > 0) {
+ find_done = self.thread_dataset.call('message_partner_info_from_emails', [[self.context.default_res_id], new_names_to_find, true]);
+ } else {
+ find_done.resolve([]);
+ }
+ $.when(find_done).pipe(function (result) {
+ var recipient_popups = result.concat(recipients_to_check);
+ _.each(recipient_popups, function (partner_info) {
+ if (partner_info.partner_id && _.indexOf(partner_info.partner_id, recipient_ids_to_remove) === -1) {
+ recipient_ids.push(partner_info.partner_id);
+ }
+ });
+ }).pipe(function () {
+ check_done.resolve(recipient_ids);
+ });
+ });
+ });
+ return check_done;
+ },
+
+ on_open_full_composer: function() {
+ if (!this.do_check_attachment_upload()){
+ return false;
+ }
+
+ var self = this;
+ var recipient_done = $.Deferred();
+ if (this.options.is_log) {
+ recipient_done.resolve([]);
+ } else {
+ var checked_suggested_partners = this.get_checked_suggested_partners();
+ recipient_done = this.check_suggested_partners(checked_suggested_partners);
+ }
+ recipient_done.then(function (partner_ids) {
+ var context = {
+ default_parent_id: self.id,
+ default_body: utils.get_text2html(self.$input.val()),
+ default_attachment_ids: _.pluck(self.get('attachment_ids'), 'id'),
+ default_partner_ids: partner_ids,
+ default_is_log: self.options.is_log,
+ mail_post_autofollow: true,
+ };
+
+ if (self.context.default_model && self.context.default_res_id) {
+ context.default_model = self.context.default_model;
+ context.default_res_id = self.context.default_res_id;
+ }
+
+ self.do_action({
+ type: 'ir.actions.act_window',
+ res_model: 'mail.compose.message',
+ view_mode: 'form',
+ view_type: 'form',
+ views: [[false, 'form']],
+ target: 'new',
+ context: context,
+ }, {
+ on_close: function() {
+ self.trigger('need_refresh');
+ var parent = self.getParent();
+ chat_manager.get_messages({model: parent.model, res_id: parent.res_id});
+ },
+ }).then(self.trigger.bind(self, 'close_composer'));
+ });
+ }
+});
+
+Chatter.include({
+ open_composer: function (options) {
+ var self = this;
+ var old_composer = this.composer;
+ // create the new composer
+ this.composer = new MailComposer(this, this.thread_dataset, {
+ commands_enabled: false,
+ context: this.context,
+ input_min_height: 50,
+ input_max_height: Number.MAX_VALUE, // no max_height limit for the chatter
+ input_baseline: 14,
+ is_log: options && options.is_log,
+ record_name: this.record_name,
+ default_body: old_composer && old_composer.$input && old_composer.$input.val(),
+ default_mention_selections: old_composer && old_composer.mention_get_listener_selections(),
+ });
+ this.composer.on('input_focused', this, function () {
+ this.composer.mention_set_prefetched_partners(this.mention_suggestions || []);
+ });
+ this.composer.insertBefore(this.$('.o_mail_thread')).then(function () {
+ // destroy existing composer
+ if (old_composer) {
+ old_composer.destroy();
+ }
+ if (!config.device.touch) {
+ self.composer.focus();
+ }
+ self.composer.on('post_message', self, self.on_post_message);
+ self.composer.on('need_refresh', self, self.refresh_followers);
+ self.composer.on('close_composer', null, self.close_composer.bind(self, true));
+ });
+ this.mute_new_message_button(true);
+ },
+});
+
var MailTools = core.Class.extend({
notify_incoming_message: function (msg, options) {
@@ -1164,7 +1451,8 @@ chat_manager.is_ready = init();
return {
ODOOBOT_ID: ODOOBOT_ID,
chat_manager: chat_manager,
- MailTools: MailTools
+ MailTools: MailTools,
+ MailComposer: MailComposer
};
});
diff --git a/mail_private/__openerp__.py b/mail_private/__openerp__.py
index 5b91b62..aab3ec2 100644
--- a/mail_private/__openerp__.py
+++ b/mail_private/__openerp__.py
@@ -16,10 +16,12 @@
"depends": [
"mail",
+ "base"
],
"external_dependencies": {"python": [], "bin": []},
"data": [
'template.xml',
+ 'full_composer_wizard.xml',
],
"qweb": [
'static/src/xml/mail_private.xml',
diff --git a/mail_private/full_composer_wizard.xml b/mail_private/full_composer_wizard.xml
new file mode 100644
index 0000000..7bb5471
--- /dev/null
+++ b/mail_private/full_composer_wizard.xml
@@ -0,0 +1,27 @@
+
+
+
+
+
+ mail.compose.message.form.private
+ mail.compose.message
+
+
+
+
+
+
+
+
+
+
+ {'invisible': [('is_private', '=', True)]}
+
+
+
+
+
+
+
+
+
diff --git a/mail_private/models.py b/mail_private/models.py
index 30eea7c..1f69756 100644
--- a/mail_private/models.py
+++ b/mail_private/models.py
@@ -1,9 +1,14 @@
# -*- coding: utf-8 -*-
-
-from odoo import models, fields
+from odoo import models, fields, api
class MailComposeMessage(models.TransientModel):
_inherit = 'mail.compose.message'
- private = fields.Boolean(string='Send Internal Message')
+ is_private = fields.Boolean(string='Send Internal Message')
+
+ @api.multi
+ def send_mail(self, auto_commit=False):
+ for w in self:
+ w.is_log = True if w.is_private else w.is_log
+ super(MailComposeMessage, self).send_mail(auto_commit=False)
diff --git a/mail_private/static/src/js/mail_private.js b/mail_private/static/src/js/mail_private.js
index 2916592..0476815 100644
--- a/mail_private/static/src/js/mail_private.js
+++ b/mail_private/static/src/js/mail_private.js
@@ -3,19 +3,22 @@ odoo.define('mail_private', function (require) {
var core = require('web.core');
var Chatter = require('mail.Chatter');
+var MailComposer = require('mail_base.base').MailComposer;
var chat_manager = require('mail.chat_manager');
var session = require('web.session');
var Model = require('web.Model');
+var config = require('web.config');
+var utils = require('mail.utils');
- Chatter.include({
- init: function () {
- this._super.apply(this, arguments);
- this.private = false;
- this.events['click .oe_compose_post_private'] = 'on_open_composer_private_message';
- },
+Chatter.include({
+ init: function () {
+ this._super.apply(this, arguments);
+ this.private = false;
+ this.events['click .oe_compose_post_private'] = 'on_open_composer_private_message';
+ },
- on_post_message: function (message) {
+ on_post_message: function (message) {
var self = this;
if (this.private) {
message.subtype = false;
@@ -30,71 +33,147 @@ var Model = require('web.Model');
}).fail(function () {
// todo: display notification
});
+ },
+
+ on_open_composer_private_message: function (event) {
+ var self = this;
+ this.private = true;
+ this.get_recipients_for_internal_message().then(function (data) {
+ self.recipients_for_internal_message = data;
+ self.open_composer({is_private: true});
+ });
},
- on_open_composer_private_message: function (event) {
- var self = this;
- this.private = true;
- this.get_recipients_for_internal_message().then(function (data) {
- var private_message = 'private_message';
- self.recipients_for_internal_message = data;
- self.open_composer(private_message);
+ on_open_composer_new_message: function () {
+ this._super.apply(this, arguments);
+ this.private = false;
+ },
+
+ open_composer: function (options) {
+ var self = this;
+ this._super.apply(this, arguments);
+ if (options && options.is_private) {
+
+ this.composer.options.is_private = options.is_private;
+
+ _.each(self.recipients_for_internal_message, function (partner) {
+ self.composer.suggested_partners.push({
+ checked: (partner.user_ids.length > 0),
+ partner_id: partner.id,
+ full_name: partner.name,
+ name: partner.name,
+ email_address: partner.email,
+ reason: _.include(partner.user_ids, self.session.uid)
+ ?'Partner'
+ :'Follower'
+ });
});
- },
+ }
+ },
- on_open_composer_new_message: function () {
- this._super.apply(this, arguments);
- this.private = false;
- },
+ get_recipients_for_internal_message: function () {
+ var self = this;
+ self.result = {};
+ return new Model(this.context.default_model).query(
+ ['message_follower_ids', 'partner_id']).filter(
+ [['id', '=', self.context.default_res_id]]).all().
+ then(function (thread) {
+ var follower_ids = thread[0].message_follower_ids;
+ self.result[self.context.default_res_id] = [];
+ self.customer = thread[0].partner_id;
- open_composer: function (options) {
- var self = this;
- this._super.apply(this, arguments);
- if (options === 'private_message') {
- //Clear existing suggested partners
- for (var i=0; i
+
+
-
-
-
-
- Followers of
+
+
+ To: Followers of
+
+ ""
- My Followers
- Followers of this document
-
-
-
+
+ this document
+
+
+
+
+
+
+