diff --git a/mail_digest/README.rst b/mail_digest/README.rst index 37b7b691..ccf5ff19 100644 --- a/mail_digest/README.rst +++ b/mail_digest/README.rst @@ -31,9 +31,11 @@ all the messages are collected inside a `mail.digest` container. A daily cron and a weekly cron will take care of creating a single email per each digest, which will be sent as a standard email. -If the message has a specific subtype, all of this will work only -if personal settings allow to receive notification for that specific subtype. -Specifically: +**Rules** + +Given that the user has `Notification management = Handle by Emails`... + +a message with subtype assigned *will be sent* via digest if: * no record for type: message passes * record disabled for type: message don't pass @@ -42,6 +44,11 @@ Specifically: NOTE: under the hood the digest notification logic excludes followers to be notified, since you really want to notify only mail.digest's partner. +a message with subtype assigned *will NOT be sent* via digest if: + + * global: `mail_digest_enabled_message_types` param disables the message type + * user: digest mode is OFF for the recipient + * user: recipient's user has disabled the subtype in her/his settings Global settings --------------- @@ -66,7 +73,7 @@ Bug Tracker Bugs are tracked on `GitHub Issues `_. In case of trouble, please check there if your issue has already been reported. If you spotted it first, -help us smashing it by providing a detailed and welcomed feedback. +help us smash it by providing a detailed and welcomed feedback. Credits ======= diff --git a/mail_digest/__manifest__.py b/mail_digest/__manifest__.py index 30ca2871..f2cb0bf9 100644 --- a/mail_digest/__manifest__.py +++ b/mail_digest/__manifest__.py @@ -1,13 +1,12 @@ -# -*- coding: utf-8 -*- -# Copyright 2017 Simone Orsi +# Copyright 2017-2018 Camptocamp - Simone Orsi # License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). { 'name': 'Mail digest', 'summary': """Basic digest mail handling.""", - 'version': '10.0.1.0.1', + 'version': '11.0.1.0.0', 'license': 'AGPL-3', - 'author': 'Camptocamp,Odoo Community Association (OCA)', + 'author': 'Camptocamp, Odoo Community Association (OCA)', 'website': 'https://github.com/OCA/social', 'depends': [ 'mail', @@ -18,7 +17,7 @@ 'security/ir.model.access.csv', 'security/record_rules.xml', 'views/mail_digest_views.xml', - 'views/partner_views.xml', + 'views/user_notification_views.xml', 'views/user_views.xml', 'templates/digest_default.xml', ], diff --git a/mail_digest/data/config_param.xml b/mail_digest/data/config_param.xml index 98dcc1c7..fd3c3fbb 100644 --- a/mail_digest/data/config_param.xml +++ b/mail_digest/data/config_param.xml @@ -1,9 +1,8 @@ - - - - mail_digest.enabled_message_types - - email,notification,comment - - + + + + mail_digest.enabled_message_types + + email,notification,comment + diff --git a/mail_digest/data/ir_cron.xml b/mail_digest/data/ir_cron.xml index 39c1087a..148eaa3d 100644 --- a/mail_digest/data/ir_cron.xml +++ b/mail_digest/data/ir_cron.xml @@ -1,27 +1,23 @@ - - - - Digest mail process - daily - - 1 - days - -1 - - - - - - - Digest mail process - weekly - - 1 - weeks - -1 - - - - - - + + + Digest mail process - daily + + + 1 + days + -1 + + model.process() + + + Digest mail process - weekly + + + 1 + weeks + -1 + + model.process(frequency='weekly') + diff --git a/mail_digest/demo/ir_ui_view.xml b/mail_digest/demo/ir_ui_view.xml deleted file mode 100644 index bf7bff5d..00000000 --- a/mail_digest/demo/ir_ui_view.xml +++ /dev/null @@ -1,39 +0,0 @@ - - - - - diff --git a/mail_digest/demo/mail_template.xml b/mail_digest/demo/mail_template.xml deleted file mode 100644 index d53b6aac..00000000 --- a/mail_digest/demo/mail_template.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - QWeb demo - qweb - - - QWeb demo email - - diff --git a/mail_digest/models/__init__.py b/mail_digest/models/__init__.py index 76368568..a14b1a65 100644 --- a/mail_digest/models/__init__.py +++ b/mail_digest/models/__init__.py @@ -1,3 +1,4 @@ from . import mail_digest +from . import user_notification_conf from . import res_partner from . import res_users diff --git a/mail_digest/models/mail_digest.py b/mail_digest/models/mail_digest.py index 9d8570ac..ac74ab25 100644 --- a/mail_digest/models/mail_digest.py +++ b/mail_digest/models/mail_digest.py @@ -1,5 +1,4 @@ -# -*- coding: utf-8 -*- -# Copyright 2017 Simone Orsi +# Copyright 2017-2018 Camptocamp - Simone Orsi # License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). from odoo import fields, models, api, exceptions, _ @@ -19,15 +18,15 @@ class MailDigest(models.Model): compute="_compute_name", readonly=True, ) - partner_id = fields.Many2one( - string='Partner', - comodel_name='res.partner', + user_id = fields.Many2one( + string='User', + comodel_name='res.users', readonly=True, required=True, ondelete='cascade', ) frequency = fields.Selection( - related='partner_id.notify_frequency', + related='user_id.digest_frequency', readonly=True, ) message_ids = fields.Many2many( @@ -52,7 +51,6 @@ class MailDigest(models.Model): ondelete='set null', default=lambda self: self._default_digest_template_id(), domain=[('type', '=', 'qweb')], - oldname='template_id', ) def _default_digest_template_id(self): @@ -61,53 +59,47 @@ class MailDigest(models.Model): raise_if_not_found=False) @api.multi - @api.depends("partner_id", "partner_id.notify_frequency") + @api.depends("user_id", "user_id.digest_frequency") def _compute_name(self): for rec in self: - rec.name = u'{} - {}'.format( - rec.partner_id.name, rec._get_subject()) + rec.name = '{} - {}'.format( + rec.user_id.name, rec._get_subject()) @api.model - def create_or_update(self, partners, message, subtype_id=None): + def create_or_update(self, partners, message): """Create or update digest. :param partners: recipients as `res.partner` browse list :param message: `mail.message` to include in digest - :param subtype_id: `mail.message.subtype` instance """ - subtype_id = subtype_id or message.subtype_id for partner in partners: - digest = self._get_or_create_by_partner(partner, message) + digest = self._get_or_create_by_user(partner.real_user_id) digest.message_ids |= message return True @api.model - def _get_by_partner(self, partner, mail_id=False): - """Retrieve digest record for given partner. + def _get_by_user(self, user): + """Retrieve digest record for given user. - :param partner: `res.partner` browse record - :param mail_id: `mail.mail` record for further filtering. + :param user: `res.users` browse record By default we lookup for pending digest without notification yet. """ domain = [ - ('partner_id', '=', partner.id), - ('mail_id', '=', mail_id), + ('user_id', '=', user.id), ] return self.search(domain, limit=1) @api.model - def _get_or_create_by_partner(self, partner, message=None, mail_id=False): - """Retrieve digest record or create it by partner. + def _get_or_create_by_user(self, user): + """Retrieve digest record or create it by user. - :param partner: `res.partner` record to create/get digest for - :param message: `mail.message` to include in digest - :param mail_id: `mail.mail` record to set on digest + :param user: `res.users` record to create/get digest for """ - existing = self._get_by_partner(partner, mail_id=mail_id) + existing = self._get_by_user(user) if existing: return existing - values = {'partner_id': partner.id, } + values = {'user_id': user.id, } return self.create(values) @api.model @@ -158,10 +150,10 @@ class MailDigest(models.Model): """Build the full subject for digest's mail.""" # TODO: shall we move this to computed field? self.ensure_one() - subject = u'[{}] '.format(self._get_site_name()) - if self.partner_id.notify_frequency == 'daily': + subject = '[{}] '.format(self._get_site_name()) + if self.user_id.digest_frequency == 'daily': subject += _('Daily update') - elif self.partner_id.notify_frequency == 'weekly': + elif self.user_id.digest_frequency == 'weekly': subject += _('Weekly update') return subject @@ -192,7 +184,7 @@ class MailDigest(models.Model): template_values = self._get_template_values() values = { 'email_from': self.env.user.company_id.email, - 'recipient_ids': [(4, self.partner_id.id)], + 'recipient_ids': [(4, self.user_id.partner_id.id)], 'subject': subject, 'body_html': template.with_context( **self._template_context() @@ -204,7 +196,7 @@ class MailDigest(models.Model): """Inject context vars. By default we make sure that digest's email - will have only digest's partner among recipients. + will have only digest's user among recipients. """ return { 'notify_only_recipients': True, @@ -214,11 +206,11 @@ class MailDigest(models.Model): def _template_context(self): """Rendering context for digest's template. - By default we enforce partner's language. + By default we enforce user's language. """ self.ensure_one() return { - 'lang': self.partner_id.lang, + 'lang': self.user_id.lang, } @api.multi @@ -252,12 +244,12 @@ class MailDigest(models.Model): def process(self, frequency='daily', domain=None): """Process existing digest records to create emails via cron. - :param frequency: lookup digest records by partners' `notify_frequency` + :param frequency: lookup digest records by users' `digest_frequency` :param domain: pass custom domain to lookup only specific digests """ if not domain: domain = [ ('mail_id', '=', False), - ('partner_id.notify_frequency', '=', frequency), + ('user_id.digest_frequency', '=', frequency), ] self.search(domain).create_email() diff --git a/mail_digest/models/res_partner.py b/mail_digest/models/res_partner.py index d39c5b57..7fa6bd9f 100644 --- a/mail_digest/models/res_partner.py +++ b/mail_digest/models/res_partner.py @@ -1,88 +1,19 @@ -# -*- coding: utf-8 -*- -# Copyright 2017 Simone Orsi +# Copyright 2017-2018 Camptocamp - Simone Orsi # License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). -from odoo import models, fields, api, _ +from odoo import models, api class ResPartner(models.Model): _inherit = 'res.partner' - notify_email = fields.Selection(selection_add=[('digest', _('Digest'))]) - notify_frequency = fields.Selection( - string='Frequency', - selection=[ - ('daily', 'Daily'), - ('weekly', 'Weekly') - ], - default='weekly', - required=True, - ) - notify_conf_ids = fields.One2many( - string='Notifications', - inverse_name='partner_id', - comodel_name='partner.notification.conf', - ) - enabled_notify_subtype_ids = fields.Many2many( - string='Partner enabled subtypes', - comodel_name='mail.message.subtype', - compute='_compute_enabled_notify_subtype_ids', - search='_search_enabled_notify_subtype_ids', - ) - disabled_notify_subtype_ids = fields.Many2many( - string='Partner disabled subtypes', - comodel_name='mail.message.subtype', - compute='_compute_disabled_notify_subtype_ids', - search='_search_disabled_notify_subtype_ids', - ) - - @api.multi - def _compute_notify_subtypes(self, enabled): - self.ensure_one() - query = ( - 'SELECT subtype_id FROM partner_notification_conf ' - 'WHERE partner_id=%s AND enabled = %s' - ) - self.env.cr.execute( - query, (self.id, enabled)) - return [x[0] for x in self.env.cr.fetchall()] - - @api.multi - @api.depends('notify_conf_ids.subtype_id') - def _compute_enabled_notify_subtype_ids(self): - for partner in self: - partner.enabled_notify_subtype_ids = \ - partner._compute_notify_subtypes(True) - - @api.multi - @api.depends('notify_conf_ids.subtype_id') - def _compute_disabled_notify_subtype_ids(self): - for partner in self: - partner.disabled_notify_subtype_ids = \ - partner._compute_notify_subtypes(False) - - def _search_notify_subtype_ids_domain(self, operator, value, enabled): - """Build domain to search notification subtypes by partner settings.""" - if operator in ('in', 'not in') and \ - not isinstance(value, (tuple, list)): - value = [value, ] - conf_value = value - if isinstance(conf_value, int): - # we search conf records always w/ 'in' - conf_value = [conf_value] - _value = self.env['partner.notification.conf'].search([ - ('subtype_id', 'in', conf_value), - ('enabled', '=', enabled), - ]).mapped('partner_id').ids - return [('id', operator, _value)] - - def _search_enabled_notify_subtype_ids(self, operator, value): - return self._search_notify_subtype_ids_domain( - operator, value, True) - - def _search_disabled_notify_subtype_ids(self, operator, value): - return self._search_notify_subtype_ids_domain( - operator, value, False) + # Shortcut to bypass this weird thing of odoo: + # `partner.user_id` is the "saleman" + # while the user is stored into `user_ids` + # but in the majority of the cases we have one real user per partner. + @property + def real_user_id(self): + return self.user_ids[0] if self.user_ids else False @api.multi def _notify(self, message, @@ -94,17 +25,14 @@ class ResPartner(models.Model): # the reason should be that anybody can write messages to a partner # and you really want to find all ppl to be notified partners = self.sudo().search(email_domain) - partners._notify_by_email( + super(ResPartner, partners)._notify( message, force_send=force_send, - send_after_commit=send_after_commit, user_signature=user_signature) + send_after_commit=send_after_commit, + user_signature=user_signature) # notify_by_digest - digest_domain = self._get_notify_by_email_domain( - message, digest=True) + digest_domain = self._get_notify_by_email_domain(message, digest=True) partners = self.sudo().search(digest_domain) partners._notify_by_digest(message) - - # notify_by_chat - self._notify_by_chat(message) return True def _digest_enabled_message_types(self): @@ -153,12 +81,10 @@ class ResPartner(models.Model): '|', ('id', 'in', ids), ('channel_ids', 'in', channels.ids), - ('email', '!=', email) + ('email', '!=', email), + ('user_ids.digest_mode', '=', digest), + ('user_ids.notification_type', '=', 'email'), ] - if not digest: - domain.append(('notify_email', 'not in', ('none', 'digest'))) - else: - domain.append(('notify_email', '=', 'digest')) if message.subtype_id: domain.extend(self._get_domain_subtype_leaf(message.subtype_id)) return domain @@ -167,65 +93,6 @@ class ResPartner(models.Model): def _get_domain_subtype_leaf(self, subtype): return [ '|', - ('disabled_notify_subtype_ids', 'not in', (subtype.id, )), - ('enabled_notify_subtype_ids', 'in', (subtype.id, )), + ('user_ids.disabled_notify_subtype_ids', 'not in', (subtype.id, )), + ('user_ids.enabled_notify_subtype_ids', 'in', (subtype.id, )), ] - - @api.multi - def _notify_update_subtype(self, subtype, enable): - """Update notification settings by subtype. - - :param subtype: `mail.message.subtype` to enable or disable - :param enable: boolean to enable or disable given subtype - """ - self.ensure_one() - exists = self.env['partner.notification.conf'].search([ - ('subtype_id', '=', subtype.id), - ('partner_id', '=', self.id) - ], limit=1) - if exists: - exists.enabled = enable - else: - self.write({ - 'notify_conf_ids': [ - (0, 0, {'enabled': enable, 'subtype_id': subtype.id})] - }) - - @api.multi - def _notify_enable_subtype(self, subtype): - """Enable given subtype.""" - self._notify_update_subtype(subtype, True) - - @api.multi - def _notify_disable_subtype(self, subtype): - """Disable given subtype.""" - self._notify_update_subtype(subtype, False) - - -class PartnerNotificationConf(models.Model): - """Hold partner's single notification configuration.""" - _name = 'partner.notification.conf' - _description = 'Partner notification configuration' - # TODO: add friendly onchange to not yield errors when editin via UI - _sql_constraints = [ - ('unique_partner_subtype_conf', - 'unique (partner_id,subtype_id)', - 'You can have only one configuration per subtype!') - ] - - partner_id = fields.Many2one( - string='Partner', - comodel_name='res.partner', - readonly=True, - required=True, - ondelete='cascade', - index=True, - ) - subtype_id = fields.Many2one( - 'mail.message.subtype', - 'Notification type', - ondelete='cascade', - required=True, - index=True, - ) - enabled = fields.Boolean(default=True, index=True) diff --git a/mail_digest/models/res_users.py b/mail_digest/models/res_users.py index ec7ad05c..9dd6e89e 100644 --- a/mail_digest/models/res_users.py +++ b/mail_digest/models/res_users.py @@ -1,8 +1,7 @@ -# -*- coding: utf-8 -*- -# Copyright 2017 Simone Orsi +# Copyright 2017-2018 Camptocamp - Simone Orsi # License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). -from odoo import models +from odoo import models, fields, api class Users(models.Model): @@ -18,11 +17,111 @@ class Users(models.Model): [copied from mail.models.users] """ super(Users, self).__init__(pool, cr) + new_fields = [ + 'digest_mode', + 'digest_frequency', + 'notify_conf_ids', + ] # duplicate list to avoid modifying the original reference type(self).SELF_WRITEABLE_FIELDS = list(self.SELF_WRITEABLE_FIELDS) - type(self).SELF_WRITEABLE_FIELDS.extend(['notify_frequency']) - type(self).SELF_WRITEABLE_FIELDS.extend(['notify_conf_ids']) + type(self).SELF_WRITEABLE_FIELDS.extend(new_fields) # duplicate list to avoid modifying the original reference type(self).SELF_READABLE_FIELDS = list(self.SELF_READABLE_FIELDS) - type(self).SELF_READABLE_FIELDS.extend(['notify_frequency']) - type(self).SELF_READABLE_FIELDS.extend(['notify_conf_ids']) + type(self).SELF_READABLE_FIELDS.extend(new_fields) + + digest_mode = fields.Boolean( + default=False, + help='If enabled, email notifications will be sent in digest mode.' + ) + digest_frequency = fields.Selection( + string='Frequency', + selection=[ + ('daily', 'Daily'), + ('weekly', 'Weekly') + ], + default='weekly', + required=True, + ) + notify_conf_ids = fields.One2many( + string='Notifications', + inverse_name='user_id', + comodel_name='user.notification.conf', + ) + enabled_notify_subtype_ids = fields.Many2many( + string='User enabled subtypes', + comodel_name='mail.message.subtype', + compute='_compute_notify_subtype_ids', + search='_search_enabled_notify_subtype_ids', + ) + disabled_notify_subtype_ids = fields.Many2many( + string='User disabled subtypes', + comodel_name='mail.message.subtype', + compute='_compute_notify_subtype_ids', + search='_search_disabled_notify_subtype_ids', + ) + + def _notify_subtypes_by_state(self, enabled): + self.ensure_one() + return self.notify_conf_ids.filtered( + lambda x: x.enabled == enabled).mapped('subtype_id') + + @api.multi + @api.depends('notify_conf_ids.subtype_id', 'notify_conf_ids.enabled') + def _compute_notify_subtype_ids(self): + for rec in self: + rec.enabled_notify_subtype_ids = \ + rec._notify_subtypes_by_state(True) + rec.disabled_notify_subtype_ids = \ + rec._notify_subtypes_by_state(False) + + def _search_notify_subtype_ids_domain(self, operator, value, enabled): + """Build domain to search notification subtypes by user conf.""" + if operator in ('in', 'not in') and \ + not isinstance(value, (tuple, list)): + value = [value, ] + conf_value = value + if isinstance(conf_value, int): + # we search conf records always w/ 'in' + conf_value = [conf_value] + _value = self.env['user.notification.conf'].search([ + ('subtype_id', 'in', conf_value), + ('enabled', '=', enabled), + ]).mapped('user_id').ids + return [('id', operator, _value)] + + def _search_enabled_notify_subtype_ids(self, operator, value): + return self._search_notify_subtype_ids_domain(operator, value, True) + + def _search_disabled_notify_subtype_ids(self, operator, value): + return self._search_notify_subtype_ids_domain(operator, value, False) + + def _notify_update_subtype(self, subtype, enable): + """Update notification settings by subtype. + + :param subtype: `mail.message.subtype` to enable or disable + :param enable: boolean to enable or disable given subtype + """ + self.ensure_one() + exists = self.env['user.notification.conf'].search([ + ('subtype_id', '=', subtype.id), + ('user_id', '=', self.id) + ], limit=1) + if exists: + exists.enabled = enable + else: + self.write({ + 'notify_conf_ids': [ + (0, 0, {'enabled': enable, 'subtype_id': subtype.id})] + }) + + @api.multi + def _notify_enable_subtype(self, subtype): + """Enable given subtype.""" + for rec in self: + rec._notify_update_subtype(subtype, True) + + @api.multi + def _notify_disable_subtype(self, subtype): + """Disable given subtype.""" + for rec in self: + rec._notify_update_subtype(subtype, False) diff --git a/mail_digest/models/user_notification_conf.py b/mail_digest/models/user_notification_conf.py new file mode 100644 index 00000000..895fec2b --- /dev/null +++ b/mail_digest/models/user_notification_conf.py @@ -0,0 +1,33 @@ +# Copyright 2017-2018 Camptocamp - Simone Orsi +# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). + +from odoo import models, fields + + +class UserNotificationConf(models.Model): + """Hold user's single notification configuration.""" + _name = 'user.notification.conf' + _description = 'User notification configuration' + # TODO: add friendly onchange to not yield errors when editin via UI + _sql_constraints = [ + ('unique_user_subtype_conf', + 'unique (user_id,subtype_id)', + 'You can have only one configuration per subtype!') + ] + + user_id = fields.Many2one( + string='User', + comodel_name='res.users', + readonly=True, + required=True, + ondelete='cascade', + index=True, + ) + subtype_id = fields.Many2one( + 'mail.message.subtype', + 'Notification type', + ondelete='cascade', + required=True, + index=True, + ) + enabled = fields.Boolean(default=True, index=True) diff --git a/mail_digest/security/ir.model.access.csv b/mail_digest/security/ir.model.access.csv index 1814f390..f422b665 100644 --- a/mail_digest/security/ir.model.access.csv +++ b/mail_digest/security/ir.model.access.csv @@ -1,4 +1,4 @@ id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink -access_partner_notification_conf_user,partner.notification.user,model_partner_notification_conf,base.group_user,1,1,1,1 +access_partner_notification_conf_user,partner.notification.user,model_user_notification_conf,base.group_user,1,1,1,1 access_mail_digest_system,mail.digest.sys,model_mail_digest,base.group_system,1,1,1,1 -access_partner_notification_conf_system,partner.notification.sys,model_partner_notification_conf,base.group_system,1,1,1,1 +access_partner_notification_conf_system,partner.notification.sys,model_user_notification_conf,base.group_system,1,1,1,1 diff --git a/mail_digest/security/record_rules.xml b/mail_digest/security/record_rules.xml index b1594eef..a97334df 100644 --- a/mail_digest/security/record_rules.xml +++ b/mail_digest/security/record_rules.xml @@ -1,14 +1,14 @@ - - Partners can edit their own notification settings - + + Users can edit their own notification settings + - ['|',('partner_id', '=', user.partner_id.id), ('create_uid', '=', user.id)] + ['|',('user_id', '=', user.id), ('create_uid', '=', user.id)] diff --git a/mail_digest/templates/digest_default.xml b/mail_digest/templates/digest_default.xml index 6c98e4b8..29391f3e 100644 --- a/mail_digest/templates/digest_default.xml +++ b/mail_digest/templates/digest_default.xml @@ -26,7 +26,7 @@

Hello,

- +
diff --git a/mail_digest/tests/test_digest.py b/mail_digest/tests/test_digest.py index 879d39a0..b9b996fb 100644 --- a/mail_digest/tests/test_digest.py +++ b/mail_digest/tests/test_digest.py @@ -1,59 +1,58 @@ -# -*- coding: utf-8 -*- -# Copyright 2017 Simone Orsi +# Copyright 2017-2018 Camptocamp - Simone Orsi # License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). -from odoo.tests.common import TransactionCase +from odoo.tests.common import SavepointCase from odoo import exceptions -class DigestCase(TransactionCase): - - def setUp(self): - super(DigestCase, self).setUp() - self.partner_model = self.env['res.partner'] - self.message_model = self.env['mail.message'] - self.subtype_model = self.env['mail.message.subtype'] - self.digest_model = self.env['mail.digest'] - self.conf_model = self.env['partner.notification.conf'] - - self.partner1 = self.partner_model.with_context( - tracking_disable=1).create({ - 'name': 'Partner 1', - 'email': 'partner1@test.foo.com', - }) - self.partner2 = self.partner_model.with_context( - tracking_disable=1).create({ - 'name': 'Partner 2', - 'email': 'partner2@test.foo.com', - }) - self.partner3 = self.partner_model.with_context( - tracking_disable=1).create({ - 'name': 'Partner 3', - 'email': 'partner3@test.foo.com', - }) - self.subtype1 = self.subtype_model.create({'name': 'Type 1'}) - self.subtype2 = self.subtype_model.create({'name': 'Type 2'}) +class DigestCase(SavepointCase): + + @classmethod + def setUpClass(cls): + super(DigestCase, cls).setUpClass() + cls.message_model = cls.env['mail.message'] + cls.subtype_model = cls.env['mail.message.subtype'] + cls.digest_model = cls.env['mail.digest'] + cls.conf_model = cls.env['user.notification.conf'] + + user_model = cls.env['res.users'].with_context( + no_reset_password=True, tracking_disable=True) + cls.user1 = user_model.create({ + 'name': 'User 1', + 'login': 'testuser1', + 'email': 'testuser1@email.com', + }) + cls.user2 = user_model.create({ + 'name': 'User 2', + 'login': 'testuser2', + 'email': 'testuser2@email.com', + }) + cls.user3 = user_model.create({ + 'name': 'User 3', + 'login': 'testuser3', + 'email': 'testuser3@email.com', + }) + cls.subtype1 = cls.subtype_model.create({'name': 'Type 1'}) + cls.subtype2 = cls.subtype_model.create({'name': 'Type 2'}) def test_get_or_create_digest(self): - message1 = self.message_model.create({ + self.message_model.create({ 'body': 'My Body 1', 'subtype_id': self.subtype1.id, }) - message2 = self.message_model.create({ + self.message_model.create({ 'body': 'My Body 2', 'subtype_id': self.subtype2.id, }) # 2 messages, 1 digest container - dig1 = self.digest_model._get_or_create_by_partner( - self.partner1, message1) - dig2 = self.digest_model._get_or_create_by_partner( - self.partner1, message2) + dig1 = self.digest_model._get_or_create_by_user(self.user1) + dig2 = self.digest_model._get_or_create_by_user(self.user1) self.assertEqual(dig1, dig2) def test_create_or_update_digest(self): - partners = self.partner_model - partners |= self.partner1 - partners |= self.partner2 + partners = self.env['res.partner'] + partners |= self.user1.partner_id + partners |= self.user2.partner_id message1 = self.message_model.create({ 'body': 'My Body 1', 'subtype_id': self.subtype1.id, @@ -63,72 +62,75 @@ class DigestCase(TransactionCase): 'subtype_id': self.subtype2.id, }) # partner 1 - self.digest_model.create_or_update(self.partner1, message1) - self.digest_model.create_or_update(self.partner1, message2) - p1dig = self.digest_model._get_or_create_by_partner(self.partner1) + self.digest_model.create_or_update(self.user1.partner_id, message1) + self.digest_model.create_or_update(self.user1.partner_id, message2) + p1dig = self.digest_model._get_or_create_by_user(self.user1) self.assertIn(message1, p1dig.message_ids) self.assertIn(message2, p1dig.message_ids) # partner 2 - self.digest_model.create_or_update(self.partner2, message1) - self.digest_model.create_or_update(self.partner2, message2) - p2dig = self.digest_model._get_or_create_by_partner(self.partner2) + self.digest_model.create_or_update(self.user2.partner_id, message1) + self.digest_model.create_or_update(self.user2.partner_id, message2) + p2dig = self.digest_model._get_or_create_by_user(self.user2) self.assertIn(message1, p2dig.message_ids) self.assertIn(message2, p2dig.message_ids) - def test_notify_partner_digest(self): + def test_notify_user_digest(self): message = self.message_model.create({ 'body': 'My Body 1', 'subtype_id': self.subtype1.id, }) - self.partner1.notify_email = 'digest' + self.user1.digest_mode = True # notify partner - self.partner1._notify(message) + self.user1.partner_id._notify(message) # we should find the message in its digest - dig1 = self.digest_model._get_or_create_by_partner( - self.partner1, message) + dig1 = self.digest_model._get_or_create_by_user(self.user1) self.assertIn(message, dig1.message_ids) def test_notify_partner_digest_followers(self): - self.partner3.message_subscribe(self.partner2.ids) - self.partner1.notify_email = 'digest' - self.partner2.notify_email = 'digest' - partners = self.partner1 + self.partner2 + # subscribe a partner to the other one + self.user3.partner_id.message_subscribe( + partner_ids=self.user2.partner_id.ids) + self.user1.digest_mode = True + self.user2.digest_mode = True + partners = self.user1.partner_id + self.user2.partner_id message = self.message_model.create({ 'body': 'My Body 1', 'subtype_id': self.subtype1.id, - 'res_id': self.partner3.id, + 'res_id': self.user3.partner_id.id, 'model': 'res.partner', - 'partner_ids': [(4, self.partner1.id)] + 'partner_ids': [(4, self.user1.partner_id.id)] }) # notify partners - partners._notify(message) + partners.with_context(foo=1)._notify(message) # we should find the a digest for each partner - dig1 = self.digest_model._get_by_partner(self.partner1) - dig2 = self.digest_model._get_by_partner(self.partner2) + dig1 = self.digest_model._get_by_user(self.user1) + dig2 = self.digest_model._get_by_user(self.user2) # and the message in them self.assertIn(message, dig1.message_ids) self.assertIn(message, dig2.message_ids) # now we exclude followers dig1.unlink() dig2.unlink() - partners.with_context(notify_only_recipients=1)._notify(message) + partners.with_context(notify_only_recipients=True)._notify(message) # we should find the a digest for each partner - self.assertTrue(self.digest_model._get_by_partner(self.partner1)) - self.assertFalse(self.digest_model._get_by_partner(self.partner2)) + self.assertTrue(self.digest_model._get_by_user(self.user1)) + self.assertFalse(self.digest_model._get_by_user(self.user2)) def test_global_conf(self): for k in ('email', 'comment', 'notification'): - self.assertIn(k, self.partner1._digest_enabled_message_types()) + self.assertIn( + k, self.env['res.partner']._digest_enabled_message_types()) self.env['ir.config_parameter'].set_param( 'mail_digest.enabled_message_types', 'email,notification' ) for k in ('email', 'notification'): - self.assertIn(k, self.partner1._digest_enabled_message_types()) + self.assertIn( + k, self.env['res.partner']._digest_enabled_message_types()) self.assertNotIn( - 'comment', self.partner1._digest_enabled_message_types()) + 'comment', self.env['res.partner']._digest_enabled_message_types()) - def test_notify_partner_digest_global_disabled(self): + def test_notify_user_digest_global_disabled(self): # change global conf self.env['ir.config_parameter'].set_param( 'mail_digest.enabled_message_types', @@ -140,46 +142,46 @@ class DigestCase(TransactionCase): # globally disabled type 'message_type': 'notification', }) - self.partner1.notify_email = 'digest' + self.user1.digest_mode = True # notify partner - self.partner1._notify(message) + self.user1.partner_id._notify(message) # we should not find any digest - self.assertFalse(self.digest_model._get_by_partner(self.partner1)) + self.assertFalse(self.digest_model._get_by_user(self.user1)) def _create_for_partner(self, partner): messages = {} for type_id in (self.subtype1.id, self.subtype2.id): - for k in xrange(1, 3): + for k in range(1, 3): key = '{}_{}'.format(type_id, k) messages[key] = self.message_model.create({ 'subject': 'My Subject {}'.format(key), 'body': 'My Body {}'.format(key), 'subtype_id': type_id, }) - self.digest_model.create_or_update( - partner, messages[key]) - return self.digest_model._get_or_create_by_partner(partner) + self.digest_model.create_or_update(partner, messages[key]) + return self.digest_model._get_by_user(partner.real_user_id) def test_digest_group_messages(self): - dig = self._create_for_partner(self.partner1) + dig = self._create_for_partner(self.user1.partner_id) grouped = dig._message_group_by() for type_id in (self.subtype1.id, self.subtype2.id): self.assertIn(type_id, grouped) self.assertEqual(len(grouped[type_id]), 2) def test_digest_mail_values(self): - dig = self._create_for_partner(self.partner1) + dig = self._create_for_partner(self.user1.partner_id) values = dig._get_email_values() expected = ('recipient_ids', 'subject', 'body_html') for k in expected: self.assertIn(k, values) self.assertEqual(self.env.user.company_id.email, values['email_from']) - self.assertEqual([(4, self.partner1.id)], values['recipient_ids']) + self.assertEqual( + [(4, self.user1.partner_id.id)], values['recipient_ids']) def test_digest_template(self): default = self.env.ref('mail_digest.default_digest_tmpl') - dig = self._create_for_partner(self.partner1) + dig = self._create_for_partner(self.user1.partner_id) # check default self.assertEqual(dig.digest_template_id, default) self.assertTrue(dig._get_email_values()) diff --git a/mail_digest/tests/test_partner_domains.py b/mail_digest/tests/test_partner_domains.py index 16e10751..bdbe9c0e 100644 --- a/mail_digest/tests/test_partner_domains.py +++ b/mail_digest/tests/test_partner_domains.py @@ -1,38 +1,44 @@ -# -*- coding: utf-8 -*- -# Copyright 2017 Simone Orsi +# Copyright 2017-2018 Camptocamp - Simone Orsi # License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). -from odoo.tests.common import TransactionCase - - -class PartnerDomainCase(TransactionCase): - - def setUp(self): - super(PartnerDomainCase, self).setUp() - self.partner_model = self.env['res.partner'] - self.message_model = self.env['mail.message'] - self.subtype_model = self.env['mail.message.subtype'] - - self.partner1 = self.partner_model.with_context( - tracking_disable=1).create({ - 'name': 'Partner 1', - 'email': 'partner1@test.foo.com', - }) - self.partner2 = self.partner_model.with_context( - tracking_disable=1).create({ - 'name': 'Partner 2', - 'email': 'partner2@test.foo.com', - }) - self.partner3 = self.partner_model.with_context( - tracking_disable=1).create({ - 'name': 'Partner 3', - 'email': 'partner3@test.foo.com', - }) - self.subtype1 = self.subtype_model.create({'name': 'Type 1'}) - self.subtype2 = self.subtype_model.create({'name': 'Type 2'}) - - def _assert_found(self, domain, not_found=False, partner=None): - partner = partner or self.partner1 +from odoo.tests.common import SavepointCase + + +class PartnerDomainCase(SavepointCase): + + @classmethod + def setUpClass(cls): + super(PartnerDomainCase, cls).setUpClass() + + cls.partner_model = cls.env['res.partner'] + cls.message_model = cls.env['mail.message'] + cls.subtype_model = cls.env['mail.message.subtype'] + + user_model = cls.env['res.users'].with_context( + no_reset_password=True, tracking_disable=True) + cls.user1 = user_model.create({ + 'name': 'User 1', + 'login': 'testuser1', + 'email': 'testuser1@email.com', + }) + cls.user2 = user_model.create({ + 'name': 'User 2', + 'login': 'testuser2', + 'email': 'testuser2@email.com', + }) + cls.user3 = user_model.create({ + 'name': 'User 3', + 'login': 'testuser3', + 'email': 'testuser3@email.com', + }) + cls.partner1 = cls.user1.partner_id + cls.partner2 = cls.user2.partner_id + cls.partner3 = cls.user3.partner_id + + cls.subtype1 = cls.subtype_model.create({'name': 'Type 1'}) + cls.subtype2 = cls.subtype_model.create({'name': 'Type 2'}) + + def _assert_found(self, partner, domain, not_found=False): if not_found: self.assertNotIn(partner, self.partner_model.search(domain)) else: @@ -43,17 +49,17 @@ class PartnerDomainCase(TransactionCase): # because we call `_get_notify_by_email_domain` directly message = self.message_model.create({'body': 'My Body', }) partner = self.partner1 - partner.notify_email = 'always' + partner.real_user_id.notification_type = 'email' domain = partner._get_notify_by_email_domain(message) - self._assert_found(domain) - domain = partner._get_notify_by_email_domain(message, digest=1) - self._assert_found(domain, not_found=1) + self._assert_found(partner, domain) + domain = partner._get_notify_by_email_domain(message, digest=True) + self._assert_found(partner, domain, not_found=True) def test_notify_domains_only_recipients(self): # we don't set recipients # because we call `_get_notify_by_email_domain` directly - self.partner1.notify_email = 'always' - self.partner2.notify_email = 'always' + self.partner1.real_user_id.notification_type = 'email' + self.partner2.real_user_id.notification_type = 'email' partners = self.partner1 + self.partner2 # followers self.partner3.message_subscribe(self.partner2.ids) @@ -66,42 +72,47 @@ class PartnerDomainCase(TransactionCase): }) domain = partners._get_notify_by_email_domain(message) # we find both of them since partner2 is a follower - self._assert_found(domain) - self._assert_found(domain, partner=self.partner2) + self._assert_found(self.partner1, domain) + self._assert_found(self.partner2, domain) # no one here in digest mode - domain = partners._get_notify_by_email_domain(message, digest=1) - self._assert_found(domain, not_found=1) - self._assert_found(domain, not_found=1, partner=self.partner2) + domain = partners._get_notify_by_email_domain(message, digest=True) + self._assert_found(self.partner1, domain, not_found=True) + self._assert_found(self.partner2, domain, not_found=True) # include only recipients domain = partners.with_context( notify_only_recipients=1)._get_notify_by_email_domain(message) - self._assert_found(domain) - self._assert_found(domain, partner=self.partner2, not_found=1) + self._assert_found(self.partner1, domain) + self._assert_found(self.partner2, domain, not_found=True) def test_notify_domains_digest(self): # we don't set recipients # because we call `_get_notify_by_email_domain` directly message = self.message_model.create({'body': 'My Body', }) partner = self.partner1 - partner.notify_email = 'digest' + partner.real_user_id.write({ + 'notification_type': 'email', + 'digest_mode': True, + }) domain = partner._get_notify_by_email_domain(message) - self._assert_found(domain, not_found=1) - domain = partner._get_notify_by_email_domain(message, digest=1) - self._assert_found(domain) + self._assert_found(partner, domain, not_found=True) + domain = partner._get_notify_by_email_domain(message, digest=True) + self._assert_found(partner, domain) def test_notify_domains_none(self): message = self.message_model.create({'body': 'My Body', }) partner = self.partner1 - partner.notify_email = 'none' + partner.real_user_id.write({ + 'notification_type': 'inbox', + }) domain = partner._get_notify_by_email_domain(message) - self._assert_found(domain, not_found=1) - domain = partner._get_notify_by_email_domain(message, digest=1) - self._assert_found(domain, not_found=1) + self._assert_found(partner, domain, not_found=True) + domain = partner._get_notify_by_email_domain(message, digest=True) + self._assert_found(partner, domain, not_found=True) def test_notify_domains_match_type_digest(self): # Test message subtype matches partner settings. - # The partner can have several `partner.notification.conf` records. + # The partner can have several `user.notification.conf` records. # Each records establish notification rules by type. # If you don't have any record in it, you allow all subtypes. # Record `typeX` with `enable=True` enables notification for `typeX`. @@ -109,7 +120,10 @@ class PartnerDomainCase(TransactionCase): partner = self.partner1 # enable digest - partner.notify_email = 'digest' + partner.real_user_id.write({ + 'notification_type': 'email', + 'digest_mode': True, + }) message_t1 = self.message_model.create({ 'body': 'My Body', 'subtype_id': self.subtype1.id, @@ -119,25 +133,25 @@ class PartnerDomainCase(TransactionCase): 'subtype_id': self.subtype2.id, }) # enable subtype on partner - partner._notify_enable_subtype(self.subtype1) + partner.real_user_id._notify_enable_subtype(self.subtype1) domain = partner._get_notify_by_email_domain( message_t1, digest=True) # notification enabled: we find the partner. - self._assert_found(domain) + self._assert_found(partner, domain) # for subtype2 we don't have any explicit rule: we find the partner domain = partner._get_notify_by_email_domain( message_t2, digest=True) - self._assert_found(domain) + self._assert_found(partner, domain) # enable subtype2: find the partner anyway - partner._notify_enable_subtype(self.subtype2) + partner.real_user_id._notify_enable_subtype(self.subtype2) domain = partner._get_notify_by_email_domain( message_t2, digest=True) - self._assert_found(domain) + self._assert_found(partner, domain) # disable subtype2: we don't find the partner anymore - partner._notify_disable_subtype(self.subtype2) + partner.real_user_id._notify_disable_subtype(self.subtype2) domain = partner._get_notify_by_email_domain( message_t2, digest=True) - self._assert_found(domain, not_found=1) + self._assert_found(partner, domain, not_found=True) def test_notify_domains_match_type_always(self): message_t1 = self.message_model.create({ @@ -150,20 +164,20 @@ class PartnerDomainCase(TransactionCase): }) # enable always partner = self.partner1 - partner.notify_email = 'always' + partner.real_user_id.notification_type = 'email' # enable subtype on partner - partner._notify_enable_subtype(self.subtype1) + partner.real_user_id._notify_enable_subtype(self.subtype1) domain = partner._get_notify_by_email_domain(message_t1) # notification enabled: we find the partner. - self._assert_found(domain) + self._assert_found(partner, domain) # for subtype2 we don't have any explicit rule: we find the partner domain = partner._get_notify_by_email_domain(message_t2) - self._assert_found(domain) + self._assert_found(partner, domain) # enable subtype2: find the partner anyway - partner._notify_enable_subtype(self.subtype2) + partner.real_user_id._notify_enable_subtype(self.subtype2) domain = partner._get_notify_by_email_domain(message_t2) - self._assert_found(domain) + self._assert_found(partner, domain) # disable subtype2: we don't find the partner anymore - partner._notify_disable_subtype(self.subtype2) + partner.real_user_id._notify_disable_subtype(self.subtype2) domain = partner._get_notify_by_email_domain(message_t2) - self._assert_found(domain, not_found=1) + self._assert_found(partner, domain, not_found=True) diff --git a/mail_digest/tests/test_subtypes_conf.py b/mail_digest/tests/test_subtypes_conf.py index 810b1bd8..e80bd7d0 100644 --- a/mail_digest/tests/test_subtypes_conf.py +++ b/mail_digest/tests/test_subtypes_conf.py @@ -1,136 +1,109 @@ -# -*- coding: utf-8 -*- -# Copyright 2017 Simone Orsi +# Copyright 2017-2018 Camptocamp - Simone Orsi # License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). -from odoo.tests.common import TransactionCase +from odoo.tests.common import SavepointCase -class SubtypesCase(TransactionCase): +class SubtypesCase(SavepointCase): - def setUp(self): - super(SubtypesCase, self).setUp() - self.partner_model = self.env['res.partner'] - self.message_model = self.env['mail.message'] - self.subtype_model = self.env['mail.message.subtype'] + @classmethod + def setUpClass(cls): + super(SubtypesCase, cls).setUpClass() - self.partner1 = self.partner_model.with_context( - tracking_disable=1).create({ - 'name': 'Partner 1!', - 'email': 'partner1@test.foo.com', - }) - self.partner2 = self.partner_model.with_context( - tracking_disable=1).create({ - 'name': 'Partner 2!', - 'email': 'partner2@test.foo.com', - }) - self.subtype1 = self.subtype_model.create({'name': 'Type 1'}) - self.subtype2 = self.subtype_model.create({'name': 'Type 2'}) + user_model = cls.env['res.users'].with_context( + no_reset_password=True, tracking_disable=True) + cls.user1 = user_model.create({ + 'name': 'User 1', + 'login': 'testuser1', + 'email': 'testuser1@email.com', + }) + cls.user2 = user_model.create({ + 'name': 'User 2', + 'login': 'testuser2', + 'email': 'testuser2@email.com', + }) + subtype_model = cls.env['mail.message.subtype'] + cls.subtype1 = subtype_model.create({'name': 'Type 1'}) + cls.subtype2 = subtype_model.create({'name': 'Type 2'}) + cls.subtype3 = subtype_model.create({'name': 'Type 3'}) + cls.subtype4 = subtype_model.create({'name': 'Type 4'}) def _test_subtypes_rel(self): # setup: # t1, t2 enabled # t3 disabled # t4 no conf - self.subtype3 = self.subtype_model.create({'name': 'Type 3'}) - self.subtype4 = self.subtype_model.create({'name': 'Type 4'}) # enable t1 t2 - self.partner1._notify_enable_subtype(self.subtype1) - self.partner1._notify_enable_subtype(self.subtype2) + self.user1._notify_enable_subtype(self.subtype1) + self.user1._notify_enable_subtype(self.subtype2) # disable t3 - self.partner1._notify_disable_subtype(self.subtype3) + self.user1._notify_disable_subtype(self.subtype3) - def test_partner_computed_subtype(self): + def test_user_computed_subtype(self): self._test_subtypes_rel() # check computed fields self.assertIn( - self.subtype1, self.partner1.enabled_notify_subtype_ids) + self.subtype1, self.user1.enabled_notify_subtype_ids) self.assertNotIn( - self.subtype1, self.partner1.disabled_notify_subtype_ids) + self.subtype1, self.user1.disabled_notify_subtype_ids) self.assertIn( - self.subtype2, self.partner1.enabled_notify_subtype_ids) + self.subtype2, self.user1.enabled_notify_subtype_ids) self.assertNotIn( - self.subtype2, self.partner1.disabled_notify_subtype_ids) + self.subtype2, self.user1.disabled_notify_subtype_ids) self.assertIn( - self.subtype3, self.partner1.disabled_notify_subtype_ids) + self.subtype3, self.user1.disabled_notify_subtype_ids) self.assertNotIn( - self.subtype3, self.partner1.enabled_notify_subtype_ids) + self.subtype3, self.user1.enabled_notify_subtype_ids) self.assertNotIn( self.subtype4, - self.partner1.enabled_notify_subtype_ids) + self.user1.enabled_notify_subtype_ids) self.assertNotIn( self.subtype4, - self.partner1.disabled_notify_subtype_ids) + self.user1.disabled_notify_subtype_ids) - def test_partner_find_by_subtype_incl(self): + def test_find_user_by_subtype_incl(self): self._test_subtypes_rel() domain = [( 'enabled_notify_subtype_ids', 'in', (self.subtype1.id, self.subtype2.id), )] - self.assertIn( - self.partner1, - self.partner_model.search(domain) - ) + self.assertIn(self.user1, self.env['res.users'].search(domain)) domain = [( 'disabled_notify_subtype_ids', 'in', self.subtype3.id, )] - self.assertIn( - self.partner1, - self.partner_model.search(domain) - ) + self.assertIn(self.user1, self.env['res.users'].search(domain)) domain = [( 'enabled_notify_subtype_ids', 'in', (self.subtype3.id, ), )] - self.assertNotIn( - self.partner1, - self.partner_model.search(domain) - ) + self.assertNotIn(self.user1, self.env['res.users'].search(domain)) domain = [( 'enabled_notify_subtype_ids', 'in', (self.subtype4.id, ), )] - self.assertNotIn( - self.partner1, - self.partner_model.search(domain) - ) + self.assertNotIn(self.user1, self.env['res.users'].search(domain)) domain = [( 'disabled_notify_subtype_ids', 'in', (self.subtype4.id, ), )] - self.assertNotIn( - self.partner1, - self.partner_model.search(domain) - ) + self.assertNotIn(self.user1, self.env['res.users'].search(domain)) - def test_partner_find_by_subtype_escl(self): + def test_find_user_by_subtype_escl(self): self._test_subtypes_rel() domain = [( 'enabled_notify_subtype_ids', 'not in', (self.subtype4.id, ), )] - self.assertIn( - self.partner1, - self.partner_model.search(domain) - ) + self.assertIn(self.user1, self.env['res.users'].search(domain)) domain = [( 'disabled_notify_subtype_ids', 'not in', (self.subtype4.id, ), )] - self.assertIn( - self.partner1, - self.partner_model.search(domain) - ) + self.assertIn(self.user1, self.env['res.users'].search(domain)) domain = [( 'enabled_notify_subtype_ids', 'not in', (self.subtype3.id, ), )] - self.assertIn( - self.partner1, - self.partner_model.search(domain) - ) + self.assertIn(self.user1, self.env['res.users'].search(domain)) domain = [( 'disabled_notify_subtype_ids', 'not in', (self.subtype1.id, self.subtype2.id), )] - self.assertIn( - self.partner1, - self.partner_model.search(domain) - ) + self.assertIn(self.user1, self.env['res.users'].search(domain)) diff --git a/mail_digest/views/mail_digest_views.xml b/mail_digest/views/mail_digest_views.xml index 61d58f41..e09bdb73 100644 --- a/mail_digest/views/mail_digest_views.xml +++ b/mail_digest/views/mail_digest_views.xml @@ -6,7 +6,7 @@ mail.digest - + @@ -27,7 +27,7 @@
- + diff --git a/mail_digest/views/partner_views.xml b/mail_digest/views/partner_views.xml deleted file mode 100644 index 4b455639..00000000 --- a/mail_digest/views/partner_views.xml +++ /dev/null @@ -1,38 +0,0 @@ - - - - mail.notifications res.partner.form - res.partner - - - - - - - - - - partner.notification.conf form - partner.notification.conf - -
- - - - -
-
-
- - - partner.notification.conf tree - partner.notification.conf - - - - - - - - -
diff --git a/mail_digest/views/user_notification_views.xml b/mail_digest/views/user_notification_views.xml new file mode 100644 index 00000000..9143bd27 --- /dev/null +++ b/mail_digest/views/user_notification_views.xml @@ -0,0 +1,28 @@ + + + + + user.notification.conf form + user.notification.conf + +
+ + + + +
+
+
+ + + user.notification.conf tree + user.notification.conf + + + + + + + + +
diff --git a/mail_digest/views/user_views.xml b/mail_digest/views/user_views.xml index c3a41172..ac82f1a4 100644 --- a/mail_digest/views/user_views.xml +++ b/mail_digest/views/user_views.xml @@ -5,13 +5,14 @@ res.users - + - - + + + - + @@ -25,17 +26,19 @@ res.users - + - - + + + - + +