diff options
| author | Thibault Delavallée <tde@odoo.com> | 2020-05-28 10:38:32 +0000 |
|---|---|---|
| committer | Thibault Delavallée <tde@odoo.com> | 2020-06-04 15:19:29 +0000 |
| commit | 14abd4fdf714ce280ab07998073328eb4d76bc09 (patch) | |
| tree | dc54db620e6ea76ed2ab22d420a308c082fb31cd | |
| parent | add1a04a9451a684b5503d92a07f0ddf37f6921e (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.py | 25 | ||||
| -rw-r--r-- | addons/digest/data/digest_data.xml | 12 | ||||
| -rw-r--r-- | addons/digest/data/digest_template_data.xml | 12 | ||||
| -rw-r--r-- | addons/digest/data/digest_tips_data.xml | 5 | ||||
| -rw-r--r-- | addons/digest/models/digest.py | 57 | ||||
| -rw-r--r-- | addons/digest/security/ir.model.access.csv | 2 |
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 |
