[MERGE] utm, link_tracker, mass_mailing: improve views usability and lint module

Purpose of this merge is to clean a bit link_tracker and utm as well as their
use in mass mailing. Main things done in this merge are

  * reorganize link_tracker and utm according to guidelines. Purpose is
    to ease code understanding and prepare future improvements in those
    modules;
  * clean views, add missing fields in views;
  * better integration of link menus and views in mass mailing;

This commit is related to task ID 1896681.

closes odoo/odoo#27975
This commit is contained in:
Robot Odoo
2018-10-29 13:09:17 +01:00
committed by GitHub
20 changed files with 413 additions and 372 deletions
+3 -1
View File
@@ -1,3 +1,5 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from . import models
from . import controller
from . import controller
+6 -5
View File
@@ -1,15 +1,16 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
{
'name': 'Link Tracker',
'category': 'Marketing',
'description': """
Create short and trackable URLs.
=====================================================
""",
Shorten URLs and use them to track clicks and UTMs
""",
'version': '1.0',
'depends': ['utm'],
'data': [
'views/link_tracker.xml',
'views/link_tracker_views.xml',
'security/ir.model.access.csv',
],
}
@@ -1,2 +1,4 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from . import main
+2
View File
@@ -1,2 +1,4 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from . import link_tracker
+78 -74
View File
@@ -1,21 +1,22 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
import base64
import datetime
import random
import re
import requests
import string
import requests
from lxml import html
from werkzeug import urls, utils
from odoo import models, fields, api, _
from odoo.tools import ustr
URL_REGEX = r'(\bhref=[\'"](?!mailto:|tel:|sms:)([^\'"]+)[\'"])'
def VALIDATE_URL(url):
if urls.url_parse(url).scheme not in ('http', 'https', 'ftp', 'ftps'):
return 'http://' + url
@@ -23,50 +24,32 @@ def VALIDATE_URL(url):
return url
class link_tracker(models.Model):
"""link_tracker allow users to wrap any URL into a short and trackable URL.
link_tracker counts clicks on each tracked link.
This module is also used by mass_mailing, where each link in mail_mail html_body are converted into
a trackable link to get the click-through rate of each mass_mailing."""
class LinkTracker(models.Model):
""" Link trackers allow users to wrap any URL into a short URL that can be
tracked by Odoo. Clicks are counter on each link. A tracker is linked to
UTMs allowing to analyze marketing actions.
This model is also used in mass_mailing where each link in html body is
automatically converted into a short link that is tracked and integrates
UTMs. """
_name = "link.tracker"
_rec_name = "short_url"
_description = 'Link Tracker'
_inherit = ['utm.mixin']
_description = "Link Tracker"
_inherit = ["utm.mixin"]
# URL info
url = fields.Char(string='Target URL', required=True)
count = fields.Integer(string='Number of Clicks', compute='_compute_count', store=True)
short_url = fields.Char(string='Tracked URL', compute='_compute_short_url')
link_click_ids = fields.One2many('link.tracker.click', 'link_id', string='Clicks')
title = fields.Char(string='Page Title', store=True)
favicon = fields.Char(string='Favicon', compute='_compute_favicon', store=True)
link_code_ids = fields.One2many('link.tracker.code', 'link_id', string='Codes')
code = fields.Char(string='Short URL code', compute='_compute_code')
redirected_url = fields.Char(string='Redirected URL', compute='_compute_redirected_url')
short_url_host = fields.Char(string='Host of the short URL', compute='_compute_short_url_host')
title = fields.Char(string='Page Title', store=True)
favicon = fields.Char(string='Favicon', compute='_compute_favicon', store=True)
icon_src = fields.Char(string='Favicon Source', compute='_compute_icon_src')
@api.model
def convert_links(self, html, vals, blacklist=None):
for match in re.findall(URL_REGEX, html):
short_schema = self.env['ir.config_parameter'].sudo().get_param('web.base.url') + '/r/'
href = match[0]
long_url = match[1]
vals['url'] = utils.unescape(long_url)
if not blacklist or not [s for s in blacklist if s in long_url] and not long_url.startswith(short_schema):
link = self.create(vals)
shorten_url = self.browse(link.id)[0].short_url
if shorten_url:
new_href = href.replace(long_url, shorten_url)
html = html.replace(href, new_href)
return html
# Tracking
link_code_ids = fields.One2many('link.tracker.code', 'link_id', string='Codes')
code = fields.Char(string='Short URL code', compute='_compute_code')
link_click_ids = fields.One2many('link.tracker.click', 'link_id', string='Clicks')
count = fields.Integer(string='Number of Clicks', compute='_compute_count', store=True)
@api.one
@api.depends('link_click_ids.link_id')
@@ -130,32 +113,6 @@ class link_tracker(models.Model):
self.favicon = icon_base64
@api.multi
def action_view_statistics(self):
action = self.env['ir.actions.act_window'].for_xml_id('link_tracker', 'action_view_click_statistics')
action['domain'] = [('link_id', '=', self.id)]
return action
@api.multi
def action_visit_page(self):
return {
'name': _("Visit Webpage"),
'type': 'ir.actions.act_url',
'url': self.url,
'target': 'new',
}
@api.model
def recent_links(self, filter, limit):
if filter == 'newest':
return self.search_read([], order='create_date DESC', limit=limit)
elif filter == 'most-clicked':
return self.search_read([('count', '!=', 0)], order='count DESC', limit=limit)
elif filter == 'recently-used':
return self.search_read([('count', '!=', 0)], order='write_date DESC', limit=limit)
else:
return {'Error': "This filter doesn't exist."}
@api.model
def create(self, vals):
create_vals = vals.copy()
@@ -182,13 +139,60 @@ class link_tracker(models.Model):
if fname not in create_vals:
create_vals[fname] = False
link = super(link_tracker, self).create(create_vals)
link = super(LinkTracker, self).create(create_vals)
code = self.env['link.tracker.code'].get_random_code_string()
self.env['link.tracker.code'].sudo().create({'code': code, 'link_id': link.id})
return link
@api.model
def convert_links(self, html, vals, blacklist=None):
for match in re.findall(URL_REGEX, html):
short_schema = self.env['ir.config_parameter'].sudo().get_param('web.base.url') + '/r/'
href = match[0]
long_url = match[1]
vals['url'] = utils.unescape(long_url)
if not blacklist or not [s for s in blacklist if s in long_url] and not long_url.startswith(short_schema):
link = self.create(vals)
shorten_url = self.browse(link.id)[0].short_url
if shorten_url:
new_href = href.replace(long_url, shorten_url)
html = html.replace(href, new_href)
return html
@api.multi
def action_view_statistics(self):
action = self.env['ir.actions.act_window'].for_xml_id('link_tracker', 'link_tracker_click_action_statistics')
action['domain'] = [('link_id', '=', self.id)]
return action
@api.multi
def action_visit_page(self):
return {
'name': _("Visit Webpage"),
'type': 'ir.actions.act_url',
'url': self.url,
'target': 'new',
}
@api.model
def recent_links(self, filter, limit):
if filter == 'newest':
return self.search_read([], order='create_date DESC', limit=limit)
elif filter == 'most-clicked':
return self.search_read([('count', '!=', 0)], order='count DESC', limit=limit)
elif filter == 'recently-used':
return self.search_read([('count', '!=', 0)], order='write_date DESC', limit=limit)
else:
return {'Error': "This filter doesn't exist."}
@api.model
def get_url_from_code(self, code, context=None):
code_rec = self.env['link.tracker.code'].sudo().search([('code', '=', code)])
@@ -203,13 +207,17 @@ class link_tracker(models.Model):
]
class link_tracker_code(models.Model):
class LinkTrackerCode(models.Model):
_name = "link.tracker.code"
_description = 'Link Tracker Code'
_description = "Link Tracker Code"
code = fields.Char(string='Short URL Code', store=True)
link_id = fields.Many2one('link.tracker', 'Link', required=True, ondelete='cascade')
_sql_constraints = [
('code', 'unique( code )', 'Code must be unique.')
]
@api.model
def get_random_code_string(self):
size = 3
@@ -221,18 +229,14 @@ class link_tracker_code(models.Model):
else:
return code_proposition
_sql_constraints = [
('code', 'unique( code )', 'Code must be unique.')
]
class link_tracker_click(models.Model):
class LinkTrackerClick(models.Model):
_name = "link.tracker.click"
_rec_name = "link_id"
_description = 'Link Tracker Click'
_description = "Link Tracker Click"
click_date = fields.Date(string='Create Date')
link_id = fields.Many2one('link.tracker', 'Link', required=True, ondelete='cascade')
click_date = fields.Date(string='Create Date')
ip = fields.Char(string='Internet Protocol')
country_id = fields.Many2one('res.country', 'Country')
@@ -1,28 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<record model="ir.actions.act_window" id="action_view_click_statistics">
<field name="name">Statistics of Clicks</field>
<field name="res_model">link.tracker.click</field>
<field name="view_mode">graph</field>
<field name="domain">[('link_id', 'IN', ids)]</field>
</record>
<!-- Search -->
<record id="view_link_tracker_filter" model="ir.ui.view">
<field name="name">Links</field>
<!-- LINT.TRACKER -->
<record id="link_tracker_view_search" model="ir.ui.view">
<field name="name">link.tracker.view.search</field>
<field name="model">link.tracker</field>
<field name="arch" type="xml">
<search string="Tracked Link">
<field name="title"/>
<search string="Links">
<field name="url" string="Title and URL" filter_domain="['|', ('title', 'ilike', self), ('url', 'ilike', self)]"/>
<field name="title"/>
</search>
</field>
</record>
<!-- Website links views -->
<record id="view_link_tracker_form" model="ir.ui.view">
<field name="name">link.tracker.form</field>
<record id="link_tracker_view_form" model="ir.ui.view">
<field name="name">link.tracker.view.form</field>
<field name="model">link.tracker</field>
<field name="arch" type="xml">
<form string="Website Link">
@@ -34,56 +26,29 @@
<button type="object" class="oe_stat_button" name="action_view_statistics" icon="fa-bar-chart-o">
<field name="count" string="Clicks" widget="statinfo"/>
</button>
</div>
<group>
<field name="title"/>
<field name="url"/>
<field name="short_url"/>
</group>
<group>
<field name="campaign_id"/>
<field name="medium_id"/>
<field name="source_id"/>
<group name="url" string="URL">
<field name="title"/>
<field name="url"/>
<field name="short_url"/>
</group>
<group name="utm" string="UTM">
<field name="campaign_id"/>
<field name="medium_id"/>
<field name="source_id"/>
</group>
</group>
</sheet>
</form>
</field>
</record>
<record id="view_link_tracker_form_stats" model="ir.ui.view">
<field name="name">link.tracker.my.form</field>
<record id="link_tracker_view_tree" model="ir.ui.view">
<field name="name">link.tracker.view.tree</field>
<field name="model">link.tracker</field>
<field name="arch" type="xml">
<form string="Website Link Graph">
<sheet>
<field name="link_click_ids">
<graph>
<field name="link_id"/>
<field name="ip"/>
<field name="country_id"/>
</graph>
</field>
</sheet>
</form>
</field>
</record>
<record model="ir.actions.act_window" id="action_link_tracker_stats">
<field name="name">link.tracker.form.graph.action</field>
<field name="res_model">link.tracker</field>
<field name="view_type">form</field>
<field name="view_mode">form</field>
<field name="view_id" ref="view_link_tracker_form_stats"/>
</record>
<record id="view_link_tracker_tree" model="ir.ui.view">
<field name="name">link.tracker.tree</field>
<field name="model">link.tracker</field>
<field name="arch" type="xml">
<tree string="Website Links">
<tree string="Links">
<field name="create_date"/>
<field name="title"/>
<field name="url"/>
@@ -93,24 +58,23 @@
</field>
</record>
<record id="view_link_tracker_graph" model="ir.ui.view" >
<field name="name">link.tracker.graph</field>
<record id="link_tracker_view_graph" model="ir.ui.view">
<field name="name">link.tracker.view.graph</field>
<field name="model">link.tracker</field>
<field name="arch" type="xml">
<graph string="Website Links" type="bar">
<graph string="Links" type="bar">
<field name="url" type="row"/>
<field name="count" type="measure"/>
</graph>
</field>
</record>
<!-- Action for website links-->
<record model="ir.actions.act_window" id="action_link_tracker">
<record id="link_tracker_action" model="ir.actions.act_window">
<field name="name">Link Tracker</field>
<field name="res_model">link.tracker</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form,graph</field>
<field name="view_id" ref="view_link_tracker_tree"/>
<field name="view_id" ref="link_tracker_view_tree"/>
<field name="help" type="html">
<p class="o_view_nocontent_smiling_face">
Create a new link tracker
@@ -118,14 +82,12 @@
</field>
</record>
<!-- Website links click views -->
<record id="view_link_tracker_click_form" model="ir.ui.view">
<field name="name">link.tracker.click.form</field>
<!-- LINK.TRACKER.CLICK -->
<record id="link_tracker_click_view_form" model="ir.ui.view">
<field name="name">link.tracker.click.view.form</field>
<field name="model">link.tracker.click</field>
<field name="arch" type="xml">
<form string="Website Link Clicks">
<header>
</header>
<form string="Link Click">
<sheet>
<group>
<field name="link_id"/>
@@ -137,11 +99,11 @@
</field>
</record>
<record id="view_link_tracker_click_tree" model="ir.ui.view">
<field name="name">link.tracker.click.tree</field>
<record id="link_tracker_click_view_tree" model="ir.ui.view">
<field name="name">link.tracker.click.view.tree</field>
<field name="model">link.tracker.click</field>
<field name="arch" type="xml">
<tree string="Website Links Clicks">
<tree string="Links Clicks">
<field name="link_id"/>
<field name="ip"/>
<field name="country_id"/>
@@ -149,11 +111,11 @@
</field>
</record>
<record id="view_link_tracker_click_graph" model="ir.ui.view" >
<field name="name">link.tracker.click.graph</field>
<record id="link_tracker_click_view_graph" model="ir.ui.view">
<field name="name">link.tracker.click.view.graph</field>
<field name="model">link.tracker.click</field>
<field name="arch" type="xml">
<graph string="Website Link Clicks">
<graph string="Link Clicks">
<field name="link_id"/>
<field name="ip"/>
<field name="country_id"/>
@@ -161,8 +123,18 @@
</field>
</record>
<!-- Action for website links click-->
<record id="link_tracker_click_action_statistics" model="ir.actions.act_window">
<field name="name">Click Statistics</field>
<field name="res_model">link.tracker.click</field>
<field name="view_mode">graph</field>
<field name="domain">[]</field>
</record>
<menuitem id="menu_url_shortener_main" name="Link Tracker" parent="utm.menu_link_tracker_root" action="action_link_tracker" groups="base.group_no_one"/>
<!-- MENUS -->
<menuitem id="link_tracker_menu_main"
name="Link Tracker"
parent="utm.menu_link_tracker_root"
action="link_tracker_action"
groups="base.group_no_one"/>
</data>
</odoo>
+1
View File
@@ -25,6 +25,7 @@
'wizard/mass_mailing_list_merge_views.xml',
'wizard/test_mailing_views.xml',
'wizard/mass_mailing_schedule_date_views.xml',
'views/mass_mailing_views_menus.xml',
'views/mass_mailing_report_views.xml',
'views/mass_mailing_stats_views.xml',
'views/link_tracker_views.xml',
@@ -1,42 +1,63 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<!-- LINK TRACKER VIEWS -->
<record model="ir.ui.view" id="view_mail_mass_mailing_links_tree">
<field name="name">link.tracker.tree</field>
<!-- LINK.TRACKER VIEWS -->
<record id="link_tracker_view_search" model="ir.ui.view">
<field name="name">link.tracker.view.search.inherit.mass.mail</field>
<field name="model">link.tracker</field>
<field name="priority">10</field>
<field name="inherit_id" ref="link_tracker.link_tracker_view_search"/>
<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">link.tracker.search</field>
<field name="model">link.tracker</field>
<field name="inherit_id" ref="link_tracker.view_link_tracker_filter"/>
<field name="arch" type="xml">
<search>
<xpath expr="//field[@name='title']" position="after">
<field name="mass_mailing_id"/>
<field name="mass_mailing_campaign_id"/>
</search>
</xpath>
</field>
</record>
<record model="ir.actions.act_window" id="action_view_mass_mailing_links_statistics">
<record id="link_tracker_view_form" model="ir.ui.view">
<field name="name">link.tracker.view.form.inherit.mass.mail</field>
<field name="model">link.tracker</field>
<field name="inherit_id" ref="link_tracker.link_tracker_view_form"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='campaign_id']" position="before">
<field name="mass_mailing_id"/>
<field name="mass_mailing_campaign_id"/>
</xpath>
</field>
</record>
<record id="link_tracker_action_mass_mailing" model="ir.actions.act_window">
<field name="name">Statistics of Clicks</field>
<field name="res_model">link.tracker</field>
<field name="view_mode">tree</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form,graph</field>
<field name="view_id" ref="link_tracker.link_tracker_view_tree"/>
<field name="help" type="html">
<p class="o_view_nocontent_smiling_face">
Create a new link tracker
</p>
</field>
<field name="context">{'search_default_mass_mailing_id': active_id}</field>
</record>
<record model="ir.actions.act_window" id="dropdb snipp">
<record id="link_tracker_action_mass_mailing_campaign" model="ir.actions.act_window">
<field name="name">Statistics of Clicks</field>
<field name="res_model">link.tracker</field>
<field name="view_mode">tree</field>
<field name="context">{'search_default_mass_mailing_campaign_id': active_id}</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form,graph</field>
<field name="view_id" ref="link_tracker.link_tracker_view_tree"/>
<field name="help" type="html">
<p class="o_view_nocontent_smiling_face">
Create a new link tracker
</p>
</field>
<field name="context">{'id="link_tracker_action_mass_mailing"': active_id}</field>
</record>
<!-- MENU TO HANLDE LINK DATA IN MM -->
<menuitem id="link_tracker_menu_mass_mailing"
name="Link Tracker"
parent="mass_mailing_configuration"
sequence="5"
action="link_tracker.link_tracker_action"/>
</odoo>
@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<odoo>
<menuitem id="mail_blacklist_mm_menu" name="Blacklist" action="mail.mail_blacklist_action" parent="menu_mass_mailing_configuration"/>
<menuitem id="mail_blacklist_mm_menu" name="Blacklist" action="mail.mail_blacklist_action" parent="mass_mailing_configuration"/>
</odoo>
@@ -1,14 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<!-- Marketing / Mailing -->
<menuitem name="Email Marketing" id="mass_mailing_menu_root" sequence="60" web_icon="mass_mailing,static/description/icon.png"/>
<menuitem name="Mailing Lists" id="mass_mailing_mailing_list_menu"
parent="mass_mailing_menu_root" sequence="2" groups="mass_mailing.group_mass_mailing_user"/>
<!-- Marketing / Configuration -->
<menuitem name="Configuration" id="mass_mailing_configuration"
parent="mass_mailing_menu_root" sequence="100"/>
<!-- MAILING CONTACT -->
<record model="ir.ui.view" id="mail_mass_mailing_list_contact_rel_view_form">
<field name="name">mail.mass_mailing.list_contact_rel.view.form</field>
@@ -712,7 +703,7 @@
</div>
<div class="row">
<div class="col-8">
<a name="%(action_view_mass_mailing_links_statistics)d"
<a name="%(link_tracker_action_mass_mailing)d"
type="action">Clicks</a>
</div>
<div class="col-4 text-right">
@@ -866,11 +857,8 @@
</field>
</record>
<menuitem id="menu_mass_mailing_configuration" name="Configuration" parent="mass_mailing_menu_root"
sequence="100" groups="mass_mailing.group_mass_mailing_user"/>
<menuitem name="Campaign Stages" id="menu_view_mass_mailing_stages"
parent="menu_mass_mailing_configuration" sequence="1"
parent="mass_mailing_configuration" sequence="1"
groups="mass_mailing.group_mass_mailing_campaign"
action="action_view_mass_mailing_stages"/>
@@ -897,7 +885,7 @@
</field>
</record>
<menuitem id="mass_mailing_tag_menu" parent="menu_mass_mailing_configuration" action="mass_mailing_tag_action" sequence="2" groups="base.group_no_one"/>
<menuitem id="mass_mailing_tag_menu" parent="mass_mailing_configuration" action="mass_mailing_tag_action" sequence="2" groups="base.group_no_one"/>
<!-- MAILING CAMPAIGNS !-->
@@ -968,7 +956,7 @@
type="action" class="oe_stat_button">
<field name="replied_ratio" widget="percentpie" string="Replied"/>
</button>
<button name="%(dropdb snipp)d"
<button name="%(link_tracker_action_mass_mailing_campaign)d"
type="action" class="oe_stat_button">
<field name="clicks_ratio" widget="percentpie" string="Clicks"/>
</button>
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<!-- Marketing / Mailing -->
<menuitem name="Email Marketing" id="mass_mailing_menu_root" sequence="60" web_icon="mass_mailing,static/description/icon.png"/>
<menuitem name="Mailing Lists" id="mass_mailing_mailing_list_menu"
parent="mass_mailing_menu_root" sequence="2" groups="mass_mailing.group_mass_mailing_user"/>
<!-- Marketing / Configuration -->
<menuitem name="Configuration" id="mass_mailing_configuration"
parent="mass_mailing_menu_root"
sequence="100"
groups="mass_mailing.group_mass_mailing_user"/>
</odoo>
@@ -74,8 +74,6 @@
<field name="context">{'module' : 'mass_mailing'}</field>
</record>
<menuitem id="menu_mass_mailing_configuration" name="Configuration" parent="mass_mailing_menu_root"
sequence="100"/>
<menuitem id="menu_mass_mailing_global_settings" name="Settings"
parent="menu_mass_mailing_configuration" sequence="0" action="action_mass_mailing_configuration" groups="base.group_system"/>
parent="mass_mailing_configuration" sequence="0" action="action_mass_mailing_configuration" groups="base.group_system"/>
</odoo>
+2
View File
@@ -28,6 +28,8 @@
<separator/>
<filter string="Starred" name="starred" domain="[('priority','in',[1, 2])]"/>
<separator/>
<filter string="Opened" name="opened" domain="[('stage_id.fold','=',False)]"/>
<separator/>
<filter string="Unread Messages" name="message_needaction" domain="[('message_needaction','=',True)]"/>
<filter string="Archived" name="inactive" domain="[('active','=',False)]"/>
<separator/>
+2
View File
@@ -1,2 +1,4 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from . import models
+7 -5
View File
@@ -1,16 +1,18 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
{
'name': 'UTM Trackers',
'category': 'Hidden',
'description': """
Enable UTM trackers in shared links.
=====================================================
""",
Enable management of UTM trackers: campaign, medium, source.
""",
'version': '1.0',
'depends': ['base'],
'data': [
'data/utm_data.xml',
'views/utm_views.xml',
'security/ir.model.access.csv',
'views/utm.xml',
'data/utm_data.xml'
],
'demo': [],
'auto_install': False,
+3
View File
@@ -1,3 +1,6 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from . import utm
from . import utm_mixin
from . import ir_http
+1 -57
View File
@@ -1,9 +1,7 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import api, fields, models, SUPERUSER_ID
from odoo.http import request
from odoo.tools import pycompat
from odoo import fields, models
class UtmMedium(models.Model):
@@ -29,57 +27,3 @@ class UtmSource(models.Model):
_description = 'UTM Source'
name = fields.Char(string='Source Name', required=True, translate=True)
class UtmMixin(models.AbstractModel):
"""Mixin class for objects which can be tracked by marketing. """
_name = 'utm.mixin'
_description = 'UTM Mixin'
campaign_id = fields.Many2one('utm.campaign', 'Campaign',
help="This is a name that helps you keep track of your different campaign efforts, e.g. Fall_Drive, Christmas_Special")
source_id = fields.Many2one('utm.source', 'Source',
help="This is the source of the link, e.g. Search Engine, another domain, or name of email list")
medium_id = fields.Many2one('utm.medium', 'Medium',
help="This is the method of delivery, e.g. Postcard, Email, or Banner Ad", oldname='channel_id')
def tracking_fields(self):
# This function cannot be overridden in a model which inherit utm.mixin
# Limitation by the heritage on AbstractModel
# record_crm_lead.tracking_fields() will call tracking_fields() from module utm.mixin (if not overridden on crm.lead)
# instead of the overridden method from utm.mixin.
# To force the call of overridden method, we use self.env['utm.mixin'].tracking_fields() which respects overridden
# methods of utm.mixin, but will ignore overridden method on crm.lead
return [
# ("URL_PARAMETER", "FIELD_NAME_MIXIN", "NAME_IN_COOKIES")
('utm_campaign', 'campaign_id', 'odoo_utm_campaign'),
('utm_source', 'source_id', 'odoo_utm_source'),
('utm_medium', 'medium_id', 'odoo_utm_medium'),
]
@api.model
def default_get(self, fields):
values = super(UtmMixin, self).default_get(fields)
# We ignore UTM for salemen, except some requests that could be done as superuser_id to bypass access rights.
if self.env.uid != SUPERUSER_ID and self.env.user.has_group('sales_team.group_sale_salesman'):
return values
for url_param, field_name, cookie_name in self.env['utm.mixin'].tracking_fields():
if field_name in fields:
field = self._fields[field_name]
value = False
if request:
# ir_http dispatch saves the url params in a cookie
value = request.httprequest.cookies.get(cookie_name)
# if we receive a string for a many2one, we search/create the id
if field.type == 'many2one' and isinstance(value, pycompat.string_types) and value:
Model = self.env[field.comodel_name]
records = Model.search([('name', '=', value)], limit=1)
if not records:
records = Model.create({'name': value})
value = records.id
if value:
values[field_name] = value
return values
+59
View File
@@ -0,0 +1,59 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import api, fields, models, SUPERUSER_ID
from odoo.http import request
from odoo.tools import pycompat
class UtmMixin(models.AbstractModel):
""" Mixin class for objects which can be tracked by marketing. """
_name = 'utm.mixin'
_description = 'UTM Mixin'
campaign_id = fields.Many2one('utm.campaign', 'Campaign',
help="This is a name that helps you keep track of your different campaign efforts, e.g. Fall_Drive, Christmas_Special")
source_id = fields.Many2one('utm.source', 'Source',
help="This is the source of the link, e.g. Search Engine, another domain, or name of email list")
medium_id = fields.Many2one('utm.medium', 'Medium',
help="This is the method of delivery, e.g. Postcard, Email, or Banner Ad", oldname='channel_id')
@api.model
def default_get(self, fields):
values = super(UtmMixin, self).default_get(fields)
# We ignore UTM for salemen, except some requests that could be done as superuser_id to bypass access rights.
if self.env.uid != SUPERUSER_ID and self.env.user.has_group('sales_team.group_sale_salesman'):
return values
for url_param, field_name, cookie_name in self.env['utm.mixin'].tracking_fields():
if field_name in fields:
field = self._fields[field_name]
value = False
if request:
# ir_http dispatch saves the url params in a cookie
value = request.httprequest.cookies.get(cookie_name)
# if we receive a string for a many2one, we search/create the id
if field.type == 'many2one' and isinstance(value, pycompat.string_types) and value:
Model = self.env[field.comodel_name]
records = Model.search([('name', '=', value)], limit=1)
if not records:
records = Model.create({'name': value})
value = records.id
if value:
values[field_name] = value
return values
def tracking_fields(self):
# This function cannot be overridden in a model which inherit utm.mixin
# Limitation by the heritage on AbstractModel
# record_crm_lead.tracking_fields() will call tracking_fields() from module utm.mixin (if not overridden on crm.lead)
# instead of the overridden method from utm.mixin.
# To force the call of overridden method, we use self.env['utm.mixin'].tracking_fields() which respects overridden
# methods of utm.mixin, but will ignore overridden method on crm.lead
return [
# ("URL_PARAMETER", "FIELD_NAME_MIXIN", "NAME_IN_COOKIES")
('utm_campaign', 'campaign_id', 'odoo_utm_campaign'),
('utm_source', 'source_id', 'odoo_utm_source'),
('utm_medium', 'medium_id', 'odoo_utm_medium'),
]
-110
View File
@@ -1,110 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<menuitem id="menu_link_tracker_root" name="Link Tracker" groups="base.group_no_one" sequence="30" web_icon="utm,static/description/icon.png"/>
<menuitem name="UTMs" id="marketing_utm" parent="menu_link_tracker_root" sequence="99" groups="base.group_no_one"/>
<!-- utm.campaign -->
<record model="ir.ui.view" id="utm_campaign_tree">
<field name="name">utm.campaign.tree</field>
<field name="model">utm.campaign</field>
<field name="arch" type="xml">
<tree string="Campaign">
<field name="name"/>
</tree>
</field>
</record>
<record model="ir.ui.view" id="utm_campaign_form">
<field name="name">utm.campaign.form</field>
<field name="model">utm.campaign</field>
<field name="arch" type="xml">
<form string="Campaign">
<group>
<field name="name"/>
</group>
</form>
</field>
</record>
<record id="utm_campaign_act" model="ir.actions.act_window">
<field name="name">Campaigns</field>
<field name="res_model">utm.campaign</field>
<field name="view_type">form</field>
<field name="view_id" ref="utm_campaign_tree"/>
</record>
<menuitem action="utm_campaign_act" id="menu_utm_campaign_act" sequence="4"
groups="base.group_no_one" parent="marketing_utm"/>
<!-- utm.medium -->
<record id="utm_medium_view_tree" model="ir.ui.view">
<field name="name">utm.medium.tree</field>
<field name="model">utm.medium</field>
<field name="arch" type="xml">
<tree string="Medium">
<field name="name"/>
<field name="active"/>
</tree>
</field>
</record>
<record id="utm_medium_view_form" model="ir.ui.view">
<field name="name">utm.medium.form</field>
<field name="model">utm.medium</field>
<field name="arch" type="xml">
<form string="Channel">
<group>
<field name="name"/>
<field name="active"/>
</group>
</form>
</field>
</record>
<record id="utm_medium_action" model="ir.actions.act_window">
<field name="name">Medium</field>
<field name="res_model">utm.medium</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
<field name="help" type="html">
<p class="o_view_nocontent_smiling_face">
Define a new medium
</p>
</field>
</record>
<menuitem action="utm_medium_action" id="menu_utm_medium" parent="marketing_utm" sequence="4" groups="base.group_no_one"/>
<!-- utm.source -->
<record id="utm_source_view_tree" model="ir.ui.view">
<field name="name">utm.source.tree</field>
<field name="model">utm.source</field>
<field name="arch" type="xml">
<tree string="Medium">
<field name="name"/>
</tree>
</field>
</record>
<record id="utm_source_view_form" model="ir.ui.view">
<field name="name">utm.source.form</field>
<field name="model">utm.source</field>
<field name="arch" type="xml">
<form string="Channel">
<group>
<field name="name"/>
</group>
</form>
</field>
</record>
<record id="utm_source_action" model="ir.actions.act_window">
<field name="name">Sources</field>
<field name="res_model">utm.source</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
<field name="help" type="html">
<p class="o_view_nocontent_smiling_face">
Define a new source
</p>
</field>
</record>
<menuitem action="utm_source_action" id="menu_utm_source" parent="marketing_utm" sequence="4" groups="base.group_no_one"/>
</odoo>
+136
View File
@@ -0,0 +1,136 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<menuitem id="menu_link_tracker_root"
name="Link Tracker"
sequence="30"
web_icon="utm,static/description/icon.png"
groups="base.group_no_one"/>
<menuitem id="marketing_utm"
name="UTMs"
parent="menu_link_tracker_root"
sequence="99"
groups="base.group_no_one"/>
<!-- utm.campaign -->
<record id="utm_campaign_view_tree" model="ir.ui.view">
<field name="name">utm.campaign.view.tree</field>
<field name="model">utm.campaign</field>
<field name="arch" type="xml">
<tree string="Campaign">
<field name="name"/>
</tree>
</field>
</record>
<record id="utm_campaign_view_form" model="ir.ui.view">
<field name="name">utm.campaign.view.form</field>
<field name="model">utm.campaign</field>
<field name="arch" type="xml">
<form string="Campaign">
<group>
<field name="name"/>
</group>
</form>
</field>
</record>
<record id="utm_campaign_action" model="ir.actions.act_window">
<field name="name">Campaigns</field>
<field name="res_model">utm.campaign</field>
<field name="view_type">form</field>
<field name="view_id" ref="utm_campaign_view_tree"/>
<field name="help" type="html">
<p class="o_view_nocontent_smiling_face">
Define a new UTM campaign
</p>
</field>
</record>
<menuitem id="menu_utm_campaign_act"
action="utm_campaign_action"
parent="marketing_utm"
sequence="1"
groups="base.group_no_one"/>
<!-- utm.medium -->
<record id="utm_medium_view_tree" model="ir.ui.view">
<field name="name">utm.medium.view.tree</field>
<field name="model">utm.medium</field>
<field name="arch" type="xml">
<tree string="Mediums">
<field name="name"/>
<field name="active"/>
</tree>
</field>
</record>
<record id="utm_medium_view_form" model="ir.ui.view">
<field name="name">utm.medium.view.form</field>
<field name="model">utm.medium</field>
<field name="arch" type="xml">
<form string="Medium">
<group>
<field name="name"/>
<field name="active"/>
</group>
</form>
</field>
</record>
<record id="utm_medium_action" model="ir.actions.act_window">
<field name="name">Mediums</field>
<field name="res_model">utm.medium</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
<field name="help" type="html">
<p class="o_view_nocontent_smiling_face">
Define a new UTM medium
</p>
</field>
</record>
<menuitem id="menu_utm_medium"
action="utm_medium_action"
parent="marketing_utm"
sequence="5"
groups="base.group_no_one"/>
<!-- utm.source -->
<record id="utm_source_view_tree" model="ir.ui.view">
<field name="name">utm.source.view.tree</field>
<field name="model">utm.source</field>
<field name="arch" type="xml">
<tree string="Source">
<field name="name"/>
</tree>
</field>
</record>
<record id="utm_source_view_form" model="ir.ui.view">
<field name="name">utm.source.view.form</field>
<field name="model">utm.source</field>
<field name="arch" type="xml">
<form string="Source">
<group>
<field name="name"/>
</group>
</form>
</field>
</record>
<record id="utm_source_action" model="ir.actions.act_window">
<field name="name">Sources</field>
<field name="res_model">utm.source</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
<field name="help" type="html">
<p class="o_view_nocontent_smiling_face">
Define a new UTM source
</p>
</field>
</record>
<menuitem id="menu_utm_source"
action="utm_source_action"
parent="marketing_utm"
sequence="10"
groups="base.group_no_one"/>
</odoo>