summaryrefslogtreecommitdiff
path: root/addons/mass_mailing/models
diff options
context:
space:
mode:
authorThibault Delavallée <tde@odoo.com>2019-07-17 09:26:42 +0000
committerThibault Delavallée <tde@odoo.com>2019-07-17 15:39:06 +0000
commit2896aad34e797b6ca65a8efe3c5d71f31500a9a2 (patch)
tree81f2298b04182860e84f2ca9815f313cc0c75ffc /addons/mass_mailing/models
parent20dfba6e11ac4553509c1a3516c6453b8f8023e7 (diff)
[REF] mass_mailing: rename mail.mail.statistics and reporting model
PURPOSE Mass mailing is currently a bit messy. As SMS will be added as a way to notify people in mass through SMS let us take this opportunity to somehow clean this application: organization, light code cleaning, model renaming. SPECIFICATIONS Rename mail.mail.statistics to mailing.trace and mail.statistics.report to mail.trace.report. Rationale : * mail.mail.statistics is linked to mail.mail model. Soon this model will hold data related to SMS sending. It makes sense to be broader in the naming; * mailing.trace is more inlined with marketing.trace model that is the marketing automation model using it in marketing automation (enterprise application); * mailing.trace is shorter to write; * mail.statistics.report model should sense to be updated at the same time; MIGRATION mail.mail.statistics model -> mailing.trace mail_mail_statistics table -> mailing_trace mail.statistics.report model -> mail.trace.report fields updated (w column change) * link.tracker.click: mail_stat_id -> mailing_trace_id fields updated (no column change) * mail.mail: statistics_ids -> mailing_trace_ids * mail.mass_mailing: statistics_ids -> mailing_trace_ids LINKS Task ID 2037906 Preparing task ID 1997464 (SMS addition in mass mailing) PR #34938
Diffstat (limited to 'addons/mass_mailing/models')
-rw-r--r--addons/mass_mailing/models/__init__.py2
-rw-r--r--addons/mass_mailing/models/link_tracker.py20
-rw-r--r--addons/mass_mailing/models/mail_mail.py24
-rw-r--r--addons/mass_mailing/models/mail_thread.py20
-rw-r--r--addons/mass_mailing/models/mailing_trace.py (renamed from addons/mass_mailing/models/mass_mailing_stats.py)38
-rw-r--r--addons/mass_mailing/models/mass_mailing.py38
6 files changed, 70 insertions, 72 deletions
diff --git a/addons/mass_mailing/models/__init__.py b/addons/mass_mailing/models/__init__.py
index afeb0313925..d00a7590cf8 100644
--- a/addons/mass_mailing/models/__init__.py
+++ b/addons/mass_mailing/models/__init__.py
@@ -5,7 +5,7 @@ from . import link_tracker
from . import mass_mailing_contact
from . import mass_mailing_list
from . import mass_mailing
-from . import mass_mailing_stats
+from . import mailing_trace
from . import mail_mail
from . import mail_template
from . import mail_thread
diff --git a/addons/mass_mailing/models/link_tracker.py b/addons/mass_mailing/models/link_tracker.py
index 2b20b007a4b..c33dae7731e 100644
--- a/addons/mass_mailing/models/link_tracker.py
+++ b/addons/mass_mailing/models/link_tracker.py
@@ -14,22 +14,22 @@ class LinkTracker(models.Model):
class LinkTrackerClick(models.Model):
_inherit = "link.tracker.click"
- mail_stat_id = fields.Many2one('mail.mail.statistics', string='Mail Statistics')
+ mailing_trace_id = fields.Many2one('mailing.trace', string='Mail Statistics')
mass_mailing_id = fields.Many2one('mail.mass_mailing', string='Mass Mailing')
mass_mailing_campaign_id = fields.Many2one('mail.mass_mailing.campaign', string='Mass Mailing Campaign')
def _prepare_click_values_from_route(self, **route_values):
click_values = super(LinkTrackerClick, self)._prepare_click_values_from_route(**route_values)
- if click_values.get('mail_stat_id'):
- stat_sudo = self.env['mail.mail.statistics'].sudo().browse(route_values['mail_stat_id']).exists()
- if not stat_sudo:
- click_values['mail_stat_id'] = False
+ if click_values.get('mailing_trace_id'):
+ trace_sudo = self.env['mailing.trace'].sudo().browse(route_values['mailing_trace_id']).exists()
+ if not trace_sudo:
+ click_values['mailing_trace_id'] = False
else:
if not click_values.get('mass_mailing_campaign_id'):
- click_values['mass_mailing_campaign_id'] = stat_sudo.mass_mailing_campaign_id.id
+ click_values['mass_mailing_campaign_id'] = trace_sudo.mass_mailing_campaign_id.id
if not click_values.get('mass_mailing_id'):
- click_values['mass_mailing_id'] = stat_sudo.mass_mailing_id.id
+ click_values['mass_mailing_id'] = trace_sudo.mass_mailing_id.id
return click_values
@@ -37,8 +37,8 @@ class LinkTrackerClick(models.Model):
def add_click(self, code, **route_values):
click = super(LinkTrackerClick, self).add_click(code, **route_values)
- if click and click.mail_stat_id:
- click.mail_stat_id.set_opened()
- click.mail_stat_id.set_clicked()
+ if click and click.mailing_trace_id:
+ click.mailing_trace_id.set_opened()
+ click.mailing_trace_id.set_clicked()
return click
diff --git a/addons/mass_mailing/models/mail_mail.py b/addons/mass_mailing/models/mail_mail.py
index a4de6be6972..1dcb643b1e7 100644
--- a/addons/mass_mailing/models/mail_mail.py
+++ b/addons/mass_mailing/models/mail_mail.py
@@ -14,16 +14,16 @@ class MailMail(models.Model):
_inherit = ['mail.mail']
mailing_id = fields.Many2one('mail.mass_mailing', string='Mass Mailing')
- statistics_ids = fields.One2many('mail.mail.statistics', 'mail_mail_id', string='Statistics')
+ mailing_trace_ids = fields.One2many('mailing.trace', 'mail_mail_id', string='Statistics')
@api.model
def create(self, values):
- """ Override mail_mail creation to create an entry in mail.mail.statistics """
+ """ Override mail_mail creation to create an entry in mailing.trace """
# TDE note: should be after 'all values computed', to have values (FIXME after merging other branch holding create refactoring)
mail = super(MailMail, self).create(values)
- if values.get('statistics_ids'):
+ if values.get('mailing_trace_ids'):
mail_sudo = mail.sudo()
- mail_sudo.statistics_ids.write({'message_id': mail_sudo.message_id, 'state': 'outgoing'})
+ mail_sudo.mailing_trace_ids.write({'message_id': mail_sudo.message_id, 'state': 'outgoing'})
return mail
def _get_tracking_url(self):
@@ -54,12 +54,12 @@ class MailMail(models.Model):
def _send_prepare_body(self):
""" Override to add the tracking URL to the body and to add
- Statistic_id in shorted urls """
+ trace ID in shortened urls """
# TDE: temporary addition (mail was parameter) due to semi-new-API
self.ensure_one()
body = super(MailMail, self)._send_prepare_body()
- if self.mailing_id and body and self.statistics_ids:
+ if self.mailing_id and body and self.mailing_trace_ids:
for match in re.findall(URL_REGEX, self.body_html):
href = match[0]
url = match[1]
@@ -67,7 +67,7 @@ class MailMail(models.Model):
parsed = werkzeug.urls.url_parse(url, scheme='http')
if parsed.scheme.startswith('http') and parsed.path.startswith('/r/'):
- new_href = href.replace(url, url + '/m/' + str(self.statistics_ids[0].id))
+ new_href = href.replace(url, url + '/m/' + str(self.mailing_trace_ids[0].id))
body = body.replace(href, new_href)
# generate tracking URL
@@ -96,8 +96,8 @@ class MailMail(models.Model):
mail_sent = not failure_type # we consider that a recipient error is a failure with mass mailling and show them as failed
for mail in self:
if mail.mailing_id:
- if mail_sent is True and mail.statistics_ids:
- mail.statistics_ids.write({'sent': fields.Datetime.now(), 'exception': False})
- elif mail_sent is False and mail.statistics_ids:
- mail.statistics_ids.write({'exception': fields.Datetime.now()})
- return super(MailMail, self)._postprocess_sent_message(success_pids, failure_reason=failure_reason, failure_type=failure_type)
+ if mail_sent is True and mail.mailing_trace_ids:
+ mail.mailing_trace_ids.write({'sent': fields.Datetime.now(), 'exception': False})
+ elif mail_sent is False and mail.mailing_trace_ids:
+ mail.mailing_trace_ids.write({'exception': fields.Datetime.now()})
+ return super(MailMail, self)._postprocess_sent_message(success_pids, failure_reason=failure_reason, failure_type=failure_type)
diff --git a/addons/mass_mailing/models/mail_thread.py b/addons/mass_mailing/models/mail_thread.py
index 5195672eead..28b02921801 100644
--- a/addons/mass_mailing/models/mail_thread.py
+++ b/addons/mass_mailing/models/mail_thread.py
@@ -13,12 +13,12 @@ BLACKLIST_MAX_BOUNCED_LIMIT = 5
class MailThread(models.AbstractModel):
- """ Update MailThread to add the support of bounce management in mass mailing statistics. """
+ """ Update MailThread to add the support of bounce management in mass mailing traces. """
_inherit = 'mail.thread'
@api.model
def message_route(self, message, message_dict, model=None, thread_id=None, custom_values=None):
- """ Override to udpate mass mailing statistics based on bounce emails """
+ """ Override to udpate mass mailing traces based on bounce emails """
bounce_alias = self.env['ir.config_parameter'].sudo().get_param("mail.bounce.alias")
email_to = decode_message_header(message, 'To')
email_to_localpart = (tools.email_split(email_to) or [''])[0].split('@', 1)[0].lower()
@@ -28,19 +28,19 @@ class MailThread(models.AbstractModel):
bounce_match = bounce_re.search(email_to)
if bounce_match:
bounced_mail_id = bounce_match.group(1)
- self.env['mail.mail.statistics'].set_bounced(mail_mail_ids=[bounced_mail_id])
+ self.env['mailing.trace'].set_bounced(mail_mail_ids=[bounced_mail_id])
return super(MailThread, self).message_route(message, message_dict, model, thread_id, custom_values)
@api.model
def message_route_process(self, message, message_dict, routes):
- """ Override to update the parent mail statistics. The parent is found
+ """ Override to update the parent mailing traces. The parent is found
by using the References header of the incoming message and looking for
- matching message_id in mail.mail.statistics. """
+ matching message_id in mailing.trace. """
if message.get('References') and routes:
message_ids = [x.strip() for x in decode_smtp_header(message['References']).split()]
- self.env['mail.mail.statistics'].set_opened(mail_message_ids=message_ids)
- self.env['mail.mail.statistics'].set_replied(mail_message_ids=message_ids)
+ self.env['mailing.trace'].set_opened(mail_message_ids=message_ids)
+ self.env['mailing.trace'].set_replied(mail_message_ids=message_ids)
return super(MailThread, self).message_route_process(message, message_dict, routes)
def message_post_with_template(self, template_id, **kwargs):
@@ -64,11 +64,11 @@ class MailThread(models.AbstractModel):
super(MailThread, self)._message_receive_bounce(email, partner, mail_id=None)
three_months_ago = fields.Datetime.to_string(datetime.datetime.now() - datetime.timedelta(weeks=13))
- stats = self.env['mail.mail.statistics'] \
+ traces = self.env['mailing.trace'] \
.search(['&', ('bounced', '>', three_months_ago), ('email', '=ilike', email)]) \
.mapped('bounced')
- if len(stats) >= BLACKLIST_MAX_BOUNCED_LIMIT:
- if max(stats) > min(stats) + datetime.timedelta(weeks=1):
+ if len(traces) >= BLACKLIST_MAX_BOUNCED_LIMIT:
+ if max(traces) > min(traces) + datetime.timedelta(weeks=1):
blacklist_rec = self.env['mail.blacklist'].sudo()._add(email)
blacklist_rec._message_log(
body='This email has been automatically blacklisted because of too much bounced.')
diff --git a/addons/mass_mailing/models/mass_mailing_stats.py b/addons/mass_mailing/models/mailing_trace.py
index 0710a0e8b1a..9f6556ae3ef 100644
--- a/addons/mass_mailing/models/mass_mailing_stats.py
+++ b/addons/mass_mailing/models/mailing_trace.py
@@ -4,14 +4,13 @@
from odoo import api, fields, models
-class MailMailStats(models.Model):
- """ MailMailStats models the statistics collected about emails. Those statistics
+class MailingTrace(models.Model):
+ """ MailingTrace models the statistics collected about emails. Those statistics
are stored in a separated model and table to avoid bloating the mail_mail table
with statistics values. This also allows to delete emails send with mass mailing
without loosing the statistics about them. """
-
- _name = 'mail.mail.statistics'
- _description = 'Email Statistics'
+ _name = 'mailing.trace'
+ _description = 'Mailing Statistics'
_rec_name = 'message_id'
_order = 'message_id'
@@ -45,7 +44,7 @@ class MailMailStats(models.Model):
replied = fields.Datetime(help='Date when this email has been replied for the first time.')
bounced = fields.Datetime(help='Date when this email has bounced.')
# Link tracking
- links_click_ids = fields.One2many('link.tracker.click', 'mail_stat_id', string='Links click')
+ links_click_ids = fields.One2many('link.tracker.click', 'mailing_trace_id', string='Links click')
clicked = fields.Datetime(help='Date when customer clicked on at least one tracked link')
# Status
state = fields.Selection(compute="_compute_state",
@@ -83,7 +82,7 @@ class MailMailStats(models.Model):
def create(self, values):
if 'mail_mail_id' in values:
values['mail_mail_id_int'] = values['mail_mail_id']
- res = super(MailMailStats, self).create(values)
+ res = super(MailingTrace, self).create(values)
return res
def _get_records(self, mail_mail_ids=None, mail_message_ids=None, domain=None):
@@ -98,22 +97,21 @@ class MailMailStats(models.Model):
return self.search(base_domain)
def set_opened(self, mail_mail_ids=None, mail_message_ids=None):
- statistics = self._get_records(mail_mail_ids, mail_message_ids, [('opened', '=', False)])
- statistics.write({'opened': fields.Datetime.now(), 'bounced': False})
- return statistics
+ traces = self._get_records(mail_mail_ids, mail_message_ids, [('opened', '=', False)])
+ traces.write({'opened': fields.Datetime.now(), 'bounced': False})
+ return traces
def set_clicked(self, mail_mail_ids=None, mail_message_ids=None):
- statistics = self._get_records(mail_mail_ids, mail_message_ids, [('clicked', '=', False)])
- statistics.write({'clicked': fields.Datetime.now()})
- return statistics
+ traces = self._get_records(mail_mail_ids, mail_message_ids, [('clicked', '=', False)])
+ traces.write({'clicked': fields.Datetime.now()})
+ return traces
def set_replied(self, mail_mail_ids=None, mail_message_ids=None):
- statistics = self._get_records(mail_mail_ids, mail_message_ids, [('replied', '=', False)])
- statistics.write({'replied': fields.Datetime.now()})
- return statistics
+ traces = self._get_records(mail_mail_ids, mail_message_ids, [('replied', '=', False)])
+ traces.write({'replied': fields.Datetime.now()})
+ return traces
def set_bounced(self, mail_mail_ids=None, mail_message_ids=None):
- statistics = self._get_records(
- mail_mail_ids, mail_message_ids, [('bounced', '=', False), ('opened', '=', False)])
- statistics.write({'bounced': fields.Datetime.now()})
- return statistics
+ traces = self._get_records(mail_mail_ids, mail_message_ids, [('bounced', '=', False), ('opened', '=', False)])
+ traces.write({'bounced': fields.Datetime.now()})
+ return traces
diff --git a/addons/mass_mailing/models/mass_mailing.py b/addons/mass_mailing/models/mass_mailing.py
index 3cc86fbebd4..d0249777baf 100644
--- a/addons/mass_mailing/models/mass_mailing.py
+++ b/addons/mass_mailing/models/mass_mailing.py
@@ -89,7 +89,7 @@ class MassMailingCampaign(models.Model):
'the effectiveness of the mailings, without causing duplicate messages.')
color = fields.Integer(string='Color Index')
clicks_ratio = fields.Integer(compute="_compute_clicks_ratio", string="Number of clicks")
- # stat fields
+ # trace statistics fields
total = fields.Integer(compute="_compute_statistics")
scheduled = fields.Integer(compute="_compute_statistics")
failed = fields.Integer(compute="_compute_statistics")
@@ -107,9 +107,9 @@ class MassMailingCampaign(models.Model):
def _compute_clicks_ratio(self):
self.env.cr.execute("""
- SELECT COUNT(DISTINCT(stats.id)) AS nb_mails, COUNT(DISTINCT(clicks.mail_stat_id)) AS nb_clicks, stats.mass_mailing_campaign_id AS id
- FROM mail_mail_statistics AS stats
- LEFT OUTER JOIN link_tracker_click AS clicks ON clicks.mail_stat_id = stats.id
+ SELECT COUNT(DISTINCT(stats.id)) AS nb_mails, COUNT(DISTINCT(clicks.mailing_trace_id)) AS nb_clicks, stats.mass_mailing_campaign_id AS id
+ FROM mailing_trace AS stats
+ LEFT OUTER JOIN link_tracker_click AS clicks ON clicks.mailing_trace_id = stats.id
WHERE stats.mass_mailing_campaign_id IN %s
GROUP BY stats.mass_mailing_campaign_id
""", (tuple(self.ids), ))
@@ -134,7 +134,7 @@ class MassMailingCampaign(models.Model):
COUNT(CASE WHEN s.replied is not null THEN 1 ELSE null END) AS replied ,
COUNT(CASE WHEN s.bounced is not null THEN 1 ELSE null END) AS bounced
FROM
- mail_mail_statistics s
+ mailing_trace s
RIGHT JOIN
mail_mass_mailing_campaign c
ON (c.id = s.mass_mailing_campaign_id)
@@ -169,7 +169,7 @@ class MassMailingCampaign(models.Model):
domain = [('mass_mailing_campaign_id', '=', campaign.id)]
if model:
domain += [('model', '=', model)]
- res[campaign.id] = set(self.env['mail.mail.statistics'].search(domain).mapped('res_id'))
+ res[campaign.id] = set(self.env['mailing.trace'].search(domain).mapped('res_id'))
return res
@api.model
@@ -253,7 +253,7 @@ class MassMailing(models.Model):
contact_ab_pc = fields.Integer(string='A/B Testing percentage',
help='Percentage of the contacts that will be mailed. Recipients will be taken randomly.', default=100)
# statistics data
- statistics_ids = fields.One2many('mail.mail.statistics', 'mass_mailing_id', string='Emails Statistics')
+ mailing_trace_ids = fields.One2many('mailing.trace', 'mass_mailing_id', string='Emails Statistics')
total = fields.Integer(compute="_compute_total")
scheduled = fields.Integer(compute="_compute_statistics")
expected = fields.Integer(compute="_compute_statistics")
@@ -277,9 +277,9 @@ class MassMailing(models.Model):
def _compute_clicks_ratio(self):
self.env.cr.execute("""
- SELECT COUNT(DISTINCT(stats.id)) AS nb_mails, COUNT(DISTINCT(clicks.mail_stat_id)) AS nb_clicks, stats.mass_mailing_id AS id
- FROM mail_mail_statistics AS stats
- LEFT OUTER JOIN link_tracker_click AS clicks ON clicks.mail_stat_id = stats.id
+ SELECT COUNT(DISTINCT(stats.id)) AS nb_mails, COUNT(DISTINCT(clicks.mailing_trace_id)) AS nb_clicks, stats.mass_mailing_id AS id
+ FROM mailing_trace AS stats
+ LEFT OUTER JOIN link_tracker_click AS clicks ON clicks.mailing_trace_id = stats.id
WHERE stats.mass_mailing_id IN %s
GROUP BY stats.mass_mailing_id
""", (tuple(self.ids), ))
@@ -311,7 +311,7 @@ class MassMailing(models.Model):
COUNT(CASE WHEN s.bounced is not null THEN 1 ELSE null END) AS bounced,
COUNT(CASE WHEN s.exception is not null THEN 1 ELSE null END) AS failed
FROM
- mail_mail_statistics s
+ mailing_trace s
RIGHT JOIN
mail_mass_mailing m
ON (m.id = s.mass_mailing_id)
@@ -441,10 +441,10 @@ class MassMailing(models.Model):
def retry_failed_mail(self):
failed_mails = self.env['mail.mail'].search([('mailing_id', 'in', self.ids), ('state', '=', 'exception')])
- failed_mails.mapped('statistics_ids').unlink()
+ failed_mails.mapped('mailing_trace_ids').unlink()
failed_mails.sudo().unlink()
res_ids = self._get_recipients()
- except_mailed = self.env['mail.mail.statistics'].search([
+ except_mailed = self.env['mailing.trace'].search([
('model', '=', self.mailing_model_real),
('res_id', 'in', res_ids),
('exception', '!=', False),
@@ -471,11 +471,11 @@ class MassMailing(models.Model):
def _action_view_documents_filtered(self, view_filter):
if view_filter in ('sent', 'opened', 'replied', 'bounced', 'clicked'):
- opened_stats = self.statistics_ids.filtered(lambda stat: stat[view_filter])
+ opened_stats = self.mailing_trace_ids.filtered(lambda stat: stat[view_filter])
elif view_filter == ('delivered'):
- opened_stats = self.statistics_ids.filtered(lambda stat: stat.sent and not stat.bounced)
+ opened_stats = self.mailing_trace_ids.filtered(lambda stat: stat.sent and not stat.bounced)
else:
- opened_stats = self.env['mail.mail.statistics']
+ opened_stats = self.env['mailing.trace']
res_ids = opened_stats.mapped('res_id')
model_name = self.env['ir.model']._get(self.mailing_model_real).display_name
return {
@@ -551,7 +551,7 @@ class MassMailing(models.Model):
# + use a basic heuristic for extracting emails
query = """
SELECT lower(substring(t.%(mail_field)s, '([^ ,;<@]+@[^> ,;]+)'))
- FROM mail_mail_statistics s
+ FROM mailing_trace s
JOIN %(target)s t ON (s.res_id = t.id)
WHERE substring(t.%(mail_field)s, '([^ ,;<@]+@[^> ,;]+)') IS NOT NULL
"""
@@ -561,7 +561,7 @@ class MassMailing(models.Model):
mail_field = 'email'
query = """
SELECT lower(substring(p.%(mail_field)s, '([^ ,;<@]+@[^> ,;]+)'))
- FROM mail_mail_statistics s
+ FROM mailing_trace s
JOIN %(target)s t ON (s.res_id = t.id)
JOIN res_partner p ON (t.partner_id = p.id)
WHERE substring(p.%(mail_field)s, '([^ ,;<@]+@[^> ,;]+)') IS NOT NULL
@@ -626,7 +626,7 @@ class MassMailing(models.Model):
def _get_remaining_recipients(self):
res_ids = self._get_recipients()
- already_mailed = self.env['mail.mail.statistics'].search_read([
+ already_mailed = self.env['mailing.trace'].search_read([
('model', '=', self.mailing_model_real),
('res_id', 'in', res_ids),
('mass_mailing_id', '=', self.id)], ['res_id'])