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)

Reply via email to