[ADD] Clicks statistics in mass_mailings
This commit is contained in:
@@ -6,4 +6,4 @@ import mail_mail
|
||||
import mail_thread
|
||||
import res_config
|
||||
import mass_mailing_report
|
||||
import website_links_click
|
||||
import website_links
|
||||
|
||||
@@ -493,7 +493,7 @@ class MassMailing(osv.Model):
|
||||
'email_from': fields.char('From', required=True),
|
||||
'create_date': fields.datetime('Creation Date'),
|
||||
'sent_date': fields.datetime('Sent Date', oldname='date', copy=False),
|
||||
'schedule_date': fields.datetime('Scheduled Send Date'),
|
||||
'schedule_date': fields.datetime('Schedule in the Future'),
|
||||
'body_html': fields.html('Body'),
|
||||
'attachment_ids': fields.many2many(
|
||||
'ir.attachment', 'mass_mailing_ir_attachments_rel',
|
||||
@@ -769,6 +769,10 @@ class MassMailing(osv.Model):
|
||||
comp_ctx = dict(context, active_ids=res_ids)
|
||||
else:
|
||||
comp_ctx = {'active_ids': res_ids}
|
||||
|
||||
# Convert links in absolute URLs before the application of the shortener
|
||||
self.write(cr, uid, [mailing.id], {'body_html': self.pool['mail.template']._replace_local_links(cr, uid, mailing.body_html, context)}, context=context)
|
||||
|
||||
composer_values = {
|
||||
'author_id': author_id,
|
||||
'attachment_ids': [(4, attachment.id) for attachment in mailing.attachment_ids],
|
||||
@@ -787,19 +791,32 @@ class MassMailing(osv.Model):
|
||||
|
||||
composer_id = self.pool['mail.compose.message'].create(cr, uid, composer_values, context=comp_ctx)
|
||||
self.pool['mail.compose.message'].send_mail(cr, uid, [composer_id], auto_commit=True, context=comp_ctx)
|
||||
self.write(cr, uid, [mailing.id], {'sent_date': fields.datetime.now(), 'state': 'done'}, context=context)
|
||||
self.write(cr, uid, [mailing.id], {'state': 'done'}, context=context)
|
||||
return True
|
||||
|
||||
def convert_links(self, cr, uid, ids, context=None):
|
||||
res = {}
|
||||
for mass_mailing in self.browse(cr, uid, ids, context=context):
|
||||
res[mass_mailing.id] = mass_mailing.body_html if mass_mailing.body_html else ''
|
||||
utm_mixin = mass_mailing.mass_mailing_campaign_id if mass_mailing.mass_mailing_campaign_id else mass_mailing
|
||||
res[mass_mailing.id] = self.pool['website.links'].convert_links(cr, uid, res[mass_mailing.id], utm_mixin, context=context)
|
||||
html = mass_mailing.body_html if mass_mailing.body_html else ''
|
||||
|
||||
vals = {'mass_mailing_id': mass_mailing.id}
|
||||
|
||||
if mass_mailing.mass_mailing_campaign_id:
|
||||
vals['mass_mailing_campaign_id'] = mass_mailing.mass_mailing_campaign_id.id
|
||||
if utm_mixin.campaign_id:
|
||||
vals['campaign_id'] = utm_mixin.campaign_id.id
|
||||
if utm_mixin.source_id:
|
||||
vals['source_id'] = utm_mixin.source_id.id
|
||||
if utm_mixin.medium_id:
|
||||
vals['medium_id'] = utm_mixin.medium_id.id
|
||||
|
||||
res[mass_mailing.id] = self.pool['website.links'].convert_links(cr, uid, html, vals, blacklist=['/unsubscribe_from_list'], context=context)
|
||||
|
||||
return res
|
||||
|
||||
def put_in_queue(self, cr, uid, ids, context=None):
|
||||
self.write(cr, uid, ids, {'state': 'in_queue'}, context=context)
|
||||
self.write(cr, uid, ids, {'sent_date': fields.datetime.now(), 'state': 'in_queue'}, context=context)
|
||||
|
||||
def cancel_mass_mailing(self, cr, uid, ids, context=None):
|
||||
self.write(cr, uid, ids, {'state': 'draft'}, context=context)
|
||||
@@ -830,18 +847,19 @@ class MassMailing(osv.Model):
|
||||
class MailMail(models.Model):
|
||||
_inherit = ['mail.mail']
|
||||
|
||||
links_backlist = ['/unsubscribe_from_list']
|
||||
|
||||
@api.model
|
||||
def send_get_mail_body(self, mail, partner=None):
|
||||
"""Override to add Statistic_id in shorted urls """
|
||||
|
||||
links_blacklist = ['/unsubscribe_from_list']
|
||||
|
||||
if mail.mailing_id and mail.body_html and mail.statistics_ids:
|
||||
for match in re.findall(URL_REGEX, mail.body_html):
|
||||
|
||||
href = match[0]
|
||||
url = match[1]
|
||||
|
||||
if not [s for s in self.links_backlist if s in href]:
|
||||
if not [s for s in links_blacklist if s in href]:
|
||||
new_href = href.replace(url, url + '/m/' + str(mail.statistics_ids[0].id))
|
||||
mail.body_html = mail.body_html.replace(href, new_href)
|
||||
|
||||
|
||||
+6
-1
@@ -1,10 +1,15 @@
|
||||
from openerp import fields
|
||||
from openerp import models
|
||||
|
||||
class website_links(models.Model):
|
||||
_inherit = "website.links"
|
||||
|
||||
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')
|
||||
|
||||
class website_links_click(models.Model):
|
||||
_inherit = "website.links.click"
|
||||
|
||||
mail_stat_id = fields.Many2one('mail.mail.statistics', 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')
|
||||
mass_mailing_campaign_id = fields.Many2one('mail.mass_mailing.campaign', string='Mass Mailing Campaign')
|
||||
@@ -4,7 +4,7 @@
|
||||
}
|
||||
.openerp .oe_kanban_view .oe_kanban_mass_mailing {
|
||||
width: 280px;
|
||||
min-height: 141px;
|
||||
min-height: 35px;
|
||||
}
|
||||
.openerp .oe_margin_top_8 {
|
||||
margin-top: 8px;
|
||||
|
||||
@@ -184,12 +184,6 @@
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.actions.act_window" id="action_view_mass_mailing_statistics">
|
||||
<field name="name">Statistics of Clicks</field>
|
||||
<field name="res_model">website.links.click</field>
|
||||
<field name="view_mode">graph</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.actions.act_window" id="action_view_mass_mailing_contacts">
|
||||
<field name="name">Mailing List Subscribers</field>
|
||||
<field name="res_model">mail.mass_mailing.contact</field>
|
||||
@@ -323,6 +317,38 @@
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.ui.view" id="view_mail_mass_mailing_links_tree">
|
||||
<field name="name">website.links.tree</field>
|
||||
<field name="model">website.links</field>
|
||||
<field name="priority">10</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Mailing Statistics of Clicks">
|
||||
<field name="title"/>
|
||||
<field name="url"/>
|
||||
<field name="count"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.ui.view" id="view_mail_mass_mailing_links_search">
|
||||
<field name="name">website.links.search</field>
|
||||
<field name="model">website.links</field>
|
||||
<field name="inherit_id" ref="website_links.view_website_links_filter"/>
|
||||
<field name="arch" type="xml">
|
||||
<search string="Tracked Link">
|
||||
<field name="mass_mailing_id"/>
|
||||
<field name="mass_mailing_campaign_id"/>
|
||||
</search>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.actions.act_window" id="action_view_mass_mailing_links_statistics">
|
||||
<field name="name">Statistics of Clicks</field>
|
||||
<field name="res_model">website.links</field>
|
||||
<field name="view_mode">tree</field>
|
||||
<field name="context">{'search_default_mass_mailing_id': active_id}</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.ui.view" id="view_mail_mass_mailing_form">
|
||||
<field name="name">mail.mass_mailing.form</field>
|
||||
<field name="model">mail.mass_mailing</field>
|
||||
@@ -375,9 +401,9 @@
|
||||
type="action" class="oe_stat_button">
|
||||
<field name="replied_ratio" string="Replied" widget="percentpie"/>
|
||||
</button>
|
||||
<button name="mass_mailing_statistics_action"
|
||||
type="object" class="oe_stat_button">
|
||||
<field name="clicks_ratio" string="clicks" widget="percentpie"/>
|
||||
<button name="%(action_view_mass_mailing_links_statistics)d"
|
||||
type="action" class="oe_stat_button">
|
||||
<field name="clicks_ratio" string="Clicks" widget="percentpie"/>
|
||||
</button>
|
||||
<button name="%(action_view_mail_mail_statistics_mailing)d"
|
||||
type="action" class="oe_stat_button">
|
||||
@@ -395,6 +421,7 @@
|
||||
|
||||
<field name="mailing_domain" widget="char_domain"
|
||||
placeholder="Select recipients"
|
||||
attrs="{'invisible': [('mailing_model', '=', 'mail.mass_mailing.contact')]}"
|
||||
options="{'model_field': 'mailing_model', 'model_domain': 'mailing_domain'}"
|
||||
context="{'search_default_not_opt_out':1}"/>
|
||||
|
||||
@@ -423,8 +450,8 @@
|
||||
attrs="{'required': [('reply_to_mode', '=', 'email')]}"/>
|
||||
</div>
|
||||
<field name="schedule_date" />
|
||||
<field name="create_date" readonly="1"/>
|
||||
<field name="sent_date" readonly="1"/>
|
||||
<field name="create_date" readonly="1" attrs="{'invisible': [('create_date', '=', False)]}"/>
|
||||
<field name="sent_date" readonly="1" attrs="{'invisible': [('sent_date', '=', False)]}"/>
|
||||
</group>
|
||||
<group string="Campaign">
|
||||
<field name="mass_mailing_campaign_id" groups="mass_mailing.group_mass_mailing_campaign" string="Campaign" on_change="onchange_mass_mailing_campaign_id(mass_mailing_campaign_id)"/>
|
||||
@@ -456,6 +483,7 @@
|
||||
<field name='color'/>
|
||||
<field name='total'/>
|
||||
<field name='failed'/>
|
||||
<field name='sent_date'/>
|
||||
<templates>
|
||||
<t t-name="kanban-box">
|
||||
<div t-attf-class="oe_kanban_color_#{kanban_getcolor(record.color.raw_value)} oe_kanban_card oe_kanban_global_click oe_kanban_mass_mailing">
|
||||
@@ -469,21 +497,25 @@
|
||||
</div>
|
||||
<div class="oe_kanban_content">
|
||||
<div>
|
||||
<h3><field name="name"/>
|
||||
<!-- <i class="fa fa-exclamation-triangle oe_kanban_mass_mailing_exclamation_sign" attrs="{'invisible': [('failed', '=', 0)]}"></i> --></h3>
|
||||
<h4 style="display: inline;"><field name="mass_mailing_campaign_id" groups="mass_mailing.group_mass_mailing_campaign"/></h4>
|
||||
<t t-if="record.mass_mailing_campaign_id.raw_value" groups="mass_mailing.group_mass_mailing_campaign"> - </t><field name="sent_date"/>
|
||||
<h3><field name="name"/></h3>
|
||||
|
||||
<div attrs="{'invisible': [('sent_date', '=', False)]}">
|
||||
<h4 style="display: inline;"><field name="mass_mailing_campaign_id" groups="mass_mailing.group_mass_mailing_campaign"/></h4>
|
||||
<t t-if="record.mass_mailing_campaign_id.raw_value" groups="mass_mailing.group_mass_mailing_campaign"> - </t><field name="sent_date"/>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div style="display: inline-block">
|
||||
<field name="delivered" widget="gauge" style="width:120px; height: 90px;"
|
||||
options="{'max_field': 'total'}"/>
|
||||
</div>
|
||||
<div style="display: inline-block; vertical-align: top;">
|
||||
<strong>Opened</strong> <field name="opened_ratio"/> %<br />
|
||||
<strong>Replied</strong> <field name="replied_ratio"/> % <br />
|
||||
<strong>Clicks</strong> <field name="clicks_ratio"/> % <br />
|
||||
</div>
|
||||
<div attrs="{'invisible': [('sent_date', '=', False)]}">
|
||||
<t t-if="record.sent_date">
|
||||
<div style="display: inline-block">
|
||||
<field name="delivered" widget="gauge" style="width:120px; height: 90px;"
|
||||
options="{'max_field': 'total'}"/>
|
||||
</div>
|
||||
<div style="display: inline-block; vertical-align: top;">
|
||||
<strong>Opened</strong> <field name="opened_ratio"/> %<br />
|
||||
<strong>Replied</strong> <field name="replied_ratio"/> % <br />
|
||||
<strong>Clicks</strong> <field name="clicks_ratio"/> % <br />
|
||||
</div>
|
||||
</t>
|
||||
</div>
|
||||
</div>
|
||||
<div class="oe_clear"></div>
|
||||
@@ -646,6 +678,13 @@
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.actions.act_window" id="dropdb snipp">
|
||||
<field name="name">Statistics of Clicks</field>
|
||||
<field name="res_model">website.links</field>
|
||||
<field name="view_mode">tree</field>
|
||||
<field name="context">{'search_default_mass_mailing_campaign_id': active_id}</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.ui.view" id="view_mail_mass_mailing_campaign_form">
|
||||
<field name="name">mail.mass_mailing.campaign.form</field>
|
||||
<field name="model">mail.mass_mailing.campaign</field>
|
||||
@@ -688,8 +727,8 @@
|
||||
type="action" class="oe_stat_button oe_inline">
|
||||
<field name="replied_ratio" widget="percentpie" string="Replied"/>
|
||||
</button>
|
||||
<button name="mass_mailing_statistics_action"
|
||||
type="object" class="oe_stat_button">
|
||||
<button name="%(dropdb snipp)d"
|
||||
type="action" class="oe_stat_button">
|
||||
<field name="clicks_ratio" widget="percentpie" string="Clicks"/>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -43,24 +43,15 @@ class website_links(models.Model):
|
||||
short_url_host = fields.Char(string='Host of the short URL', compute='_compute_short_url_host')
|
||||
icon_src = fields.Char(string='Favicon Source', compute='_compute_icon_src')
|
||||
|
||||
# List of link's href that will not be converted by the shortener
|
||||
links_backlist = ['/unsubscribe_from_list']
|
||||
|
||||
@api.model
|
||||
def convert_links(self, html, utm_mixin):
|
||||
def convert_links(self, html, vals, blacklist=None):
|
||||
for match in re.findall(URL_REGEX, html):
|
||||
href = match[0]
|
||||
long_url = match[1]
|
||||
|
||||
if not [s for s in self.links_backlist if s in long_url]:
|
||||
vals = {'url': long_url}
|
||||
vals['url'] = long_url
|
||||
|
||||
if utm_mixin.campaign_id:
|
||||
vals['campaign_id'] = utm_mixin.campaign_id.id
|
||||
if utm_mixin.source_id:
|
||||
vals['source_id'] = utm_mixin.source_id.id
|
||||
if utm_mixin.medium_id:
|
||||
vals['medium_id'] = utm_mixin.medium_id.id
|
||||
if not blacklist or blacklist and not [s for s in blacklist if s in long_url]:
|
||||
|
||||
link = self.create(vals)
|
||||
shorten_url = self.browse(link.id)[0].short_url
|
||||
@@ -68,6 +59,7 @@ class website_links(models.Model):
|
||||
if shorten_url:
|
||||
new_href = href.replace(long_url, shorten_url)
|
||||
html = html.replace(href, new_href)
|
||||
|
||||
return html
|
||||
|
||||
@api.one
|
||||
@@ -159,10 +151,12 @@ class website_links(models.Model):
|
||||
|
||||
@api.model
|
||||
def create(self, vals):
|
||||
create_vals = vals.copy()
|
||||
|
||||
if 'url' not in vals:
|
||||
raise ValueError('URL field required')
|
||||
else:
|
||||
vals['url'] = VALIDATE_URL(vals['url'])
|
||||
create_vals['url'] = VALIDATE_URL(vals['url'])
|
||||
|
||||
search_domain = []
|
||||
for fname, value in vals.iteritems():
|
||||
@@ -174,14 +168,14 @@ class website_links(models.Model):
|
||||
return result
|
||||
|
||||
if not vals.get('title'):
|
||||
vals['title'] = self._get_title_from_url(vals['url'])
|
||||
create_vals['title'] = self._get_title_from_url(vals['url'])
|
||||
|
||||
# Prevent the UTMs to be set by the values of UTM cookies
|
||||
for (key, fname) in self.env['utm.mixin'].tracking_fields():
|
||||
if fname not in vals:
|
||||
vals[fname] = False
|
||||
create_vals[fname] = False
|
||||
|
||||
link = super(website_links, self).create(vals)
|
||||
link = super(website_links, self).create(create_vals)
|
||||
|
||||
code = self.env['website.links.code'].get_random_code_string()
|
||||
self.env['website.links.code'].create({'code': code, 'link_id': link.id})
|
||||
|
||||
Reference in New Issue
Block a user