changeset e356d97a0f59 in trytond:default
details: https://hg.tryton.org/trytond?cmd=changeset;node=e356d97a0f59
description:
Add optional PYSON recipients to email template
issue9617
review306401002
diffstat:
trytond/ir/email_.py | 103 +++++++++++++++++++++++++++----
trytond/ir/message.xml | 6 +
trytond/ir/view/email_template_form.xml | 21 ++++-
trytond/tests/test_ir.py | 39 ++++++++++++
4 files changed, 148 insertions(+), 21 deletions(-)
diffs (277 lines):
diff -r 8f06869ba27d -r e356d97a0f59 trytond/ir/email_.py
--- a/trytond/ir/email_.py Fri Oct 09 21:21:33 2020 +0200
+++ b/trytond/ir/email_.py Sun Oct 11 13:32:18 2020 +0200
@@ -19,10 +19,10 @@
from trytond.i18n import gettext
from trytond.config import config
-from trytond.model import ModelSQL, ModelView, fields
+from trytond.model import ModelSQL, ModelView, fields, EvalEnvironment
from trytond.model.exceptions import ValidationError, AccessError
from trytond.pool import Pool
-from trytond.pyson import Eval
+from trytond.pyson import Eval, Bool, PYSONDecoder
from trytond.rpc import RPC
from trytond.sendmail import sendmail_transactional, SMTPDataManager
from trytond.tools import escape_wildcard
@@ -255,22 +255,55 @@
domain=[
('model', '=', Eval('model')),
],
- depends=['model'],
+ states={
+ 'invisible': Bool(Eval('recipients_pyson')),
+ },
+ depends=['model', 'recipients_pyson'],
help="The field that contains the recipient(s).")
+ recipients_pyson = fields.Char(
+ "Recipients",
+ states={
+ 'invisible': Bool(Eval('recipients')),
+ },
+ depends=['recipients'],
+ help="A PYSON expression that generates a list of recipients"
+ 'with the record represented by "self".')
recipients_secondary = fields.Many2One(
'ir.model.field', "Secondary Recipients",
domain=[
('model', '=', Eval('model')),
],
- depends=['model'],
+ states={
+ 'invisible': Bool(Eval('recipients_secondary_pyson')),
+ },
+ depends=['model', 'recipients_secondary_pyson'],
help="The field that contains the secondary recipient(s).")
+ recipients_secondary_pyson = fields.Char(
+ "Secondary Recipients",
+ states={
+ 'invisible': Bool(Eval('recipients_secondary')),
+ },
+ depends=['recipients_secondary'],
+ help="A PYSON expression that generates a list of secondary recipients"
+ 'with the record represented by "self".')
recipients_hidden = fields.Many2One(
'ir.model.field', "Hidden Recipients",
domain=[
('model', '=', Eval('model')),
],
- depends=['model'],
+ states={
+ 'invisible': Bool(Eval('recipients_hidden_pyson')),
+ },
+ depends=['model', 'recipients_hidden_pyson'],
help="The field that contains the secondary recipient(s).")
+ recipients_hidden_pyson = fields.Char(
+ "Hidden Recipients",
+ states={
+ 'invisible': Bool(Eval('recipients_hidden')),
+ },
+ depends=['recipients_hidden'],
+ help="A PYSON expression that generates a list of hidden recipients"
+ 'with the record represented by "self".')
subject = fields.Char("Subject", translate=True)
body = fields.Text("Body", translate=True)
reports = fields.Many2Many(
@@ -316,6 +349,7 @@
for template in templates:
template.check_subject()
template.check_body()
+ template.check_fields_pyson()
def check_subject(self):
if not self.subject:
@@ -339,27 +373,57 @@
template=self.rec_name,
exception=exception)) from exception
+ def check_fields_pyson(self):
+ encoder = PYSONDecoder(noeval=True)
+ for field in [
+ 'recipients_pyson',
+ 'recipients_secondary_pyson',
+ 'recipients_hidden_pyson',
+ ]:
+ value = getattr(self, field)
+ if not value:
+ continue
+ try:
+ pyson = encoder.decode(value)
+ except Exception as exception:
+ raise EmailTemplateError(
+ gettext('ir.msg_email_template_invalid_field_pyson',
+ template=self.rec_name,
+ field=self.__names__(field)['field'],
+ exception=exception)) from exception
+ if not isinstance(pyson, list) and pyson.types() != {list}:
+ raise EmailTemplateError(
+ gettext('ir.msg_email_template_invalid_field_pyson_type',
+ template=self.rec_name,
+ field=self.__names__(field)['field'],
+ ))
+
def get(self, record):
pool = Pool()
Model = pool.get(self.model.model)
record = Model(int(record))
values = {}
- for field, key in [
+ for attr, key in [
('recipients', 'to'),
('recipients_secondary', 'cc'),
('recipients_hidden', 'bcc'),
]:
- field = getattr(self, field)
- if not field:
- continue
+ field = getattr(self, attr)
try:
- if field.name == 'id':
- value = record
+ if field:
+ if field.name == 'id':
+ value = record
+ else:
+ value = getattr(record, field.name, None)
+ if value:
+ values[key] = self.get_addresses(value)
else:
- value = getattr(record, field.name, None)
- if value:
- values[key] = self.get_addresses(value)
+ value = getattr(self, attr + '_pyson')
+ if value:
+ value = self.eval(record, value)
+ if value:
+ values[key] = self.get_addresses(value)
except AccessError:
continue
@@ -381,6 +445,13 @@
values['reports'] = [r.id for r in self.reports]
return values
+ def eval(self, record, pyson):
+ 'Evaluate the pyson with the record'
+ env = {}
+ env['context'] = Transaction().context
+ env['self'] = EvalEnvironment(record, record.__class__)
+ return PYSONDecoder(env).decode(pyson)
+
@classmethod
def _get_default_exclude(cls, record):
return ['create_uid', 'write_uid']
@@ -441,7 +512,9 @@
def _get_address(cls, record):
pool = Pool()
User = pool.get('res.user')
- if isinstance(record, User) and record.email:
+ if isinstance(record, str):
+ return (None, record)
+ elif isinstance(record, User) and record.email:
return (record.name, record.email)
@classmethod
diff -r 8f06869ba27d -r e356d97a0f59 trytond/ir/message.xml
--- a/trytond/ir/message.xml Fri Oct 09 21:21:33 2020 +0200
+++ b/trytond/ir/message.xml Sun Oct 11 13:32:18 2020 +0200
@@ -323,5 +323,11 @@
<record model="ir.message" id="msg_email_template_invalid_body">
<field name="text">Invalid body in e-mail template "%(template)s"
with exception "%(exception)s"</field>
</record>
+ <record model="ir.message" id="msg_email_template_invalid_field_pyson">
+ <field name="text">Invalid PYSON %(field)s in e-mail template
"%(template)s" with exception "%(exception)s".</field>
+ </record>
+ <record model="ir.message"
id="msg_email_template_invalid_field_pyson_type">
+ <field name="text">The PYSON %(field)s in e-mail template
"%(template)s" must generate a list.</field>
+ </record>
</data>
</tryton>
diff -r 8f06869ba27d -r e356d97a0f59 trytond/ir/view/email_template_form.xml
--- a/trytond/ir/view/email_template_form.xml Fri Oct 09 21:21:33 2020 +0200
+++ b/trytond/ir/view/email_template_form.xml Sun Oct 11 13:32:18 2020 +0200
@@ -6,12 +6,21 @@
<field name="name"/>
<label name="model"/>
<field name="model"/>
- <label name="recipients"/>
- <field name="recipients" colspan="3"/>
- <label name="recipients_secondary"/>
- <field name="recipients_secondary" colspan="3"/>
- <label name="recipients_hidden"/>
- <field name="recipients_hidden" colspan="3"/>
+ <label id="recipients_label" string="Recipients:"/>
+ <group id="recipients" col="-1" colspan="3">
+ <field name="recipients"/>
+ <field name="recipients_pyson" widget="pyson"/>
+ </group>
+ <label id="recipients_secondary_label" string="Secondary Recipients:"/>
+ <group id="recipients_secondary" col="-1" colspan="3">
+ <field name="recipients_secondary"/>
+ <field name="recipients_secondary_pyson"/>
+ </group>
+ <label id="recipients_hidden_label" string="Hidden Recipients:"/>
+ <group id="recipients_hidden" col="-1" colspan="3">
+ <field name="recipients_hidden"/>
+ <field name="recipients_hidden_pyson"/>
+ </group>
<label name="subject"/>
<field name="subject" colspan="3"/>
<separator name="body" colspan="4"/>
diff -r 8f06869ba27d -r e356d97a0f59 trytond/tests/test_ir.py
--- a/trytond/tests/test_ir.py Fri Oct 09 21:21:33 2020 +0200
+++ b/trytond/tests/test_ir.py Sun Oct 11 13:32:18 2020 +0200
@@ -9,6 +9,7 @@
from trytond.config import config
from trytond.pool import Pool
+from trytond.pyson import Eval, If, PYSONEncoder
from trytond.transaction import Transaction
from .test_tryton import ModuleTestCase, with_transaction
@@ -246,6 +247,44 @@
'subject': "User: Administrator",
})
+ @with_transaction()
+ def test_email_template_get_pyson(self):
+ "Test email template get with pyson"
+ pool = Pool()
+ Template = pool.get('ir.email.template')
+ IrModel = pool.get('ir.model')
+ IrModelField = pool.get('ir.model.field')
+ User = pool.get('res.user')
+
+ admin = User(1)
+ admin.email = '[email protected]'
+ admin.save()
+ model, = IrModel.search([('model', '=', 'res.user')])
+ field, = IrModelField.search([
+ ('model', '=', model.id),
+ ('name', '=', 'id'),
+ ])
+
+ template = Template(
+ model=model,
+ name="Test",
+ recipients_pyson=PYSONEncoder().encode(
+ [Eval('self.email')]),
+ recipients_secondary_pyson=PYSONEncoder().encode(
+ If(Eval('self.email'),
+ ['[email protected]'],
+ [])),
+ )
+ template.save()
+
+ values = template.get(admin)
+
+ self.assertEqual(
+ values, {
+ 'to': ['[email protected]'],
+ 'cc': ['[email protected]'],
+ })
+
def suite():
return unittest.TestLoader().loadTestsFromTestCase(IrTestCase)