[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
This commit is contained in:
@@ -28,13 +28,13 @@
|
||||
'wizard/test_mailing_views.xml',
|
||||
'wizard/mass_mailing_schedule_date_views.xml',
|
||||
'views/mass_mailing_views_menus.xml',
|
||||
'views/mass_mailing_stats_views.xml',
|
||||
'views/mailing_trace_views.xml',
|
||||
'views/link_tracker_views.xml',
|
||||
'views/mass_mailing_contact_views.xml',
|
||||
'views/mass_mailing_list_views.xml',
|
||||
'views/mass_mailing_views.xml',
|
||||
'views/res_config_settings_views.xml',
|
||||
'report/mass_mailing_stats_report_views.xml',
|
||||
'report/mailing_trace_report_views.xml',
|
||||
'views/assets.xml',
|
||||
'views/mass_mailing_templates_portal.xml',
|
||||
'views/themes_templates.xml',
|
||||
|
||||
@@ -94,15 +94,15 @@ class MassMailController(http.Controller):
|
||||
@http.route('/mail/track/<int:mail_id>/blank.gif', type='http', auth='public')
|
||||
def track_mail_open(self, mail_id, **post):
|
||||
""" Email tracking. """
|
||||
request.env['mail.mail.statistics'].sudo().set_opened(mail_mail_ids=[mail_id])
|
||||
request.env['mailing.trace'].sudo().set_opened(mail_mail_ids=[mail_id])
|
||||
response = werkzeug.wrappers.Response()
|
||||
response.mimetype = 'image/gif'
|
||||
response.data = base64.b64decode(b'R0lGODlhAQABAIAAANvf7wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==')
|
||||
|
||||
return response
|
||||
|
||||
@http.route('/r/<string:code>/m/<int:stat_id>', type='http', auth="public")
|
||||
def full_url_redirect(self, code, stat_id, **post):
|
||||
@http.route('/r/<string:code>/m/<int:mailing_trace_id>', type='http', auth="public")
|
||||
def full_url_redirect(self, code, mailing_trace_id, **post):
|
||||
# don't assume geoip is set, it is part of the website module
|
||||
# which mass_mailing doesn't depend on
|
||||
country_code = request.session.get('geoip', False) and request.session.geoip.get('country_code', False)
|
||||
@@ -111,7 +111,7 @@ class MassMailController(http.Controller):
|
||||
code,
|
||||
ip=request.httprequest.remote_addr,
|
||||
country_code=country_code,
|
||||
mail_stat_id=stat_id
|
||||
mailing_trace_id=mailing_trace_id
|
||||
)
|
||||
return werkzeug.utils.redirect(request.env['link.tracker'].get_url_from_code(code), 301)
|
||||
|
||||
|
||||
@@ -198,7 +198,7 @@
|
||||
<!-- Generate link tracker information from it -->
|
||||
<function model="mail.mass_mailing" name="convert_links" eval="[ref('mass_mailing.mass_mail_1')]"/>
|
||||
|
||||
<record id="mass_mail_1_stat_0" model="mail.mail.statistics">
|
||||
<record id="mass_mail_1_stat_0" model="mailing.trace">
|
||||
<field name="mass_mailing_id" eval="ref('mass_mail_1')"/>
|
||||
<field name="message_id">1111000@odoo.com</field>
|
||||
<field name="model">res.partner</field>
|
||||
@@ -207,7 +207,7 @@
|
||||
<field name="opened" eval="(DateTime.today() - relativedelta(days=2)).strftime('%Y-%m-%d %H:%M:%S')"/>
|
||||
<field name="replied" eval="(DateTime.today() - relativedelta(days=1)).strftime('%Y-%m-%d %H:%M:%S')"/>
|
||||
</record>
|
||||
<record id="mass_mail_1_stat_1" model="mail.mail.statistics">
|
||||
<record id="mass_mail_1_stat_1" model="mailing.trace">
|
||||
<field name="mass_mailing_id" eval="ref('mass_mail_1')"/>
|
||||
<field name="message_id">1111001@odoo.com</field>
|
||||
<field name="model">res.partner</field>
|
||||
@@ -216,7 +216,7 @@
|
||||
<field name="opened" eval="(DateTime.today() - relativedelta(days=2)).strftime('%Y-%m-%d %H:%M:%S')"/>
|
||||
<field name="replied" eval="(DateTime.today() - relativedelta(days=0)).strftime('%Y-%m-%d %H:%M:%S')"/>
|
||||
</record>
|
||||
<record id="mass_mail_1_stat_2" model="mail.mail.statistics">
|
||||
<record id="mass_mail_1_stat_2" model="mailing.trace">
|
||||
<field name="mass_mailing_id" eval="ref('mass_mail_1')"/>
|
||||
<field name="message_id">1111002@odoo.com</field>
|
||||
<field name="model">res.partner</field>
|
||||
@@ -224,7 +224,7 @@
|
||||
<field name="sent" eval="(DateTime.today() - relativedelta(days=5)).strftime('%Y-%m-%d %H:%M:%S')"/>
|
||||
<field name="opened" eval="(DateTime.today() - relativedelta(days=2)).strftime('%Y-%m-%d %H:%M:%S')"/>
|
||||
</record>
|
||||
<record id="mass_mail_1_stat_3" model="mail.mail.statistics">
|
||||
<record id="mass_mail_1_stat_3" model="mailing.trace">
|
||||
<field name="mass_mailing_id" eval="ref('mass_mail_1')"/>
|
||||
<field name="message_id">1111003@odoo.com</field>
|
||||
<field name="model">res.partner</field>
|
||||
@@ -232,7 +232,7 @@
|
||||
<field name="sent" eval="(DateTime.today() - relativedelta(days=5)).strftime('%Y-%m-%d %H:%M:%S')"/>
|
||||
<field name="opened" eval="(DateTime.today() - relativedelta(days=1)).strftime('%Y-%m-%d %H:%M:%S')"/>
|
||||
</record>
|
||||
<record id="mass_mail_1_stat_4" model="mail.mail.statistics">
|
||||
<record id="mass_mail_1_stat_4" model="mailing.trace">
|
||||
<field name="mass_mailing_id" eval="ref('mass_mail_1')"/>
|
||||
<field name="message_id">1111004@odoo.com</field>
|
||||
<field name="model">res.partner</field>
|
||||
@@ -240,7 +240,7 @@
|
||||
<field name="sent" eval="(DateTime.today() - relativedelta(days=5)).strftime('%Y-%m-%d %H:%M:%S')"/>
|
||||
<field name="opened" eval="(DateTime.today() - relativedelta(days=1)).strftime('%Y-%m-%d %H:%M:%S')"/>
|
||||
</record>
|
||||
<record id="mass_mail_1_stat_5" model="mail.mail.statistics">
|
||||
<record id="mass_mail_1_stat_5" model="mailing.trace">
|
||||
<field name="mass_mailing_id" eval="ref('mass_mail_1')"/>
|
||||
<field name="message_id">1111004@odoo.com</field>
|
||||
<field name="model">res.partner</field>
|
||||
@@ -248,7 +248,7 @@
|
||||
<field name="sent" eval="False"/>
|
||||
<field name="exception" eval="(DateTime.today() - relativedelta(days=5)).strftime('%Y-%m-%d %H:%M:%S')"/>
|
||||
</record>
|
||||
<record id="mass_mail_1_stat_6" model="mail.mail.statistics">
|
||||
<record id="mass_mail_1_stat_6" model="mailing.trace">
|
||||
<field name="mass_mailing_id" eval="ref('mass_mail_1')"/>
|
||||
<field name="message_id">1111004@odoo.com</field>
|
||||
<field name="model">res.partner</field>
|
||||
@@ -264,7 +264,7 @@
|
||||
use="code"/>
|
||||
<value name="ip">100.01.02.03</value>
|
||||
<value name="country_code">BE</value>
|
||||
<value name="mail_stat_id" eval="ref('mass_mail_1_stat_0')"/>
|
||||
<value name="mailing_trace_id" eval="ref('mass_mail_1_stat_0')"/>
|
||||
</function>
|
||||
<function model="link.tracker.click" name="add_click">
|
||||
<value model="link.tracker.code"
|
||||
@@ -272,7 +272,7 @@
|
||||
use="code"/>
|
||||
<value name="ip">100.01.02.03</value>
|
||||
<value name="country_code">BE</value>
|
||||
<value name="mail_stat_id" eval="ref('mass_mail_1_stat_0')"/>
|
||||
<value name="mailing_trace_id" eval="ref('mass_mail_1_stat_0')"/>
|
||||
</function>
|
||||
<function model="link.tracker.click" name="add_click">
|
||||
<value model="link.tracker.code"
|
||||
@@ -280,7 +280,7 @@
|
||||
use="code"/>
|
||||
<value name="ip">100.01.02.04</value>
|
||||
<value name="country_code">BE</value>
|
||||
<value name="mail_stat_id" eval="ref('mass_mail_1_stat_1')"/>
|
||||
<value name="mailing_trace_id" eval="ref('mass_mail_1_stat_1')"/>
|
||||
</function>
|
||||
<function model="link.tracker.click" name="add_click">
|
||||
<value model="link.tracker.code"
|
||||
@@ -288,7 +288,7 @@
|
||||
use="code"/>
|
||||
<value name="ip">100.01.02.04</value>
|
||||
<value name="country_code">BE</value>
|
||||
<value name="mail_stat_id" eval="ref('mass_mail_1_stat_0')"/>
|
||||
<value name="mailing_trace_id" eval="ref('mass_mail_1_stat_0')"/>
|
||||
</function>
|
||||
<function model="link.tracker.click" name="add_click">
|
||||
<value model="link.tracker.code"
|
||||
@@ -296,7 +296,7 @@
|
||||
use="code"/>
|
||||
<value name="ip">100.01.02.05</value>
|
||||
<value name="country_code">BE</value>
|
||||
<value name="mail_stat_id" eval="ref('mass_mail_1_stat_2')"/>
|
||||
<value name="mailing_trace_id" eval="ref('mass_mail_1_stat_2')"/>
|
||||
</function>
|
||||
|
||||
</data>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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.')
|
||||
|
||||
+18
-20
@@ -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
|
||||
@@ -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'])
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from . import mass_mailing_stats_report
|
||||
from . import mailing_trace_report
|
||||
|
||||
+7
-7
@@ -1,11 +1,11 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from odoo import api, fields, models, tools
|
||||
from odoo import fields, models, tools
|
||||
|
||||
|
||||
class MassMailingReport(models.Model):
|
||||
_name = 'mail.statistics.report'
|
||||
class MailingTraceReport(models.Model):
|
||||
_name = 'mailing.trace.report'
|
||||
_auto = False
|
||||
_description = 'Mass Mailing Statistics'
|
||||
|
||||
@@ -23,12 +23,12 @@ class MassMailingReport(models.Model):
|
||||
email_from = fields.Char('From', readonly=True)
|
||||
|
||||
def init(self):
|
||||
"""Mass Mail Statistical Report: based on mail.mail.statistics that models the various
|
||||
"""Mass Mail Statistical Report: based on mailing.trace that models the various
|
||||
statistics collected for each mailing, and mail.mass_mailing model that models the
|
||||
various mailing performed. """
|
||||
tools.drop_view_if_exists(self.env.cr, 'mail_statistics_report')
|
||||
tools.drop_view_if_exists(self.env.cr, 'mailing_trace_report')
|
||||
self.env.cr.execute("""
|
||||
CREATE OR REPLACE VIEW mail_statistics_report AS (
|
||||
CREATE OR REPLACE VIEW mailing_trace_report AS (
|
||||
SELECT
|
||||
min(ms.id) as id,
|
||||
ms.scheduled as scheduled_date,
|
||||
@@ -43,7 +43,7 @@ class MassMailingReport(models.Model):
|
||||
mm.state,
|
||||
mm.email_from
|
||||
FROM
|
||||
mail_mail_statistics as ms
|
||||
mailing_trace as ms
|
||||
left join mail_mass_mailing as mm ON (ms.mass_mailing_id=mm.id)
|
||||
left join mail_mass_mailing_campaign as mc ON (ms.mass_mailing_campaign_id=mc.id)
|
||||
left join utm_campaign as utm_campaign ON (mc.campaign_id = utm_campaign.id)
|
||||
+12
-12
@@ -1,8 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<record id="view_mail_statistics_report_pivot" model="ir.ui.view">
|
||||
<field name="name">mail.statistics.report.pivot</field>
|
||||
<field name="model">mail.statistics.report</field>
|
||||
<record id="mailing_trace_report_view_pivot" model="ir.ui.view">
|
||||
<field name="name">mailing.trace.report.view.pivot</field>
|
||||
<field name="model">mailing.trace.report</field>
|
||||
<field name="arch" type="xml">
|
||||
<pivot string="Mass Mailing Statistics" disable_linking="True">
|
||||
<field name="campaign" type="row"/>
|
||||
@@ -16,9 +16,9 @@
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_mail_statistics_report_graph" model="ir.ui.view">
|
||||
<field name="name">mail.statistics.report.graph</field>
|
||||
<field name="model">mail.statistics.report</field>
|
||||
<record id="mailing_trace_report_view_graph" model="ir.ui.view">
|
||||
<field name="name">mailing.trace.report.view.graph</field>
|
||||
<field name="model">mailing.trace.report</field>
|
||||
<field name="arch" type="xml">
|
||||
<graph string="Mass Mailing Statistics">
|
||||
<field name="campaign"/>
|
||||
@@ -27,9 +27,9 @@
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_mail_statistics_report_search" model="ir.ui.view">
|
||||
<field name="name">mail.statistics.report.search</field>
|
||||
<field name="model">mail.statistics.report</field>
|
||||
<record id="mailing_trace_report_view_search" model="ir.ui.view">
|
||||
<field name="name">mailing.trace.report.view.search</field>
|
||||
<field name="model">mailing.trace.report</field>
|
||||
<field name="arch" type="xml">
|
||||
<search string="Mass Mailing Statistics">
|
||||
<group expand="0" string="Extended Filters...">
|
||||
@@ -51,14 +51,14 @@
|
||||
</record>
|
||||
|
||||
<!-- Actions and Menuitems -->
|
||||
<record id="action_mail_statistics_report" model="ir.actions.act_window">
|
||||
<record id="mailing_trace_report_action" model="ir.actions.act_window">
|
||||
<field name="name">Mass Mailing Analysis</field>
|
||||
<field name="res_model">mail.statistics.report</field>
|
||||
<field name="res_model">mailing.trace.report</field>
|
||||
<field name="view_mode">graph,pivot</field>
|
||||
<field name="help">Mass Mailing Statistics allows you to check different mailing related information like number of bounced mails, opened mails, replied mails. You can sort out your analysis by different groups to get accurate grained analysis.</field>
|
||||
</record>
|
||||
|
||||
<menuitem name="Mass Mailing" id="mass_mailing_menu_root" sequence="60"/>
|
||||
<menuitem name="Reporting" id="menu_mass_mailing_report" sequence="99"
|
||||
parent="mass_mailing_menu_root" action="action_mail_statistics_report" groups="mass_mailing.group_mass_mailing_user"/>
|
||||
parent="mass_mailing_menu_root" action="mailing_trace_report_action" groups="mass_mailing.group_mass_mailing_user"/>
|
||||
</odoo>
|
||||
@@ -7,9 +7,9 @@ access_mass_mailing_campaign,mail.mass_mailing.campaign,model_mail_mass_mailing_
|
||||
access_mass_mailing_campaign_system,mail.mass_mailing.campaign.system,model_mail_mass_mailing_campaign,base.group_system,1,1,1,1
|
||||
access_mass_mailing,mail.mass_mailing,model_mail_mass_mailing,mass_mailing.group_mass_mailing_user,1,1,1,1
|
||||
access_mass_mailing_system,mail.mass_mailing.system,model_mail_mass_mailing,base.group_system,1,1,1,1
|
||||
access_mail_mail_statistics_user,mail.mail.statistics,model_mail_mail_statistics,base.group_user,1,1,1,1
|
||||
access_mail_mail_statistics_mass_mailing_user,mail.mail.statistics,model_mail_mail_statistics,mass_mailing.group_mass_mailing_user,1,1,1,1
|
||||
access_mail_statistics_report,mail.statistics.report,model_mail_statistics_report,mass_mailing.group_mass_mailing_user,1,1,1,1
|
||||
access_mailing_trace_user,mailing.trace.user,model_mailing_trace,base.group_user,1,1,1,1
|
||||
access_mailing_trace_mm_user,access.mailing.trace.mm.user,model_mailing_trace,mass_mailing.group_mass_mailing_user,1,1,1,1
|
||||
access_mailing_trace_report_mm_user,access.mailing.trace.report.mm.user,model_mailing_trace_report,mass_mailing.group_mass_mailing_user,1,1,1,1
|
||||
access_utm_source,access_utm_source,utm.model_utm_source,mass_mailing.group_mass_mailing_user,1,1,1,0
|
||||
access_ir_mail_server,access_ir_mail_server,base.model_ir_mail_server,mass_mailing.group_mass_mailing_user,1,0,0,0
|
||||
access_mail_blacklist_mass_mailing_user,access.mail.blacklist.mass_mailing_user,mail.model_mail_blacklist,mass_mailing.group_mass_mailing_user,1,1,1,1
|
||||
|
||||
|
@@ -80,7 +80,7 @@
|
||||
<xpath expr="//field[@name='country_id']" position="after">
|
||||
<field name="mass_mailing_campaign_id"/>
|
||||
<field name="mass_mailing_id"/>
|
||||
<field name="mail_stat_id"/>
|
||||
<field name="mailing_trace_id"/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
+14
-14
@@ -1,9 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<!-- MAIL MAIL STATISTICS !-->
|
||||
<record model="ir.ui.view" id="view_mail_mail_statistics_search">
|
||||
<field name="name">mail.mail.statistics.search</field>
|
||||
<field name="model">mail.mail.statistics</field>
|
||||
<!-- MAILING TRACE !-->
|
||||
<record model="ir.ui.view" id="mailing_trace_view_search">
|
||||
<field name="name">mailing.trace.search</field>
|
||||
<field name="model">mailing.trace</field>
|
||||
<field name="arch" type="xml">
|
||||
<search string="Mail Statistics">
|
||||
<field name="mail_mail_id_int"/>
|
||||
@@ -30,9 +30,9 @@
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.ui.view" id="view_mail_mail_statistics_tree">
|
||||
<field name="name">mail.mail.statistics.tree</field>
|
||||
<field name="model">mail.mail.statistics</field>
|
||||
<record model="ir.ui.view" id="mailing_trace_view_tree">
|
||||
<field name="name">mailing.trace.tree</field>
|
||||
<field name="model">mailing.trace</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Mail Statistics" create="0">
|
||||
<field name="email"/>
|
||||
@@ -49,9 +49,9 @@
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.ui.view" id="view_mail_mail_statistics_form">
|
||||
<field name="name">mail.mail.statistics.form</field>
|
||||
<field name="model">mail.mail.statistics</field>
|
||||
<record model="ir.ui.view" id="mailing_trace_view_form">
|
||||
<field name="name">mailing.trace.form</field>
|
||||
<field name="model">mailing.trace</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Mail Statistics" create="0">
|
||||
<header>
|
||||
@@ -88,13 +88,13 @@
|
||||
|
||||
<record id="action_view_mail_mail_statistics" model="ir.actions.act_window">
|
||||
<field name="name">Mail Statistics</field>
|
||||
<field name="res_model">mail.mail.statistics</field>
|
||||
<field name="res_model">mailing.trace</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
</record>
|
||||
|
||||
<record id="action_view_mail_mail_statistics_mailing" model="ir.actions.act_window">
|
||||
<field name="name">Mail Statistics</field>
|
||||
<field name="res_model">mail.mail.statistics</field>
|
||||
<field name="res_model">mailing.trace</field>
|
||||
<field name="view_mode">graph,tree,form,pivot</field>
|
||||
<field name="domain">[]</field>
|
||||
<field name="context">{'search_default_mass_mailing_id': active_id}</field>
|
||||
@@ -102,7 +102,7 @@
|
||||
|
||||
<record id="action_view_mail_mail_statistics_mailing_list" model="ir.actions.act_window">
|
||||
<field name="name">Emails Sent</field>
|
||||
<field name="res_model">mail.mail.statistics</field>
|
||||
<field name="res_model">mailing.trace</field>
|
||||
<field name="view_mode">tree,graph,form,pivot</field>
|
||||
<field name="domain">[]</field>
|
||||
<field name="context">{'search_default_mass_mailing_id': active_id}</field>
|
||||
@@ -110,7 +110,7 @@
|
||||
|
||||
<record id="view_mail_mail_statistics_graph" model="ir.ui.view">
|
||||
<field name="name">Mail Statistics Graph</field>
|
||||
<field name="model">mail.mail.statistics</field>
|
||||
<field name="model">mailing.trace</field>
|
||||
<field name="arch" type="xml">
|
||||
<graph string="Mail Statistics" type="bar" stacked="True" interval="day">
|
||||
<field name="state_update" type="row" interval="day"/>
|
||||
@@ -16,7 +16,7 @@ class MailComposeMessage(models.TransientModel):
|
||||
|
||||
def get_mail_values(self, res_ids):
|
||||
""" Override method that generated the mail content by creating the
|
||||
mail.mail.statistics values in the o2m of mail_mail, when doing pure
|
||||
mailing.trace values in the o2m of mail_mail, when doing pure
|
||||
email mass mailing. """
|
||||
self.ensure_one()
|
||||
res = super(MailComposeMessage, self).get_mail_values(res_ids)
|
||||
@@ -71,7 +71,7 @@ class MailComposeMessage(models.TransientModel):
|
||||
mail_values['state'] = 'cancel'
|
||||
elif seen_list is not None:
|
||||
seen_list.add(mail_to)
|
||||
stat_vals = {
|
||||
trace_vals = {
|
||||
'model': self.model,
|
||||
'res_id': res_id,
|
||||
'mass_mailing_id': mass_mailing.id,
|
||||
@@ -79,12 +79,12 @@ class MailComposeMessage(models.TransientModel):
|
||||
}
|
||||
if mail_values.get('body_html') and mass_mail_layout:
|
||||
mail_values['body_html'] = mass_mail_layout.render({'body': mail_values['body_html']}, engine='ir.qweb', minimal_qcontext=True)
|
||||
# propagate ignored state to stat when still-born
|
||||
# propagate ignored state to trace when still-born
|
||||
if mail_values.get('state') == 'cancel':
|
||||
stat_vals['ignored'] = fields.Datetime.now()
|
||||
trace_vals['ignored'] = fields.Datetime.now()
|
||||
mail_values.update({
|
||||
'mailing_id': mass_mailing.id,
|
||||
'statistics_ids': [(0, 0, stat_vals)],
|
||||
'mailing_trace_ids': [(0, 0, trace_vals)],
|
||||
# email-mode: keep original message for routing
|
||||
'notification': mass_mailing.reply_to_mode == 'thread',
|
||||
'auto_delete': not mass_mailing.keep_archives,
|
||||
|
||||
@@ -48,7 +48,7 @@ class TestLinkTracker(common.MassMailingCase):
|
||||
mailing = self.env['mail.mass_mailing'].create({'name': 'Test Mailing', "subject": "Hi!"})
|
||||
code = self.link.code
|
||||
self.assertEqual(self.link.count, 1)
|
||||
stat = self.env['mail.mail.statistics'].create({'mass_mailing_id': mailing.id})
|
||||
stat = self.env['mailing.trace'].create({'mass_mailing_id': mailing.id})
|
||||
self.assertFalse(stat.opened)
|
||||
self.assertFalse(stat.clicked)
|
||||
|
||||
@@ -57,7 +57,7 @@ class TestLinkTracker(common.MassMailingCase):
|
||||
code,
|
||||
ip='100.00.00.01',
|
||||
country_code='BEL',
|
||||
mail_stat_id=stat.id
|
||||
mailing_trace_id=stat.id
|
||||
)
|
||||
self.assertEqual(self.link.count, 2)
|
||||
self.assertEqual(click.mass_mailing_id, mailing)
|
||||
|
||||
@@ -9,7 +9,7 @@ class TestAutoBlacklist(common.TransactionCase):
|
||||
mass_mailing_contacts = self.env['mail.mass_mailing.contact']
|
||||
mass_mailing = self.env['mail.mass_mailing']
|
||||
mail_blacklist = self.env['mail.blacklist']
|
||||
mail_statistics = self.env['mail.mail.statistics']
|
||||
mail_statistics = self.env['mailing.trace']
|
||||
mail_thread = self.env['mail.thread']
|
||||
|
||||
# create mailing contact record
|
||||
@@ -45,7 +45,6 @@ class TestAutoBlacklist(common.TransactionCase):
|
||||
})
|
||||
self.mailing_contact_1._message_receive_bounce(self.mailing_contact_1.email, self.mailing_contact_1)
|
||||
|
||||
|
||||
# create mass mailing record
|
||||
self.mass_mailing = mass_mailing.create({
|
||||
'name': 'test',
|
||||
|
||||
Reference in New Issue
Block a user