diff options
| author | Julien De Coster <jdc@odoo.com> | 2014-08-12 14:54:26 +0530 |
|---|---|---|
| committer | Julien De Coster <jdc@odoo.com> | 2014-12-17 17:14:33 +0100 |
| commit | ddac26cdbb3535239f5dbb41f5b464366065f3ba (patch) | |
| tree | b54e4d34060f1c7f80a8c6404f7f4fd56d914e52 /addons/mass_mailing/models | |
| parent | 7f97bf4ec07329e58c818632bf23017b390bb099 (diff) | |
[ADD] Add the website_links module.
This module tracks clicks in mass mailing mails and allow the generation of trackable links in a website interface.
Modules modifications
---------------------
Refractoring of the crm_tracking_* classes in a new module.
* Extract the crm_tracking_* from the crm module into a new module "utm"
* Remove the crm_mass_mailing bridge module
* New dependencies of mass_mailing and website_links to utm.
Diffstat (limited to 'addons/mass_mailing/models')
| -rw-r--r-- | addons/mass_mailing/models/__init__.py | 1 | ||||
| -rw-r--r-- | addons/mass_mailing/models/mass_mailing.py | 133 | ||||
| -rw-r--r-- | addons/mass_mailing/models/mass_mailing_stats.py | 5 | ||||
| -rw-r--r-- | addons/mass_mailing/models/website_links_click.py | 10 |
4 files changed, 146 insertions, 3 deletions
diff --git a/addons/mass_mailing/models/__init__.py b/addons/mass_mailing/models/__init__.py index 702da268d84..7cc1ba680b4 100644 --- a/addons/mass_mailing/models/__init__.py +++ b/addons/mass_mailing/models/__init__.py @@ -6,3 +6,4 @@ import mail_mail import mail_thread import res_config import mass_mailing_report +import website_links_click diff --git a/addons/mass_mailing/models/mass_mailing.py b/addons/mass_mailing/models/mass_mailing.py index 0e5f7821a9a..555b10725b6 100644 --- a/addons/mass_mailing/models/mass_mailing.py +++ b/addons/mass_mailing/models/mass_mailing.py @@ -4,14 +4,17 @@ from datetime import datetime from dateutil import relativedelta import json import random +import re from openerp import tools +from openerp import models, api, _ from openerp.exceptions import Warning from openerp.tools.safe_eval import safe_eval as eval -from openerp.tools.translate import _ from openerp.tools import ustr from openerp.osv import osv, fields +URL_REGEX = r'https?://[^\s<>"]+|www\.[^\s<>"]+' + class MassMailingCategory(osv.Model): """Model of categories of mass mailing, i.e. marketing, newsletter, ... """ @@ -148,6 +151,9 @@ class MassMailingCampaign(osv.Model): _name = "mail.mass_mailing.campaign" _description = 'Mass Mailing Campaign' + _inherit = ['utm.mixin'] + _inherits = {'utm.campaign': 'campaign_id'} + def _get_statistics(self, cr, uid, ids, name, arg, context=None): """ Compute statistics of the mass mailing campaign """ results = {} @@ -181,6 +187,21 @@ class MassMailingCampaign(osv.Model): row['replied_ratio'] = 100.0 * row['replied'] / total return results + def _get_clicks_ratio(self, cr, uid, ids, name, arg, context=None): + res = dict.fromkeys(ids, 0) + 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 website_links_click AS clicks ON clicks.mail_stat_id = stats.id + WHERE stats.mass_mailing_campaign_id IN %s + GROUP BY stats.mass_mailing_campaign_id + """, (tuple(ids), )) + + for record in cr.dictfetchall(): + res[record['id']] = 100 * record['nb_clicks'] / record['nb_mails'] + + return res + _columns = { 'name': fields.char('Name', required=True), 'stage_id': fields.many2one('mail.mass_mailing.stage', 'Stage', required=True), @@ -188,6 +209,8 @@ class MassMailingCampaign(osv.Model): 'res.users', 'Responsible', required=True, ), + 'campaign_id': fields.many2one('utm.campaign', 'campaign_id', + required=True, ondelete='cascade'), 'category_ids': fields.many2many( 'mail.mass_mailing.category', 'mail_mass_mailing_category_rel', 'category_id', 'campaign_id', string='Categories'), @@ -201,6 +224,10 @@ class MassMailingCampaign(osv.Model): 'various mailings in a single campaign to test the effectiveness' 'of the mailings.'), 'color': fields.integer('Color Index'), + 'clicks_ratio': fields.function( + _get_clicks_ratio, string="Number of clicks", + type="integer", + ), # stat fields 'total': fields.function( _get_statistics, string='Total', @@ -252,11 +279,24 @@ class MassMailingCampaign(osv.Model): stage_ids = self.pool['mail.mass_mailing.stage'].search(cr, uid, [], limit=1, context=context) return stage_ids and stage_ids[0] or False + def _get_source_id(self, cr, uid, context=None): + return self.pool['ir.model.data'].xmlid_to_res_id(cr, uid, 'utm.utm_source_newsletter') + + def _get_medium_id(self, cr, uid, context=None): + return self.pool['ir.model.data'].xmlid_to_res_id(cr, uid, 'utm.utm_medium_email') + _defaults = { 'user_id': lambda self, cr, uid, ctx=None: uid, 'stage_id': lambda self, *args: self._get_default_stage_id(*args), + 'source_id': lambda self, *args: self._get_source_id(*args), + 'medium_id': lambda self,*args: self._get_medium_id(*args), } + def mass_mailing_statistics_action(self, cr, uid, ids, context=None): + res = self.pool['ir.actions.act_window'].for_xml_id(cr, uid, 'mass_mailing', 'action_view_mass_mailing_statistics', context=context) + res['domain'] = [('mass_mailing_campaign_id', 'in', ids)] + return res + def get_recipients(self, cr, uid, ids, model=None, context=None): """Return the recipients of a mailing campaign. This is based on the statistics build for each mailing. """ @@ -270,6 +310,17 @@ class MassMailingCampaign(osv.Model): res[cid] = set(stat.res_id for stat in Statistics.browse(cr, uid, stat_ids, context=context)) return res + def on_change_campaign_name(self, cr, uid, ids, name, context=None): + if name: + mass_mailing_campaign = self.browse(cr, uid, ids, context=context) + if mass_mailing_campaign.campaign_id: + utm_campaign_id = mass_mailing_campaign.campaign_id.id + self.pool['utm.campaign'].write(cr, uid, [utm_campaign_id], {'name': name}, context=context) + else: + utm_campaign_id = self.pool['utm.campaign'].create(cr, uid, {'name': name}, context=context) + + return {'value': {'campaign_id': utm_campaign_id}} + class MassMailing(osv.Model): """ MassMailing models a wave of emails for a mass mailign campaign. @@ -281,6 +332,8 @@ class MassMailing(osv.Model): _period_number = 6 _order = 'sent_date DESC' + _inherit = ['utm.mixin'] + def __get_bar_values(self, cr, uid, obj, domain, read_fields, value_field, groupby_field, date_begin, context=None): """ Generic method to generate data for bar chart values using SparklineBarWidget. This method performs obj.read_group(cr, uid, domain, read_fields, groupby_field). @@ -370,6 +423,21 @@ class MassMailing(osv.Model): res.append(('mail.mass_mailing.contact', _('Mailing List'))) return res + def _get_clicks_ratio(self, cr, uid, ids, name, arg, context=None): + res = dict.fromkeys(ids, 0) + 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 website_links_click AS clicks ON clicks.mail_stat_id = stats.id + WHERE stats.mass_mailing_id IN %s + GROUP BY stats.mass_mailing_id + """, (tuple(ids), )) + + for record in cr.dictfetchall(): + res[record['id']] = 100 * record['nb_clicks'] / record['nb_mails'] + + return res + # indirections for inheritance _mailing_model = lambda self, *args, **kwargs: self._get_mailing_model(*args, **kwargs) @@ -388,6 +456,10 @@ class MassMailing(osv.Model): 'mail.mass_mailing.campaign', 'Mass Mailing Campaign', ondelete='set null', ), + 'clicks_ratio': fields.function( + _get_clicks_ratio, string="Number of Clicks", + type="integer", + ), 'state': fields.selection( [('draft', 'Draft'), ('test', 'Tested'), ('done', 'Sent')], string='Status', required=True, copy=False, @@ -473,6 +545,12 @@ class MassMailing(osv.Model): ) } + def mass_mailing_statistics_action(self, cr, uid, ids, context=None): + res = self.pool['ir.actions.act_window'].for_xml_id(cr, uid, 'mass_mailing', 'action_view_mass_mailing_statistics', context=context) + link_click_ids = self.pool['website.links.click'].search(cr, uid, [('mass_mailing_id', 'in', ids)], context=context) + res['domain'] = [('id', 'in', link_click_ids)] + return res + def default_get(self, cr, uid, fields, context=None): res = super(MassMailing, self).default_get(cr, uid, fields, context=context) if 'reply_to_mode' in fields and not 'reply_to_mode' in res and res.get('mailing_model'): @@ -490,6 +568,16 @@ class MassMailing(osv.Model): 'contact_ab_pc': 100, } + def onchange_mass_mailing_campaign_id(self, cr, uid, id, mass_mailing_campaign_ids, context=None): + if mass_mailing_campaign_ids: + mass_mailing_campaign = self.pool['mail.mass_mailing.campaign'].browse(cr, uid, mass_mailing_campaign_ids, context=context) + + dic = {'campaign_id': mass_mailing_campaign[0].campaign_id.id, + 'source_id': mass_mailing_campaign[0].source_id.id, + 'medium_id': mass_mailing_campaign[0].medium_id.id} + print dic + return {'value': dic} + #------------------------------------------------------ # Technical stuff #------------------------------------------------------ @@ -559,6 +647,7 @@ class MassMailing(osv.Model): 'res_model': 'mail.mass_mailing', 'res_id': copy_id, 'context': context, + 'flags': {'initial_mode': 'edit'}, } return False @@ -622,7 +711,7 @@ class MassMailing(osv.Model): composer_values = { 'author_id': author_id, 'attachment_ids': [(4, attachment.id) for attachment in mailing.attachment_ids], - 'body': mailing.body_html, + 'body': self.convert_link(cr, uid, [mailing.id], context=context)[mailing.id], 'subject': mailing.name, 'model': mailing.mailing_model, 'email_from': mailing.email_from, @@ -638,3 +727,43 @@ class MassMailing(osv.Model): self.pool['mail.compose.message'].send_mail(cr, uid, [composer_id], context=comp_ctx) self.write(cr, uid, [mailing.id], {'sent_date': fields.datetime.now(), 'state': 'done'}, context=context) return True + + def convert_link(self, cr, uid, ids, context=None): + website_links = self.pool['website.links'] + 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 '' + + for long_url in re.findall(URL_REGEX, res[mass_mailing.id]): + utm_object = mass_mailing.mass_mailing_campaign_id if mass_mailing.mass_mailing_campaign_id else mass_mailing + + vals = {'url': long_url} + + if utm_object.campaign_id: + vals['campaign_id'] = utm_object.campaign_id.id + if utm_object.source_id: + vals['source_id'] = utm_object.source_id.id + if utm_object.medium_id: + vals['medium_id'] = utm_object.medium_id.id + + link_id = website_links.create(cr, uid, vals, context=context) + shorten_url = website_links.browse(cr, uid, link_id, context=context)[0].short_url + + if shorten_url: + res[mass_mailing.id] = res[mass_mailing.id].replace(long_url, shorten_url) + return res + + +class MailMail(models.Model): + _inherit = ['mail.mail'] + + @api.model + def send_get_mail_body(self, mail, partner=None): + """Override to add Statistic_id in shorted urls """ + if mail.mailing_id and mail.body_html: + urls = re.findall(URL_REGEX, mail.body_html) + + for url in urls: + mail.body_html = mail.body_html.replace(url, url + '/m/' + str(mail.statistics_ids[0].id)) + + return super(MailMail, self).send_get_mail_body(mail, partner=partner) diff --git a/addons/mass_mailing/models/mass_mailing_stats.py b/addons/mass_mailing/models/mass_mailing_stats.py index c3cd4314fa6..1ec50ebbee3 100644 --- a/addons/mass_mailing/models/mass_mailing_stats.py +++ b/addons/mass_mailing/models/mass_mailing_stats.py @@ -19,7 +19,9 @@ # ############################################################################## -from openerp.osv import osv, fields +import openerp +from openerp.osv import fields, osv +from openerp import models, api, _ class MailMailStats(osv.Model): @@ -63,6 +65,7 @@ class MailMailStats(osv.Model): 'opened': fields.datetime('Opened', help='Date when the email has been opened the first time'), 'replied': fields.datetime('Replied', help='Date when this email has been replied for the first time.'), 'bounced': fields.datetime('Bounced', help='Date when this email has bounced.'), + 'links_click_ids': fields.one2many('website.links.click', 'mail_stat_id', 'Links click'), } _defaults = { diff --git a/addons/mass_mailing/models/website_links_click.py b/addons/mass_mailing/models/website_links_click.py new file mode 100644 index 00000000000..31e93445ef8 --- /dev/null +++ b/addons/mass_mailing/models/website_links_click.py @@ -0,0 +1,10 @@ +from openerp import fields +from openerp import models + + +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') |
