Merge PR #412 into 12.0

Signed-off-by pedrobaeza
pull/417/head
OCA-git-bot 2019-07-19 07:58:21 +00:00
commit f0ec1a91cb
12 changed files with 237 additions and 20 deletions

View File

@ -70,6 +70,9 @@ These are all available status icons:
.. |unknown| image:: mail_tracking/static/src/img/unknown.png .. |unknown| image:: mail_tracking/static/src/img/unknown.png
:width: 10px :width: 10px
.. |cc| image:: static/src/img/cc.png
:width: 10px
|unknown| **Unknown**: No email tracking info available. Maybe this notified partner has 'Receive Inbox Notifications by Email' == 'Never' |unknown| **Unknown**: No email tracking info available. Maybe this notified partner has 'Receive Inbox Notifications by Email' == 'Never'
|waiting| **Waiting**: Waiting to be sent |waiting| **Waiting**: Waiting to be sent
@ -82,12 +85,14 @@ These are all available status icons:
|opened| **Opened**: Opened by partner |opened| **Opened**: Opened by partner
|cc| **Cc**: It's a Carbon-Copy recipient. Can't know the status so is 'Unknown'
If you want to see all tracking emails and events you can go to If you want to see all tracking emails and events you can go to
* Settings > Technical > Email > Tracking emails * Settings > Technical > Email > Tracking emails
* Settings > Technical > Email > Tracking events * Settings > Technical > Email > Tracking events
Bug Tracker Bug Tracker
=========== ===========
@ -116,6 +121,7 @@ Contributors
* David Vidal * David Vidal
* Ernesto Tejeda * Ernesto Tejeda
* Rafael Blasco * Rafael Blasco
* Alexandre Díaz
Other credits Other credits
~~~~~~~~~~~~~ ~~~~~~~~~~~~~

View File

@ -7,7 +7,7 @@
{ {
"name": "Email tracking", "name": "Email tracking",
"summary": "Email tracking system for all mails sent", "summary": "Email tracking system for all mails sent",
"version": "12.0.1.0.1", "version": "12.0.1.1.0",
"category": "Social Network", "category": "Social Network",
"website": "http://github.com/OCA/social", "website": "http://github.com/OCA/social",
"author": "Tecnativa, " "author": "Tecnativa, "

View File

@ -27,6 +27,12 @@ msgid " * The 'Error' status indicates that there was an error when trying to se
"" ""
msgstr "" msgstr ""
#. module: mail_tracking
#: model:ir.model.fields,help:mail_tracking.field_mail_compose_message__email_cc
#: model:ir.model.fields,help:mail_tracking.field_mail_message__email_cc
msgid "Additional recipients that receive a \"Carbon Copy\" of the e-mail"
msgstr ""
#. module: mail_tracking #. module: mail_tracking
#: model_terms:ir.ui.view,arch_db:mail_tracking.view_mail_tracking_event_search #: model_terms:ir.ui.view,arch_db:mail_tracking.view_mail_tracking_event_search
msgid "Bounce" msgid "Bounce"
@ -47,6 +53,15 @@ msgstr ""
msgid "Bounced" msgid "Bounced"
msgstr "" msgstr ""
#. module: mail_tracking
#: code:addons/mail_tracking/models/mail_thread.py:36
#: code:addons/mail_tracking/models/mail_thread.py:41
#: model:ir.model.fields,field_description:mail_tracking.field_mail_compose_message__email_cc
#: model:ir.model.fields,field_description:mail_tracking.field_mail_message__email_cc
#, python-format
msgid "Cc"
msgstr ""
#. module: mail_tracking #. module: mail_tracking
#: model_terms:ir.ui.view,arch_db:mail_tracking.view_mail_tracking_event_search #: model_terms:ir.ui.view,arch_db:mail_tracking.view_mail_tracking_event_search
msgid "Click" msgid "Click"
@ -143,6 +158,11 @@ msgstr ""
msgid "Email Score" msgid "Email Score"
msgstr "" msgstr ""
#. module: mail_tracking
#: model:ir.model,name:mail_tracking.model_mail_thread
msgid "Email Thread"
msgstr ""
#. module: mail_tracking #. module: mail_tracking
#: model_terms:ir.ui.view,arch_db:mail_tracking.view_res_partner_filter #: model_terms:ir.ui.view,arch_db:mail_tracking.view_res_partner_filter
msgid "Email bounced" msgid "Email bounced"
@ -288,7 +308,7 @@ msgstr ""
#. module: mail_tracking #. module: mail_tracking
#. openerp-web #. openerp-web
#: code:addons/mail_tracking/static/src/js/mail_tracking.js:88 #: code:addons/mail_tracking/static/src/js/mail_tracking.js:126
#, python-format #, python-format
msgid "Message tracking" msgid "Message tracking"
msgstr "" msgstr ""
@ -403,6 +423,13 @@ msgstr ""
msgid "State" msgid "State"
msgstr "" msgstr ""
#. module: mail_tracking
#. openerp-web
#: code:addons/mail_tracking/static/src/xml/mail_tracking.xml:96
#, python-format
msgid "Status: unknown"
msgstr ""
#. module: mail_tracking #. module: mail_tracking
#: model:ir.model.fields,field_description:mail_tracking.field_mail_tracking_email__name #: model:ir.model.fields,field_description:mail_tracking.field_mail_tracking_email__name
#: model_terms:ir.ui.view,arch_db:mail_tracking.view_mail_tracking_email_search #: model_terms:ir.ui.view,arch_db:mail_tracking.view_mail_tracking_email_search
@ -419,7 +446,7 @@ msgstr ""
#. module: mail_tracking #. module: mail_tracking
#. openerp-web #. openerp-web
#: code:addons/mail_tracking/static/src/xml/mail_tracking.xml:47 #: code:addons/mail_tracking/static/src/xml/mail_tracking.xml:53
#, python-format #, python-format
msgid "To:" msgid "To:"
msgstr "" msgstr ""
@ -445,7 +472,7 @@ msgstr ""
#. module: mail_tracking #. module: mail_tracking
#. openerp-web #. openerp-web
#: code:addons/mail_tracking/static/src/js/mail_tracking.js:68 #: code:addons/mail_tracking/static/src/js/mail_tracking.js:106
#, python-format #, python-format
msgid "Tracking partner" msgid "Tracking partner"
msgstr "" msgstr ""

View File

@ -7,3 +7,4 @@ from . import mail_message
from . import mail_tracking_email from . import mail_tracking_email
from . import mail_tracking_event from . import mail_tracking_event
from . import res_partner from . import res_partner
from . import mail_thread

View File

@ -1,12 +1,18 @@
# Copyright 2016 Antonio Espinosa - <antonio.espinosa@tecnativa.com> # Copyright 2016 Antonio Espinosa - <antonio.espinosa@tecnativa.com>
# Copyright 2019 Alexandre Díaz
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from odoo import models, api from odoo import models, api, fields
from odoo.tools import email_split
class MailMessage(models.Model): class MailMessage(models.Model):
_inherit = "mail.message" _inherit = "mail.message"
# Recipients
email_cc = fields.Char("Cc", help='Additional recipients that receive a '
'"Carbon Copy" of the e-mail')
def _tracking_status_map_get(self): def _tracking_status_map_get(self):
return { return {
'False': 'waiting', 'False': 'waiting',
@ -58,10 +64,37 @@ class MailMessage(models.Model):
for partner in partners: for partner in partners:
# If there is partners not included, then status is 'unknown' # If there is partners not included, then status is 'unknown'
partner_trackings.append(( partner_trackings.append((
'unknown', False, partner.name, partner.id)) 'unknown', False, partner.name, partner.id, partner.email))
res[message.id] = partner_trackings res[message.id] = partner_trackings
return res return res
@api.multi
def _get_email_cc(self):
"""This method gets all Cc mails and the associated partner if exist.
The result is a dictionary by 'message id' with a list of tuples
(str:email_cc, list:[partner id, partner display_name] or False)
"""
res = {}
ResPartnerObj = self.env['res.partner']
for message in self:
email_cc_list = email_split(message.email_cc)
email_cc_list_checked = []
if any(email_cc_list):
partners = ResPartnerObj.search([
('email', 'in', email_cc_list)
])
email_cc_list = set(email_cc_list)
for partner in partners:
email_cc_list.discard(partner.email)
email_cc_list_checked.append(
(partner.email, [partner.id, partner.display_name]))
for email in email_cc_list:
email_cc_list_checked.append((email, False))
res.update({
message.id: email_cc_list_checked
})
return res
@api.model @api.model
def _message_read_dict_postprocess(self, messages, message_tree): def _message_read_dict_postprocess(self, messages, message_tree):
res = super(MailMessage, self)._message_read_dict_postprocess( res = super(MailMessage, self)._message_read_dict_postprocess(
@ -69,9 +102,12 @@ class MailMessage(models.Model):
mail_message_ids = {m.get('id') for m in messages if m.get('id')} mail_message_ids = {m.get('id') for m in messages if m.get('id')}
mail_messages = self.browse(mail_message_ids) mail_messages = self.browse(mail_message_ids)
partner_trackings = mail_messages.tracking_status() partner_trackings = mail_messages.tracking_status()
email_cc = mail_messages._get_email_cc()
for message_dict in messages: for message_dict in messages:
mail_message_id = message_dict.get('id', False) mail_message_id = message_dict.get('id', False)
if mail_message_id: if mail_message_id:
message_dict['partner_trackings'] = \ message_dict.update({
partner_trackings[mail_message_id] 'partner_trackings': partner_trackings[mail_message_id],
'email_cc': email_cc[mail_message_id],
})
return res return res

View File

@ -0,0 +1,42 @@
# Copyright 2019 Alexandre Díaz
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from odoo import models, api, _
from email.utils import getaddresses
from odoo.tools import email_split_and_format
class MailThread(models.AbstractModel):
_inherit = "mail.thread"
@api.multi
@api.returns('self', lambda value: value.id)
def message_post(self, *args, **kwargs):
new_message = super().message_post(*args, **kwargs)
email_cc = kwargs.get('cc')
if email_cc:
new_message.sudo().write({
'email_cc': email_cc,
})
return new_message
@api.multi
def message_get_suggested_recipients(self):
res = super().message_get_suggested_recipients()
ResPartnerObj = self.env['res.partner']
for record in self:
messages = record.message_ids.filtered('email_cc')
for msg in messages:
email_cc_list = email_split_and_format(msg.email_cc)
for cc in email_cc_list:
email_parts = getaddresses([cc])[0]
partner_id = record.message_partner_info_from_emails(
[email_parts[1]])[0].get('partner_id')
if not partner_id:
res[record.id].append((False, cc, _('Cc')))
else:
partner = ResPartnerObj.browse(partner_id,
self._prefetch)
record._message_add_suggested_recipient(
res, partner=partner, reason=_('Cc'))
return res

View File

@ -5,3 +5,4 @@
* David Vidal * David Vidal
* Ernesto Tejeda * Ernesto Tejeda
* Rafael Blasco * Rafael Blasco
* Alexandre Díaz

View File

@ -22,6 +22,9 @@ These are all available status icons:
.. |unknown| image:: mail_tracking/static/src/img/unknown.png .. |unknown| image:: mail_tracking/static/src/img/unknown.png
:width: 10px :width: 10px
.. |cc| image:: static/src/img/cc.png
:width: 10px
|unknown| **Unknown**: No email tracking info available. Maybe this notified partner has 'Receive Inbox Notifications by Email' == 'Never' |unknown| **Unknown**: No email tracking info available. Maybe this notified partner has 'Receive Inbox Notifications by Email' == 'Never'
|waiting| **Waiting**: Waiting to be sent |waiting| **Waiting**: Waiting to be sent
@ -34,8 +37,10 @@ These are all available status icons:
|opened| **Opened**: Opened by partner |opened| **Opened**: Opened by partner
|cc| **Cc**: It's a Carbon-Copy recipient. Can't know the status so is 'Unknown'
If you want to see all tracking emails and events you can go to If you want to see all tracking emails and events you can go to
* Settings > Technical > Email > Tracking emails * Settings > Technical > Email > Tracking emails
* Settings > Technical > Email > Tracking events * Settings > Technical > Email > Tracking events

View File

@ -409,6 +409,7 @@ status icon will appear just right to name of notified partner.</p>
<p><img alt="sent" src="mail_tracking/static/src/img/sent.png" style="width: 10px;" /> <strong>Sent</strong>: Sent to SMTP server configured</p> <p><img alt="sent" src="mail_tracking/static/src/img/sent.png" style="width: 10px;" /> <strong>Sent</strong>: Sent to SMTP server configured</p>
<p><img alt="delivered" src="mail_tracking/static/src/img/delivered.png" style="width: 15px;" /> <strong>Delivered</strong>: Delivered to final MX server</p> <p><img alt="delivered" src="mail_tracking/static/src/img/delivered.png" style="width: 15px;" /> <strong>Delivered</strong>: Delivered to final MX server</p>
<p><img alt="opened" src="mail_tracking/static/src/img/opened.png" style="width: 15px;" /> <strong>Opened</strong>: Opened by partner</p> <p><img alt="opened" src="mail_tracking/static/src/img/opened.png" style="width: 15px;" /> <strong>Opened</strong>: Opened by partner</p>
<p><img alt="cc" src="static/src/img/cc.png" style="width: 10px;" /> <strong>Cc</strong>: Its a Carbon-Copy recipient. Cant know the status so is Unknown</p>
<p>If you want to see all tracking emails and events you can go to</p> <p>If you want to see all tracking emails and events you can go to</p>
<ul class="simple"> <ul class="simple">
<li>Settings &gt; Technical &gt; Email &gt; Tracking emails</li> <li>Settings &gt; Technical &gt; Email &gt; Tracking emails</li>
@ -440,6 +441,7 @@ If you spotted it first, help us smashing it by providing a detailed and welcome
<li>David Vidal</li> <li>David Vidal</li>
<li>Ernesto Tejeda</li> <li>Ernesto Tejeda</li>
<li>Rafael Blasco</li> <li>Rafael Blasco</li>
<li>Alexandre Díaz</li>
</ul> </ul>
</li> </li>
</ul> </ul>

View File

@ -28,6 +28,7 @@ odoo.define('mail_tracking.partner_tracking', function(require){
init: function (parent, data, emojis) { init: function (parent, data, emojis) {
this._super.apply(this, arguments); this._super.apply(this, arguments);
this._partnerTrackings = data.partner_trackings || []; this._partnerTrackings = data.partner_trackings || [];
this._emailCc = data.email_cc || [];
}, },
/** /**
@ -37,7 +38,16 @@ odoo.define('mail_tracking.partner_tracking', function(require){
* @return {boolean} * @return {boolean}
*/ */
hasPartnerTrackings: function () { hasPartnerTrackings: function () {
return !!(this._partnerTrackings && (this._partnerTrackings.length > 0)); return _.some(this._partnerTrackings);
},
/**
* State whether this message contains some email Cc values
*
* @return {boolean}
*/
hasEmailCc: function () {
return _.some(this._emailCc);
}, },
/** /**
@ -53,6 +63,34 @@ odoo.define('mail_tracking.partner_tracking', function(require){
} }
return this._partnerTrackings; return this._partnerTrackings;
}, },
/**
* Get the email Cc values of this message
* If this message has no email Cc values, returns []
*
* @return {Array}
*/
getEmailCc: function () {
if (!this.hasEmailCc()) {
return [];
}
return this._emailCc;
},
/**
* Check if the email is an Cc
* If this message has no email Cc values, returns false
*
* @return {Boolean}
*/
isEmailCc: function (email) {
if (!this.hasEmailCc()) {
return false;
}
return _.some(this._emailCc, function (item) {
return item[0] === email;
});
},
}); });
ThreadWidget.include({ ThreadWidget.include({

View File

@ -1,37 +1,43 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!-- Copyright 2016 Antonio Espinosa - <antonio.espinosa@tecnativa.com> <!-- Copyright 2016 Antonio Espinosa - <antonio.espinosa@tecnativa.com>
Copyright 2019 Alexandre Díaz
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). --> License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). -->
<template> <template>
<t t-name="mail.tracking.status"> <t t-name="mail.tracking.status">
<t t-if="tracking[0] == 'unknown'"> <t t-if="isCc">
<span class="mail_tracking_cc">
<i class="fa fa-cc"></i>
</span>
</t>
<t t-elif="tracking[0] == 'unknown'">
<span class="mail_tracking_unknown"> <span class="mail_tracking_unknown">
<i class="fa fa-ban"></i> <i class="fa fa-ban"></i>
</span> </span>
</t> </t>
<t t-if="tracking[0] == 'waiting'"> <t t-elif="tracking[0] == 'waiting'">
<span class="mail_tracking_waiting mail_tracking_pointer"> <span class="mail_tracking_waiting mail_tracking_pointer">
<i class="fa fa-clock-o"></i> <i class="fa fa-clock-o"></i>
</span> </span>
</t> </t>
<t t-if="tracking[0] == 'error'"> <t t-elif="tracking[0] == 'error'">
<span class="mail_tracking_error mail_tracking_pointer"> <span class="mail_tracking_error mail_tracking_pointer">
<i class="fa fa-remove"></i> <i class="fa fa-remove"></i>
</span> </span>
</t> </t>
<t t-if="tracking[0] == 'sent'"> <t t-elif="tracking[0] == 'sent'">
<span class="mail_tracking_sent mail_tracking_pointer"> <span class="mail_tracking_sent mail_tracking_pointer">
<i class="fa fa-check"></i> <i class="fa fa-check"></i>
</span> </span>
</t> </t>
<t t-if="tracking[0] == 'delivered'"> <t t-elif="tracking[0] == 'delivered'">
<span class="fa-stack mail_tracking_delivered mail_tracking_pointer"> <span class="fa-stack mail_tracking_delivered mail_tracking_pointer">
<i class="fa fa-check fa-stack-1x" style="margin-left:1px"></i> <i class="fa fa-check fa-stack-1x" style="margin-left:1px"></i>
<i class="fa fa-check fa-inverse fa-stack-1x" style="margin-left:-2px;"></i> <i class="fa fa-check fa-inverse fa-stack-1x" style="margin-left:-2px;"></i>
<i class="fa fa-check fa-stack-1x" style="margin-left:-3px"></i> <i class="fa fa-check fa-stack-1x" style="margin-left:-3px"></i>
</span> </span>
</t> </t>
<t t-if="tracking[0] == 'opened'"> <t t-elif="tracking[0] == 'opened'">
<span class="fa-stack mail_tracking_opened mail_tracking_pointer"> <span class="fa-stack mail_tracking_opened mail_tracking_pointer">
<i class="fa fa-check fa-stack-1x" style="margin-left:1px"></i> <i class="fa fa-check fa-stack-1x" style="margin-left:1px"></i>
<i class="fa fa-check fa-inverse fa-stack-1x" style="margin-left:-2px;"></i> <i class="fa fa-check fa-inverse fa-stack-1x" style="margin-left:-2px;"></i>
@ -42,16 +48,17 @@
<t t-extend="mail.widget.Thread.Message"> <t t-extend="mail.widget.Thread.Message">
<t t-jquery="p.o_mail_info" t-operation="after"> <t t-jquery="p.o_mail_info" t-operation="after">
<t t-if="message.hasPartnerTrackings()" > <t t-if="message.hasPartnerTrackings() || message.hasEmailCc()" >
<p class="o_mail_tracking"> <p class="o_mail_tracking">
<strong>To:</strong> <strong>To:</strong>
<t t-set="first_tracking" t-value="true"/> <t t-set="first_tracking" t-value="true"/>
<t t-foreach="message.getPartnerTrackings()" t-as="tracking"> <t t-foreach="message.getPartnerTrackings()" t-as="tracking">
<t t-set="isCc" t-value="message.isEmailCc(tracking[4])" />
<t t-if="!first_tracking"> <t t-if="!first_tracking">
- -
</t> </t>
<t t-if="tracking[3]"> <t t-if="tracking[3]">
<a class="o_mail_action_tracking_partner" <a t-attf-class="o_mail_action_tracking_partner #{isCc ? 'o_mail_cc' : ''}"
t-att-data-partner="tracking[3]" t-att-data-partner="tracking[3]"
t-attf-href="#model=res.partner&amp;id=#{tracking[3]}"> t-attf-href="#model=res.partner&amp;id=#{tracking[3]}">
<t t-esc="tracking[2]"/> <t t-esc="tracking[2]"/>
@ -67,6 +74,30 @@
</span> </span>
<t t-set="first_tracking" t-value="false"/> <t t-set="first_tracking" t-value="false"/>
</t> </t>
<t t-foreach="message.getEmailCc()" t-as="cc">
<t t-set="needPrint" t-value="true" />
<t t-foreach="message.getPartnerTrackings()" t-as="tracking">
<t t-if="cc[0] == tracking[4]" t-set="needPrint" t-value="false" />
</t>
<t t-if="needPrint">
<t t-set="isCc" t-value="true" />
<t t-if="cc[1]">
<a t-attf-class="o_mail_action_tracking_partner o_mail_cc"
t-att-data-partner="cc[1][0]"
t-attf-href="#model=res.partner&amp;id=#{cc[1][0]}">
<t t-esc="cc[1][1]"/>
</a>
</t>
<t t-else="">
<span class="o_mail_cc"><t t-esc="cc[0]" /></span>
</t>
<span class="mail_tracking"
title="Status: unknown">
<t t-call="mail.tracking.status"/>
</span>
</t>
</t>
</p> </p>
</t> </t>
</t> </t>

View File

@ -113,6 +113,34 @@ class TestMailTracking(TransactionCase):
tracking_email.event_create('open', metadata) tracking_email.event_create('open', metadata)
self.assertEqual(tracking_email.state, 'opened') self.assertEqual(tracking_email.state, 'opened')
def test_email_cc(self):
message = self.env['mail.message'].create({
'subject': 'Message test',
'author_id': self.sender.id,
'email_from': self.sender.email,
'message_type': 'comment',
'model': 'res.partner',
'res_id': self.recipient.id,
'partner_ids': [(4, self.recipient.id)],
'email_cc': 'unnamed@test.com, sender@example.com',
'body': '<p>This is a test message</p>',
})
message_dict = message.message_format()[0]
self.assertEqual(len(message_dict['email_cc']), 2)
# mail cc
# 'mail.message' First check Cc with res.partner
email_cc = message_dict['email_cc'][0]
self.assertEqual(email_cc[0], 'sender@example.com')
self.assertTrue(email_cc[1])
email_cc = message_dict['email_cc'][1]
self.assertEqual(email_cc[0], 'unnamed@test.com')
self.assertFalse(email_cc[1])
# suggested recipients
recipients = self.recipient.message_get_suggested_recipients()
self.assertEqual(recipients[self.recipient.id][0][1],
'unnamed@test.com')
def mail_send(self, recipient): def mail_send(self, recipient):
mail = self.env['mail.mail'].create({ mail = self.env['mail.mail'].create({
'subject': 'Test subject', 'subject': 'Test subject',