summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThibault Delavallée <tde@odoo.com>2020-05-28 10:38:32 +0000
committerThibault Delavallée <tde@odoo.com>2020-06-04 15:19:29 +0000
commit14abd4fdf714ce280ab07998073328eb4d76bc09 (patch)
treedc54db620e6ea76ed2ab22d420a308c082fb31cd
parentadd1a04a9451a684b5503d92a07f0ddf37f6921e (diff)
[IMP] digest: improve digest by adding daily sending and preferences
PURPOSE Make digest email and tips more appealing. The goals of these tips are * to encourage the adoption of other apps (Did you know ?); * to make Odoo look more fun (Fun tips and tricks, young and dynamic style); * to show social proof and increase trust (emphasis on already existing projects / customers to); SPECIFICATIONS Add a daily digest option, allowing to send digests on a daily basis. It will be the default settings to help users coming back to odoo. Add a slowdown heuristics. If not any user targeted by a daily digest logs himself within 3 days, digest is slowed down to a weekly setting to avoid spam. Add a preference section in template, to hold notably links to some configuration steps sent mainly for admin / CEOs. Improve access on models. LINKS Task ID 2197417 PR odoo/odoo#51619
-rw-r--r--addons/digest/controllers/portal.py25
-rw-r--r--addons/digest/data/digest_data.xml12
-rw-r--r--addons/digest/data/digest_template_data.xml12
-rw-r--r--addons/digest/data/digest_tips_data.xml5
-rw-r--r--addons/digest/models/digest.py57
-rw-r--r--addons/digest/security/ir.model.access.csv2
6 files changed, 99 insertions, 14 deletions
diff --git a/addons/digest/controllers/portal.py b/addons/digest/controllers/portal.py
index 0e7f8a5b4e5..451956a7bfa 100644
--- a/addons/digest/controllers/portal.py
+++ b/addons/digest/controllers/portal.py
@@ -1,15 +1,36 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
+from werkzeug.exceptions import Forbidden
+from werkzeug.urls import url_encode
+
+from odoo import _
from odoo.http import Controller, request, route
class DigestController(Controller):
@route('/digest/<int:digest_id>/unsubscribe', type='http', website=True, auth='user')
- def digest_unsubscribe(self, digest_id, **post):
- digest = request.env['digest.digest'].sudo().browse(digest_id)
+ def digest_unsubscribe(self, digest_id):
+ digest = request.env['digest.digest'].browse(digest_id).exists()
digest.action_unsubcribe()
return request.render('digest.portal_digest_unsubscribed', {
'digest': digest,
})
+
+ @route('/digest/<int:digest_id>/set_periodicity', type='http', website=True, auth='user')
+ def digest_set_periodicity(self, digest_id, periodicity='weekly'):
+ if not request.env.user.has_group('base.group_erp_manager'):
+ raise Forbidden()
+ if periodicity not in ('daily', 'weekly', 'monthly', 'quarterly'):
+ raise ValueError(_('Invalid periodicity set on digest'))
+
+ digest = request.env['digest.digest'].browse(digest_id).exists()
+ digest.action_set_periodicity(periodicity)
+
+ url_params = {
+ 'model': digest._name,
+ 'id': digest.id,
+ 'active_id': digest.id,
+ }
+ return request.redirect('/web?#%s' % url_encode(url_params))
diff --git a/addons/digest/data/digest_data.xml b/addons/digest/data/digest_data.xml
index 67bd019bc00..80678308c79 100644
--- a/addons/digest/data/digest_data.xml
+++ b/addons/digest/data/digest_data.xml
@@ -53,4 +53,16 @@
</body>
</html>
</template>
+
+ <!-- DIGEST PART: PREFERENCES -->
+ <template id="digest_section_preferences">
+<p t-if="object._context.get('digest_slowdown')" class="font-12" style="font-size: 15px; color: #6b6d70">
+ We've noticed you did not connect these last few days so we've automatically switched your preference to weekly Digests.
+</p>
+<p t-elif="user.has_group('base.group_erp_manager') and object.periodicity == 'daily'" class="font-12" style="font-size: 15px; color: #6b6d70">
+ Prefer a broader overview ?
+ <a t-att-href="'/digest/%s/set_periodicity?periodicity=weekly' % object.id" target="_blank" style="color:#875A7B; font-weight: bold;">Switch to weekly Digests.</a>
+</p>
+<p t-else=""/>
+ </template>
</data></odoo>
diff --git a/addons/digest/data/digest_template_data.xml b/addons/digest/data/digest_template_data.xml
index dc5109c4b56..448fa8b2033 100644
--- a/addons/digest/data/digest_template_data.xml
+++ b/addons/digest/data/digest_template_data.xml
@@ -12,6 +12,7 @@
% set data = object.compute_kpis(company, user)
% set tips = object.compute_tips(company, user, tips_count=ctx.get('tips_count', 1))
% set kpi_actions = object.compute_kpis_actions(company, user)
+ % set preferences = object.compute_preferences(company, user)
% set kpis = data.yesterday.keys()
<table cellspacing="0" cellpadding="0" align="center" border="0" bgcolor="#eeeeee" style="width:100%; font-family: Arial,Helvetica,Verdana,sans-serif;">
<tr class="mobile-hide" bgcolor="#875a7b"><td height="70"> </td></tr>
@@ -46,6 +47,7 @@
<table bgcolor="#ffffff" cellspacing="0" cellpadding="0" width="650" align="center" border="0" style="border: 1px solid #eeeeee; border-bottom: none;width: 100%; max-width: 650px; padding:30px 30px">
<tr>
<td>
+ % for tip in tips:
<table cellspacing="0" cellpadding="0" border="0" width="580" align="center" style="width:100%; max-width:580px;">
<tr>
<td valign="top">
@@ -53,6 +55,7 @@
</td>
</tr>
</table>
+ % endfor
</td>
</tr>
</table>
@@ -137,6 +140,15 @@
</tr>
</table>
% endfor
+ % if preferences:
+ <table bgcolor="#ffffff" cellspacing="0" cellpadding="0" width="650" align="center" border="0" style="border-left: 1px solid #eeeeee; border-right: 1px solid #eeeeee; width: 100%; max-width: 650px; padding:30px 30px">
+ <tr>
+ <td bgcolor="#fafafa" width="100%" height="50" align="center">
+ ${preferences | safe}
+ </td>
+ </tr>
+ </table>
+ % endif
% if user.has_group('base.group_system'):
<table bgcolor="#ffffff" cellspacing="0" cellpadding="0" width="650" align="center" border="0" style="border-left: 1px solid #eeeeee; border-right: 1px solid #eeeeee; width: 100%; max-width: 650px; padding:30px 30px">
<tr>
diff --git a/addons/digest/data/digest_tips_data.xml b/addons/digest/data/digest_tips_data.xml
index 375dd660681..ae7ed018ed8 100644
--- a/addons/digest/data/digest_tips_data.xml
+++ b/addons/digest/data/digest_tips_data.xml
@@ -2,9 +2,10 @@
<odoo>
<data noupdate="1">
<record id="digest_digest_default" model="digest.digest">
- <field name="name">Weekly Stats in Odoo</field>
+ <field name="name">Awesome Stats with Odoo</field>
+ <field name="periodicity">daily</field>
<field name="user_ids" eval="[(4, ref('base.user_admin'))]"/>
- <field name="next_run_date" eval="(DateTime.now() + timedelta(days=7)).strftime('%Y-%m-%d')"/>
+ <field name="next_run_date" eval="(DateTime.now() + timedelta(days=1)).strftime('%Y-%m-%d')"/>
<field name="kpi_res_users_connected">True</field>
<field name="kpi_mail_message_total">True</field>
</record>
diff --git a/addons/digest/models/digest.py b/addons/digest/models/digest.py
index 4b33ebc7937..3c39f49e244 100644
--- a/addons/digest/models/digest.py
+++ b/addons/digest/models/digest.py
@@ -2,7 +2,6 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
import logging
-import math
import pytz
from datetime import datetime, date
@@ -23,10 +22,11 @@ class Digest(models.Model):
# Digest description
name = fields.Char(string='Name', required=True, translate=True)
user_ids = fields.Many2many('res.users', string='Recipients', domain="[('share', '=', False)]")
- periodicity = fields.Selection([('weekly', 'Weekly'),
+ periodicity = fields.Selection([('daily', 'Daily'),
+ ('weekly', 'Weekly'),
('monthly', 'Monthly'),
('quarterly', 'Quarterly')],
- string='Periodicity', default='weekly', required=True)
+ string='Periodicity', default='daily', required=True)
next_run_date = fields.Date(string='Next Send Date')
template_id = fields.Many2one('mail.template', string='Email Template',
domain="[('model','=','digest.digest')]",
@@ -77,19 +77,21 @@ class Digest(models.Model):
@api.model
def create(self, vals):
- vals['next_run_date'] = date.today() + relativedelta(days=3)
- return super(Digest, self).create(vals)
+ digest = super(Digest, self).create(vals)
+ if not digest.next_run_date:
+ digest.next_run_date = digest._get_next_run_date()
+ return digest
# ------------------------------------------------------------
# ACTIONS
# ------------------------------------------------------------
def action_subscribe(self):
- if self.env.user not in self.user_ids:
+ if self.env.user.has_group('base.group_user') and self.env.user not in self.user_ids:
self.sudo().user_ids |= self.env.user
def action_unsubcribe(self):
- if self.env.user in self.user_ids:
+ if self.env.user.has_group('base.group_user') and self.env.user in self.user_ids:
self.sudo().user_ids -= self.env.user
def action_activate(self):
@@ -98,10 +100,16 @@ class Digest(models.Model):
def action_deactivate(self):
self.state = 'deactivated'
+ def action_set_periodicity(self, periodicity):
+ self.periodicity = periodicity
+
def action_send(self):
+ to_slowdown = self._check_daily_logs()
for digest in self:
for user in digest.user_ids:
- digest._action_send_to_user(user, tips_count=1)
+ digest.with_context(digest_slowdown=digest in to_slowdown)._action_send_to_user(user, tips_count=1)
+ if digest in to_slowdown:
+ digest.write({'periodicity': 'weekly'})
digest.next_run_date = digest._get_next_run_date()
def _action_send_to_user(self, user, tips_count=1):
@@ -167,7 +175,7 @@ class Digest(models.Model):
self.env['mail.render.mixin']._render_template(tools.html_sanitize(tip.tip_description), 'digest.tip', tip.ids, post_process=True)[tip.id]
for tip in tips
]
- # tip.user_ids += user
+ tip.user_ids += user
return tip_descriptions
def compute_kpis_actions(self, company, user):
@@ -178,8 +186,27 @@ class Digest(models.Model):
"""
return {}
+ def compute_preferences(self, company, user):
+ """ Give an optional text for preferences, like a shortcut for configuration.
+
+ :return string: html to put in template
+ """
+ preferences = self.env['mail.render.mixin']._render_template(
+ 'digest.digest_section_preferences',
+ 'digest.digest',
+ self.ids,
+ engine='qweb',
+ add_context={
+ 'company': company,
+ 'user': user,
+ },
+ post_process=True)[self.id]
+ return preferences
+
def _get_next_run_date(self):
self.ensure_one()
+ if self.periodicity == 'daily':
+ delta = relativedelta(days=1)
if self.periodicity == 'weekly':
delta = relativedelta(weeks=1)
elif self.periodicity == 'monthly':
@@ -216,6 +243,18 @@ class Digest(models.Model):
margin = float_round((float(value-previous_value) / previous_value or 1) * 100, precision_digits=2)
return margin
+ def _check_daily_logs(self):
+ three_days_ago = datetime.now().replace(hour=0, minute=0, second=0, microsecond=0) - relativedelta(days=3)
+ to_slowdown = self.env['digest.digest']
+ for digest in self.filtered(lambda digest: digest.periodicity == 'daily'):
+ users_logs = self.env['res.users.log'].sudo().search_count([
+ ('create_uid', 'in', digest.user_ids.ids),
+ ('create_date', '>=', three_days_ago)
+ ])
+ if not users_logs:
+ to_slowdown += digest
+ return to_slowdown
+
def _format_currency_amount(self, amount, currency_id):
pre = currency_id.position == 'before'
symbol = u'{symbol}'.format(symbol=currency_id.symbol or '')
diff --git a/addons/digest/security/ir.model.access.csv b/addons/digest/security/ir.model.access.csv
index 2891b43b673..49ef355262e 100644
--- a/addons/digest/security/ir.model.access.csv
+++ b/addons/digest/security/ir.model.access.csv
@@ -2,4 +2,4 @@ id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_digest_digest_system,digest.digest.administration,model_digest_digest,base.group_erp_manager,1,1,1,1
access_digest_digest_user,digest.digest.user,model_digest_digest,base.group_user,1,0,0,0
access_digest_tip_system,digest.tip.administration,model_digest_tip,base.group_erp_manager,1,1,1,1
-access_digest_tip_user,digest.tip.user,model_digest_tip,base.group_user,0,0,0,0
+access_digest_tip_user,digest.tip.user,model_digest_tip,base.group_user,1,0,0,0