Browse Source
Merge pull request #28 from hbrunn/8.0-mail_follower_custom_notification
Merge pull request #28 from hbrunn/8.0-mail_follower_custom_notification
[ADD] mail_follower_custom_notificationpull/46/head
Rafael Blasco
9 years ago
22 changed files with 718 additions and 0 deletions
-
73mail_follower_custom_notification/README.rst
-
5mail_follower_custom_notification/__init__.py
-
27mail_follower_custom_notification/__openerp__.py
-
BINmail_follower_custom_notification/images/mail_follower_custom_notification.png
-
9mail_follower_custom_notification/models/__init__.py
-
92mail_follower_custom_notification/models/base_patch_models_mixin.py
-
42mail_follower_custom_notification/models/mail_followers.py
-
25mail_follower_custom_notification/models/mail_message.py
-
22mail_follower_custom_notification/models/mail_message_subtype.py
-
33mail_follower_custom_notification/models/mail_notification.py
-
80mail_follower_custom_notification/models/mail_thread.py
-
BINmail_follower_custom_notification/static/description/icon.png
-
5mail_follower_custom_notification/static/src/css/mail_follower_custom_notification.css
-
79mail_follower_custom_notification/static/src/js/mail_follower_custom_notification.js
-
38mail_follower_custom_notification/static/src/xml/mail_follower_custom_notification.xml
-
4mail_follower_custom_notification/tests/__init__.py
-
75mail_follower_custom_notification/tests/test_mail_follower_custom_notification.py
-
18mail_follower_custom_notification/views/mail_message_subtype.xml
-
11mail_follower_custom_notification/views/templates.xml
-
4mail_follower_custom_notification/wizards/__init__.py
-
46mail_follower_custom_notification/wizards/mail_subtype_assign_custom_notifications.py
-
30mail_follower_custom_notification/wizards/mail_subtype_assign_custom_notifications.xml
@ -0,0 +1,73 @@ |
|||||
|
.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg |
||||
|
:alt: License: AGPL-3 |
||||
|
|
||||
|
========================================== |
||||
|
Custom notification settings for followers |
||||
|
========================================== |
||||
|
|
||||
|
In standard Odoo, receiving mail notifications is an all or nothing affair. |
||||
|
This module allows you users to decide per followed record if they want to |
||||
|
receive emails or not. Further, they can choose to receive notification about |
||||
|
their own messages. |
||||
|
|
||||
|
You can also set defaults for this settings on the subtype in question. |
||||
|
|
||||
|
Configuration |
||||
|
============= |
||||
|
|
||||
|
When followers open their subscriptions, they will be offered the choice to |
||||
|
override mail settings and to force being notified about their own messages. |
||||
|
|
||||
|
You can add defaults per message sub type for this settings in Settings / |
||||
|
Technical / Email / Subtypes. Here, you also have the opportunity to apply |
||||
|
those defaults to existing subscriptions. Note that this overrides all |
||||
|
customizations your users already have done. |
||||
|
|
||||
|
Usage |
||||
|
===== |
||||
|
|
||||
|
To use this module, for example you need to: |
||||
|
|
||||
|
- Go to Sales -> Sales -> Customers |
||||
|
- Go Inside any customer and in the right-botton corner press "Follow" button |
||||
|
- Unfold Following menu and check new functionality with "mail notificacions" |
||||
|
|
||||
|
|
||||
|
.. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas |
||||
|
:alt: Try me on Runbot |
||||
|
:target: https://runbot.odoo-community.org/runbot/205/8.0 |
||||
|
|
||||
|
For further information, please visit: |
||||
|
|
||||
|
* https://www.odoo.com/forum/help-1 |
||||
|
|
||||
|
Bug Tracker |
||||
|
=========== |
||||
|
|
||||
|
Bugs are tracked on `GitHub Issues <https://github.com/OCA/social/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 |
||||
|
`here <https://github.com/OCA/social/issues/new?body=module:%20mail_follower_custom_notification%0Aversion:%208.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_. |
||||
|
|
||||
|
Credits |
||||
|
======= |
||||
|
|
||||
|
Contributors |
||||
|
------------ |
||||
|
|
||||
|
* Holger Brunn <hbrunn@therp.nl> |
||||
|
|
||||
|
Maintainer |
||||
|
---------- |
||||
|
|
||||
|
.. image:: https://odoo-community.org/logo.png |
||||
|
:alt: Odoo Community Association |
||||
|
:target: https://odoo-community.org |
||||
|
|
||||
|
This module is maintained by the OCA. |
||||
|
|
||||
|
OCA, or the Odoo Community Association, is a nonprofit organization whose |
||||
|
mission is to support the collaborative development of Odoo features and |
||||
|
promote its widespread use. |
||||
|
|
||||
|
To contribute to this module, please visit http://odoo-community.org. |
@ -0,0 +1,5 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
# © 2015 Therp BV <http://therp.nl> |
||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
||||
|
from . import models |
||||
|
from . import wizards |
@ -0,0 +1,27 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
# © 2015 Therp BV <http://therp.nl> |
||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
||||
|
{ |
||||
|
"name": "Custom notification settings for followers", |
||||
|
"version": "8.0.1.0.0", |
||||
|
"author": "Therp BV,Odoo Community Association (OCA)", |
||||
|
"license": "AGPL-3", |
||||
|
"category": "Social Network", |
||||
|
"summary": "Let followers choose if they want to receive email " |
||||
|
"notifications for a given subscription", |
||||
|
"depends": [ |
||||
|
'mail', |
||||
|
], |
||||
|
"data": [ |
||||
|
"wizards/mail_subtype_assign_custom_notifications.xml", |
||||
|
"views/mail_message_subtype.xml", |
||||
|
'views/templates.xml', |
||||
|
], |
||||
|
"qweb": [ |
||||
|
'static/src/xml/mail_follower_custom_notification.xml', |
||||
|
], |
||||
|
"images": [ |
||||
|
'images/mail_follower_custom_notification.png', |
||||
|
], |
||||
|
"installable": True, |
||||
|
} |
After Width: 451 | Height: 156 | Size: 8.6 KiB |
@ -0,0 +1,9 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
# © 2015 Therp BV <http://therp.nl> |
||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
||||
|
from . import base_patch_models_mixin |
||||
|
from . import mail_followers |
||||
|
from . import mail_thread |
||||
|
from . import mail_message |
||||
|
from . import mail_notification |
||||
|
from . import mail_message_subtype |
@ -0,0 +1,92 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
# © 2016 Therp BV <http://therp.nl> |
||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
||||
|
import logging |
||||
|
from openerp import models |
||||
|
|
||||
|
|
||||
|
_logger = logging.getLogger(__file__) |
||||
|
|
||||
|
|
||||
|
# TODO: this should be a helper module to cetralize the point of failure |
||||
|
# in case this introduces tacit bugs |
||||
|
class BasePatchModelsMixin(models.AbstractModel): |
||||
|
""" |
||||
|
This is a mixin class meant to simplify working with patches |
||||
|
on BaseModel or on abstract models like mail.thread. |
||||
|
If you just change them, models created earlier will lack the |
||||
|
attributes you add. Just inherit from this mixin, it will check |
||||
|
which existing models need your changes and apply them. |
||||
|
|
||||
|
In your module, do something like |
||||
|
|
||||
|
class MailThread(models.AbstractModel): |
||||
|
_name = 'mail.thread' |
||||
|
_inherit = ['base.patch.models.mixin', 'mail.thread'] |
||||
|
|
||||
|
in case you need to patch BaseModel, say |
||||
|
|
||||
|
class BaseModel(models.BaseModel): |
||||
|
_name = 'my.unique.model.name' |
||||
|
_inherit = 'base.patch.models.mixin' |
||||
|
|
||||
|
Your code will behave as if it was an inherited class of the class you pass |
||||
|
in the second parameter to _base_patch_models. |
||||
|
""" |
||||
|
_name = 'base.patch.models.mixin' |
||||
|
|
||||
|
def _base_patch_models(self, cr, our_class=None, parent_class=None): |
||||
|
"""iterate through existing models to apply our changes there if |
||||
|
necessary""" |
||||
|
if self._name == BasePatchModelsMixin._name: |
||||
|
return |
||||
|
my_bases = self.__class__.__bases__ |
||||
|
for i in range(max(len(my_bases) - 1, 0)): |
||||
|
if my_bases[i]._name == BasePatchModelsMixin._name: |
||||
|
our_class = my_bases[i - 1] |
||||
|
parent_class = my_bases[i + 1] |
||||
|
inherit = [self._inherit]\ |
||||
|
if isinstance(self._inherit, basestring) else self._inherit |
||||
|
for i in range(len(my_bases) - 1, 0, -1): |
||||
|
# this can be different from the above if our mixin is used |
||||
|
# multiple times on the same model |
||||
|
if my_bases[i]._name in inherit: |
||||
|
parent_class = my_bases[i] |
||||
|
break |
||||
|
if self.__class__.__bases__[-1] == BasePatchModelsMixin\ |
||||
|
and not our_class or not parent_class: |
||||
|
our_class = self.__class__.__bases__[-2] |
||||
|
parent_class = models.BaseModel |
||||
|
if not our_class or not parent_class: |
||||
|
_logger.info( |
||||
|
'Failed to autodetect own class or parent class for %s, ' |
||||
|
'ignoring', self._name) |
||||
|
return |
||||
|
|
||||
|
for model_name, model_object in self.pool.models.iteritems(): |
||||
|
if not isinstance(model_object, parent_class): |
||||
|
continue |
||||
|
if isinstance(model_object, our_class): |
||||
|
continue |
||||
|
if not isinstance(model_object, models.Model): |
||||
|
continue |
||||
|
bases = list(model_object.__class__.__bases__) |
||||
|
position = 1 |
||||
|
if parent_class == models.BaseModel: |
||||
|
position = len(bases) |
||||
|
else: |
||||
|
for i in range(len(bases) - 1, position, -1): |
||||
|
if bases[i]._name in inherit: |
||||
|
position = i |
||||
|
break |
||||
|
bases.insert(position, our_class) |
||||
|
model_object.__class__.__bases__ = tuple(bases) |
||||
|
|
||||
|
def _register_hook(self, cr): |
||||
|
self._base_patch_models(cr) |
||||
|
for base in self.__class__.__bases__: |
||||
|
if not hasattr(super(base, self), '_register_hook'): |
||||
|
return |
||||
|
if super(base, self)._register_hook != self._register_hook: |
||||
|
return super(base, self)._register_hook.__func__( |
||||
|
super(base, self), cr) |
@ -0,0 +1,42 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
# © 2015 Therp BV <http://therp.nl> |
||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
||||
|
from openerp import api, fields, models |
||||
|
|
||||
|
|
||||
|
class MailFollowers(models.Model): |
||||
|
_inherit = 'mail.followers' |
||||
|
|
||||
|
force_mail_subtype_ids = fields.Many2many( |
||||
|
'mail.message.subtype', 'mail_followers_force_mail_rel', |
||||
|
'mail_followers_id', 'mail_message_subtype_id', |
||||
|
string='Force mails from subtype') |
||||
|
|
||||
|
force_nomail_subtype_ids = fields.Many2many( |
||||
|
'mail.message.subtype', 'mail_followers_force_nomail_rel', |
||||
|
'mail_followers_id', 'mail_message_subtype_id', |
||||
|
string='Force no mails from subtype') |
||||
|
|
||||
|
force_own_subtype_ids = fields.Many2many( |
||||
|
'mail.message.subtype', 'mail_followers_force_own_rel', |
||||
|
'mail_followers_id', 'mail_message_subtype_id', |
||||
|
string='Force own mails from subtype') |
||||
|
|
||||
|
@api.model |
||||
|
@api.returns('self', lambda x: x.id) |
||||
|
def create(self, values): |
||||
|
this = super(MailFollowers, self).create(values) |
||||
|
for subtype in this.subtype_ids: |
||||
|
if not subtype.res_model and\ |
||||
|
subtype.custom_notification_model_ids and\ |
||||
|
this.res_model not in\ |
||||
|
subtype.custom_notification_model_ids\ |
||||
|
.mapped('model'): |
||||
|
continue |
||||
|
if subtype.custom_notification_mail == 'force_yes': |
||||
|
this.force_mail_subtype_ids += subtype |
||||
|
if subtype.custom_notification_mail == 'force_no': |
||||
|
this.force_nomail_subtype_ids += subtype |
||||
|
if subtype.custom_notification_own: |
||||
|
this.force_own_subtype_ids += subtype |
||||
|
return this |
@ -0,0 +1,25 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
# © 2015 Therp BV <http://therp.nl> |
||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
||||
|
from openerp import api, models |
||||
|
|
||||
|
|
||||
|
class MailMessage(models.Model): |
||||
|
_inherit = 'mail.message' |
||||
|
|
||||
|
@api.multi |
||||
|
def _notify(self, force_send=False, user_signature=True): |
||||
|
"""notify author if she's a follower and turned on force_own""" |
||||
|
self.ensure_one() |
||||
|
if self.subtype_id and self.model and self.res_id: |
||||
|
author_follower = self.env['mail.followers'].search([ |
||||
|
('res_model', '=', self.model), |
||||
|
('res_id', '=', self.res_id), |
||||
|
('partner_id', '=', self.author_id.id), |
||||
|
('force_own_subtype_ids', '=', self.subtype_id.id), |
||||
|
]) |
||||
|
self.env['mail.notification']._notify( |
||||
|
self.id, partners_to_notify=author_follower.partner_id.ids, |
||||
|
force_send=force_send, user_signature=user_signature) |
||||
|
return super(MailMessage, self)._notify( |
||||
|
self.id, force_send=force_send, user_signature=user_signature) |
@ -0,0 +1,22 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
# © 2015 Therp BV <http://therp.nl> |
||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
||||
|
from openerp import fields, models |
||||
|
|
||||
|
|
||||
|
class MailMessageSubtype(models.Model): |
||||
|
_inherit = 'mail.message.subtype' |
||||
|
|
||||
|
custom_notification_mail = fields.Selection( |
||||
|
[('force_yes', 'Force yes'), ('force_no', 'Force no')], |
||||
|
string='Send mail notification', help='Leave empty to use the ' |
||||
|
'on the partner\'s form, set to "Force yes" to always send messages ' |
||||
|
'of this type via email, and "Force no" to never send messages of ' |
||||
|
'type via email') |
||||
|
custom_notification_own = fields.Boolean( |
||||
|
'Notify about own messages', help='Check this to have notifications ' |
||||
|
'generated and sent via email about own messages') |
||||
|
custom_notification_model_ids = fields.Many2many( |
||||
|
'ir.model', string='Models', help='Choose for which models the ' |
||||
|
'custom configuration applies. This is only necessary if your subtype ' |
||||
|
'doesn\'t set a model itself', domain=[('osv_memory', '=', False)]) |
@ -0,0 +1,33 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
# © 2015 Therp BV <http://therp.nl> |
||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
||||
|
from openerp import api, models |
||||
|
|
||||
|
|
||||
|
class MailNotification(models.Model): |
||||
|
_inherit = 'mail.notification' |
||||
|
|
||||
|
@api.multi |
||||
|
def get_partners_to_email(self, message): |
||||
|
partner_ids = super(MailNotification, self)\ |
||||
|
.get_partners_to_email(message) |
||||
|
for this in self: |
||||
|
follower = self.env['mail.followers'].search([ |
||||
|
('res_model', '=', message.model), |
||||
|
('res_id', '=', message.res_id), |
||||
|
('partner_id', '=', this.partner_id.id), |
||||
|
'|', '|', |
||||
|
('force_nomail_subtype_ids', '=', message.subtype_id.id), |
||||
|
('force_mail_subtype_ids', '=', message.subtype_id.id), |
||||
|
('force_own_subtype_ids', '=', message.subtype_id.id), |
||||
|
]) |
||||
|
if not follower: |
||||
|
continue |
||||
|
if (message.subtype_id in follower.force_mail_subtype_ids or |
||||
|
message.subtype_id in follower.force_own_subtype_ids) and\ |
||||
|
this.partner_id.id not in partner_ids: |
||||
|
partner_ids.append(this.partner_id.id) |
||||
|
if message.subtype_id in follower.force_nomail_subtype_ids and\ |
||||
|
this.partner_id.id in partner_ids: |
||||
|
partner_ids.remove(this.partner_id.id) |
||||
|
return partner_ids |
@ -0,0 +1,80 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
# © 2015 Therp BV <http://therp.nl> |
||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
||||
|
from openerp import api, models |
||||
|
|
||||
|
|
||||
|
class MailThread(models.AbstractModel): |
||||
|
_inherit = ['base.patch.models.mixin', 'mail.thread'] |
||||
|
_name = 'mail.thread' |
||||
|
|
||||
|
@api.multi |
||||
|
def _get_subscription_data(self, name, args, user_pid=None): |
||||
|
result = super(MailThread, self)._get_subscription_data( |
||||
|
name, args, user_pid=user_pid) |
||||
|
subtypes = self.env['mail.message.subtype'].search([ |
||||
|
('hidden', '=', False), |
||||
|
'|', |
||||
|
('res_model', '=', self._name), |
||||
|
('res_model', '=', False), |
||||
|
]) |
||||
|
for follower in self.env['mail.followers'].search([ |
||||
|
('res_model', '=', self._name), |
||||
|
('res_id', 'in', result.keys()), |
||||
|
('partner_id', '=', user_pid or self.env.user.partner_id.id), |
||||
|
]): |
||||
|
# values are ordered dicts, so we get the correct matches |
||||
|
for subtype, data in zip( |
||||
|
subtypes, |
||||
|
result[follower.res_id]['message_subtype_data'].values()): |
||||
|
data['force_mail'] = 'default' |
||||
|
if subtype in follower.force_mail_subtype_ids: |
||||
|
data['force_mail'] = 'force_yes' |
||||
|
elif subtype in follower.force_nomail_subtype_ids: |
||||
|
data['force_mail'] = 'force_no' |
||||
|
data['force_own'] =\ |
||||
|
subtype in follower.force_own_subtype_ids |
||||
|
return result |
||||
|
|
||||
|
@api.multi |
||||
|
def message_custom_notification_update_user(self, custom_notifications): |
||||
|
"""change custom_notifications from user ids to partner ids""" |
||||
|
user2partner = dict( |
||||
|
self.env['res.users'].browse(map(int, custom_notifications.keys())) |
||||
|
.mapped(lambda user: (str(user.id), str(user.partner_id.id))) |
||||
|
) |
||||
|
return self.message_custom_notification_update({ |
||||
|
user2partner[user_id]: data |
||||
|
for user_id, data in custom_notifications.iteritems() |
||||
|
}) |
||||
|
|
||||
|
@api.multi |
||||
|
def message_custom_notification_update(self, custom_notifications): |
||||
|
"""custom_notifications is a dictionary with partner ids as keys |
||||
|
and dictionaries mapping message subtype ids to custom notification |
||||
|
values""" |
||||
|
def ids_with_value(data, key, value): |
||||
|
return map(lambda x: int(x[0]), |
||||
|
filter(lambda x: x[1][key] == value, |
||||
|
data.iteritems())) |
||||
|
|
||||
|
custom_notifications = { |
||||
|
int(key): value |
||||
|
for key, value in custom_notifications.iteritems() |
||||
|
if key != 'False' |
||||
|
} |
||||
|
|
||||
|
for follower in self.env['mail.followers'].search([ |
||||
|
('res_model', '=', self._name), |
||||
|
('res_id', 'in', self.ids), |
||||
|
('partner_id', 'in', custom_notifications.keys()), |
||||
|
]): |
||||
|
data = custom_notifications[follower.partner_id.id] |
||||
|
follower.write({ |
||||
|
'force_mail_subtype_ids': [(6, 0, ids_with_value( |
||||
|
data, 'force_mail', 'force_yes'))], |
||||
|
'force_nomail_subtype_ids': [(6, 0, ids_with_value( |
||||
|
data, 'force_mail', 'force_no'))], |
||||
|
'force_own_subtype_ids': [(6, 0, ids_with_value( |
||||
|
data, 'force_own', '1'))] |
||||
|
}), |
After Width: 128 | Height: 128 | Size: 9.2 KiB |
@ -0,0 +1,5 @@ |
|||||
|
.oe_custom_notification legend |
||||
|
{ |
||||
|
font-size: inherit; |
||||
|
margin-bottom: 0px; |
||||
|
} |
@ -0,0 +1,79 @@ |
|||||
|
//-*- coding: utf-8 -*-
|
||||
|
//© 2015 Therp BV <http://therp.nl>
|
||||
|
//License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
|
||||
|
openerp.mail_follower_custom_notification = function(instance) |
||||
|
{ |
||||
|
instance.mail_followers.Followers.include({ |
||||
|
display_subtypes: function(data, id, dialog) |
||||
|
{ |
||||
|
var $list = this.$('.oe_subtype_list ul'); |
||||
|
if (dialog) |
||||
|
{ |
||||
|
$list = this.$dialog.$el; |
||||
|
} |
||||
|
$list.empty(); |
||||
|
this._super(data, id, dialog); |
||||
|
$list.find('input[type=checkbox]').change(function() |
||||
|
{ |
||||
|
$list.find(_.str.sprintf( |
||||
|
'#custom_notification_%s%s', |
||||
|
jQuery(this).data('id'), |
||||
|
dialog ? '_dialog' : '' |
||||
|
)) |
||||
|
.toggle(jQuery(this).prop('checked')); |
||||
|
}); |
||||
|
if(!dialog) |
||||
|
{ |
||||
|
$list.find('.oe_custom_notification input[type=radio]') |
||||
|
.change(this.proxy('do_update_subscription')); |
||||
|
}; |
||||
|
}, |
||||
|
do_update_subscription: function(event, user_pid) |
||||
|
{ |
||||
|
/* |
||||
|
if(jQuery(event.currentTarget).parents('.oe_custom_notification') |
||||
|
.length) |
||||
|
{ |
||||
|
// mail reacts on all inputs, suppress for our inputs
|
||||
|
return jQuery.when(); |
||||
|
} |
||||
|
*/ |
||||
|
var self = this, |
||||
|
update_func = 'message_custom_notification_update_user', |
||||
|
follower_ids = [this.session.uid], |
||||
|
custom_notifications = {}, |
||||
|
oe_action = this.$('.oe_actions'); |
||||
|
if(user_pid) |
||||
|
{ |
||||
|
update_func = 'message_custom_notification_update'; |
||||
|
follower_ids = [user_pid]; |
||||
|
oe_action = jQuery('.oe_edit_actions'); |
||||
|
} |
||||
|
_(follower_ids).each(function(follower) |
||||
|
{ |
||||
|
|
||||
|
var follower_settings = custom_notifications[follower] = {}; |
||||
|
oe_action.find('.oe_custom_notification') |
||||
|
.each(function() |
||||
|
{ |
||||
|
var id = parseInt(jQuery(this).data('id')), |
||||
|
settings = follower_settings[id] = {}; |
||||
|
settings['force_mail'] = jQuery(this) |
||||
|
.find('.oe_custom_notification_mail input:checked') |
||||
|
.val(); |
||||
|
settings['force_own'] = jQuery(this) |
||||
|
.find('.oe_custom_notification_own input:checked') |
||||
|
.val(); |
||||
|
}); |
||||
|
}); |
||||
|
return jQuery.when(this._super.apply(this, arguments)) |
||||
|
.then(function() |
||||
|
{ |
||||
|
return self.ds_model.call( |
||||
|
update_func, |
||||
|
[[self.view.datarecord.id], custom_notifications]) |
||||
|
}) |
||||
|
}, |
||||
|
}); |
||||
|
} |
@ -0,0 +1,38 @@ |
|||||
|
<?xml version="1.0" encoding="UTF-8"?> |
||||
|
<template> |
||||
|
<t t-extend="mail.followers.subtype"> |
||||
|
<t t-jquery="table" t-operation="append"> |
||||
|
<tr class="oe_custom_notification" t-att-style="record.followed ? '' : 'display: none'" t-attf-id="custom_notification_#{record.id}#{dialog ? '_dialog' : ''}" t-att-data-id="record.id"> |
||||
|
<td /> |
||||
|
<td> |
||||
|
<fieldset class="oe_custom_notification_mail"> |
||||
|
<legend>Mail notifications</legend> |
||||
|
<div> |
||||
|
<input type="radio" t-att-checked="record.force_mail=='default' ? 'checked' : null" t-attf-name="custom_notification_mail_#{record.id}" t-attf-id="custom_notification_mail_default_#{record.id}#{dialog ? '_dialog' : ''}" value="default" /> |
||||
|
<label t-attf-for="custom_notification_mail_default_#{record.id}#{dialog ? '_dialog' : ''}">Use default mail preferences</label> |
||||
|
</div> |
||||
|
<div> |
||||
|
<input type="radio" t-att-checked="record.force_mail=='force_yes' ? 'checked' : null" t-attf-name="custom_notification_mail_#{record.id}" t-attf-id="custom_notification_mail_force_#{record.id}#{dialog ? '_dialog' : ''}" value="force_yes" /> |
||||
|
<label t-attf-for="custom_notification_mail_force_#{record.id}#{dialog ? '_dialog' : ''}">Force sending mails</label> |
||||
|
</div> |
||||
|
<div> |
||||
|
<input type="radio" t-att-checked="record.force_mail=='force_no' ? 'checked' : null" t-attf-name="custom_notification_mail_#{record.id}" t-attf-id="custom_notification_mail_force_no_#{record.id}#{dialog ? '_dialog' : ''}" value="force_no" /> |
||||
|
<label t-attf-for="custom_notification_mail_force_no_#{record.id}#{dialog ? '_dialog' : ''}">Force not sending mails</label> |
||||
|
</div> |
||||
|
</fieldset> |
||||
|
<fieldset class="oe_custom_notification_own"> |
||||
|
<legend>Own messages</legend> |
||||
|
<div> |
||||
|
<input type="radio" t-att-checked="!record.force_own ? 'checked' : null" t-attf-name="custom_notification_own_#{record.id}" t-attf-id="custom_notification_own_no_#{record.id}#{dialog ? '_dialog' : ''}" value="" /> |
||||
|
<label t-attf-for="custom_notification_own_no_#{record.id}#{dialog ? '_dialog' : ''}">No notification</label> |
||||
|
</div> |
||||
|
<div> |
||||
|
<input type="radio" t-att-checked="record.force_own ? 'checked' : null" t-attf-name="custom_notification_own_#{record.id}" t-attf-id="custom_notification_own_yes_#{record.id}#{dialog ? '_dialog' : ''}" value="1" /> |
||||
|
<label t-attf-for="custom_notification_own_yes_#{record.id}#{dialog ? '_dialog' : ''}">Notify me</label> |
||||
|
</div> |
||||
|
</fieldset> |
||||
|
</td> |
||||
|
</tr> |
||||
|
</t> |
||||
|
</t> |
||||
|
</template> |
@ -0,0 +1,4 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
# © 2015 Therp BV <http://therp.nl> |
||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
||||
|
from . import test_mail_follower_custom_notification |
@ -0,0 +1,75 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
# © 2015 Therp BV <http://therp.nl> |
||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
||||
|
from openerp.tests.common import TransactionCase |
||||
|
|
||||
|
|
||||
|
class TestMailFollowerCustomNotification(TransactionCase): |
||||
|
def test_mail_follower_custom_notification(self): |
||||
|
self.env['mail.thread']._register_hook() |
||||
|
followed_partner = self.env['res.partner'].create({ |
||||
|
'name': 'I\'m followed', |
||||
|
}) |
||||
|
demo_user = self.env.ref('base.user_demo') |
||||
|
followed_partner_demo = followed_partner.sudo(demo_user.id) |
||||
|
followed_partner_demo.message_subscribe_users() |
||||
|
|
||||
|
# see if default subscriptions return default custom settings |
||||
|
subscription_data = followed_partner_demo._get_subscription_data( |
||||
|
None, None) |
||||
|
self.assertEqual( |
||||
|
subscription_data[followed_partner.id]['message_subtype_data'] |
||||
|
['Discussions']['force_mail'], |
||||
|
'default') |
||||
|
self.assertEqual( |
||||
|
subscription_data[followed_partner.id]['message_subtype_data'] |
||||
|
['Discussions']['force_own'], |
||||
|
False) |
||||
|
|
||||
|
# set custom settings |
||||
|
mt_comment = self.env.ref('mail.mt_comment') |
||||
|
followed_partner_demo.message_custom_notification_update_user({ |
||||
|
str(demo_user.id): { |
||||
|
str(mt_comment.id): { |
||||
|
'force_mail': 'force_yes', |
||||
|
'force_own': '1', |
||||
|
}, |
||||
|
}, |
||||
|
}) |
||||
|
# see if we can read them back |
||||
|
subscription_data = followed_partner_demo._get_subscription_data( |
||||
|
None, None) |
||||
|
self.assertEqual( |
||||
|
subscription_data[followed_partner.id]['message_subtype_data'] |
||||
|
['Discussions']['force_mail'], |
||||
|
'force_yes') |
||||
|
self.assertEqual( |
||||
|
subscription_data[followed_partner.id]['message_subtype_data'] |
||||
|
['Discussions']['force_own'], |
||||
|
True) |
||||
|
|
||||
|
# post a message and see if we successfully forced a notification to |
||||
|
# ourselves |
||||
|
followed_partner_demo.message_post('hello world', subtype='mt_comment') |
||||
|
self.assertEqual( |
||||
|
followed_partner_demo.message_ids[:-1].notification_ids.partner_id, |
||||
|
demo_user.partner_id) |
||||
|
|
||||
|
# assign default values on message subtype and apply them to all |
||||
|
# followers |
||||
|
mt_comment.custom_notification_model_ids = self.env['ir.model']\ |
||||
|
.search([('model', '=', 'res.partner')]) |
||||
|
wizard = self.env['mail.subtype.assign.custom.notifications']\ |
||||
|
.with_context(active_ids=mt_comment.ids)\ |
||||
|
.create({}) |
||||
|
wizard.button_apply() |
||||
|
subscription_data = followed_partner_demo._get_subscription_data( |
||||
|
None, None) |
||||
|
self.assertEqual( |
||||
|
subscription_data[followed_partner.id]['message_subtype_data'] |
||||
|
['Discussions']['force_mail'], |
||||
|
'default') |
||||
|
self.assertEqual( |
||||
|
subscription_data[followed_partner.id]['message_subtype_data'] |
||||
|
['Discussions']['force_own'], |
||||
|
False) |
@ -0,0 +1,18 @@ |
|||||
|
<?xml version="1.0" encoding="UTF-8"?> |
||||
|
<openerp> |
||||
|
<data> |
||||
|
<record id="view_mail_message_subtype_form" model="ir.ui.view"> |
||||
|
<field name="model">mail.message.subtype</field> |
||||
|
<field name="inherit_id" ref="mail.view_mail_message_subtype_form" /> |
||||
|
<field name="arch" type="xml"> |
||||
|
<group position="inside"> |
||||
|
<group string="Custom notifications"> |
||||
|
<field name="custom_notification_mail" /> |
||||
|
<field name="custom_notification_own" /> |
||||
|
<field name="custom_notification_model_ids" attrs="{'invisible': [('res_model', '!=', False)]}" widget="many2many_tags" /> |
||||
|
</group> |
||||
|
</group> |
||||
|
</field> |
||||
|
</record> |
||||
|
</data> |
||||
|
</openerp> |
@ -0,0 +1,11 @@ |
|||||
|
<?xml version="1.0" encoding="UTF-8"?> |
||||
|
<openerp> |
||||
|
<data> |
||||
|
<template id="assets_backend" name="mail_follower_custom_notification assets" inherit_id="web.assets_backend"> |
||||
|
<xpath expr="." position="inside"> |
||||
|
<script type="text/javascript" src="/mail_follower_custom_notification/static/src/js/mail_follower_custom_notification.js"></script> |
||||
|
<link rel="stylesheet" href="/mail_follower_custom_notification/static/src/css/mail_follower_custom_notification.css"/> |
||||
|
</xpath> |
||||
|
</template> |
||||
|
</data> |
||||
|
</openerp> |
@ -0,0 +1,4 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
# © 2015 Therp BV <http://therp.nl> |
||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
||||
|
from . import mail_subtype_assign_custom_notifications |
@ -0,0 +1,46 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
# © 2015 Therp BV <http://therp.nl> |
||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
||||
|
from openerp import api, fields, models |
||||
|
|
||||
|
|
||||
|
class MailSubtypeAssignCustomNotifications(models.TransientModel): |
||||
|
_name = 'mail.subtype.assign.custom.notifications' |
||||
|
_description = 'Assign custom notification settings to existing followers' |
||||
|
|
||||
|
subtype_ids = fields.Many2many( |
||||
|
'mail.message.subtype', 'mail_subtype_assign_custom_notifications_rel', |
||||
|
string='Subtypes', required=True, |
||||
|
default=lambda self: [(6, 0, self.env.context.get('active_ids', []))]) |
||||
|
|
||||
|
@api.multi |
||||
|
def button_apply(self): |
||||
|
self.ensure_one() |
||||
|
for subtype in self.subtype_ids: |
||||
|
domain = [('subtype_ids', '=', subtype.id)] |
||||
|
if subtype.custom_notification_model_ids: |
||||
|
domain.append( |
||||
|
('res_model', 'in', |
||||
|
subtype.custom_notification_model_ids.mapped('model'))) |
||||
|
self.env['mail.followers'].with_context(active_test=False)\ |
||||
|
.search(domain)\ |
||||
|
.write({ |
||||
|
'force_mail_subtype_ids': [ |
||||
|
(4, subtype.id) |
||||
|
if subtype.custom_notification_mail == 'force_yes' |
||||
|
else |
||||
|
(3, subtype.id) |
||||
|
], |
||||
|
'force_nomail_subtype_ids': [ |
||||
|
(4, subtype.id) |
||||
|
if subtype.custom_notification_mail == 'force_no' |
||||
|
else |
||||
|
(3, subtype.id) |
||||
|
], |
||||
|
'force_own_subtype_ids': [ |
||||
|
(4, subtype.id) |
||||
|
if subtype.custom_notification_own |
||||
|
else |
||||
|
(3, subtype.id) |
||||
|
], |
||||
|
}) |
@ -0,0 +1,30 @@ |
|||||
|
<?xml version="1.0" encoding="UTF-8"?> |
||||
|
<openerp> |
||||
|
<data> |
||||
|
<record id="view_mail_subtype_assign_custom_notifications" model="ir.ui.view"> |
||||
|
<field name="model">mail.subtype.assign.custom.notifications</field> |
||||
|
<field name="arch" type="xml"> |
||||
|
<form> |
||||
|
<group> |
||||
|
<field name="subtype_ids" widget="many2many_tags" /> |
||||
|
</group> |
||||
|
<footer> |
||||
|
<button type="object" name="button_apply" string="Apply" |
||||
|
class="oe_highlight" /> |
||||
|
or |
||||
|
<button type="special" special="cancel" string="Cancel" |
||||
|
class="oe_link" /> |
||||
|
</footer> |
||||
|
</form> |
||||
|
</field> |
||||
|
</record> |
||||
|
<act_window id="action_mail_subtype_assign_custom_notifications" |
||||
|
name="Update existing subscriptions" |
||||
|
src_model="mail.message.subtype" |
||||
|
res_model="mail.subtype.assign.custom.notifications" |
||||
|
view_id="view_mail_subtype_assign_custom_notifications" |
||||
|
multi="False" |
||||
|
key2="client_action_multi" |
||||
|
target="new" /> |
||||
|
</data> |
||||
|
</openerp> |
Write
Preview
Loading…
Cancel
Save
Reference in new issue