diff options
| author | stephanchrst <stephanchrst@gmail.com> | 2022-05-10 21:51:50 +0700 |
|---|---|---|
| committer | stephanchrst <stephanchrst@gmail.com> | 2022-05-10 21:51:50 +0700 |
| commit | 3751379f1e9a4c215fb6eb898b4ccc67659b9ace (patch) | |
| tree | a44932296ef4a9b71d5f010906253d8c53727726 /addons/utm/models | |
| parent | 0a15094050bfde69a06d6eff798e9a8ddf2b8c21 (diff) | |
initial commit 2
Diffstat (limited to 'addons/utm/models')
| -rw-r--r-- | addons/utm/models/__init__.py | 6 | ||||
| -rw-r--r-- | addons/utm/models/ir_http.py | 35 | ||||
| -rw-r--r-- | addons/utm/models/utm.py | 80 | ||||
| -rw-r--r-- | addons/utm/models/utm_mixin.py | 61 |
4 files changed, 182 insertions, 0 deletions
diff --git a/addons/utm/models/__init__.py b/addons/utm/models/__init__.py new file mode 100644 index 00000000..6ebdc46b --- /dev/null +++ b/addons/utm/models/__init__.py @@ -0,0 +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 diff --git a/addons/utm/models/ir_http.py b/addons/utm/models/ir_http.py new file mode 100644 index 00000000..7de6922c --- /dev/null +++ b/addons/utm/models/ir_http.py @@ -0,0 +1,35 @@ +# -*- coding: utf-8 -*- +from odoo.http import request +from odoo import models + + +class IrHttp(models.AbstractModel): + _inherit = 'ir.http' + + @classmethod + def get_utm_domain_cookies(cls): + return request.httprequest.host + + @classmethod + def _set_utm(cls, response): + if isinstance(response, Exception): + return response + # the parent dispatch might destroy the session + if not request.db: + return response + + domain = cls.get_utm_domain_cookies() + for var, dummy, cook in request.env['utm.mixin'].tracking_fields(): + if var in request.params and request.httprequest.cookies.get(var) != request.params[var]: + response.set_cookie(cook, request.params[var], domain=domain) + return response + + @classmethod + def _dispatch(cls): + response = super(IrHttp, cls)._dispatch() + return cls._set_utm(response) + + @classmethod + def _handle_exception(cls, exc): + response = super(IrHttp, cls)._handle_exception(exc) + return cls._set_utm(response) diff --git a/addons/utm/models/utm.py b/addons/utm/models/utm.py new file mode 100644 index 00000000..a670539d --- /dev/null +++ b/addons/utm/models/utm.py @@ -0,0 +1,80 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from random import randint + +from odoo import fields, models, api, SUPERUSER_ID + + +class UtmStage(models.Model): + + """Stage for utm campaigns. """ + _name = 'utm.stage' + _description = 'Campaign Stage' + _order = 'sequence' + + name = fields.Char(required=True, translate=True) + sequence = fields.Integer() + + +class UtmMedium(models.Model): + # OLD crm.case.channel + _name = 'utm.medium' + _description = 'UTM Medium' + _order = 'name' + + name = fields.Char(string='Medium Name', required=True) + active = fields.Boolean(default=True) + + +class UtmCampaign(models.Model): + # OLD crm.case.resource.type + _name = 'utm.campaign' + _description = 'UTM Campaign' + + name = fields.Char(string='Campaign Name', required=True, translate=True) + + user_id = fields.Many2one( + 'res.users', string='Responsible', + required=True, default=lambda self: self.env.uid) + stage_id = fields.Many2one('utm.stage', string='Stage', ondelete='restrict', required=True, + default=lambda self: self.env['utm.stage'].search([], limit=1), + group_expand='_group_expand_stage_ids') + tag_ids = fields.Many2many( + 'utm.tag', 'utm_tag_rel', + 'tag_id', 'campaign_id', string='Tags') + + is_website = fields.Boolean(default=False, help="Allows us to filter relevant Campaign") + color = fields.Integer(string='Color Index') + + @api.model + def _group_expand_stage_ids(self, stages, domain, order): + """ Read group customization in order to display all the stages in the + kanban view, even if they are empty + """ + stage_ids = stages._search([], order=order, access_rights_uid=SUPERUSER_ID) + return stages.browse(stage_ids) + +class UtmSource(models.Model): + _name = 'utm.source' + _description = 'UTM Source' + + name = fields.Char(string='Source Name', required=True, translate=True) + +class UtmTag(models.Model): + """Model of categories of utm campaigns, i.e. marketing, newsletter, ... """ + _name = 'utm.tag' + _description = 'UTM Tag' + _order = 'name' + + def _default_color(self): + return randint(1, 11) + + name = fields.Char(required=True, translate=True) + color = fields.Integer( + string='Color Index', default=lambda self: self._default_color(), + help='Tag color. No color means no display in kanban to distinguish internal tags from public categorization tags.') + + _sql_constraints = [ + ('name_uniq', 'unique (name)', "Tag name already exists !"), + ] diff --git a/addons/utm/models/utm_mixin.py b/addons/utm/models/utm_mixin.py new file mode 100644 index 00000000..b74d3385 --- /dev/null +++ b/addons/utm/models/utm_mixin.py @@ -0,0 +1,61 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo import api, fields, models +from odoo.http import request + + +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") + + @api.model + def default_get(self, fields): + values = super(UtmMixin, self).default_get(fields) + + # We ignore UTM for salesmen, except some requests that could be done as superuser_id to bypass access rights. + if not self.env.is_superuser() 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, str) and value: + Model = self.env[field.comodel_name] + records = Model.search([('name', '=', value)], limit=1) + if not records: + if 'is_website' in records._fields: + records = Model.create({'name': value, 'is_website': True}) + else: + 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'), + ] |
