Browse Source

Merge pull request #87 from Tecnativa/9.0-mail_tracking

[MIG] mail_tracking
pull/89/head
Pedro M. Baeza 8 years ago
committed by GitHub
parent
commit
f65f1e291b
  1. 112
      mail_tracking/README.rst
  2. 8
      mail_tracking/__init__.py
  3. 32
      mail_tracking/__openerp__.py
  4. 6
      mail_tracking/controllers/__init__.py
  5. 86
      mail_tracking/controllers/main.py
  6. 13
      mail_tracking/data/tracking_data.xml
  7. 36
      mail_tracking/hooks.py
  8. 448
      mail_tracking/i18n/de.po
  9. 440
      mail_tracking/i18n/es.po
  10. 448
      mail_tracking/i18n/fr.po
  11. 458
      mail_tracking/i18n/sl.po
  12. 11
      mail_tracking/models/__init__.py
  13. 94
      mail_tracking/models/ir_mail_server.py
  14. 36
      mail_tracking/models/mail_mail.py
  15. 79
      mail_tracking/models/mail_message.py
  16. 313
      mail_tracking/models/mail_tracking_email.py
  17. 136
      mail_tracking/models/mail_tracking_event.py
  18. 46
      mail_tracking/models/res_partner.py
  19. 5
      mail_tracking/security/ir.model.access.csv
  20. BIN
      mail_tracking/static/description/icon.png
  21. 21
      mail_tracking/static/src/css/mail_tracking.css
  22. BIN
      mail_tracking/static/src/img/delivered.png
  23. BIN
      mail_tracking/static/src/img/error.png
  24. BIN
      mail_tracking/static/src/img/opened.png
  25. BIN
      mail_tracking/static/src/img/sent.png
  26. BIN
      mail_tracking/static/src/img/unknown.png
  27. BIN
      mail_tracking/static/src/img/waiting.png
  28. 103
      mail_tracking/static/src/js/mail_tracking.js
  29. 73
      mail_tracking/static/src/xml/mail_tracking.xml
  30. 6
      mail_tracking/tests/__init__.py
  31. 262
      mail_tracking/tests/test_mail_tracking.py
  32. 17
      mail_tracking/views/assets.xml
  33. 120
      mail_tracking/views/mail_tracking_email_view.xml
  34. 123
      mail_tracking/views/mail_tracking_event_view.xml
  35. 31
      mail_tracking/views/res_partner_view.xml

112
mail_tracking/README.rst

@ -0,0 +1,112 @@
.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
:alt: License: AGPL-3
=============
Mail tracking
=============
This module shows email notification tracking status for any messages in
mail thread (chatter). Each notified partner will have an intuitive icon just
right to his name.
Installation
============
If you're using a multi-database installation (with or without dbfilter option)
where /web/databse/selector returns a list of more than one database, then
you need to add ``mail_tracking`` addon to wide load addons list
(by default, only ``web`` addon), setting ``--load`` option.
For example, ``--load=web,mail_tracking``
Usage
=====
When user sends a message in mail_thread (chatter), for instance in partner
form, then an email tracking is created for each email notification. Then a
status icon will appear just right to name of notified partner.
These are all available status icons:
.. |sent| image:: mail_tracking/static/src/img/sent.png
:width: 10px
.. |delivered| image:: mail_tracking/static/src/img/delivered.png
:width: 15px
.. |opened| image:: mail_tracking/static/src/img/opened.png
:width: 15px
.. |error| image:: mail_tracking/static/src/img/error.png
:width: 10px
.. |waiting| image:: mail_tracking/static/src/img/waiting.png
:width: 10px
.. |unknown| image:: mail_tracking/static/src/img/unknown.png
:width: 10px
|unknown| **Unknown**: No email tracking info available. Maybe this notified partner has 'Receive Inbox Notifications by Email' == 'Never'
|waiting| **Waiting**: Waiting to be sent
|error| **Error**: Error while sending
|sent| **Sent**: Sent to SMTP server configured
|delivered| **Delivered**: Delivered to final MX server
|opened| **Opened**: Opened by partner
.. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas
:alt: Try me on Runbot
:target: https://runbot.odoo-community.org/runbot/205/9.0
If you want to see all tracking emails and events you can go to
* Settings > Technical > Email > Tracking emails
* Settings > Technical > Email > Tracking events
Bug Tracker
===========
Bugs are tracked on `GitHub Issues
<https://github.com/OCA/social/issues>`_. In case of trouble, please
check there if your issue has already been reported. If you spotted it first,
help us smashing it by providing a detailed and welcomed feedback.
Credits
=======
Images
------
* Odoo Community Association: `Icon <https://github.com/OCA/maintainer-tools/blob/master/template/module/static/description/icon.svg>`_.
* Thanks to `LlubNek <https://openclipart.org/user-detail/LlubNek>`_ and `Openclipart
<https://openclipart.org>`_ for `the icon
<https://openclipart.org/detail/19342/open-envelope>`_.
Contributors
------------
* Pedro M. Baeza <pedro.baeza@tecnativa.com>
* Antonio Espinosa <antonio.espinosa@tecnativa.com>
Maintainer
----------
.. image:: https://odoo-community.org/logo.png
:alt: Odoo Community Association
:target: https://odoo-community.org
This module is maintained by the OCA.
OCA, or the Odoo Community Association, is a nonprofit organization whose
mission is to support the collaborative development of Odoo features and
promote its widespread use.
To contribute to this module, please visit https://odoo-community.org.

8
mail_tracking/__init__.py

@ -0,0 +1,8 @@
# -*- coding: utf-8 -*-
# © 2016 Antonio Espinosa - <antonio.espinosa@tecnativa.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
# flake8: noqa
from . import models
from . import controllers
from .hooks import pre_init_hook

32
mail_tracking/__openerp__.py

@ -0,0 +1,32 @@
# -*- coding: utf-8 -*-
# © 2016 Antonio Espinosa - <antonio.espinosa@tecnativa.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
{
"name": "Email tracking",
"summary": "Email tracking system for all mails sent",
"version": "9.0.1.0.0",
"category": "Social Network",
"website": "http://www.tecnativa.com",
"author": "Tecnativa, "
"Odoo Community Association (OCA)",
"license": "AGPL-3",
"application": False,
"installable": True,
"depends": [
"decimal_precision",
"mail",
],
"data": [
"data/tracking_data.xml",
"security/ir.model.access.csv",
"views/assets.xml",
"views/mail_tracking_email_view.xml",
"views/mail_tracking_event_view.xml",
"views/res_partner_view.xml",
],
"qweb": [
"static/src/xml/mail_tracking.xml",
],
"pre_init_hook": "pre_init_hook",
}

6
mail_tracking/controllers/__init__.py

@ -0,0 +1,6 @@
# -*- coding: utf-8 -*-
# © 2016 Antonio Espinosa - <antonio.espinosa@tecnativa.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
# flake8: noqa
from . import main

86
mail_tracking/controllers/main.py

@ -0,0 +1,86 @@
# -*- coding: utf-8 -*-
# © 2016 Antonio Espinosa - <antonio.espinosa@tecnativa.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
import werkzeug
from psycopg2 import OperationalError
from openerp import api, http, registry, SUPERUSER_ID
import logging
_logger = logging.getLogger(__name__)
BLANK = 'R0lGODlhAQABAIAAANvf7wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw=='
def _env_get(db):
reg = False
try:
reg = registry(db)
except OperationalError:
_logger.warning("Selected BD '%s' not found", db)
except: # pragma: no cover
_logger.warning("Selected BD '%s' connection error", db)
if reg:
return api.Environment(reg.cursor(), SUPERUSER_ID, {})
return False
class MailTrackingController(http.Controller):
def _request_metadata(self):
request = http.request.httprequest
return {
'ip': request.remote_addr or False,
'user_agent': request.user_agent or False,
'os_family': request.user_agent.platform or False,
'ua_family': request.user_agent.browser or False,
}
@http.route('/mail/tracking/all/<string:db>',
type='http', auth='none', csrf=False)
def mail_tracking_all(self, db, **kw):
env = _env_get(db)
if not env:
return 'NOT FOUND'
metadata = self._request_metadata()
response = env['mail.tracking.email'].event_process(
http.request, kw, metadata)
env.cr.commit()
env.cr.close()
return response
@http.route('/mail/tracking/event/<string:db>/<string:event_type>',
type='http', auth='none', csrf=False)
def mail_tracking_event(self, db, event_type, **kw):
env = _env_get(db)
if not env:
return 'NOT FOUND'
metadata = self._request_metadata()
response = env['mail.tracking.email'].event_process(
http.request, kw, metadata, event_type=event_type)
env.cr.commit()
env.cr.close()
return response
@http.route('/mail/tracking/open/<string:db>'
'/<int:tracking_email_id>/blank.gif',
type='http', auth='none')
def mail_tracking_open(self, db, tracking_email_id, **kw):
env = _env_get(db)
if env:
tracking_email = env['mail.tracking.email'].search([
('id', '=', tracking_email_id),
])
if tracking_email:
metadata = self._request_metadata()
tracking_email.event_create('open', metadata)
else:
_logger.warning(
"MailTracking email '%s' not found", tracking_email_id)
env.cr.commit()
env.cr.close()
# Always return GIF blank image
response = werkzeug.wrappers.Response()
response.mimetype = 'image/gif'
response.data = BLANK.decode('base64')
return response

13
mail_tracking/data/tracking_data.xml

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- © 2016 Antonio Espinosa - <antonio.espinosa@tecnativa.com>
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). -->
<openerp>
<data>
<record forcecreate="True" id="decimal_tracking_timestamp" model="decimal.precision">
<field name="name">MailTracking Timestamp</field>
<field name="digits">6</field>
</record>
</data>
</openerp>

36
mail_tracking/hooks.py

@ -0,0 +1,36 @@
# -*- coding: utf-8 -*-
# © 2016 Antonio Espinosa - <antonio.espinosa@tecnativa.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
import logging
from psycopg2.extensions import AsIs
_logger = logging.getLogger(__name__)
def column_exists(cr, table, column):
cr.execute("""
SELECT column_name
FROM information_schema.columns
WHERE table_name = %s AND column_name = %s""", (table, column))
return bool(cr.fetchall())
def column_add_with_value(cr, table, column, field_type, value):
if not column_exists(cr, table, column):
cr.execute("""
ALTER TABLE %s
ADD COLUMN %s %s""", (AsIs(table), AsIs(column), AsIs(field_type)))
cr.execute("""
UPDATE %s SET %s = %s""", (AsIs(table), AsIs(column), value))
def pre_init_hook(cr):
_logger.info("Creating res.partner.tracking_emails_count column "
"with value 0")
column_add_with_value(
cr, "res_partner", "tracking_emails_count", "integer", 0)
_logger.info("Creating res.partner.email_score column "
"with value 50.0")
column_add_with_value(
cr, "res_partner", "email_score", "double precision", 50.0)

448
mail_tracking/i18n/de.po

@ -0,0 +1,448 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * mail_tracking
#
# Translators:
# OCA Transbot <transbot@odoo-community.org>, 2016
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 8.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2016-09-02 02:43+0000\n"
"PO-Revision-Date: 2016-09-02 02:43+0000\n"
"Last-Translator: OCA Transbot <transbot@odoo-community.org>, 2016\n"
"Language-Team: German (https://www.transifex.com/oca/teams/23907/de/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Language: de\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#. module: mail_tracking
#: help:mail.tracking.email,state:0
msgid ""
" * The 'Error' status indicates that there was an error when trying to sent the email, for example, 'No valid recipient'\n"
" * The 'Sent' status indicates that message was succesfully sent via outgoing email server (SMTP).\n"
" * The 'Delivered' status indicates that message was succesfully delivered to recipient Mail Exchange (MX) server.\n"
" * The 'Open' status indicates that message was opened or clicked by recipient.\n"
" * The 'Rejected' status indicates that recipient email address is blacklisted by outgoing email server (SMTP). It is recomended to delete this email address.\n"
" * The 'Spam' status indicates that outgoing email server (SMTP) consider this message as spam.\n"
" * The 'Unsubscribed' status indicates that recipient has requested to be unsubscribed from this message.\n"
" * The 'Bounced' status indicates that message was bounced by recipient Mail Exchange (MX) server.\n"
" * The 'Soft bounced' status indicates that message was soft bounced by recipient Mail Exchange (MX) server.\n"
msgstr ""
#. module: mail_tracking
#: view:mail.tracking.event:mail_tracking.view_mail_tracking_event_search
msgid "Bounce"
msgstr ""
#. module: mail_tracking
#: field:mail.tracking.email,bounce_description:0
msgid "Bounce description"
msgstr ""
#. module: mail_tracking
#: field:mail.tracking.email,bounce_type:0
msgid "Bounce type"
msgstr ""
#. module: mail_tracking
#: selection:mail.tracking.email,state:0
msgid "Bounced"
msgstr ""
#. module: mail_tracking
#: view:mail.tracking.event:mail_tracking.view_mail_tracking_event_search
msgid "Click"
msgstr ""
#. module: mail_tracking
#: selection:mail.tracking.event,event_type:0
msgid "Clicked"
msgstr ""
#. module: mail_tracking
#: field:mail.tracking.event,url:0
msgid "Clicked URL"
msgstr ""
#. module: mail_tracking
#: view:mail.tracking.email:mail_tracking.view_mail_tracking_email_form
#: view:mail.tracking.event:mail_tracking.view_mail_tracking_event_search
#: view:mail.tracking.event:mail_tracking.view_mail_tracking_event_tree
msgid "Country"
msgstr ""
#. module: mail_tracking
#: field:mail.tracking.email,create_uid:0
#: field:mail.tracking.event,create_uid:0
msgid "Created by"
msgstr ""
#. module: mail_tracking
#: field:mail.tracking.email,create_date:0
#: field:mail.tracking.event,create_date:0
msgid "Created on"
msgstr ""
#. module: mail_tracking
#: view:mail.tracking.email:mail_tracking.view_mail_tracking_email_search
#: field:mail.tracking.email,date:0
#: view:mail.tracking.event:mail_tracking.view_mail_tracking_event_search
#: field:mail.tracking.event,date:0
msgid "Date"
msgstr ""
#. module: mail_tracking
#: selection:mail.tracking.event,event_type:0
msgid "Deferral"
msgstr ""
#. module: mail_tracking
#: view:mail.tracking.email:mail_tracking.view_mail_tracking_email_search
#: selection:mail.tracking.email,state:0
msgid "Deferred"
msgstr ""
#. module: mail_tracking
#: view:mail.tracking.email:mail_tracking.view_mail_tracking_email_search
#: selection:mail.tracking.email,state:0
#: view:mail.tracking.event:mail_tracking.view_mail_tracking_event_search
#: selection:mail.tracking.event,event_type:0
msgid "Delivered"
msgstr ""
#. module: mail_tracking
#: field:mail.tracking.event,display_name:0
msgid "Display Name"
msgstr ""
#. module: mail_tracking
#: field:mail.tracking.email,display_name:0
msgid "Display name"
msgstr ""
#. module: mail_tracking
#: view:mail.tracking.email:mail_tracking.view_mail_tracking_email_search
#: field:mail.tracking.email,mail_id:0
msgid "Email"
msgstr "Email"
#. module: mail_tracking
#: field:res.partner,email_score:0
msgid "Email score"
msgstr ""
#. module: mail_tracking
#: selection:mail.tracking.email,state:0
#: view:mail.tracking.event:mail_tracking.view_mail_tracking_event_form
msgid "Error"
msgstr ""
#. module: mail_tracking
#: field:mail.tracking.email,error_smtp_server:0
msgid "Error SMTP server"
msgstr ""
#. module: mail_tracking
#: field:mail.tracking.email,error_description:0
#: field:mail.tracking.event,error_description:0
msgid "Error description"
msgstr ""
#. module: mail_tracking
#: field:mail.tracking.event,error_details:0
msgid "Error details"
msgstr ""
#. module: mail_tracking
#: field:mail.tracking.email,error_type:0
#: field:mail.tracking.event,error_type:0
msgid "Error type"
msgstr ""
#. module: mail_tracking
#: field:mail.tracking.event,event_type:0
msgid "Event type"
msgstr ""
#. module: mail_tracking
#: view:mail.tracking.email:mail_tracking.view_mail_tracking_email_search
#: view:mail.tracking.event:mail_tracking.view_mail_tracking_event_search
msgid "Failed"
msgstr ""
#. module: mail_tracking
#: view:mail.tracking.email:mail_tracking.view_mail_tracking_email_search
#: view:mail.tracking.event:mail_tracking.view_mail_tracking_event_search
msgid "Group By"
msgstr ""
#. module: mail_tracking
#: selection:mail.tracking.event,event_type:0
msgid "Hard bounce"
msgstr ""
#. module: mail_tracking
#: field:mail.tracking.email,id:0 field:mail.tracking.event,id:0
msgid "ID"
msgstr ""
#. module: mail_tracking
#: field:mail.tracking.event,mobile:0
msgid "Is mobile?"
msgstr ""
#. module: mail_tracking
#: field:mail.tracking.email,__last_update:0
#: field:mail.tracking.event,__last_update:0
msgid "Last Modified on"
msgstr ""
#. module: mail_tracking
#: field:mail.tracking.email,write_uid:0 field:mail.tracking.event,write_uid:0
msgid "Last Updated by"
msgstr ""
#. module: mail_tracking
#: field:mail.tracking.email,write_date:0
#: field:mail.tracking.event,write_date:0
msgid "Last Updated on"
msgstr ""
#. module: mail_tracking
#: model:ir.model,name:mail_tracking.model_mail_tracking_email
msgid "MailTracking email"
msgstr ""
#. module: mail_tracking
#: view:mail.tracking.email:mail_tracking.view_mail_tracking_email_search
msgid "MailTracking email search"
msgstr ""
#. module: mail_tracking
#: model:ir.actions.act_window,name:mail_tracking.action_view_mail_tracking_email
#: view:mail.tracking.email:mail_tracking.view_mail_tracking_email_tree
msgid "MailTracking emails"
msgstr ""
#. module: mail_tracking
#: model:ir.model,name:mail_tracking.model_mail_tracking_event
#: view:mail.tracking.email:mail_tracking.view_mail_tracking_email_form
#: view:mail.tracking.event:mail_tracking.view_mail_tracking_event_form
msgid "MailTracking event"
msgstr ""
#. module: mail_tracking
#: view:mail.tracking.event:mail_tracking.view_mail_tracking_event_search
msgid "MailTracking event search"
msgstr ""
#. module: mail_tracking
#: model:ir.actions.act_window,name:mail_tracking.action_view_mail_tracking_event
#: view:mail.tracking.event:mail_tracking.view_mail_tracking_event_tree
msgid "MailTracking events"
msgstr ""
#. module: mail_tracking
#: model:ir.model,name:mail_tracking.model_mail_message
#: field:mail.tracking.email,mail_message_id:0
#: view:mail.tracking.event:mail_tracking.view_mail_tracking_event_search
#: field:mail.tracking.event,tracking_email_id:0
msgid "Message"
msgstr ""
#. module: mail_tracking
#. openerp-web
#: code:addons/mail_tracking/static/src/js/mail_tracking.js:30
#, python-format
msgid "Message tracking"
msgstr ""
#. module: mail_tracking
#: view:mail.tracking.email:mail_tracking.view_mail_tracking_email_search
#: view:mail.tracking.event:mail_tracking.view_mail_tracking_event_search
msgid "Month"
msgstr ""
#. module: mail_tracking
#: selection:mail.tracking.email,state:0
#: view:mail.tracking.event:mail_tracking.view_mail_tracking_event_search
#: selection:mail.tracking.event,event_type:0
msgid "Open"
msgstr ""
#. module: mail_tracking
#: field:mail.tracking.event,os_family:0
msgid "Operating system family"
msgstr ""
#. module: mail_tracking
#: model:ir.model,name:mail_tracking.model_mail_mail
msgid "Outgoing Mails"
msgstr ""
#. module: mail_tracking
#: model:ir.model,name:mail_tracking.model_res_partner
#: field:mail.tracking.email,partner_id:0
msgid "Partner"
msgstr ""
#. module: mail_tracking
#: view:mail.tracking.email:mail_tracking.view_mail_tracking_email_tree
#: view:mail.tracking.event:mail_tracking.view_mail_tracking_event_search
#: field:mail.tracking.event,recipient:0
msgid "Recipient"
msgstr ""
#. module: mail_tracking
#: field:mail.tracking.email,recipient:0
msgid "Recipient email"
msgstr ""
#. module: mail_tracking
#: field:mail.tracking.email,recipient_address:0
msgid "Recipient email address"
msgstr ""
#. module: mail_tracking
#: selection:mail.tracking.email,state:0
#: selection:mail.tracking.event,event_type:0
msgid "Rejected"
msgstr ""
#. module: mail_tracking
#: field:mail.tracking.event,smtp_server:0
msgid "SMTP server"
msgstr ""
#. module: mail_tracking
#: view:mail.tracking.email:mail_tracking.view_mail_tracking_email_search
#: view:mail.tracking.email:mail_tracking.view_mail_tracking_email_tree
msgid "Sender"
msgstr ""
#. module: mail_tracking
#: field:mail.tracking.email,sender:0
msgid "Sender email"
msgstr ""
#. module: mail_tracking
#: view:mail.tracking.email:mail_tracking.view_mail_tracking_email_search
#: selection:mail.tracking.email,state:0
#: view:mail.tracking.event:mail_tracking.view_mail_tracking_event_search
#: selection:mail.tracking.event,event_type:0
msgid "Sent"
msgstr ""
#. module: mail_tracking
#: selection:mail.tracking.event,event_type:0
msgid "Soft bounce"
msgstr ""
#. module: mail_tracking
#: selection:mail.tracking.email,state:0
msgid "Soft bounced"
msgstr ""
#. module: mail_tracking
#: selection:mail.tracking.email,state:0
#: selection:mail.tracking.event,event_type:0
msgid "Spam"
msgstr ""
#. module: mail_tracking
#: view:mail.tracking.email:mail_tracking.view_mail_tracking_email_search
#: field:mail.tracking.email,state:0
msgid "State"
msgstr ""
#. module: mail_tracking
#: view:mail.tracking.email:mail_tracking.view_mail_tracking_email_search
#: field:mail.tracking.email,name:0
msgid "Subject"
msgstr ""
#. module: mail_tracking
#: view:mail.tracking.email:mail_tracking.view_mail_tracking_email_search
#: field:mail.tracking.email,time:0
#: view:mail.tracking.event:mail_tracking.view_mail_tracking_event_search
#: field:mail.tracking.event,time:0
msgid "Time"
msgstr ""
#. module: mail_tracking
#: model:ir.ui.menu,name:mail_tracking.menu_mail_tracking_email
#: view:res.partner:mail_tracking.view_partner_form
#: field:res.partner,tracking_email_ids:0
msgid "Tracking emails"
msgstr ""
#. module: mail_tracking
#: field:res.partner,tracking_emails_count:0
msgid "Tracking emails count"
msgstr ""
#. module: mail_tracking
#: model:ir.ui.menu,name:mail_tracking.menu_mail_tracking_event
#: view:mail.tracking.email:mail_tracking.view_mail_tracking_email_form
#: field:mail.tracking.email,tracking_event_ids:0
msgid "Tracking events"
msgstr ""
#. module: mail_tracking
#: view:mail.tracking.event:mail_tracking.view_mail_tracking_event_search
msgid "Type"
msgstr ""
#. module: mail_tracking
#: view:mail.tracking.event:mail_tracking.view_mail_tracking_event_search
msgid "URL"
msgstr ""
#. module: mail_tracking
#: field:mail.tracking.email,timestamp:0 field:mail.tracking.event,timestamp:0
msgid "UTC timestamp"
msgstr ""
#. module: mail_tracking
#: view:mail.tracking.event:mail_tracking.view_mail_tracking_event_search
msgid "Unsubscribe"
msgstr ""
#. module: mail_tracking
#: view:mail.tracking.email:mail_tracking.view_mail_tracking_email_search
#: selection:mail.tracking.email,state:0
#: selection:mail.tracking.event,event_type:0
msgid "Unsubscribed"
msgstr ""
#. module: mail_tracking
#: field:mail.tracking.event,ip:0
msgid "User IP"
msgstr ""
#. module: mail_tracking
#: view:mail.tracking.email:mail_tracking.view_mail_tracking_email_form
#: view:mail.tracking.event:mail_tracking.view_mail_tracking_event_search
#: view:mail.tracking.event:mail_tracking.view_mail_tracking_event_tree
#: field:mail.tracking.event,user_agent:0
msgid "User agent"
msgstr ""
#. module: mail_tracking
#: field:mail.tracking.event,ua_family:0
msgid "User agent family"
msgstr ""
#. module: mail_tracking
#: view:mail.tracking.event:mail_tracking.view_mail_tracking_event_search
#: field:mail.tracking.event,ua_type:0
msgid "User agent type"
msgstr ""
#. module: mail_tracking
#: field:mail.tracking.event,user_country_id:0
msgid "User country"
msgstr ""

440
mail_tracking/i18n/es.po

@ -0,0 +1,440 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * mail_tracking
#
# Translators:
# OCA Transbot <transbot@odoo-community.org>, 2016
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 8.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2016-08-08 00:45+0000\n"
"PO-Revision-Date: 2016-08-08 00:45+0000\n"
"Last-Translator: OCA Transbot <transbot@odoo-community.org>, 2016\n"
"Language-Team: Spanish (https://www.transifex.com/oca/teams/23907/es/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Language: es\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#. module: mail_tracking
#: help:mail.tracking.email,state:0
msgid ""
" * The 'Error' status indicates that there was an error when trying to sent the email, for example, 'No valid recipient'\n"
" * The 'Sent' status indicates that message was succesfully sent via outgoing email server (SMTP).\n"
" * The 'Delivered' status indicates that message was succesfully delivered to recipient Mail Exchange (MX) server.\n"
" * The 'Open' status indicates that message was opened or clicked by recipient.\n"
" * The 'Rejected' status indicates that recipient email address is blacklisted by outgoing email server (SMTP). It is recomended to delete this email address.\n"
" * The 'Spam' status indicates that outgoing email server (SMTP) consider this message as spam.\n"
" * The 'Unsubscribed' status indicates that recipient has requested to be unsubscribed from this message.\n"
" * The 'Bounced' status indicates that message was bounced by recipient Mail Exchange (MX) server.\n"
" * The 'Soft bounced' status indicates that message was soft bounced by recipient Mail Exchange (MX) server.\n"
msgstr ""
#. module: mail_tracking
#: view:mail.tracking.event:mail_tracking.view_mail_tracking_event_search
msgid "Bounce"
msgstr ""
#. module: mail_tracking
#: field:mail.tracking.email,bounce_description:0
msgid "Bounce description"
msgstr ""
#. module: mail_tracking
#: field:mail.tracking.email,bounce_type:0
msgid "Bounce type"
msgstr ""
#. module: mail_tracking
#: selection:mail.tracking.email,state:0
msgid "Bounced"
msgstr ""
#. module: mail_tracking
#: view:mail.tracking.event:mail_tracking.view_mail_tracking_event_search
msgid "Click"
msgstr ""
#. module: mail_tracking
#: selection:mail.tracking.event,event_type:0
msgid "Clicked"
msgstr ""
#. module: mail_tracking
#: field:mail.tracking.event,url:0
msgid "Clicked URL"
msgstr ""
#. module: mail_tracking
#: view:mail.tracking.email:mail_tracking.view_mail_tracking_email_form
#: view:mail.tracking.event:mail_tracking.view_mail_tracking_event_search
#: view:mail.tracking.event:mail_tracking.view_mail_tracking_event_tree
msgid "Country"
msgstr ""
#. module: mail_tracking
#: field:mail.tracking.email,create_uid:0
#: field:mail.tracking.event,create_uid:0
msgid "Created by"
msgstr ""
#. module: mail_tracking
#: field:mail.tracking.email,create_date:0
#: field:mail.tracking.event,create_date:0
msgid "Created on"
msgstr "Creado en"
#. module: mail_tracking
#: view:mail.tracking.email:mail_tracking.view_mail_tracking_email_search
#: field:mail.tracking.email,date:0
#: view:mail.tracking.event:mail_tracking.view_mail_tracking_event_search
#: field:mail.tracking.event,date:0
msgid "Date"
msgstr "Fecha"
#. module: mail_tracking
#: selection:mail.tracking.event,event_type:0
msgid "Deferral"
msgstr ""
#. module: mail_tracking
#: view:mail.tracking.email:mail_tracking.view_mail_tracking_email_search
#: selection:mail.tracking.email,state:0
msgid "Deferred"
msgstr ""
#. module: mail_tracking
#: view:mail.tracking.email:mail_tracking.view_mail_tracking_email_search
#: selection:mail.tracking.email,state:0
#: view:mail.tracking.event:mail_tracking.view_mail_tracking_event_search
#: selection:mail.tracking.event,event_type:0
msgid "Delivered"
msgstr ""
#. module: mail_tracking
#: field:mail.tracking.event,display_name:0
msgid "Display Name"
msgstr "Nombre mostrado"
#. module: mail_tracking
#: field:mail.tracking.email,display_name:0
msgid "Display name"
msgstr ""
#. module: mail_tracking
#: view:mail.tracking.email:mail_tracking.view_mail_tracking_email_search
#: field:mail.tracking.email,mail_id:0
msgid "Email"
msgstr "Correo electrónico"
#. module: mail_tracking
#: field:res.partner,email_score:0
msgid "Email score"
msgstr ""
#. module: mail_tracking
#: selection:mail.tracking.email,state:0
msgid "Error"
msgstr ""
#. module: mail_tracking
#: field:mail.tracking.email,error_smtp_server:0
msgid "Error SMTP server"
msgstr ""
#. module: mail_tracking
#: field:mail.tracking.email,error_description:0
msgid "Error description"
msgstr ""
#. module: mail_tracking
#: field:mail.tracking.email,error_type:0
msgid "Error type"
msgstr ""
#. module: mail_tracking
#: field:mail.tracking.event,event_type:0
msgid "Event type"
msgstr ""
#. module: mail_tracking
#: view:mail.tracking.email:mail_tracking.view_mail_tracking_email_search
#: view:mail.tracking.event:mail_tracking.view_mail_tracking_event_search
msgid "Failed"
msgstr ""
#. module: mail_tracking
#: view:mail.tracking.email:mail_tracking.view_mail_tracking_email_search
#: view:mail.tracking.event:mail_tracking.view_mail_tracking_event_search
msgid "Group By"
msgstr ""
#. module: mail_tracking
#: selection:mail.tracking.event,event_type:0
msgid "Hard bounce"
msgstr ""
#. module: mail_tracking
#: field:mail.tracking.email,id:0 field:mail.tracking.event,id:0
msgid "ID"
msgstr ""
#. module: mail_tracking
#: field:mail.tracking.event,mobile:0
msgid "Is mobile?"
msgstr ""
#. module: mail_tracking
#: field:mail.tracking.email,__last_update:0
#: field:mail.tracking.event,__last_update:0
msgid "Last Modified on"
msgstr "Última modificación en"
#. module: mail_tracking
#: field:mail.tracking.email,write_uid:0 field:mail.tracking.event,write_uid:0
msgid "Last Updated by"
msgstr ""
#. module: mail_tracking
#: field:mail.tracking.email,write_date:0
#: field:mail.tracking.event,write_date:0
msgid "Last Updated on"
msgstr "Última actualización en"
#. module: mail_tracking
#: model:ir.model,name:mail_tracking.model_mail_tracking_email
msgid "MailTracking email"
msgstr ""
#. module: mail_tracking
#: view:mail.tracking.email:mail_tracking.view_mail_tracking_email_search
msgid "MailTracking email search"
msgstr ""
#. module: mail_tracking
#: model:ir.actions.act_window,name:mail_tracking.action_view_mail_tracking_email
#: view:mail.tracking.email:mail_tracking.view_mail_tracking_email_tree
msgid "MailTracking emails"
msgstr ""
#. module: mail_tracking
#: model:ir.model,name:mail_tracking.model_mail_tracking_event
#: view:mail.tracking.email:mail_tracking.view_mail_tracking_email_form
#: view:mail.tracking.event:mail_tracking.view_mail_tracking_event_form
msgid "MailTracking event"
msgstr ""
#. module: mail_tracking
#: view:mail.tracking.event:mail_tracking.view_mail_tracking_event_search
msgid "MailTracking event search"
msgstr ""
#. module: mail_tracking
#: model:ir.actions.act_window,name:mail_tracking.action_view_mail_tracking_event
#: view:mail.tracking.event:mail_tracking.view_mail_tracking_event_tree
msgid "MailTracking events"
msgstr ""
#. module: mail_tracking
#: model:ir.model,name:mail_tracking.model_mail_message
#: field:mail.tracking.email,mail_message_id:0
#: view:mail.tracking.event:mail_tracking.view_mail_tracking_event_search
#: field:mail.tracking.event,tracking_email_id:0
msgid "Message"
msgstr ""
#. module: mail_tracking
#. openerp-web
#: code:addons/mail_tracking/static/src/js/mail_tracking.js:30
#, python-format
msgid "Message tracking"
msgstr ""
#. module: mail_tracking
#: view:mail.tracking.email:mail_tracking.view_mail_tracking_email_search
#: view:mail.tracking.event:mail_tracking.view_mail_tracking_event_search
msgid "Month"
msgstr "Mes"
#. module: mail_tracking
#: selection:mail.tracking.email,state:0
#: view:mail.tracking.event:mail_tracking.view_mail_tracking_event_search
#: selection:mail.tracking.event,event_type:0
msgid "Open"
msgstr ""
#. module: mail_tracking
#: field:mail.tracking.event,os_family:0
msgid "Operating system family"
msgstr ""
#. module: mail_tracking
#: model:ir.model,name:mail_tracking.model_mail_mail
msgid "Outgoing Mails"
msgstr ""
#. module: mail_tracking
#: model:ir.model,name:mail_tracking.model_res_partner
#: field:mail.tracking.email,partner_id:0
msgid "Partner"
msgstr ""
#. module: mail_tracking
#: view:mail.tracking.email:mail_tracking.view_mail_tracking_email_tree
#: view:mail.tracking.event:mail_tracking.view_mail_tracking_event_search
#: field:mail.tracking.event,recipient:0
msgid "Recipient"
msgstr ""
#. module: mail_tracking
#: field:mail.tracking.email,recipient:0
msgid "Recipient email"
msgstr ""
#. module: mail_tracking
#: field:mail.tracking.email,recipient_address:0
msgid "Recipient email address"
msgstr ""
#. module: mail_tracking
#: selection:mail.tracking.email,state:0
#: selection:mail.tracking.event,event_type:0
msgid "Rejected"
msgstr ""
#. module: mail_tracking
#: field:mail.tracking.event,smtp_server:0
msgid "SMTP server"
msgstr ""
#. module: mail_tracking
#: view:mail.tracking.email:mail_tracking.view_mail_tracking_email_search
#: view:mail.tracking.email:mail_tracking.view_mail_tracking_email_tree
msgid "Sender"
msgstr ""
#. module: mail_tracking
#: field:mail.tracking.email,sender:0
msgid "Sender email"
msgstr ""
#. module: mail_tracking
#: view:mail.tracking.email:mail_tracking.view_mail_tracking_email_search
#: selection:mail.tracking.email,state:0
#: view:mail.tracking.event:mail_tracking.view_mail_tracking_event_search
#: selection:mail.tracking.event,event_type:0
msgid "Sent"
msgstr ""
#. module: mail_tracking
#: selection:mail.tracking.event,event_type:0
msgid "Soft bounce"
msgstr ""
#. module: mail_tracking
#: selection:mail.tracking.email,state:0
msgid "Soft bounced"
msgstr ""
#. module: mail_tracking
#: selection:mail.tracking.email,state:0
#: selection:mail.tracking.event,event_type:0
msgid "Spam"
msgstr ""
#. module: mail_tracking
#: view:mail.tracking.email:mail_tracking.view_mail_tracking_email_search
#: field:mail.tracking.email,state:0
msgid "State"
msgstr ""
#. module: mail_tracking
#: view:mail.tracking.email:mail_tracking.view_mail_tracking_email_search
#: field:mail.tracking.email,name:0
msgid "Subject"
msgstr ""
#. module: mail_tracking
#: view:mail.tracking.email:mail_tracking.view_mail_tracking_email_search
#: field:mail.tracking.email,time:0
#: view:mail.tracking.event:mail_tracking.view_mail_tracking_event_search
#: field:mail.tracking.event,time:0
msgid "Time"
msgstr ""
#. module: mail_tracking
#: model:ir.ui.menu,name:mail_tracking.menu_mail_tracking_email
#: view:res.partner:mail_tracking.view_partner_form
#: field:res.partner,tracking_email_ids:0
msgid "Tracking emails"
msgstr ""
#. module: mail_tracking
#: field:res.partner,tracking_emails_count:0
msgid "Tracking emails count"
msgstr ""
#. module: mail_tracking
#: model:ir.ui.menu,name:mail_tracking.menu_mail_tracking_event
#: view:mail.tracking.email:mail_tracking.view_mail_tracking_email_form
#: field:mail.tracking.email,tracking_event_ids:0
msgid "Tracking events"
msgstr ""
#. module: mail_tracking
#: view:mail.tracking.event:mail_tracking.view_mail_tracking_event_search
msgid "Type"
msgstr ""
#. module: mail_tracking
#: view:mail.tracking.event:mail_tracking.view_mail_tracking_event_search
msgid "URL"
msgstr ""
#. module: mail_tracking
#: field:mail.tracking.email,timestamp:0 field:mail.tracking.event,timestamp:0
msgid "UTC timestamp"
msgstr ""
#. module: mail_tracking
#: view:mail.tracking.event:mail_tracking.view_mail_tracking_event_search
msgid "Unsubscribe"
msgstr ""
#. module: mail_tracking
#: view:mail.tracking.email:mail_tracking.view_mail_tracking_email_search
#: selection:mail.tracking.email,state:0
#: selection:mail.tracking.event,event_type:0
msgid "Unsubscribed"
msgstr ""
#. module: mail_tracking
#: field:mail.tracking.event,ip:0
msgid "User IP"
msgstr ""
#. module: mail_tracking
#: view:mail.tracking.email:mail_tracking.view_mail_tracking_email_form
#: view:mail.tracking.event:mail_tracking.view_mail_tracking_event_search
#: view:mail.tracking.event:mail_tracking.view_mail_tracking_event_tree
#: field:mail.tracking.event,user_agent:0
msgid "User agent"
msgstr ""
#. module: mail_tracking
#: field:mail.tracking.event,ua_family:0
msgid "User agent family"
msgstr ""
#. module: mail_tracking
#: view:mail.tracking.event:mail_tracking.view_mail_tracking_event_search
#: field:mail.tracking.event,ua_type:0
msgid "User agent type"
msgstr ""
#. module: mail_tracking
#: field:mail.tracking.event,user_country_id:0
msgid "User country"
msgstr ""

448
mail_tracking/i18n/fr.po

@ -0,0 +1,448 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * mail_tracking
#
# Translators:
# OCA Transbot <transbot@odoo-community.org>, 2016
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 8.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2016-09-02 02:43+0000\n"
"PO-Revision-Date: 2016-09-02 02:43+0000\n"
"Last-Translator: OCA Transbot <transbot@odoo-community.org>, 2016\n"
"Language-Team: French (https://www.transifex.com/oca/teams/23907/fr/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Language: fr\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
#. module: mail_tracking
#: help:mail.tracking.email,state:0
msgid ""
" * The 'Error' status indicates that there was an error when trying to sent the email, for example, 'No valid recipient'\n"
" * The 'Sent' status indicates that message was succesfully sent via outgoing email server (SMTP).\n"
" * The 'Delivered' status indicates that message was succesfully delivered to recipient Mail Exchange (MX) server.\n"
" * The 'Open' status indicates that message was opened or clicked by recipient.\n"
" * The 'Rejected' status indicates that recipient email address is blacklisted by outgoing email server (SMTP). It is recomended to delete this email address.\n"
" * The 'Spam' status indicates that outgoing email server (SMTP) consider this message as spam.\n"
" * The 'Unsubscribed' status indicates that recipient has requested to be unsubscribed from this message.\n"
" * The 'Bounced' status indicates that message was bounced by recipient Mail Exchange (MX) server.\n"
" * The 'Soft bounced' status indicates that message was soft bounced by recipient Mail Exchange (MX) server.\n"
msgstr ""
#. module: mail_tracking
#: view:mail.tracking.event:mail_tracking.view_mail_tracking_event_search
msgid "Bounce"
msgstr "Erreurs de remise"
#. module: mail_tracking
#: field:mail.tracking.email,bounce_description:0
msgid "Bounce description"
msgstr "Descriptif du rebond"
#. module: mail_tracking
#: field:mail.tracking.email,bounce_type:0
msgid "Bounce type"
msgstr "Type de rebond"
#. module: mail_tracking
#: selection:mail.tracking.email,state:0
msgid "Bounced"
msgstr "Rebonds"
#. module: mail_tracking
#: view:mail.tracking.event:mail_tracking.view_mail_tracking_event_search
msgid "Click"
msgstr "Cliquer"
#. module: mail_tracking
#: selection:mail.tracking.event,event_type:0
msgid "Clicked"
msgstr "Cliqué"
#. module: mail_tracking
#: field:mail.tracking.event,url:0
msgid "Clicked URL"
msgstr "URL cliquée"
#. module: mail_tracking
#: view:mail.tracking.email:mail_tracking.view_mail_tracking_email_form
#: view:mail.tracking.event:mail_tracking.view_mail_tracking_event_search
#: view:mail.tracking.event:mail_tracking.view_mail_tracking_event_tree
msgid "Country"
msgstr "Pays"
#. module: mail_tracking
#: field:mail.tracking.email,create_uid:0
#: field:mail.tracking.event,create_uid:0
msgid "Created by"
msgstr "Créée par"
#. module: mail_tracking
#: field:mail.tracking.email,create_date:0
#: field:mail.tracking.event,create_date:0
msgid "Created on"
msgstr "Créée le"
#. module: mail_tracking
#: view:mail.tracking.email:mail_tracking.view_mail_tracking_email_search
#: field:mail.tracking.email,date:0
#: view:mail.tracking.event:mail_tracking.view_mail_tracking_event_search
#: field:mail.tracking.event,date:0
msgid "Date"
msgstr "Date"
#. module: mail_tracking
#: selection:mail.tracking.event,event_type:0
msgid "Deferral"
msgstr "Déférer"
#. module: mail_tracking
#: view:mail.tracking.email:mail_tracking.view_mail_tracking_email_search
#: selection:mail.tracking.email,state:0
msgid "Deferred"
msgstr ""
#. module: mail_tracking
#: view:mail.tracking.email:mail_tracking.view_mail_tracking_email_search
#: selection:mail.tracking.email,state:0
#: view:mail.tracking.event:mail_tracking.view_mail_tracking_event_search
#: selection:mail.tracking.event,event_type:0
msgid "Delivered"
msgstr "Livré"
#. module: mail_tracking
#: field:mail.tracking.event,display_name:0
msgid "Display Name"
msgstr "Nom à afficher"
#. module: mail_tracking
#: field:mail.tracking.email,display_name:0
msgid "Display name"
msgstr "Nom affiché"
#. module: mail_tracking
#: view:mail.tracking.email:mail_tracking.view_mail_tracking_email_search
#: field:mail.tracking.email,mail_id:0
msgid "Email"
msgstr "Courriel"
#. module: mail_tracking
#: field:res.partner,email_score:0
msgid "Email score"
msgstr "Score du courriel"
#. module: mail_tracking
#: selection:mail.tracking.email,state:0
#: view:mail.tracking.event:mail_tracking.view_mail_tracking_event_form
msgid "Error"
msgstr "Erreur"
#. module: mail_tracking
#: field:mail.tracking.email,error_smtp_server:0
msgid "Error SMTP server"
msgstr "Erreur du serveur SMTP"
#. module: mail_tracking
#: field:mail.tracking.email,error_description:0
#: field:mail.tracking.event,error_description:0
msgid "Error description"
msgstr "Desciptif de l'erreur"
#. module: mail_tracking
#: field:mail.tracking.event,error_details:0
msgid "Error details"
msgstr ""
#. module: mail_tracking
#: field:mail.tracking.email,error_type:0
#: field:mail.tracking.event,error_type:0
msgid "Error type"
msgstr "Type d'erreur"
#. module: mail_tracking
#: field:mail.tracking.event,event_type:0
msgid "Event type"
msgstr "Type d'évènement"
#. module: mail_tracking
#: view:mail.tracking.email:mail_tracking.view_mail_tracking_email_search
#: view:mail.tracking.event:mail_tracking.view_mail_tracking_event_search
msgid "Failed"
msgstr "Échec"
#. module: mail_tracking
#: view:mail.tracking.email:mail_tracking.view_mail_tracking_email_search
#: view:mail.tracking.event:mail_tracking.view_mail_tracking_event_search
msgid "Group By"
msgstr "Regrouper par"
#. module: mail_tracking
#: selection:mail.tracking.event,event_type:0
msgid "Hard bounce"
msgstr ""
#. module: mail_tracking
#: field:mail.tracking.email,id:0 field:mail.tracking.event,id:0
msgid "ID"
msgstr "ID"
#. module: mail_tracking
#: field:mail.tracking.event,mobile:0
msgid "Is mobile?"
msgstr "Est mobile?"
#. module: mail_tracking
#: field:mail.tracking.email,__last_update:0
#: field:mail.tracking.event,__last_update:0
msgid "Last Modified on"
msgstr "Dernière modification le"
#. module: mail_tracking
#: field:mail.tracking.email,write_uid:0 field:mail.tracking.event,write_uid:0
msgid "Last Updated by"
msgstr "Dernière modification par"
#. module: mail_tracking
#: field:mail.tracking.email,write_date:0
#: field:mail.tracking.event,write_date:0
msgid "Last Updated on"
msgstr "Modifié le"
#. module: mail_tracking
#: model:ir.model,name:mail_tracking.model_mail_tracking_email
msgid "MailTracking email"
msgstr "Suivi du courriel: courriel"
#. module: mail_tracking
#: view:mail.tracking.email:mail_tracking.view_mail_tracking_email_search
msgid "MailTracking email search"
msgstr "Suivi du courriel: recherche du courriel"
#. module: mail_tracking
#: model:ir.actions.act_window,name:mail_tracking.action_view_mail_tracking_email
#: view:mail.tracking.email:mail_tracking.view_mail_tracking_email_tree
msgid "MailTracking emails"
msgstr "Suivi du courriel: courriels"
#. module: mail_tracking
#: model:ir.model,name:mail_tracking.model_mail_tracking_event
#: view:mail.tracking.email:mail_tracking.view_mail_tracking_email_form
#: view:mail.tracking.event:mail_tracking.view_mail_tracking_event_form
msgid "MailTracking event"
msgstr "Suivi du courriel: évènement"
#. module: mail_tracking
#: view:mail.tracking.event:mail_tracking.view_mail_tracking_event_search
msgid "MailTracking event search"
msgstr "Suivi du courriel: recherche d'un évènement"
#. module: mail_tracking
#: model:ir.actions.act_window,name:mail_tracking.action_view_mail_tracking_event
#: view:mail.tracking.event:mail_tracking.view_mail_tracking_event_tree
msgid "MailTracking events"
msgstr "Suivi du courriel: évènements"
#. module: mail_tracking
#: model:ir.model,name:mail_tracking.model_mail_message
#: field:mail.tracking.email,mail_message_id:0
#: view:mail.tracking.event:mail_tracking.view_mail_tracking_event_search
#: field:mail.tracking.event,tracking_email_id:0
msgid "Message"
msgstr "Message"
#. module: mail_tracking
#. openerp-web
#: code:addons/mail_tracking/static/src/js/mail_tracking.js:30
#, python-format
msgid "Message tracking"
msgstr "Destinataire du courriel"
#. module: mail_tracking
#: view:mail.tracking.email:mail_tracking.view_mail_tracking_email_search
#: view:mail.tracking.event:mail_tracking.view_mail_tracking_event_search
msgid "Month"
msgstr "Mois"
#. module: mail_tracking
#: selection:mail.tracking.email,state:0
#: view:mail.tracking.event:mail_tracking.view_mail_tracking_event_search
#: selection:mail.tracking.event,event_type:0
msgid "Open"
msgstr "Ouverte"
#. module: mail_tracking
#: field:mail.tracking.event,os_family:0
msgid "Operating system family"
msgstr "Famille du système d'exploitation"
#. module: mail_tracking
#: model:ir.model,name:mail_tracking.model_mail_mail
msgid "Outgoing Mails"
msgstr "Courriels sortants"
#. module: mail_tracking
#: model:ir.model,name:mail_tracking.model_res_partner
#: field:mail.tracking.email,partner_id:0
msgid "Partner"
msgstr "Partenaire"
#. module: mail_tracking
#: view:mail.tracking.email:mail_tracking.view_mail_tracking_email_tree
#: view:mail.tracking.event:mail_tracking.view_mail_tracking_event_search
#: field:mail.tracking.event,recipient:0
msgid "Recipient"
msgstr "Destinataire"
#. module: mail_tracking
#: field:mail.tracking.email,recipient:0
msgid "Recipient email"
msgstr "Courriel du destinataire "
#. module: mail_tracking
#: field:mail.tracking.email,recipient_address:0
msgid "Recipient email address"
msgstr "Adresse de courriel du destinataire"
#. module: mail_tracking
#: selection:mail.tracking.email,state:0
#: selection:mail.tracking.event,event_type:0
msgid "Rejected"
msgstr "Refusé"
#. module: mail_tracking
#: field:mail.tracking.event,smtp_server:0
msgid "SMTP server"
msgstr "Serveur SMTP"
#. module: mail_tracking
#: view:mail.tracking.email:mail_tracking.view_mail_tracking_email_search
#: view:mail.tracking.email:mail_tracking.view_mail_tracking_email_tree
msgid "Sender"
msgstr "Émetteur"
#. module: mail_tracking
#: field:mail.tracking.email,sender:0
msgid "Sender email"
msgstr "Courriel de l'expéditeur"
#. module: mail_tracking
#: view:mail.tracking.email:mail_tracking.view_mail_tracking_email_search
#: selection:mail.tracking.email,state:0
#: view:mail.tracking.event:mail_tracking.view_mail_tracking_event_search
#: selection:mail.tracking.event,event_type:0
msgid "Sent"
msgstr "Envoyé"
#. module: mail_tracking
#: selection:mail.tracking.event,event_type:0
msgid "Soft bounce"
msgstr ""
#. module: mail_tracking
#: selection:mail.tracking.email,state:0
msgid "Soft bounced"
msgstr ""
#. module: mail_tracking
#: selection:mail.tracking.email,state:0
#: selection:mail.tracking.event,event_type:0
msgid "Spam"
msgstr "Pourriel"
#. module: mail_tracking
#: view:mail.tracking.email:mail_tracking.view_mail_tracking_email_search
#: field:mail.tracking.email,state:0
msgid "State"
msgstr "État"
#. module: mail_tracking
#: view:mail.tracking.email:mail_tracking.view_mail_tracking_email_search
#: field:mail.tracking.email,name:0
msgid "Subject"
msgstr "Objet"
#. module: mail_tracking
#: view:mail.tracking.email:mail_tracking.view_mail_tracking_email_search
#: field:mail.tracking.email,time:0
#: view:mail.tracking.event:mail_tracking.view_mail_tracking_event_search
#: field:mail.tracking.event,time:0
msgid "Time"
msgstr "Heure"
#. module: mail_tracking
#: model:ir.ui.menu,name:mail_tracking.menu_mail_tracking_email
#: view:res.partner:mail_tracking.view_partner_form
#: field:res.partner,tracking_email_ids:0
msgid "Tracking emails"
msgstr "Suivi du courriel: courriels"
#. module: mail_tracking
#: field:res.partner,tracking_emails_count:0
msgid "Tracking emails count"
msgstr "Suivi du courriel: nombre de courriels"
#. module: mail_tracking
#: model:ir.ui.menu,name:mail_tracking.menu_mail_tracking_event
#: view:mail.tracking.email:mail_tracking.view_mail_tracking_email_form
#: field:mail.tracking.email,tracking_event_ids:0
msgid "Tracking events"
msgstr "Suivi du courriel: évènements"
#. module: mail_tracking
#: view:mail.tracking.event:mail_tracking.view_mail_tracking_event_search
msgid "Type"
msgstr "Type"
#. module: mail_tracking
#: view:mail.tracking.event:mail_tracking.view_mail_tracking_event_search
msgid "URL"
msgstr "URL"
#. module: mail_tracking
#: field:mail.tracking.email,timestamp:0 field:mail.tracking.event,timestamp:0
msgid "UTC timestamp"
msgstr "Horodatage en UTC"
#. module: mail_tracking
#: view:mail.tracking.event:mail_tracking.view_mail_tracking_event_search
msgid "Unsubscribe"
msgstr "Se désabonner"
#. module: mail_tracking
#: view:mail.tracking.email:mail_tracking.view_mail_tracking_email_search
#: selection:mail.tracking.email,state:0
#: selection:mail.tracking.event,event_type:0
msgid "Unsubscribed"
msgstr "Désincrit"
#. module: mail_tracking
#: field:mail.tracking.event,ip:0
msgid "User IP"
msgstr "IP de l'utilisateur"
#. module: mail_tracking
#: view:mail.tracking.email:mail_tracking.view_mail_tracking_email_form
#: view:mail.tracking.event:mail_tracking.view_mail_tracking_event_search
#: view:mail.tracking.event:mail_tracking.view_mail_tracking_event_tree
#: field:mail.tracking.event,user_agent:0
msgid "User agent"
msgstr "Navigateur"
#. module: mail_tracking
#: field:mail.tracking.event,ua_family:0
msgid "User agent family"
msgstr "Famille du navigateur"
#. module: mail_tracking
#: view:mail.tracking.event:mail_tracking.view_mail_tracking_event_search
#: field:mail.tracking.event,ua_type:0
msgid "User agent type"
msgstr "type de navigateur"
#. module: mail_tracking
#: field:mail.tracking.event,user_country_id:0
msgid "User country"
msgstr "Pays de l'utilisateur"

458
mail_tracking/i18n/sl.po

@ -0,0 +1,458 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * mail_tracking
#
# Translators:
# OCA Transbot <transbot@odoo-community.org>, 2016
# Matjaž Mozetič <m.mozetic@matmoz.si>, 2016
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 8.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2016-09-02 02:43+0000\n"
"PO-Revision-Date: 2016-09-02 02:43+0000\n"
"Last-Translator: Matjaž Mozetič <m.mozetic@matmoz.si>, 2016\n"
"Language-Team: Slovenian (https://www.transifex.com/oca/teams/23907/sl/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Language: sl\n"
"Plural-Forms: nplurals=4; plural=(n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n%100==4 ? 2 : 3);\n"
#. module: mail_tracking
#: help:mail.tracking.email,state:0
msgid ""
" * The 'Error' status indicates that there was an error when trying to sent the email, for example, 'No valid recipient'\n"
" * The 'Sent' status indicates that message was succesfully sent via outgoing email server (SMTP).\n"
" * The 'Delivered' status indicates that message was succesfully delivered to recipient Mail Exchange (MX) server.\n"
" * The 'Open' status indicates that message was opened or clicked by recipient.\n"
" * The 'Rejected' status indicates that recipient email address is blacklisted by outgoing email server (SMTP). It is recomended to delete this email address.\n"
" * The 'Spam' status indicates that outgoing email server (SMTP) consider this message as spam.\n"
" * The 'Unsubscribed' status indicates that recipient has requested to be unsubscribed from this message.\n"
" * The 'Bounced' status indicates that message was bounced by recipient Mail Exchange (MX) server.\n"
" * The 'Soft bounced' status indicates that message was soft bounced by recipient Mail Exchange (MX) server.\n"
msgstr ""
" * Stanje 'Napaka' pomeni, da je prišlo do napake pri pošiljanju e-pošte, npr. 'Ni veljavnih prejemnikov'\n"
" * Stanje 'Poslano' pomeni, da je bilo sporočilo uspešno poslano preko izhodnega e-poštnega strežnika (SMTP).\n"
" * Stanje 'Dostavljeno' pomeni, da je bilo sporočilo uspešno dostavljeno na prejemnikov Mail Exchange (MX) strežnik.\n"
" * Stanje 'Odprto' pomeni, da je prejemnik sporočilo odprl ali kliknil.\n"
" * Stanje 'Zavrnjeno' pomeni, da je prejemnikov e-poštni naslov na črni listi odhodnega e-poštnega strežnika (SMTP). Priporočeno je, da se ta e-poštni naslov izbriše.\n"
" * Stanje 'Neželjeno' pomeni, da izhodni strežnik (SMTP) obravnava to sporočilo kot neželjeno pošto.\n"
" * Stanje 'Izpisan' pomeni, da je prejemnik zahteval izpis iz seznama prejemnikov tega sporočila.\n"
" * Stanje 'Odbito' pomeni, da je bilo sporočilo odbito s strani prejemnikovega Mail Exchange (MX) strežnika.\n"
" * Stanje 'Mehko odbito' pomeni, da je bilo sporočilo 'mehko' odbito s strani prejemnikovega Mail Exchange (MX) strežnika.\n"
#. module: mail_tracking
#: view:mail.tracking.event:mail_tracking.view_mail_tracking_event_search
msgid "Bounce"
msgstr "Odboj"
#. module: mail_tracking
#: field:mail.tracking.email,bounce_description:0
msgid "Bounce description"
msgstr "Opis odboja"
#. module: mail_tracking
#: field:mail.tracking.email,bounce_type:0
msgid "Bounce type"
msgstr "Tip odboja"
#. module: mail_tracking
#: selection:mail.tracking.email,state:0
msgid "Bounced"
msgstr "Odbito"
#. module: mail_tracking
#: view:mail.tracking.event:mail_tracking.view_mail_tracking_event_search
msgid "Click"
msgstr "Kilk"
#. module: mail_tracking
#: selection:mail.tracking.event,event_type:0
msgid "Clicked"
msgstr "Kliknjeno"
#. module: mail_tracking
#: field:mail.tracking.event,url:0
msgid "Clicked URL"
msgstr "Kliknjena URL"
#. module: mail_tracking
#: view:mail.tracking.email:mail_tracking.view_mail_tracking_email_form
#: view:mail.tracking.event:mail_tracking.view_mail_tracking_event_search
#: view:mail.tracking.event:mail_tracking.view_mail_tracking_event_tree
msgid "Country"
msgstr "Država"
#. module: mail_tracking
#: field:mail.tracking.email,create_uid:0
#: field:mail.tracking.event,create_uid:0
msgid "Created by"
msgstr "Ustvaril"
#. module: mail_tracking
#: field:mail.tracking.email,create_date:0
#: field:mail.tracking.event,create_date:0
msgid "Created on"
msgstr "Ustvarjeno"
#. module: mail_tracking
#: view:mail.tracking.email:mail_tracking.view_mail_tracking_email_search
#: field:mail.tracking.email,date:0
#: view:mail.tracking.event:mail_tracking.view_mail_tracking_event_search
#: field:mail.tracking.event,date:0
msgid "Date"
msgstr "Datum"
#. module: mail_tracking
#: selection:mail.tracking.event,event_type:0
msgid "Deferral"
msgstr "Odložitev"
#. module: mail_tracking
#: view:mail.tracking.email:mail_tracking.view_mail_tracking_email_search
#: selection:mail.tracking.email,state:0
msgid "Deferred"
msgstr "Odloženo"
#. module: mail_tracking
#: view:mail.tracking.email:mail_tracking.view_mail_tracking_email_search
#: selection:mail.tracking.email,state:0
#: view:mail.tracking.event:mail_tracking.view_mail_tracking_event_search
#: selection:mail.tracking.event,event_type:0
msgid "Delivered"
msgstr "Dostavljeno"
#. module: mail_tracking
#: field:mail.tracking.event,display_name:0
msgid "Display Name"
msgstr "Prikazni naziv"
#. module: mail_tracking
#: field:mail.tracking.email,display_name:0
msgid "Display name"
msgstr "Prikazni naziv"
#. module: mail_tracking
#: view:mail.tracking.email:mail_tracking.view_mail_tracking_email_search
#: field:mail.tracking.email,mail_id:0
msgid "Email"
msgstr "E-pošta"
#. module: mail_tracking
#: field:res.partner,email_score:0
msgid "Email score"
msgstr "Točkovanje e-pošte"
#. module: mail_tracking
#: selection:mail.tracking.email,state:0
#: view:mail.tracking.event:mail_tracking.view_mail_tracking_event_form
msgid "Error"
msgstr "Napaka"
#. module: mail_tracking
#: field:mail.tracking.email,error_smtp_server:0
msgid "Error SMTP server"
msgstr "Napaka SMTP strežnika"
#. module: mail_tracking
#: field:mail.tracking.email,error_description:0
#: field:mail.tracking.event,error_description:0
msgid "Error description"
msgstr "Opis napake"
#. module: mail_tracking
#: field:mail.tracking.event,error_details:0
msgid "Error details"
msgstr "Podrobnosti o napaki"
#. module: mail_tracking
#: field:mail.tracking.email,error_type:0
#: field:mail.tracking.event,error_type:0
msgid "Error type"
msgstr "Tip napake"
#. module: mail_tracking
#: field:mail.tracking.event,event_type:0
msgid "Event type"
msgstr "Tip dogodka"
#. module: mail_tracking
#: view:mail.tracking.email:mail_tracking.view_mail_tracking_email_search
#: view:mail.tracking.event:mail_tracking.view_mail_tracking_event_search
msgid "Failed"
msgstr "Neuspelo"
#. module: mail_tracking
#: view:mail.tracking.email:mail_tracking.view_mail_tracking_email_search
#: view:mail.tracking.event:mail_tracking.view_mail_tracking_event_search
msgid "Group By"
msgstr "Združi po"
#. module: mail_tracking
#: selection:mail.tracking.event,event_type:0
msgid "Hard bounce"
msgstr "Trdo odbito"
#. module: mail_tracking
#: field:mail.tracking.email,id:0 field:mail.tracking.event,id:0
msgid "ID"
msgstr "ID"
#. module: mail_tracking
#: field:mail.tracking.event,mobile:0
msgid "Is mobile?"
msgstr "Mobilno?"
#. module: mail_tracking
#: field:mail.tracking.email,__last_update:0
#: field:mail.tracking.event,__last_update:0
msgid "Last Modified on"
msgstr "Zadnjič spremenjeno"
#. module: mail_tracking
#: field:mail.tracking.email,write_uid:0 field:mail.tracking.event,write_uid:0
msgid "Last Updated by"
msgstr "Zadnji posodobil"
#. module: mail_tracking
#: field:mail.tracking.email,write_date:0
#: field:mail.tracking.event,write_date:0
msgid "Last Updated on"
msgstr "Zadnjič posodobljeno"
#. module: mail_tracking
#: model:ir.model,name:mail_tracking.model_mail_tracking_email
msgid "MailTracking email"
msgstr "Sledenje e-pošte"
#. module: mail_tracking
#: view:mail.tracking.email:mail_tracking.view_mail_tracking_email_search
msgid "MailTracking email search"
msgstr "Iskalnik sledenja e-pošte"
#. module: mail_tracking
#: model:ir.actions.act_window,name:mail_tracking.action_view_mail_tracking_email
#: view:mail.tracking.email:mail_tracking.view_mail_tracking_email_tree
msgid "MailTracking emails"
msgstr "Sporočila sledenja"
#. module: mail_tracking
#: model:ir.model,name:mail_tracking.model_mail_tracking_event
#: view:mail.tracking.email:mail_tracking.view_mail_tracking_email_form
#: view:mail.tracking.event:mail_tracking.view_mail_tracking_event_form
msgid "MailTracking event"
msgstr "Dogodek sledenja e-pošte"
#. module: mail_tracking
#: view:mail.tracking.event:mail_tracking.view_mail_tracking_event_search
msgid "MailTracking event search"
msgstr "Iskalnik dogodkov sledenja e-pošte"
#. module: mail_tracking
#: model:ir.actions.act_window,name:mail_tracking.action_view_mail_tracking_event
#: view:mail.tracking.event:mail_tracking.view_mail_tracking_event_tree
msgid "MailTracking events"
msgstr "Dogodki sledenja e-pošte"
#. module: mail_tracking
#: model:ir.model,name:mail_tracking.model_mail_message
#: field:mail.tracking.email,mail_message_id:0
#: view:mail.tracking.event:mail_tracking.view_mail_tracking_event_search
#: field:mail.tracking.event,tracking_email_id:0
msgid "Message"
msgstr "Sporočilo"
#. module: mail_tracking
#. openerp-web
#: code:addons/mail_tracking/static/src/js/mail_tracking.js:30
#, python-format
msgid "Message tracking"
msgstr "Sledenje sporočila"
#. module: mail_tracking
#: view:mail.tracking.email:mail_tracking.view_mail_tracking_email_search
#: view:mail.tracking.event:mail_tracking.view_mail_tracking_event_search
msgid "Month"
msgstr "Mesec"
#. module: mail_tracking
#: selection:mail.tracking.email,state:0
#: view:mail.tracking.event:mail_tracking.view_mail_tracking_event_search
#: selection:mail.tracking.event,event_type:0
msgid "Open"
msgstr "Odprto"
#. module: mail_tracking
#: field:mail.tracking.event,os_family:0
msgid "Operating system family"
msgstr "Družina operacijskega sistema"
#. module: mail_tracking
#: model:ir.model,name:mail_tracking.model_mail_mail
msgid "Outgoing Mails"
msgstr "Izhodna pošta"
#. module: mail_tracking
#: model:ir.model,name:mail_tracking.model_res_partner
#: field:mail.tracking.email,partner_id:0
msgid "Partner"
msgstr "Partner"
#. module: mail_tracking
#: view:mail.tracking.email:mail_tracking.view_mail_tracking_email_tree
#: view:mail.tracking.event:mail_tracking.view_mail_tracking_event_search
#: field:mail.tracking.event,recipient:0
msgid "Recipient"
msgstr "Prejemnik"
#. module: mail_tracking
#: field:mail.tracking.email,recipient:0
msgid "Recipient email"
msgstr "Prejemnikova e-pošta"
#. module: mail_tracking
#: field:mail.tracking.email,recipient_address:0
msgid "Recipient email address"
msgstr "Prejemnikova e-pošta"
#. module: mail_tracking
#: selection:mail.tracking.email,state:0
#: selection:mail.tracking.event,event_type:0
msgid "Rejected"
msgstr "Zavrnjeno"
#. module: mail_tracking
#: field:mail.tracking.event,smtp_server:0
msgid "SMTP server"
msgstr "SMTP strežnik"
#. module: mail_tracking
#: view:mail.tracking.email:mail_tracking.view_mail_tracking_email_search
#: view:mail.tracking.email:mail_tracking.view_mail_tracking_email_tree
msgid "Sender"
msgstr "Pošiljatelj"
#. module: mail_tracking
#: field:mail.tracking.email,sender:0
msgid "Sender email"
msgstr "Pošiljateljeva e-pošta"
#. module: mail_tracking
#: view:mail.tracking.email:mail_tracking.view_mail_tracking_email_search
#: selection:mail.tracking.email,state:0
#: view:mail.tracking.event:mail_tracking.view_mail_tracking_event_search
#: selection:mail.tracking.event,event_type:0
msgid "Sent"
msgstr "Poslano"
#. module: mail_tracking
#: selection:mail.tracking.event,event_type:0
msgid "Soft bounce"
msgstr "Mehki odboj"
#. module: mail_tracking
#: selection:mail.tracking.email,state:0
msgid "Soft bounced"
msgstr "Mehko odbito"
#. module: mail_tracking
#: selection:mail.tracking.email,state:0
#: selection:mail.tracking.event,event_type:0
msgid "Spam"
msgstr "Spam"
#. module: mail_tracking
#: view:mail.tracking.email:mail_tracking.view_mail_tracking_email_search
#: field:mail.tracking.email,state:0
msgid "State"
msgstr "Stanje"
#. module: mail_tracking
#: view:mail.tracking.email:mail_tracking.view_mail_tracking_email_search
#: field:mail.tracking.email,name:0
msgid "Subject"
msgstr "Zadeva"
#. module: mail_tracking
#: view:mail.tracking.email:mail_tracking.view_mail_tracking_email_search
#: field:mail.tracking.email,time:0
#: view:mail.tracking.event:mail_tracking.view_mail_tracking_event_search
#: field:mail.tracking.event,time:0
msgid "Time"
msgstr "Čas"
#. module: mail_tracking
#: model:ir.ui.menu,name:mail_tracking.menu_mail_tracking_email
#: view:res.partner:mail_tracking.view_partner_form
#: field:res.partner,tracking_email_ids:0
msgid "Tracking emails"
msgstr "Sledilna e-pošta"
#. module: mail_tracking
#: field:res.partner,tracking_emails_count:0
msgid "Tracking emails count"
msgstr "Števec sledenja e-pošte"
#. module: mail_tracking
#: model:ir.ui.menu,name:mail_tracking.menu_mail_tracking_event
#: view:mail.tracking.email:mail_tracking.view_mail_tracking_email_form
#: field:mail.tracking.email,tracking_event_ids:0
msgid "Tracking events"
msgstr "Sledilni dogodki"
#. module: mail_tracking
#: view:mail.tracking.event:mail_tracking.view_mail_tracking_event_search
msgid "Type"
msgstr "Tip"
#. module: mail_tracking
#: view:mail.tracking.event:mail_tracking.view_mail_tracking_event_search
msgid "URL"
msgstr "URL"
#. module: mail_tracking
#: field:mail.tracking.email,timestamp:0 field:mail.tracking.event,timestamp:0
msgid "UTC timestamp"
msgstr "UTC časovni žig"
#. module: mail_tracking
#: view:mail.tracking.event:mail_tracking.view_mail_tracking_event_search
msgid "Unsubscribe"
msgstr "Odjava"
#. module: mail_tracking
#: view:mail.tracking.email:mail_tracking.view_mail_tracking_email_search
#: selection:mail.tracking.email,state:0
#: selection:mail.tracking.event,event_type:0
msgid "Unsubscribed"
msgstr "Odjavljeno"
#. module: mail_tracking
#: field:mail.tracking.event,ip:0
msgid "User IP"
msgstr "Uporabnikov IP"
#. module: mail_tracking
#: view:mail.tracking.email:mail_tracking.view_mail_tracking_email_form
#: view:mail.tracking.event:mail_tracking.view_mail_tracking_event_search
#: view:mail.tracking.event:mail_tracking.view_mail_tracking_event_tree
#: field:mail.tracking.event,user_agent:0
msgid "User agent"
msgstr "Uporabnikov odjemalec"
#. module: mail_tracking
#: field:mail.tracking.event,ua_family:0
msgid "User agent family"
msgstr "Družina uporabnikovih odjemalcev"
#. module: mail_tracking
#: view:mail.tracking.event:mail_tracking.view_mail_tracking_event_search
#: field:mail.tracking.event,ua_type:0
msgid "User agent type"
msgstr "Tip uporabnikovega odjemalca"
#. module: mail_tracking
#: field:mail.tracking.event,user_country_id:0
msgid "User country"
msgstr "Država uporabnika"

11
mail_tracking/models/__init__.py

@ -0,0 +1,11 @@
# -*- coding: utf-8 -*-
# © 2016 Antonio Espinosa - <antonio.espinosa@tecnativa.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
# flake8: noqa
from . import ir_mail_server
from . import mail_mail
from . import mail_message
from . import mail_tracking_email
from . import mail_tracking_event
from . import res_partner

94
mail_tracking/models/ir_mail_server.py

@ -0,0 +1,94 @@
# -*- coding: utf-8 -*-
# © 2016 Antonio Espinosa - <antonio.espinosa@tecnativa.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
import re
import threading
from openerp import models, api, tools
class IrMailServer(models.Model):
_inherit = "ir.mail_server"
def _tracking_headers_add(self, tracking_email_id, headers):
"""Allow other addons to add its own tracking SMTP headers"""
headers = headers or {}
headers['X-Odoo-Database'] = getattr(
threading.currentThread(), 'dbname', None),
headers['X-Odoo-Tracking-ID'] = tracking_email_id
return headers
def _tracking_email_id_body_get(self, body):
body = body or ''
tracking_email_id = False
# https://regex101.com/r/lW4cB1/2
match = re.search(
r'<img [^>]* data-odoo-tracking-email=["\']([0-9]*)["\']', body)
if match:
try:
tracking_email_id = int(match.group(1))
except: # pragma: no cover
pass
return tracking_email_id
def build_email(self, email_from, email_to, subject, body, email_cc=None,
email_bcc=None, reply_to=False, attachments=None,
message_id=None, references=None, object_id=False,
subtype='plain', headers=None, body_alternative=None,
subtype_alternative='plain'):
tracking_email_id = self._tracking_email_id_body_get(body)
if tracking_email_id:
headers = self._tracking_headers_add(tracking_email_id, headers)
msg = super(IrMailServer, self).build_email(
email_from, email_to, subject, body, email_cc=email_cc,
email_bcc=email_bcc, reply_to=reply_to, attachments=attachments,
message_id=message_id, references=references, object_id=object_id,
subtype=subtype, headers=headers,
body_alternative=body_alternative,
subtype_alternative=subtype_alternative)
return msg
def _tracking_email_get(self, message):
tracking_email_id = False
if message.get('X-Odoo-Tracking-ID', '').isdigit():
tracking_email_id = int(message['X-Odoo-Tracking-ID'])
return self.env['mail.tracking.email'].browse(tracking_email_id)
def _smtp_server_get(self, mail_server_id, smtp_server):
smtp_server_used = False
mail_server = None
if mail_server_id:
mail_server = self.browse(mail_server_id)
elif not smtp_server:
mail_server_ids = self.search([], order='sequence', limit=1)
mail_server = mail_server_ids[0] if mail_server_ids else None
if mail_server:
smtp_server_used = mail_server.smtp_host
else: # pragma: no cover
smtp_server_used = smtp_server or tools.config.get('smtp_server')
return smtp_server_used
@api.model
def send_email(self, message, mail_server_id=None, smtp_server=None,
smtp_port=None, smtp_user=None, smtp_password=None,
smtp_encryption=None, smtp_debug=False):
message_id = False
tracking_email = self._tracking_email_get(message)
smtp_server_used = self._smtp_server_get(
mail_server_id, smtp_server)
try:
message_id = super(IrMailServer, self).send_email(
message, mail_server_id=mail_server_id,
smtp_server=smtp_server, smtp_port=smtp_port,
smtp_user=smtp_user, smtp_password=smtp_password,
smtp_encryption=smtp_encryption, smtp_debug=smtp_debug)
except Exception as e:
if tracking_email:
tracking_email.smtp_error(self, smtp_server_used, e)
raise
if message_id and tracking_email:
vals = tracking_email._tracking_sent_prepare(
self, smtp_server_used, message, message_id)
if vals:
self.env['mail.tracking.event'].sudo().create(vals)
return message_id

36
mail_tracking/models/mail_mail.py

@ -0,0 +1,36 @@
# -*- coding: utf-8 -*-
# © 2016 Antonio Espinosa - <antonio.espinosa@tecnativa.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
import time
from datetime import datetime
from email.utils import COMMASPACE
from openerp import models, api, fields
class MailMail(models.Model):
_inherit = 'mail.mail'
def _tracking_email_prepare(self, partner, email):
ts = time.time()
dt = datetime.utcfromtimestamp(ts)
email_to_list = email.get('email_to', [])
email_to = COMMASPACE.join(email_to_list)
return {
'name': email.get('subject', False),
'timestamp': '%.6f' % ts,
'time': fields.Datetime.to_string(dt),
'mail_id': self.id,
'mail_message_id': self.mail_message_id.id,
'partner_id': partner.id if partner else False,
'recipient': email_to,
'sender': self.email_from,
}
@api.multi
def send_get_email_dict(self, partner=None):
email = super(MailMail, self).send_get_email_dict(partner=partner)
vals = self._tracking_email_prepare(partner, email)
tracking_email = self.env['mail.tracking.email'].sudo().create(vals)
return tracking_email.tracking_img_add(email)

79
mail_tracking/models/mail_message.py

@ -0,0 +1,79 @@
# -*- coding: utf-8 -*-
# © 2016 Antonio Espinosa - <antonio.espinosa@tecnativa.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from openerp import models, api
class MailMessage(models.Model):
_inherit = "mail.message"
def _tracking_status_map_get(self):
return {
'False': 'waiting',
'error': 'error',
'deferred': 'sent',
'sent': 'sent',
'delivered': 'delivered',
'opened': 'opened',
'rejected': 'error',
'spam': 'error',
'unsub': 'opened',
'bounced': 'error',
'soft-bounced': 'error',
}
def _partner_tracking_status_get(self, tracking_email):
tracking_status_map = self._tracking_status_map_get()
status = 'unknown'
if tracking_email:
tracking_email_status = str(tracking_email.state)
status = tracking_status_map.get(tracking_email_status, 'unknown')
return status
@api.multi
def tracking_status(self):
res = {}
for message in self:
partner_trackings = []
partners_already = self.env['res.partner']
partners = self.env['res.partner']
trackings = self.env['mail.tracking.email'].search([
('mail_message_id', '=', message.id),
])
# Search all trackings for this message
for tracking in trackings:
status = self._partner_tracking_status_get(tracking)
recipient = (
tracking.partner_id.display_name or tracking.recipient)
partner_trackings.append((
status, tracking.id, recipient, tracking.partner_id.id))
if tracking.partner_id:
partners_already |= tracking.partner_id
# Search all recipients for this message
if message.partner_ids:
partners |= message.partner_ids
if message.needaction_partner_ids:
partners |= message.needaction_partner_ids
# Remove recipients already included
partners -= partners_already
for partner in partners:
# If there is partners not included, then status is 'unknown'
partner_trackings.append((
'unknown', False, partner.display_name, partner.id))
res[message.id] = partner_trackings
return res
@api.model
def _message_read_dict_postprocess(self, messages, message_tree):
res = super(MailMessage, self)._message_read_dict_postprocess(
messages, message_tree)
mail_message_ids = {m.get('id') for m in messages if m.get('id')}
mail_messages = self.browse(mail_message_ids)
partner_trackings = mail_messages.tracking_status()
for message_dict in messages:
mail_message_id = message_dict.get('id', False)
if mail_message_id:
message_dict['partner_trackings'] = \
partner_trackings[mail_message_id]
return res

313
mail_tracking/models/mail_tracking_email.py

@ -0,0 +1,313 @@
# -*- coding: utf-8 -*-
# © 2016 Antonio Espinosa - <antonio.espinosa@tecnativa.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
import logging
import urlparse
import time
import re
from datetime import datetime
from openerp import models, api, fields, tools
import openerp.addons.decimal_precision as dp
_logger = logging.getLogger(__name__)
EVENT_OPEN_DELTA = 10 # seconds
EVENT_CLICK_DELTA = 5 # seconds
class MailTrackingEmail(models.Model):
_name = "mail.tracking.email"
_order = 'time desc'
_rec_name = 'display_name'
_description = 'MailTracking email'
name = fields.Char(string="Subject", readonly=True, index=True)
display_name = fields.Char(
string="Display name", readonly=True, store=True,
compute="_compute_display_name")
timestamp = fields.Float(
string='UTC timestamp', readonly=True,
digits=dp.get_precision('MailTracking Timestamp'))
time = fields.Datetime(string="Time", readonly=True)
date = fields.Date(
string="Date", readonly=True, compute="_compute_date", store=True)
mail_message_id = fields.Many2one(
string="Message", comodel_name='mail.message', readonly=True)
mail_id = fields.Many2one(
string="Email", comodel_name='mail.mail', readonly=True)
partner_id = fields.Many2one(
string="Partner", comodel_name='res.partner', readonly=True)
recipient = fields.Char(string='Recipient email', readonly=True)
recipient_address = fields.Char(
string='Recipient email address', readonly=True, store=True,
compute='_compute_recipient_address')
sender = fields.Char(string='Sender email', readonly=True)
state = fields.Selection([
('error', 'Error'),
('deferred', 'Deferred'),
('sent', 'Sent'),
('delivered', 'Delivered'),
('opened', 'Open'),
('rejected', 'Rejected'),
('spam', 'Spam'),
('unsub', 'Unsubscribed'),
('bounced', 'Bounced'),
('soft-bounced', 'Soft bounced'),
], string='State', index=True, readonly=True, default=False,
help=" * The 'Error' status indicates that there was an error "
"when trying to sent the email, for example, "
"'No valid recipient'\n"
" * The 'Sent' status indicates that message was succesfully "
"sent via outgoing email server (SMTP).\n"
" * The 'Delivered' status indicates that message was "
"succesfully delivered to recipient Mail Exchange (MX) server.\n"
" * The 'Open' status indicates that message was opened or "
"clicked by recipient.\n"
" * The 'Rejected' status indicates that recipient email "
"address is blacklisted by outgoing email server (SMTP). "
"It is recomended to delete this email address.\n"
" * The 'Spam' status indicates that outgoing email "
"server (SMTP) consider this message as spam.\n"
" * The 'Unsubscribed' status indicates that recipient has "
"requested to be unsubscribed from this message.\n"
" * The 'Bounced' status indicates that message was bounced "
"by recipient Mail Exchange (MX) server.\n"
" * The 'Soft bounced' status indicates that message was soft "
"bounced by recipient Mail Exchange (MX) server.\n")
error_smtp_server = fields.Char(string='Error SMTP server', readonly=True)
error_type = fields.Char(string='Error type', readonly=True)
error_description = fields.Char(
string='Error description', readonly=True)
bounce_type = fields.Char(string='Bounce type', readonly=True)
bounce_description = fields.Char(
string='Bounce description', readonly=True)
tracking_event_ids = fields.One2many(
string="Tracking events", comodel_name='mail.tracking.event',
inverse_name='tracking_email_id', readonly=True)
@api.model
def tracking_ids_recalculate(self, model, email_field, tracking_field,
email, new_tracking=None):
objects = self.env[model].search([
(email_field, '=ilike', email),
])
for obj in objects:
trackings = obj[tracking_field]
if new_tracking:
trackings |= new_tracking
trackings = trackings._email_score_tracking_filter()
if set(obj[tracking_field].ids) != set(trackings.ids):
if trackings:
obj.write({
tracking_field: [(6, False, trackings.ids)]
})
else:
obj.write({
tracking_field: [(5, False, False)]
})
return objects
@api.model
def _tracking_ids_to_write(self, email):
trackings = self.env['mail.tracking.email'].search([
('recipient_address', '=ilike', email)
])
trackings = trackings._email_score_tracking_filter()
if trackings:
return [(6, False, trackings.ids)]
else:
return [(5, False, False)]
@api.multi
def _email_score_tracking_filter(self):
"""Default email score filter for tracking emails"""
# Consider only last 10 tracking emails
return self.sorted(key=lambda r: r.time, reverse=True)[:10]
@api.model
def email_score_from_email(self, email):
trackings = self.env['mail.tracking.email'].search([
('recipient_address', '=ilike', email)
])
return trackings.email_score()
@api.multi
def email_score(self):
"""Default email score algorimth"""
score = 50.0
trackings = self._email_score_tracking_filter()
for tracking in trackings:
if tracking.state in ('error',):
score -= 50.0
elif tracking.state in ('rejected', 'spam', 'bounced'):
score -= 25.0
elif tracking.state in ('soft-bounced', 'unsub'):
score -= 10.0
elif tracking.state in ('delivered',):
score += 5.0
elif tracking.state in ('opened',):
score += 10.0
if score > 100.0:
score = 100.0
return score
@api.multi
@api.depends('recipient')
def _compute_recipient_address(self):
for email in self:
matches = re.search(r'<(.*@.*)>', email.recipient)
if matches:
email.recipient_address = matches.group(1)
else:
email.recipient_address = email.recipient
@api.multi
@api.depends('name', 'recipient')
def _compute_display_name(self):
for email in self:
parts = [email.name or '']
if email.recipient:
parts.append(email.recipient)
email.display_name = ' - '.join(parts)
@api.multi
@api.depends('time')
def _compute_date(self):
for email in self:
email.date = fields.Date.to_string(
fields.Date.from_string(email.time))
@api.model
def create(self, vals):
tracking = super(MailTrackingEmail, self).create(vals)
self.tracking_ids_recalculate(
'res.partner', 'email', 'tracking_email_ids',
tracking.recipient_address, new_tracking=tracking)
return tracking
def _get_mail_tracking_img(self):
base_url = self.env['ir.config_parameter'].get_param('web.base.url')
path_url = (
'mail/tracking/open/%(db)s/%(tracking_email_id)s/blank.gif' % {
'db': self.env.cr.dbname,
'tracking_email_id': self.id,
})
track_url = urlparse.urljoin(base_url, path_url)
return (
'<img src="%(url)s" alt="" '
'data-odoo-tracking-email="%(tracking_email_id)s"/>' % {
'url': track_url,
'tracking_email_id': self.id,
})
@api.multi
def smtp_error(self, mail_server, smtp_server, exception):
self.sudo().write({
'error_smtp_server': tools.ustr(smtp_server),
'error_type': exception.__class__.__name__,
'error_description': tools.ustr(exception),
'state': 'error',
})
return True
@api.multi
def tracking_img_add(self, email):
self.ensure_one()
tracking_url = self._get_mail_tracking_img()
if tracking_url:
body = tools.append_content_to_html(
email.get('body', ''), tracking_url, plaintext=False,
container_tag='div')
email['body'] = body
return email
def _message_partners_check(self, message, message_id):
mail_message = self.mail_message_id
partners = (
mail_message.needaction_partner_ids | mail_message.partner_ids)
if (self.partner_id and self.partner_id not in partners):
# If mail_message haven't tracking partner, then
# add it in order to see his tracking status in chatter
if mail_message.subtype_id:
mail_message.sudo().write({
'needaction_partner_ids': [(4, self.partner_id.id)],
})
else:
mail_message.sudo().write({
'partner_ids': [(4, self.partner_id.id)],
})
return True
@api.multi
def _tracking_sent_prepare(self, mail_server, smtp_server, message,
message_id):
self.ensure_one()
ts = time.time()
dt = datetime.utcfromtimestamp(ts)
self._message_partners_check(message, message_id)
self.sudo().write({'state': 'sent'})
return {
'recipient': message['To'],
'timestamp': '%.6f' % ts,
'time': fields.Datetime.to_string(dt),
'tracking_email_id': self.id,
'event_type': 'sent',
'smtp_server': smtp_server,
}
def _event_prepare(self, event_type, metadata):
self.ensure_one()
m_event = self.env['mail.tracking.event']
method = getattr(m_event, 'process_' + event_type, None)
if method and hasattr(method, '__call__'):
return method(self, metadata)
else: # pragma: no cover
_logger.info('Unknown event type: %s' % event_type)
return False
def _concurrent_events(self, event_type, metadata):
m_event = self.env['mail.tracking.event']
self.ensure_one()
concurrent_event_ids = False
if event_type in {'open', 'click'}:
ts = metadata.get('timestamp', time.time())
delta = EVENT_OPEN_DELTA if event_type == 'open' \
else EVENT_CLICK_DELTA
domain = [
('timestamp', '>=', ts - delta),
('timestamp', '<=', ts + delta),
('tracking_email_id', '=', self.id),
('event_type', '=', event_type),
]
if event_type == 'click':
domain.append(('url', '=', metadata.get('url', False)))
concurrent_event_ids = m_event.search(domain)
return concurrent_event_ids
@api.multi
def event_create(self, event_type, metadata):
event_ids = self.env['mail.tracking.event']
for tracking_email in self:
other_ids = tracking_email._concurrent_events(event_type, metadata)
if not other_ids:
vals = tracking_email._event_prepare(event_type, metadata)
if vals:
event_ids += event_ids.sudo().create(vals)
partners = self.tracking_ids_recalculate(
'res.partner', 'email', 'tracking_email_ids',
tracking_email.recipient_address)
if partners:
partners.email_score_calculate()
else:
_logger.debug("Concurrent event '%s' discarded", event_type)
return event_ids
@api.model
def event_process(self, request, post, metadata, event_type=None):
# Generic event process hook, inherit it and
# - return 'OK' if processed
# - return 'NONE' if this request is not for you
# - return 'ERROR' if any error
return 'NONE' # pragma: no cover

136
mail_tracking/models/mail_tracking_event.py

@ -0,0 +1,136 @@
# -*- coding: utf-8 -*-
# © 2016 Antonio Espinosa - <antonio.espinosa@tecnativa.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
import time
from datetime import datetime
from openerp import models, api, fields
import openerp.addons.decimal_precision as dp
class MailTrackingEvent(models.Model):
_name = "mail.tracking.event"
_order = 'timestamp desc'
_rec_name = 'event_type'
_description = 'MailTracking event'
recipient = fields.Char(string="Recipient", readonly=True)
timestamp = fields.Float(
string='UTC timestamp', readonly=True,
digits=dp.get_precision('MailTracking Timestamp'))
time = fields.Datetime(string="Time", readonly=True)
date = fields.Date(
string="Date", readonly=True, compute="_compute_date", store=True)
tracking_email_id = fields.Many2one(
string='Message', readonly=True,
comodel_name='mail.tracking.email')
event_type = fields.Selection(string='Event type', selection=[
('sent', 'Sent'),
('delivered', 'Delivered'),
('deferral', 'Deferral'),
('hard_bounce', 'Hard bounce'),
('soft_bounce', 'Soft bounce'),
('open', 'Open'),
('click', 'Clicked'),
('spam', 'Spam'),
('unsub', 'Unsubscribed'),
('reject', 'Rejected'),
], readonly=True)
smtp_server = fields.Char(string='SMTP server', readonly=True)
url = fields.Char(string='Clicked URL', readonly=True)
ip = fields.Char(string='User IP', readonly=True)
user_agent = fields.Char(string='User agent', readonly=True)
mobile = fields.Boolean(string='Is mobile?', readonly=True)
os_family = fields.Char(string='Operating system family', readonly=True)
ua_family = fields.Char(string='User agent family', readonly=True)
ua_type = fields.Char(string='User agent type', readonly=True)
user_country_id = fields.Many2one(string='User country', readonly=True,
comodel_name='res.country')
error_type = fields.Char(string='Error type', readonly=True)
error_description = fields.Char(string='Error description', readonly=True)
error_details = fields.Text(string='Error details', readonly=True)
@api.multi
@api.depends('time')
def _compute_date(self):
for email in self:
email.date = fields.Date.to_string(
fields.Date.from_string(email.time))
def _process_data(self, tracking_email, metadata, event_type, state):
ts = time.time()
dt = datetime.utcfromtimestamp(ts)
return {
'recipient': metadata.get('recipient', tracking_email.recipient),
'timestamp': metadata.get('timestamp', ts),
'time': metadata.get('time', fields.Datetime.to_string(dt)),
'date': metadata.get('date', fields.Date.to_string(dt)),
'tracking_email_id': tracking_email.id,
'event_type': event_type,
'ip': metadata.get('ip', False),
'url': metadata.get('url', False),
'user_agent': metadata.get('user_agent', False),
'mobile': metadata.get('mobile', False),
'os_family': metadata.get('os_family', False),
'ua_family': metadata.get('ua_family', False),
'ua_type': metadata.get('ua_type', False),
'user_country_id': metadata.get('user_country_id', False),
'error_type': metadata.get('error_type', False),
'error_description': metadata.get('error_description', False),
'error_details': metadata.get('error_details', False),
}
def _process_status(self, tracking_email, metadata, event_type, state):
tracking_email.sudo().write({'state': state})
return self._process_data(tracking_email, metadata, event_type, state)
def _process_bounce(self, tracking_email, metadata, event_type, state):
tracking_email.sudo().write({
'state': state,
'bounce_type': metadata.get('bounce_type', False),
'bounce_description': metadata.get('bounce_description', False),
})
return self._process_data(tracking_email, metadata, event_type, state)
@api.model
def process_delivered(self, tracking_email, metadata):
return self._process_status(
tracking_email, metadata, 'delivered', 'delivered')
@api.model
def process_deferral(self, tracking_email, metadata):
return self._process_status(
tracking_email, metadata, 'deferral', 'deferred')
@api.model
def process_hard_bounce(self, tracking_email, metadata):
return self._process_bounce(
tracking_email, metadata, 'hard_bounce', 'bounced')
@api.model
def process_soft_bounce(self, tracking_email, metadata):
return self._process_bounce(
tracking_email, metadata, 'soft_bounce', 'soft-bounced')
@api.model
def process_open(self, tracking_email, metadata):
return self._process_status(tracking_email, metadata, 'open', 'opened')
@api.model
def process_click(self, tracking_email, metadata):
return self._process_status(
tracking_email, metadata, 'click', 'opened')
@api.model
def process_spam(self, tracking_email, metadata):
return self._process_status(tracking_email, metadata, 'spam', 'spam')
@api.model
def process_unsub(self, tracking_email, metadata):
return self._process_status(tracking_email, metadata, 'unsub', 'unsub')
@api.model
def process_reject(self, tracking_email, metadata):
return self._process_status(
tracking_email, metadata, 'reject', 'rejected')

46
mail_tracking/models/res_partner.py

@ -0,0 +1,46 @@
# -*- coding: utf-8 -*-
# © 2016 Antonio Espinosa - <antonio.espinosa@tecnativa.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from openerp import models, api, fields
class ResPartner(models.Model):
_inherit = 'res.partner'
tracking_email_ids = fields.Many2many(
string="Tracking emails", comodel_name="mail.tracking.email",
readonly=True)
tracking_emails_count = fields.Integer(
string="Tracking emails count", store=True, readonly=True,
compute="_compute_tracking_emails_count")
email_score = fields.Float(
string="Email score", readonly=True, default=50.0)
@api.multi
def email_score_calculate(self):
# This is not a compute method because is causing a inter-block
# in mail_tracking_email PostgreSQL table
# We suspect that tracking_email write to state field block that
# table and then inside write ORM try to read from DB
# tracking_email_ids because it's not in cache.
# PostgreSQL blocks read because we have not committed yet the write
for partner in self:
partner.email_score = partner.tracking_email_ids.email_score()
@api.one
@api.depends('tracking_email_ids')
def _compute_tracking_emails_count(self):
self.tracking_emails_count = self.env['mail.tracking.email'].\
search_count([
('recipient_address', '=ilike', self.email)
])
@api.multi
def write(self, vals):
email = vals.get('email')
if email is not None:
m_track = self.env['mail.tracking.email']
vals['tracking_email_ids'] = m_track._tracking_ids_to_write(email)
vals['email_score'] = m_track.email_score_from_email(email)
return super(ResPartner, self).write(vals)

5
mail_tracking/security/ir.model.access.csv

@ -0,0 +1,5 @@
"id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink"
"access_mail_tracking_email_group_user","mail_tracking_email group_user","model_mail_tracking_email","base.group_user",1,0,0,0
"access_mail_tracking_event_group_user","mail_tracking_event group_user","model_mail_tracking_event","base.group_user",1,0,0,0
"access_mail_tracking_email_group_system","mail_tracking_email group_system","model_mail_tracking_email","base.group_system",1,1,1,1
"access_mail_tracking_event_group_system","mail_tracking_event group_system","model_mail_tracking_event","base.group_system",1,1,1,1

BIN
mail_tracking/static/description/icon.png

After

Width: 128  |  Height: 128  |  Size: 5.8 KiB

21
mail_tracking/static/src/css/mail_tracking.css

@ -0,0 +1,21 @@
/* © 2016 Antonio Espinosa - <antonio.espinosa@tecnativa.com>
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). */
.mail_tracking span {
color: #909090;
}
.mail_tracking_pointer {
cursor: pointer;
}
.mail_tracking span.mail_tracking_opened {
color: #a34a8b;
}
.o_mail_thread .o_thread_message .o_thread_message_core .o_mail_info {
margin: 0;
}
.o_mail_thread .o_thread_message .o_thread_message_core .o_mail_tracking {
margin: 0 0 2px 0;
}

BIN
mail_tracking/static/src/img/delivered.png

After

Width: 23  |  Height: 16  |  Size: 285 B

BIN
mail_tracking/static/src/img/error.png

After

Width: 16  |  Height: 16  |  Size: 257 B

BIN
mail_tracking/static/src/img/opened.png

After

Width: 23  |  Height: 16  |  Size: 368 B

BIN
mail_tracking/static/src/img/sent.png

After

Width: 16  |  Height: 16  |  Size: 294 B

BIN
mail_tracking/static/src/img/unknown.png

After

Width: 16  |  Height: 16  |  Size: 425 B

BIN
mail_tracking/static/src/img/waiting.png

After

Width: 16  |  Height: 16  |  Size: 348 B

103
mail_tracking/static/src/js/mail_tracking.js

@ -0,0 +1,103 @@
/* © 2016 Antonio Espinosa - <antonio.espinosa@tecnativa.com>
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). */
odoo.define('mail_tracking.partner_tracking', function(require){
"use strict";
var $ = require('$');
var core = require('web.core');
var session = require('web.session');
var Model = require('web.Model');
var ActionManager = require('web.ActionManager');
var chat_manager = require('mail.chat_manager');
var ChatThread = require('mail.ChatThread');
var Chatter = require('mail.Chatter');
var _t = core._t;
var MessageModel = new Model('mail.message', session.context);
// chat_manager is a simple dictionary, not an OdooClass
chat_manager._make_message_super = chat_manager.make_message;
chat_manager.make_message = function(data) {
var msg = this._make_message_super(data);
msg.partner_trackings = data.partner_trackings || [];
return msg;
};
ChatThread.include({
on_tracking_partner_click: function (event) {
var partner_id = $(event.currentTarget).data('partner');
var state = {
'model': 'res.partner',
'id': partner_id,
'title': _t("Tracking partner"),
};
event.preventDefault();
this.action_manager.do_push_state(state);
var action = {
type:'ir.actions.act_window',
view_type: 'form',
view_mode: 'form',
res_model: 'res.partner',
views: [[false, 'form']],
target: 'current',
res_id: partner_id,
};
this.do_action(action);
},
on_tracking_status_click: function (event) {
var tracking_email_id = $(event.currentTarget).data('tracking');
var state = {
'model': 'mail.tracking.email',
'id': tracking_email_id,
'title': _t("Message tracking"),
};
event.preventDefault();
this.action_manager.do_push_state(state);
var action = {
type:'ir.actions.act_window',
view_type: 'form',
view_mode: 'form',
res_model: 'mail.tracking.email',
views: [[false, 'form']],
target: 'new',
res_id: tracking_email_id,
};
this.do_action(action);
},
bind_events: function () {
this.$el.on('click', '.o_mail_action_tracking_partner',
this.on_tracking_partner_click);
this.$el.on('click', '.o_mail_action_tracking_status',
this.on_tracking_status_click);
},
init: function (parent, options) {
this._super.apply(this, arguments);
this.action_manager = this.findAncestor(function(ancestor){
return ancestor instanceof ActionManager;
});
},
start: function () {
this._super();
this.bind_events();
},
render: function(messages, options) {
var self = this, render_super = this._super,
msgs = {},
msg_ids = [];
// Update trackings (async) each time we re-render thread
_.each(messages, function (message) {
msgs[message.id] = message;
msg_ids.push(message.id);
});
MessageModel.call('tracking_status', [msg_ids]).then(function (trackings) {
_.each(trackings, function (tracking, id) {
msgs[id].partner_trackings = tracking;
});
render_super.apply(self, [messages, options]);
});
},
});
}); // odoo.define

73
mail_tracking/static/src/xml/mail_tracking.xml

@ -0,0 +1,73 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- © 2016 Antonio Espinosa - <antonio.espinosa@tecnativa.com>
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). -->
<template>
<t t-name="mail.tracking.status">
<t t-if="tracking[0] == 'unknown'">
<span class="mail_tracking_unknown">
<i class="fa fa-ban"></i>
</span>
</t>
<t t-if="tracking[0] == 'waiting'">
<span class="mail_tracking_waiting mail_tracking_pointer">
<i class="fa fa-clock-o"></i>
</span>
</t>
<t t-if="tracking[0] == 'error'">
<span class="mail_tracking_error mail_tracking_pointer">
<i class="fa fa-remove"></i>
</span>
</t>
<t t-if="tracking[0] == 'sent'">
<span class="mail_tracking_sent mail_tracking_pointer">
<i class="fa fa-check"></i>
</span>
</t>
<t t-if="tracking[0] == 'delivered'">
<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-inverse fa-stack-1x" style="margin-left:-2px;"></i>
<i class="fa fa-check fa-stack-1x" style="margin-left:-3px"></i>
</span>
</t>
<t t-if="tracking[0] == 'opened'">
<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-inverse fa-stack-1x" style="margin-left:-2px;"></i>
<i class="fa fa-check fa-stack-1x" style="margin-left:-3px"></i>
</span>
</t>
</t>
<t t-extend="mail.ChatThread.Message">
<t t-jquery="p[class='o_mail_info']" t-operation="after">
<p class="o_mail_tracking">
<strong>To:</strong>
<t t-set="first_tracking" t-value="true"/>
<t t-foreach="message.partner_trackings" t-as="tracking">
<t t-if="!first_tracking">
-
</t>
<t t-if="tracking[3]">
<a class="o_mail_action_tracking_partner"
t-att-data-partner="tracking[3]"
t-attf-href="#model=res.partner&amp;id=#{tracking[3]}">
<t t-esc="tracking[2]"/>
</a>
</t>
<t t-if="!tracking[3]">
<span><t t-esc="tracking[2]"/></span>
</t>
<span class="mail_tracking o_mail_action_tracking_status"
t-att-data-tracking="tracking[1]"
t-attf-title="Status: #{tracking[0]}">
<t t-call="mail.tracking.status"/>
</span>
<t t-set="first_tracking" t-value="false"/>
</t>
</p>
</t>
</t>
</template>

6
mail_tracking/tests/__init__.py

@ -0,0 +1,6 @@
# -*- coding: utf-8 -*-
# © 2016 Antonio Espinosa - <antonio.espinosa@tecnativa.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
# flake8: noqa
from . import test_mail_tracking

262
mail_tracking/tests/test_mail_tracking.py

@ -0,0 +1,262 @@
# -*- coding: utf-8 -*-
# © 2016 Antonio Espinosa - <antonio.espinosa@tecnativa.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
import mock
import base64
import time
from openerp.tests.common import TransactionCase
from ..controllers.main import MailTrackingController, BLANK
mock_request = 'openerp.http.request'
mock_send_email = ('openerp.addons.base.ir.ir_mail_server.'
'ir_mail_server.send_email')
class FakeUserAgent(object):
browser = 'Test browser'
platform = 'Test platform'
def __str__(self):
"""Return name"""
return 'Test suite'
# One test case per method
class TestMailTracking(TransactionCase):
# Use case : Prepare some data for current test case
def setUp(self):
super(TestMailTracking, self).setUp()
self.sender = self.env['res.partner'].create({
'name': 'Test sender',
'email': 'sender@example.com',
'notify_email': 'always',
})
self.recipient = self.env['res.partner'].create({
'name': 'Test recipient',
'email': 'recipient@example.com',
'notify_email': 'always',
})
self.request = {
'httprequest': type('obj', (object,), {
'remote_addr': '123.123.123.123',
'user_agent': FakeUserAgent(),
}),
}
def test_message_post(self):
# This message will generate a notification for recipient
message = self.env['mail.message'].create({
'subject': 'Message test',
'author_id': self.sender.id,
'email_from': self.sender.email,
'type': 'comment',
'model': 'res.partner',
'res_id': self.recipient.id,
'partner_ids': [(4, self.recipient.id)],
'body': '<p>This is a test message</p>',
})
# Search tracking created
tracking_email = self.env['mail.tracking.email'].search([
('mail_message_id', '=', message.id),
('partner_id', '=', self.recipient.id),
])
# The tracking email must be sent
self.assertTrue(tracking_email)
self.assertEqual(tracking_email.state, 'sent')
# message_dict read by web interface
message_dict = message.message_read()
# First item in threads is message content
message_dict = message_dict['threads'][0][0]
self.assertTrue(len(message_dict['partner_ids']) > 0)
# First partner is recipient
partner_id = message_dict['partner_ids'][0][0]
self.assertEqual(partner_id, self.recipient.id)
status = message_dict['partner_trackings'][0]
# Tracking status must be sent and
# mail tracking must be the one search before
self.assertEqual(status[0], 'sent')
self.assertEqual(status[1], tracking_email.id)
self.assertEqual(status[2], self.recipient.display_name)
self.assertEqual(status[3], self.recipient.id)
# And now open the email
metadata = {
'ip': '127.0.0.1',
'user_agent': 'Odoo Test/1.0',
'os_family': 'linux',
'ua_family': 'odoo',
}
tracking_email.event_create('open', metadata)
self.assertEqual(tracking_email.state, 'opened')
def mail_send(self, recipient):
mail = self.env['mail.mail'].create({
'subject': 'Test subject',
'email_from': 'from@domain.com',
'email_to': recipient,
'body_html': '<p>This is a test message</p>',
})
mail.send()
# Search tracking created
tracking_email = self.env['mail.tracking.email'].search([
('mail_id', '=', mail.id),
])
return mail, tracking_email
def test_mail_send(self):
controller = MailTrackingController()
db = self.env.cr.dbname
image = base64.decodestring(BLANK)
mail, tracking = self.mail_send(self.recipient.email)
self.assertEqual(mail.email_to, tracking.recipient)
self.assertEqual(mail.email_from, tracking.sender)
with mock.patch(mock_request) as mock_func:
mock_func.return_value = type('obj', (object,), self.request)
res = controller.mail_tracking_open(db, tracking.id)
self.assertEqual(image, res.response[0])
def test_concurrent_open(self):
mail, tracking = self.mail_send(self.recipient.email)
ts = time.time()
metadata = {
'ip': '127.0.0.1',
'user_agent': 'Odoo Test/1.0',
'os_family': 'linux',
'ua_family': 'odoo',
'timestamp': ts,
}
# First open event
tracking.event_create('open', metadata)
opens = tracking.tracking_event_ids.filtered(
lambda r: r.event_type == 'open'
)
self.assertEqual(len(opens), 1)
# Concurrent open event
metadata['timestamp'] = ts + 2
tracking.event_create('open', metadata)
opens = tracking.tracking_event_ids.filtered(
lambda r: r.event_type == 'open'
)
self.assertEqual(len(opens), 1)
# Second open event
metadata['timestamp'] = ts + 350
tracking.event_create('open', metadata)
opens = tracking.tracking_event_ids.filtered(
lambda r: r.event_type == 'open'
)
self.assertEqual(len(opens), 2)
def test_concurrent_click(self):
mail, tracking = self.mail_send(self.recipient.email)
ts = time.time()
metadata = {
'ip': '127.0.0.1',
'user_agent': 'Odoo Test/1.0',
'os_family': 'linux',
'ua_family': 'odoo',
'timestamp': ts,
'url': 'https://www.example.com/route/1',
}
# First click event (URL 1)
tracking.event_create('click', metadata)
opens = tracking.tracking_event_ids.filtered(
lambda r: r.event_type == 'click'
)
self.assertEqual(len(opens), 1)
# Concurrent click event (URL 1)
metadata['timestamp'] = ts + 2
tracking.event_create('click', metadata)
opens = tracking.tracking_event_ids.filtered(
lambda r: r.event_type == 'click'
)
self.assertEqual(len(opens), 1)
# Second click event (URL 1)
metadata['timestamp'] = ts + 350
tracking.event_create('click', metadata)
opens = tracking.tracking_event_ids.filtered(
lambda r: r.event_type == 'click'
)
self.assertEqual(len(opens), 2)
# Concurrent click event (URL 2)
metadata['timestamp'] = ts + 2
metadata['url'] = 'https://www.example.com/route/2'
tracking.event_create('click', metadata)
opens = tracking.tracking_event_ids.filtered(
lambda r: r.event_type == 'click'
)
self.assertEqual(len(opens), 3)
def test_smtp_error(self):
with mock.patch(mock_send_email) as mock_func:
mock_func.side_effect = Warning('Test error')
mail, tracking = self.mail_send(self.recipient.email)
self.assertEqual('error', tracking.state)
self.assertEqual('Warning', tracking.error_type)
self.assertEqual('Test error', tracking.error_description)
def test_partner_email_change(self):
mail, tracking = self.mail_send(self.recipient.email)
tracking.event_create('open', {})
orig_score = self.recipient.email_score
orig_email = self.recipient.email
self.recipient.email = orig_email + '2'
self.assertEqual(50.0, self.recipient.email_score)
self.recipient.email = orig_email
self.assertEqual(orig_score, self.recipient.email_score)
def test_process_hard_bounce(self):
mail, tracking = self.mail_send(self.recipient.email)
tracking.event_create('hard_bounce', {})
self.assertEqual('bounced', tracking.state)
def test_process_soft_bounce(self):
mail, tracking = self.mail_send(self.recipient.email)
tracking.event_create('soft_bounce', {})
self.assertEqual('soft-bounced', tracking.state)
def test_process_delivered(self):
mail, tracking = self.mail_send(self.recipient.email)
tracking.event_create('delivered', {})
self.assertEqual('delivered', tracking.state)
def test_process_deferral(self):
mail, tracking = self.mail_send(self.recipient.email)
tracking.event_create('deferral', {})
self.assertEqual('deferred', tracking.state)
def test_process_spam(self):
mail, tracking = self.mail_send(self.recipient.email)
tracking.event_create('spam', {})
self.assertEqual('spam', tracking.state)
def test_process_unsub(self):
mail, tracking = self.mail_send(self.recipient.email)
tracking.event_create('unsub', {})
self.assertEqual('unsub', tracking.state)
def test_process_reject(self):
mail, tracking = self.mail_send(self.recipient.email)
tracking.event_create('reject', {})
self.assertEqual('rejected', tracking.state)
def test_process_open(self):
mail, tracking = self.mail_send(self.recipient.email)
tracking.event_create('open', {})
self.assertEqual('opened', tracking.state)
def test_process_click(self):
mail, tracking = self.mail_send(self.recipient.email)
tracking.event_create('click', {})
self.assertEqual('opened', tracking.state)
def test_db(self):
db = self.env.cr.dbname
controller = MailTrackingController()
with mock.patch(mock_request) as mock_func:
mock_func.return_value = type('obj', (object,), self.request)
not_found = controller.mail_tracking_all('not_found_db')
self.assertEqual('NOT FOUND', not_found.response[0])
none = controller.mail_tracking_all(db)
self.assertEqual('NONE', none.response[0])
none = controller.mail_tracking_event(db, 'open')
self.assertEqual('NONE', none.response[0])

17
mail_tracking/views/assets.xml

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- © 2016 Antonio Espinosa - <antonio.espinosa@tecnativa.com>
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). -->
<odoo>
<template id="assets_backend"
name="mail_tracking assets"
inherit_id="web.assets_backend">
<xpath expr="." position="inside">
<link rel="stylesheet"
href="/mail_tracking/static/src/css/mail_tracking.css"/>
<script type="text/javascript"
src="/mail_tracking/static/src/js/mail_tracking.js"/>
</xpath>
</template>
</odoo>

120
mail_tracking/views/mail_tracking_email_view.xml

@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- © 2016 Antonio Espinosa - <antonio.espinosa@tecnativa.com>
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). -->
<odoo>
<record model="ir.ui.view" id="view_mail_tracking_email_form">
<field name="name">mail.tracking.email.form</field>
<field name="model">mail.tracking.email</field>
<field name="arch" type="xml">
<form string="MailTracking event" create="false" edit="false" delete="false">
<header>
<field name="state" widget="statusbar"/>
</header>
<sheet>
<group>
<field name="name"/>
</group>
<group>
<group>
<field name="mail_message_id"/>
<field name="mail_id"/>
<field name="partner_id"/>
<field name="recipient"/>
<field name="sender"/>
</group>
<group>
<field name="timestamp"/>
<field name="time"/>
<field name="date"/>
</group>
</group>
<group attrs="{'invisible': [('bounce_type', '=', False)]}">
<field name="bounce_type"/>
<field name="bounce_description"/>
</group>
<group attrs="{'invisible': [('error_type', '=', False)]}">
<field name="error_smtp_server"
attrs="{'invisible': [('error_smtp_server', '=', False)]}"/>
<field name="error_type"/>
<field name="error_description"/>
</group>
<label for="tracking_event_ids"/>
<div>
<field name="tracking_event_ids">
<tree string="Tracking events" colors="grey:event_type in ('deferral');black:event_type in ('send');red:event_type in ('hard_bounce', 'soft_bounce', 'spam', 'reject');blue:event_type in ('unsub', 'click', 'open')">
<field name="time"/>
<field name="event_type"/>
<field name="ip"/>
<field name="url"/>
<field name="user_country_id" string="Country"/>
<field name="os_family" string="OS"/>
<field name="ua_family" string="User agent"/>
</tree>
</field>
</div>
</sheet>
</form>
</field>
</record>
<record model="ir.ui.view" id="view_mail_tracking_email_tree">
<field name="name">mail.tracking.email.tree</field>
<field name="model">mail.tracking.email</field>
<field name="arch" type="xml">
<tree string="MailTracking emails" create="false" edit="false" delete="false"
colors="grey:state in (False, 'deferred');black:state in ('sent', 'delivered');green:state in ('opened');red:state in ('rejected', 'spam', 'bounced', 'soft-bounced');blue:state in ('unsub')">
<field name="time"/>
<field name="date" invisible="1"/>
<field name="name"/>
<field name="sender" string="Sender"/>
<field name="recipient" string="Recipient"/>
<field name="state"/>
</tree>
</field>
</record>
<record model="ir.ui.view" id="view_mail_tracking_email_search">
<field name="name">mail.tracking.email.search</field>
<field name="model">mail.tracking.email</field>
<field name="arch" type="xml">
<search string="MailTracking email search">
<field name="display_name" string="Email"
filter_domain="['|', ('sender', 'ilike', self), ('recipient', 'ilike', self)]"/>
<field name="sender" string="Sender"/>
<field name="recipient" string="Sender"/>
<field name="name" string="Subject"/>
<field name="time" string="Time"/>
<field name="date" string="Date"/>
<filter name="sent" string="Sent" domain="[('state', 'in', ('sent',))]"/>
<filter name="deferred" string="Deferred" domain="[('state', '=', 'deferred')]"/>
<filter name="delivered" string="Delivered" domain="[('state', 'in', ('delivered', 'opened'))]"/>
<filter name="unsub" string="Unsubscribed" domain="[('state', '=', 'unsub')]"/>
<filter name="exception" string="Failed"
domain="[('state', 'in', ('error', 'rejected', 'spam', 'bounced', 'soft-bounced'))]"/>
<separator/>
<group expand="0" string="Group By">
<filter string="State" domain="[]" context="{'group_by': 'state'}"/>
<filter string="Subject" domain="[]" context="{'group_by': 'name'}"/>
<filter string="Sender" domain="[]" context="{'group_by': 'sender'}"/>
<filter string="Month" domain="[]" context="{'group_by': 'date'}"/>
</group>
</search>
</field>
</record>
<record id="action_view_mail_tracking_email" model="ir.actions.act_window">
<field name="name">MailTracking emails</field>
<field name="res_model">mail.tracking.email</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
<field name="search_view_id" ref="view_mail_tracking_email_search"/>
</record>
<!-- Add menu entry in Settings/Email -->
<menuitem name="Tracking emails" id="menu_mail_tracking_email"
parent="base.menu_email"
action="action_view_mail_tracking_email"/>
</odoo>

123
mail_tracking/views/mail_tracking_event_view.xml

@ -0,0 +1,123 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- © 2016 Antonio Espinosa - <antonio.espinosa@tecnativa.com>
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). -->
<odoo>
<record model="ir.ui.view" id="view_mail_tracking_event_form">
<field name="name">mail.tracking.event.form</field>
<field name="model">mail.tracking.event</field>
<field name="arch" type="xml">
<form string="MailTracking event" create="false" edit="false" delete="false">
<sheet>
<group>
<group>
<field name="tracking_email_id"/>
<field name="recipient"/>
<field name="event_type"/>
</group>
<group>
<field name="timestamp"/>
<field name="time"/>
<field name="date"/>
</group>
</group>
<group attrs="{'invisible': [('event_type', 'not in', ('sent',))]}">
<field name="smtp_server"/>
</group>
<group attrs="{'invisible': [('event_type', 'not in', ('open', 'click'))]}">
<field name="url"/>
</group>
<group attrs="{'invisible': [('event_type', 'not in', ('open', 'click'))]}">
<group>
<field name="mobile"/>
<field name="ip"/>
<field name="user_country_id"/>
</group>
<group>
<field name="user_agent"/>
<field name="ua_family"/>
<field name="ua_type"/>
<field name="os_family"/>
</group>
</group>
<group string="Error"
attrs="{'invisible': [('error_type', '=', False)]}">
<field name="error_type"/>
<field name="error_description"/>
<field name="error_details"/>
</group>
</sheet>
</form>
</field>
</record>
<record model="ir.ui.view" id="view_mail_tracking_event_tree">
<field name="name">mail.tracking.event.tree</field>
<field name="model">mail.tracking.event</field>
<field name="arch" type="xml">
<tree string="MailTracking events" create="false" edit="false" delete="false"
colors="grey:event_type in ('deferral',);black:event_type in ('sent', 'delivered');red:event_type in ('hard_bounce', 'soft_bounce', 'spam', 'reject');blue:event_type in ('unsub', 'click', 'open')">
<field name="time"/>
<field name="tracking_email_id"/>
<field name="recipient"/>
<field name="event_type"/>
<field name="date" invisible="1"/>
<field name="ip"/>
<field name="url"/>
<field name="user_country_id" string="Country"/>
<field name="os_family" string="OS"/>
<field name="ua_family" string="User agent"/>
</tree>
</field>
</record>
<record model="ir.ui.view" id="view_mail_tracking_event_search">
<field name="name">mail.tracking.event.search</field>
<field name="model">mail.tracking.event</field>
<field name="arch" type="xml">
<search string="MailTracking event search">
<field name="tracking_email_id" string="Message"
filter_domain="[('tracking_email_id', 'ilike', self)]"/>
<field name="recipient" string="Recipient"/>
<field name="time" string="Time"/>
<field name="date" string="Date"/>
<field name="ip" string="IP"/>
<field name="url" string="URL"/>
<filter name="sent" string="Sent" domain="[('event_type', '=', 'sent')]"/>
<filter name="delivered" string="Delivered" domain="[('event_type', '=', 'delivered')]"/>
<filter name="click" string="Click" domain="[('event_type', '=', 'click')]"/>
<filter name="open" string="Open" domain="[('event_type', '=', 'open')]"/>
<filter name="unsub" string="Unsubscribe" domain="[('event_type', '=', 'unsub')]"/>
<filter name="bounce" string="Bounce"
domain="[('event_type', 'in', ('hard_bounce', 'soft_bounce'))]"/>
<filter name="exception" string="Failed"
domain="[('event_type', 'in', ('reject', 'spam'))]"/>
<separator/>
<group expand="0" string="Group By">
<filter string="Type" domain="[]" context="{'group_by': 'event_type'}"/>
<filter string="Message" domain="[]" context="{'group_by': 'tracking_email_id'}"/>
<filter string="OS" domain="[('os_family', '!=', False)]" context="{'group_by': 'os_family'}"/>
<filter string="User agent" domain="[('ua_family', '!=', False)]" context="{'group_by': 'ua_family'}"/>
<filter string="User agent type" domain="[('ua_type', '!=', False)]" context="{'group_by': 'ua_type'}"/>
<filter string="Country" domain="[('user_country_id', '!=', False)]" context="{'group_by': 'user_country_id'}"/>
<filter string="Month" domain="[]" context="{'group_by': 'date'}"/>
</group>
</search>
</field>
</record>
<record id="action_view_mail_tracking_event" model="ir.actions.act_window">
<field name="name">MailTracking events</field>
<field name="res_model">mail.tracking.event</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
<field name="search_view_id" ref="view_mail_tracking_event_search"/>
</record>
<!-- Add menu entry in Settings/Email -->
<menuitem name="Tracking events" id="menu_mail_tracking_event"
parent="base.menu_email"
action="action_view_mail_tracking_event"/>
</odoo>

31
mail_tracking/views/res_partner_view.xml

@ -0,0 +1,31 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- © 2016 Antonio Espinosa - <antonio.espinosa@tecnativa.com>
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). -->
<odoo>
<record model="ir.ui.view" id="view_partner_form">
<field name="name">Partner Form with tracking emails</field>
<field name="model">res.partner</field>
<field name="inherit_id" ref="base.view_partner_form"/>
<field name="arch" type="xml">
<div name="button_box" position="inside">
<button name="%(mail_tracking.action_view_mail_tracking_email)d"
context="{'search_default_recipient': email,
'default_recipient': email}"
type="action"
class="oe_stat_button oe_inline"
icon="fa-envelope-o"
attrs="{'invisible': [('email', '=', False)]}">
<field name="tracking_emails_count"
widget="statinfo"
string="Tracking emails"/>
</button>
</div>
<field name="email" position="after">
<field name="email_score" widget="progressbar"
attrs="{'invisible': [('email', '=', False)]}"/>
</field>
</field>
</record>
</odoo>
Loading…
Cancel
Save