summaryrefslogtreecommitdiff
path: root/addons
diff options
context:
space:
mode:
authorOdoo's Mergebot <robodoo@odoo.com>2020-12-11 17:37:27 +0100
committerGitHub <noreply@github.com>2020-12-11 17:37:27 +0100
commitd33d7bdf21d8a0743a1fa10b9f248d42a20f7785 (patch)
tree7ffb846554da48cc3cf904cee84e3cc57f3c8ae4 /addons
parent47079f67f586adf45da15fc98dbc81571f7a9100 (diff)
parent4f83be33d4cc53d50081050b3a9dee2892c562a4 (diff)
[MERGE] mass_mailing(_sms / _sale), utm: provide various fixes
PURPOSE Provide various fixes related to mass mailing (sms) and marketing automation applications. SPECIFICATIONS See sub commits for more details. [FIX] link_tracker: disable create and edit on clicks list view [FIX] sale: prevent creating quotations from UTM campaign reporting buttons [REF] mass_mailing: split mailing.trace.report sql to ease inheritance [FIX] mass_mailing: let subscription_ids won over default_list_ids [FIX] utm: fix naming of utm campaign card [FIX] utm: show campaign tags by default by giving them a color LINKS Task ID-2300385 COM PR odoo/odoo#59872 ENT PR odoo/enterprise#14031 Signed-off-by: Thibault Delavallee (tde) <tde@openerp.com>
Diffstat (limited to 'addons')
-rw-r--r--addons/link_tracker/views/link_tracker_views.xml8
-rw-r--r--addons/mass_mailing/i18n/mass_mailing.pot2
-rw-r--r--addons/mass_mailing/models/mailing_contact.py44
-rw-r--r--addons/mass_mailing/report/mailing_trace_report.py75
-rw-r--r--addons/mass_mailing/tests/test_mailing_list.py34
-rw-r--r--addons/sale/models/utm.py6
-rw-r--r--addons/utm/i18n/utm.pot12
-rw-r--r--addons/utm/models/utm.py11
-rw-r--r--addons/utm/views/utm_campaign_views.xml2
9 files changed, 161 insertions, 33 deletions
diff --git a/addons/link_tracker/views/link_tracker_views.xml b/addons/link_tracker/views/link_tracker_views.xml
index 8999a5de34e..8dff64a7758 100644
--- a/addons/link_tracker/views/link_tracker_views.xml
+++ b/addons/link_tracker/views/link_tracker_views.xml
@@ -26,7 +26,7 @@
<field name="name">link.tracker.view.form</field>
<field name="model">link.tracker</field>
<field name="arch" type="xml">
- <form string="Website Link" duplicate="0">
+ <form string="Website Link" duplicate="0" create="0">
<sheet>
<div class="oe_button_box" name="button_box">
<button type="object" icon="fa-sign-out" name="action_visit_page"
@@ -58,7 +58,7 @@
<field name="name">link.tracker.view.tree</field>
<field name="model">link.tracker</field>
<field name="arch" type="xml">
- <tree string="Links" sample="1">
+ <tree string="Links" sample="1" create="0">
<field name="create_date"/>
<field name="title"/>
<field name="label"/>
@@ -115,7 +115,7 @@
<field name="name">link.tracker.click.view.form</field>
<field name="model">link.tracker.click</field>
<field name="arch" type="xml">
- <form string="Link Click">
+ <form string="Link Click" create="0">
<sheet>
<group>
<field name="link_id"/>
@@ -131,7 +131,7 @@
<field name="name">link.tracker.click.view.tree</field>
<field name="model">link.tracker.click</field>
<field name="arch" type="xml">
- <tree string="Links Clicks">
+ <tree string="Links Clicks" create="0">
<field name="link_id"/>
<field name="ip"/>
<field name="country_id"/>
diff --git a/addons/mass_mailing/i18n/mass_mailing.pot b/addons/mass_mailing/i18n/mass_mailing.pot
index 9e9a8239571..24ddf9c5a5f 100644
--- a/addons/mass_mailing/i18n/mass_mailing.pot
+++ b/addons/mass_mailing/i18n/mass_mailing.pot
@@ -257,7 +257,7 @@ msgstr ""
#. module: mass_mailing
#: model:ir.model.constraint,message:mass_mailing.constraint_mailing_contact_list_rel_unique_contact_list
-msgid "A contact cannot be subscribed multiple times to the same list!"
+msgid "A mailing contact cannot subscribe to the same mailing list multiple times."
msgstr ""
#. module: mass_mailing
diff --git a/addons/mass_mailing/models/mailing_contact.py b/addons/mass_mailing/models/mailing_contact.py
index 6ebd1132820..5d74fd511f9 100644
--- a/addons/mass_mailing/models/mailing_contact.py
+++ b/addons/mass_mailing/models/mailing_contact.py
@@ -24,7 +24,7 @@ class MassMailingContactListRel(models.Model):
_sql_constraints = [
('unique_contact_list', 'unique (contact_id, list_id)',
- 'A contact cannot be subscribed multiple times to the same list!')
+ 'A mailing contact cannot subscribe to the same mailing list multiple times.')
]
@api.model
@@ -49,6 +49,18 @@ class MassMailingContact(models.Model):
_description = 'Mailing Contact'
_order = 'email'
+ def default_get(self, fields):
+ """ When coming from a mailing list we may have a default_list_ids context
+ key. We should use it to create subscription_list_ids default value that
+ are displayed to the user as list_ids is not displayed on form view. """
+ res = super(MassMailingContact, self).default_get(fields)
+ if 'subscription_list_ids' in fields and not res.get('subscription_list_ids'):
+ list_ids = self.env.context.get('default_list_ids')
+ if 'default_list_ids' not in res and list_ids and isinstance(list_ids, (list, tuple)):
+ res['subscription_list_ids'] = [
+ (0, 0, {'list_id': list_id}) for list_id in list_ids]
+ return res
+
name = fields.Char()
company_name = fields.Char(string='Company Name')
title_id = fields.Many2one('res.partner.title', string='Title')
@@ -80,6 +92,7 @@ class MassMailingContact(models.Model):
return expression.FALSE_DOMAIN if value else expression.TRUE_DOMAIN
@api.depends('subscription_list_ids')
+ @api.depends_context('default_list_ids')
def _compute_opt_out(self):
if 'default_list_ids' in self._context and isinstance(self._context['default_list_ids'], (list, tuple)) and len(self._context['default_list_ids']) == 1:
[active_list_id] = self._context['default_list_ids']
@@ -98,6 +111,35 @@ class MassMailingContact(models.Model):
name = email
return name, email
+ @api.model_create_multi
+ def create(self, vals_list):
+ """ Synchronize default_list_ids (currently used notably for computed
+ fields) default key with subscription_list_ids given by user when creating
+ contacts.
+
+ Those two values have the same purpose, adding a list to to the contact
+ either through a direct write on m2m, either through a write on middle
+ model subscription.
+
+ This is a bit hackish but is due to default_list_ids key being
+ used to compute oupt_out field. This should be cleaned in master but here
+ we simply try to limit issues while keeping current behavior. """
+ default_list_ids = self._context.get('default_list_ids')
+ default_list_ids = default_list_ids if isinstance(default_list_ids, (list, tuple)) else []
+
+ if default_list_ids:
+ for vals in vals_list:
+ current_list_ids = []
+ subscription_ids = vals.get('subscription_list_ids') or []
+ for subscription in subscription_ids:
+ if len(subscription) == 3:
+ current_list_ids.append(subscription[2]['list_id'])
+ for list_id in set(default_list_ids) - set(current_list_ids):
+ subscription_ids.append((0, 0, {'list_id': list_id}))
+ vals['subscription_list_ids'] = subscription_ids
+
+ return super(MassMailingContact, self.with_context(default_list_ids=False)).create(vals_list)
+
@api.model
def name_create(self, name):
name, email = self.get_name_email(name)
diff --git a/addons/mass_mailing/report/mailing_trace_report.py b/addons/mass_mailing/report/mailing_trace_report.py
index 71c39fd389d..02931d629d4 100644
--- a/addons/mass_mailing/report/mailing_trace_report.py
+++ b/addons/mass_mailing/report/mailing_trace_report.py
@@ -31,26 +31,55 @@ class MailingTraceReport(models.Model):
statistics collected for each mailing, and mailing.mailing model that models the
various mailing performed. """
tools.drop_view_if_exists(self.env.cr, 'mailing_trace_report')
- self.env.cr.execute("""
- CREATE OR REPLACE VIEW mailing_trace_report AS (
- SELECT
- min(trace.id) as id,
- utm_source.name as name,
- mailing.mailing_type,
- utm_campaign.name as campaign,
- trace.scheduled as scheduled_date,
- mailing.state,
- mailing.email_from,
- count(trace.sent) as sent,
- (count(trace.sent) - count(trace.bounced)) as delivered,
- count(trace.opened) as opened,
- count(trace.replied) as replied,
- count(trace.clicked) as clicked,
- count(trace.bounced) as bounced
- FROM
- mailing_trace as trace
- left join mailing_mailing as mailing ON (trace.mass_mailing_id=mailing.id)
- left join utm_campaign as utm_campaign ON (mailing.campaign_id = utm_campaign.id)
- left join utm_source as utm_source ON (mailing.source_id = utm_source.id)
- GROUP BY trace.scheduled, utm_source.name, utm_campaign.name, mailing.mailing_type, mailing.state, mailing.email_from
- )""")
+ self.env.cr.execute(self._report_get_request())
+
+ def _report_get_request(self):
+ sql_select = 'SELECT %s' % ', '.join(self._report_get_request_select_items())
+ sql_from = 'FROM %s' % ' '.join(self._report_get_request_from_items())
+ sql_where_items = self._report_get_request_where_items()
+ if sql_where_items and len(sql_where_items) == 1:
+ sql_where = 'WHERE %s' % sql_where_items[0]
+ elif sql_where_items:
+ sql_where = 'WHERE %s' % ' AND '.join(sql_where_items)
+ else:
+ sql_where = ''
+ sql_group_by = 'GROUP BY %s' % ', '.join(self._report_get_request_group_by_items())
+ return f"CREATE OR REPLACE VIEW mailing_trace_report AS ({sql_select} {sql_from} {sql_where} {sql_group_by} )"
+
+ def _report_get_request_select_items(self):
+ return [
+ 'min(trace.id) as id',
+ 'utm_source.name as name',
+ 'mailing.mailing_type',
+ 'utm_campaign.name as campaign',
+ 'trace.scheduled as scheduled_date',
+ 'mailing.state',
+ 'mailing.email_from',
+ 'count(trace.sent) as sent',
+ '(count(trace.sent) - count(trace.bounced)) as delivered',
+ 'count(trace.opened) as opened',
+ 'count(trace.replied) as replied',
+ 'count(trace.clicked) as clicked',
+ 'count(trace.bounced) as bounced'
+ ]
+
+ def _report_get_request_from_items(self):
+ return [
+ 'mailing_trace as trace',
+ 'left join mailing_mailing as mailing ON (trace.mass_mailing_id=mailing.id)',
+ 'left join utm_campaign as utm_campaign ON (mailing.campaign_id = utm_campaign.id)',
+ 'left join utm_source as utm_source ON (mailing.source_id = utm_source.id)'
+ ]
+
+ def _report_get_request_where_items(self):
+ return []
+
+ def _report_get_request_group_by_items(self):
+ return [
+ 'trace.scheduled',
+ 'utm_source.name',
+ 'utm_campaign.name',
+ 'mailing.mailing_type',
+ 'mailing.state',
+ 'mailing.email_from'
+ ]
diff --git a/addons/mass_mailing/tests/test_mailing_list.py b/addons/mass_mailing/tests/test_mailing_list.py
index dc029facc43..a9c6b5a2c2e 100644
--- a/addons/mass_mailing/tests/test_mailing_list.py
+++ b/addons/mass_mailing/tests/test_mailing_list.py
@@ -19,6 +19,40 @@ class TestMailingListMerge(MassMailCommon):
]
})
+
+ @users('user_marketing')
+ def test_mailing_contact_create(self):
+ default_list_ids = (self.mailing_list_2 | self.mailing_list_3).ids
+
+ # simply set default list in context
+ new = self.env['mailing.contact'].with_context(default_list_ids=default_list_ids).create([{
+ 'name': 'Contact_%d' % x,
+ 'email': 'contact_%d@test.example.com' % x,
+ } for x in range(0, 5)])
+ self.assertEqual(new.list_ids, (self.mailing_list_2 | self.mailing_list_3))
+
+ # default list and subscriptions should be merged
+ new = self.env['mailing.contact'].with_context(default_list_ids=default_list_ids).create([{
+ 'name': 'Contact_%d' % x,
+ 'email': 'contact_%d@test.example.com' % x,
+ 'subscription_list_ids': [(0, 0, {
+ 'list_id': self.mailing_list_1.id,
+ 'opt_out': True,
+ }), (0, 0, {
+ 'list_id': self.mailing_list_2.id,
+ 'opt_out': True,
+ })],
+ } for x in range(0, 5)])
+ self.assertEqual(new.list_ids, (self.mailing_list_1 | self.mailing_list_2 | self.mailing_list_3))
+ # should correctly take subscription opt_out value
+ for list_id in (self.mailing_list_1 | self.mailing_list_2).ids:
+ new = new.with_context(default_list_ids=[list_id])
+ self.assertTrue(all(contact.opt_out for contact in new))
+ # not opt_out for new subscription without specific create values
+ for list_id in self.mailing_list_3.ids:
+ new = new.with_context(default_list_ids=[list_id])
+ self.assertFalse(any(contact.opt_out for contact in new))
+
@users('user_marketing')
def test_mailing_list_merge(self):
# TEST CASE: Merge A,B into the existing mailing list C
diff --git a/addons/sale/models/utm.py b/addons/sale/models/utm.py
index 1eec837aa90..cc31dfdf84b 100644
--- a/addons/sale/models/utm.py
+++ b/addons/sale/models/utm.py
@@ -48,7 +48,11 @@ class UtmCampaign(models.Model):
def action_redirect_to_quotations(self):
action = self.env["ir.actions.actions"]._for_xml_id("sale.action_quotations_with_onboarding")
action['domain'] = [('campaign_id', '=', self.id)]
- action['context'] = {'default_campaign_id': self.id}
+ action['context'] = {
+ 'create': False,
+ 'edit': False,
+ 'default_campaign_id': self.id
+ }
return action
def action_redirect_to_invoiced(self):
diff --git a/addons/utm/i18n/utm.pot b/addons/utm/i18n/utm.pot
index f125c9d286b..c0392cbe3e8 100644
--- a/addons/utm/i18n/utm.pot
+++ b/addons/utm/i18n/utm.pot
@@ -222,6 +222,11 @@ msgid "Dropdown menu"
msgstr ""
#. module: utm
+#: model_terms:ir.ui.view,arch_db:utm.utm_campaign_view_kanban
+msgid "Edit"
+msgstr ""
+
+#. module: utm
#: model:utm.campaign,name:utm.utm_campaign_email_campaign_products
msgid "Email Campaign - Products"
msgstr ""
@@ -550,6 +555,13 @@ msgid ""
msgstr ""
#. module: utm
+#: model:ir.model.fields,help:utm.field_utm_tag__color
+msgid ""
+"Tag color. No color means no display in kanban to distinguish internal tags "
+"from public categorization tags."
+msgstr ""
+
+#. module: utm
#: model:ir.model.constraint,message:utm.constraint_utm_tag_name_uniq
msgid "Tag name already exists !"
msgstr ""
diff --git a/addons/utm/models/utm.py b/addons/utm/models/utm.py
index 3c197d1814e..0bf712c4be4 100644
--- a/addons/utm/models/utm.py
+++ b/addons/utm/models/utm.py
@@ -1,6 +1,8 @@
# -*- 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
@@ -64,9 +66,14 @@ class UtmTag(models.Model):
_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')
+ 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 !"),
+ ('name_uniq', 'unique (name)', "Tag name already exists !"),
]
diff --git a/addons/utm/views/utm_campaign_views.xml b/addons/utm/views/utm_campaign_views.xml
index f9103d21253..84c67499b1c 100644
--- a/addons/utm/views/utm_campaign_views.xml
+++ b/addons/utm/views/utm_campaign_views.xml
@@ -86,7 +86,7 @@
</a>
<div class="dropdown-menu" role="menu">
<t t-if="widget.editable">
- <a role="menuitem" type="edit" class="dropdown-item">Settings</a>
+ <a role="menuitem" type="edit" class="dropdown-item">Edit</a>
</t>
<t t-if="widget.deletable">
<a role="menuitem" type="delete" class="dropdown-item">Delete</a>