Simone Orsi
7 years ago
committed by
Holger Brunn
21 changed files with 489 additions and 563 deletions
-
15mail_digest/README.rst
-
7mail_digest/__manifest__.py
-
5mail_digest/data/config_param.xml
-
16mail_digest/data/ir_cron.xml
-
39mail_digest/demo/ir_ui_view.xml
-
10mail_digest/demo/mail_template.xml
-
1mail_digest/models/__init__.py
-
64mail_digest/models/mail_digest.py
-
169mail_digest/models/res_partner.py
-
113mail_digest/models/res_users.py
-
33mail_digest/models/user_notification_conf.py
-
4mail_digest/security/ir.model.access.csv
-
8mail_digest/security/record_rules.xml
-
2mail_digest/templates/digest_default.xml
-
146mail_digest/tests/test_digest.py
-
140mail_digest/tests/test_partner_domains.py
-
115mail_digest/tests/test_subtypes_conf.py
-
4mail_digest/views/mail_digest_views.xml
-
38mail_digest/views/partner_views.xml
-
28mail_digest/views/user_notification_views.xml
-
23mail_digest/views/user_views.xml
@ -1,9 +1,8 @@ |
|||
<odoo> |
|||
<data noupdate="1"> |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<odoo noupdate="1"> |
|||
<record id="mail_digest_enabled_message_types" model="ir.config_parameter"> |
|||
<field name="key">mail_digest.enabled_message_types</field> |
|||
<!-- enabled by default for each message type --> |
|||
<field name="value">email,notification,comment</field> |
|||
</record> |
|||
</data> |
|||
</odoo> |
@ -1,27 +1,23 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<odoo> |
|||
<data noupdate="1"> |
|||
<odoo noupdate="1"> |
|||
<record forcecreate="True" id="ir_cron_mail_digest_daily_action" model="ir.cron"> |
|||
<field name="name">Digest mail process - daily</field> |
|||
<field name="model_id" ref="model_mail_digest"/> |
|||
<field name="user_id" ref="base.user_root"/> |
|||
<field name="interval_number">1</field> |
|||
<field name="interval_type">days</field> |
|||
<field name="numbercall">-1</field> |
|||
<field eval="False" name="doall"/> |
|||
<field eval="'mail.digest'" name="model"/> |
|||
<field eval="'process'" name="function"/> |
|||
<field eval="'()'" name="args"/> |
|||
<field name="code">model.process()</field> |
|||
</record> |
|||
<record forcecreate="True" id="ir_cron_mail_digest_weekly_action" model="ir.cron"> |
|||
<field name="name">Digest mail process - weekly</field> |
|||
<field name="model_id" ref="model_mail_digest"/> |
|||
<field name="user_id" ref="base.user_root"/> |
|||
<field name="interval_number">1</field> |
|||
<field name="interval_type">weeks</field> |
|||
<field name="numbercall">-1</field> |
|||
<field eval="False" name="doall"/> |
|||
<field eval="'mail.digest'" name="model"/> |
|||
<field eval="'process'" name="function"/> |
|||
<field eval="'(\'weekly\',)'" name="args"/> |
|||
<field name="doall" eval="False"/> |
|||
<field name="code">model.process(frequency='weekly')</field> |
|||
</record> |
|||
</data> |
|||
</odoo> |
@ -1,39 +0,0 @@ |
|||
<?xml version="1.0" encoding="UTF-8"?> |
|||
<odoo> |
|||
<template id="view_email_template_corporate_identity"> |
|||
<body> |
|||
<html> |
|||
<img style="float: right" t-attf-src="data:image;base64,{{env.user.company_id.logo}}" /> |
|||
<!-- if some template calling us sets this variable, |
|||
we print a h1 tag /--> |
|||
<h1 t-if="email_heading"><t t-esc="email_heading" /></h1> |
|||
<t t-raw="0" /> |
|||
<!-- use some standard footer if the user doesn't have |
|||
a signature /--> |
|||
<footer t-if="not email_use_user_signature"> |
|||
<p> |
|||
<a t-att-href="env.user.company_id.website"> |
|||
<t t-esc="env.user.company_id.name" /> |
|||
</a> |
|||
</p> |
|||
<p><t t-esc="env.user.company_id.phone" /></p> |
|||
</footer> |
|||
<footer t-if="email_use_user_signature"> |
|||
<t t-raw="env.user.signature" /> |
|||
</footer> |
|||
</html> |
|||
</body> |
|||
</template> |
|||
<template id="view_email_template_demo1"> |
|||
<!-- because we can simply call the ci here, we don't need to |
|||
repeat it /--> |
|||
<t t-call="email_template_qweb.view_email_template_corporate_identity"> |
|||
<!-- the template we call uses this as title if we set it /--> |
|||
<t t-set="email_heading" t-value="email_template.subject" /> |
|||
<h2>Dear <t t-esc="object.name" />,</h2> |
|||
<p> |
|||
This is an email template using qweb. |
|||
</p> |
|||
</t> |
|||
</template> |
|||
</odoo> |
@ -1,10 +0,0 @@ |
|||
<?xml version="1.0" encoding="UTF-8"?> |
|||
<odoo> |
|||
<record id="email_template_demo1" model="mail.template"> |
|||
<field name="name">QWeb demo</field> |
|||
<field name="body_type">qweb</field> |
|||
<field name="body_view_id" ref="view_email_template_demo1" /> |
|||
<field name="model_id" ref="base.model_res_users" /> |
|||
<field name="subject">QWeb demo email</field> |
|||
</record> |
|||
</odoo> |
@ -1,3 +1,4 @@ |
|||
from . import mail_digest |
|||
from . import user_notification_conf |
|||
from . import res_partner |
|||
from . import res_users |
@ -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) |
@ -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 |
@ -1,14 +1,14 @@ |
|||
<?xml version="1.0"?> |
|||
<odoo> |
|||
|
|||
<record model="ir.rule" id="partner_notification_conf_owner"> |
|||
<field name="name">Partners can edit their own notification settings</field> |
|||
<field name="model_id" ref="model_partner_notification_conf"/> |
|||
<record model="ir.rule" id="user_notification_conf_owner"> |
|||
<field name="name">Users can edit their own notification settings</field> |
|||
<field name="model_id" ref="model_user_notification_conf"/> |
|||
<field name="perm_read" eval="False"/> |
|||
<field name="perm_create" eval="False"/> |
|||
<field name="perm_write" eval="True"/> |
|||
<field name="perm_unlink" eval="True"/> |
|||
<field name="domain_force">['|',('partner_id', '=', user.partner_id.id), ('create_uid', '=', user.id)]</field> |
|||
<field name="domain_force">['|',('user_id', '=', user.id), ('create_uid', '=', user.id)]</field> |
|||
</record> |
|||
|
|||
</odoo> |
@ -1,136 +1,109 @@ |
|||
# -*- coding: utf-8 -*- |
|||
# Copyright 2017 Simone Orsi <simone.orsi@camptocamp.com> |
|||
# 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', |
|||
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', |
|||
}) |
|||
self.partner2 = self.partner_model.with_context( |
|||
tracking_disable=1).create({ |
|||
'name': 'Partner 2!', |
|||
'email': 'partner2@test.foo.com', |
|||
cls.user2 = user_model.create({ |
|||
'name': 'User 2', |
|||
'login': 'testuser2', |
|||
'email': 'testuser2@email.com', |
|||
}) |
|||
self.subtype1 = self.subtype_model.create({'name': 'Type 1'}) |
|||
self.subtype2 = self.subtype_model.create({'name': 'Type 2'}) |
|||
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)) |
@ -1,38 +0,0 @@ |
|||
<?xml version="1.0"?> |
|||
<odoo> |
|||
<record id="notifications_emails_partner_info_form" model="ir.ui.view"> |
|||
<field name="name">mail.notifications res.partner.form</field> |
|||
<field name="model">res.partner</field> |
|||
<field name="inherit_id" ref="mail.view_emails_partner_info_form"/> |
|||
<field name="arch" type="xml"> |
|||
<xpath expr="//field[@name='notify_email']" position="after"> |
|||
<field name="notify_conf_ids" attrs="{'invisible': [('notify_email','=', 'none')]}"/> |
|||
</xpath> |
|||
</field> |
|||
</record> |
|||
|
|||
<record model="ir.ui.view" id="notification_form"> |
|||
<field name="name">partner.notification.conf form</field> |
|||
<field name="model">partner.notification.conf</field> |
|||
<field name="arch" type="xml"> |
|||
<form string="Notification"> |
|||
<group name="main"> |
|||
<field name="enabled" /> |
|||
<field name="subtype_id" options="{'no_create': True}" /> |
|||
</group> |
|||
</form> |
|||
</field> |
|||
</record> |
|||
|
|||
<record model="ir.ui.view" id="notification_tree"> |
|||
<field name="name">partner.notification.conf tree</field> |
|||
<field name="model">partner.notification.conf</field> |
|||
<field name="arch" type="xml"> |
|||
<tree string="Notifications" editable="top"> |
|||
<field name="enabled" /> |
|||
<field name="subtype_id" /> |
|||
</tree> |
|||
</field> |
|||
</record> |
|||
|
|||
</odoo> |
@ -0,0 +1,28 @@ |
|||
<?xml version="1.0"?> |
|||
<odoo> |
|||
|
|||
<record model="ir.ui.view" id="notification_form"> |
|||
<field name="name">user.notification.conf form</field> |
|||
<field name="model">user.notification.conf</field> |
|||
<field name="arch" type="xml"> |
|||
<form string="Notification"> |
|||
<group name="main"> |
|||
<field name="enabled" /> |
|||
<field name="subtype_id" options="{'no_create': True}" /> |
|||
</group> |
|||
</form> |
|||
</field> |
|||
</record> |
|||
|
|||
<record model="ir.ui.view" id="notification_tree"> |
|||
<field name="name">user.notification.conf tree</field> |
|||
<field name="model">user.notification.conf</field> |
|||
<field name="arch" type="xml"> |
|||
<tree string="Notifications" editable="top"> |
|||
<field name="enabled" /> |
|||
<field name="subtype_id" /> |
|||
</tree> |
|||
</field> |
|||
</record> |
|||
|
|||
</odoo> |
Write
Preview
Loading…
Cancel
Save
Reference in new issue