[FIX] email_template: various improvements and fixes.

email_template.py: fixed attachments
mail.compose.message: fixed various bugs of onchanges and the use of templates
with the composer. Cleaned and added tests related to the composer using
email_template.
mail.compose.message form view: the use of templates is now for
advanced formatting only.

bzr revid: tde@openerp.com-20120905155626-h6laee191ttnglkh
This commit is contained in:
Thibault Delavallée 2012-09-05 17:56:26 +02:00
parent 9fb978ea81
commit 089b64214d
4 changed files with 139 additions and 105 deletions

View File

@ -99,7 +99,7 @@ class email_template(osv.osv):
mod_name = False
if model_id:
mod_name = self.pool.get('ir.model').browse(cr, uid, model_id, context).model
return {'value':{'model': mod_name}}
return {'value': {'model': mod_name}}
_columns = {
'name': fields.char('Name'),
@ -320,7 +320,7 @@ class email_template(osv.osv):
# Add template attachments
for attach in template.attachment_ids:
attachments.append(attach.datas_fname, attach.datas)
attachments.append((attach.datas_fname, attach.datas))
values['attachments'] = attachments
return values

View File

@ -19,8 +19,8 @@
#
##############################################################################
import base64
from openerp.tests import common
import tools
class test_message_compose(common.TransactionCase):
@ -44,10 +44,12 @@ class test_message_compose(common.TransactionCase):
self.build_email_real = self.registry('ir.mail_server').build_email
self.registry('ir.mail_server').build_email = self._mock_build_email
self.registry('ir.mail_server').send_email = self._mock_smtp_gateway
# create a 'pigs' group that will be used through the various tests
# create a 'pigs' and 'bird' groups that will be used through the various tests
self.group_pigs_id = self.mail_group.create(self.cr, self.uid,
{'name': 'Pigs', 'description': 'Fans of Pigs, unite !'})
self.group_bird_id = self.mail_group.create(self.cr, self.uid,
{'name': 'Bird', 'description': 'I am angry !'})
def test_00_message_compose_wizard(self):
""" Tests designed for the mail.compose.message wizard updated by email_template. """
@ -55,74 +57,116 @@ class test_message_compose(common.TransactionCase):
mail_compose = self.registry('mail.compose.message')
self.res_users.write(cr, uid, [uid], {'signature': 'Admin', 'email': 'a@a.a'})
user_admin = self.res_users.browse(cr, uid, uid)
p_a_id = user_admin.partner_id.id
group_pigs = self.mail_group.browse(cr, uid, self.group_pigs_id)
group_bird_id = self.mail_group.create(cr, uid, {'name': 'Bird', 'description': 'I am angry !'})
group_bird = self.mail_group.browse(cr, uid, group_bird_id)
group_bird = self.mail_group.browse(cr, uid, self.group_bird_id)
# Create template on mail.group
# Mail data
_subject1 = 'Pigs'
_subject2 = 'Bird'
_body_html1 = 'Fans of Pigs, unite !\n<pre>Admin</pre>\n'
_body_html2 = 'I am angry !\n<pre>Admin</pre>\n'
_attachments = [
{'name': 'First', 'datas_fname': 'first.txt', 'datas': base64.b64encode('My first attachment')},
{'name': 'Second', 'datas_fname': 'second.txt', 'datas': base64.b64encode('My second attachment')}
]
_attachments_test = [('first.txt', 'My first attachment'), ('second.txt', 'My second attachment')]
# Create template on mail.group, with attachments
group_model_id = self.registry('ir.model').search(cr, uid, [('model', '=', 'mail.group')])[0]
email_template = self.registry('email.template')
email_template_id = email_template.create(cr, uid, {'model_id': group_model_id,
'name': 'Pigs Template', 'subject': '${object.name}',
'body_html': '${object.description}', 'user_signature': True,
'attachment_ids': [(0, 0, _attachments[0]), (0, 0, _attachments[1])],
'email_to': 'b@b.b c@c.c', 'email_cc': 'd@d.d'})
# Mail data
_subject1 = 'Pigs'
_subject2 = 'Bird'
_body_text1 = 'Pigs rules'
_body_text_html1 = 'Fans of Pigs, unite !\n<pre>Admin</pre>\n'
_body_text2 = 'I am angry !'
_body_text_html2 = 'I am angry !<pre>Admin</pre>'
# ----------------------------------------
# CASE1: comment and save as template
# ----------------------------------------
# CASE1: create in comment
# 1. Comment on pigs
compose_id = mail_compose.create(cr, uid,
{'subject': 'Forget me subject', 'body': '<p>Dummy body</p>'},
{'default_composition_mode': 'comment', 'default_model': 'mail.group',
'default_res_id': self.group_pigs_id,
'default_template_id': email_template_id,
'active_ids': [self.group_pigs_id, self.group_bird_id]})
compose = mail_compose.browse(cr, uid, compose_id)
# 2. Save current composition form as a template
mail_compose.save_as_template(cr, uid, [compose_id], context={'default_model': 'mail.group'})
# Test: email_template subject, body_html, model
last_template_id = email_template.search(cr, uid, [('model', '=', 'mail.group'), ('subject', '=', 'Forget me subject')], limit=1)[0]
self.assertTrue(last_template_id, 'email_template not found for model mail.group, subject Forget me subject')
last_template = email_template.browse(cr, uid, last_template_id)
self.assertEqual(last_template.body_html, '<p>Dummy body</p>', 'email_template incorrect body_html')
# ----------------------------------------
# CASE2: comment with template, save as template
# ----------------------------------------
# 1. Comment on pigs
compose_id = mail_compose.create(cr, uid,
{'subject': 'Forget me subject', 'body': 'Dummy body'},
{'default_composition_mode': 'comment', 'default_model': 'mail.group',
'default_res_id': self.group_pigs_id, 'default_use_template': True,
'active_ids': [self.group_pigs_id, group_bird_id] })
'default_res_id': self.group_pigs_id,
'default_template_id': email_template_id,
'active_ids': [self.group_pigs_id, self.group_bird_id]})
compose = mail_compose.browse(cr, uid, compose_id)
# Perform 'onchange_template_id' with 'use_template' set
values = mail_compose.onchange_template_id(cr, uid, [], compose.use_template, email_template_id, compose.composition_mode, compose.model, compose.res_id)
compose.write(values.get('value', {}), {'default_composition_mode': 'comment', 'default_model': 'mail.group'})
# 2. Perform 'toggle_template', to set use_template and use template_id
mail_compose.toggle_template(cr, uid, [compose_id], {'default_composition_mode': 'comment', 'default_model': 'mail.group'})
compose.refresh()
message_pids = [partner.id for partner in compose.partner_ids]
partner_ids = self.res_partner.search(cr, uid, [('email', 'in', ['b@b.b', 'c@c.c', 'd@d.d'])])
partners = self.res_partner.browse(cr, uid, partner_ids)
# Test: subject, body, partner_ids
# Test: mail.compose.message: subject, body, content_subtype, partner_ids
self.assertEqual(compose.subject, _subject1, 'mail.compose.message subject incorrect')
self.assertEqual(compose.body, _body_text_html1, 'mail.compose.message body incorrect')
self.assertEqual(compose.body, _body_html1, 'mail.compose.message body incorrect')
self.assertEqual(compose.content_subtype, 'html', 'mail.compose.message content_subtype incorrect')
self.assertEqual(set(message_pids), set(partner_ids), 'mail.compose.message partner_ids incorrect')
# Test: mail.compose.message: attachments
# Test: mail.message: attachments
for attach in compose.attachment_ids:
self.assertEqual(attach.res_model, 'mail.group', 'mail.message attachment res_model incorrect')
self.assertEqual(attach.res_id, self.group_pigs_id, 'mail.message attachment res_id incorrect')
self.assertIn((attach.name, base64.b64decode(attach.datas)), _attachments_test,
'mail.message attachment name / data incorrect')
# Perform 'onchange_use_template': use_template is not set anymore
values = mail_compose.onchange_use_template(cr, uid, [], not compose.use_template, compose.template_id, compose.composition_mode, compose.model, compose.res_id)
compose.write(values.get('value', {}), {'default_composition_mode': 'comment', 'default_model': 'mail.group'})
# 3. Perform 'toggle_template': template is not set anymore
mail_compose.toggle_template(cr, uid, [compose_id], {'default_composition_mode': 'comment', 'default_model': 'mail.group'})
compose.refresh()
# Test: subject, body, partner_ids
self.assertEqual(compose.subject, False, 'mail.compose.message subject incorrect')
self.assertEqual(compose.body, '', 'mail.compose.message body incorrect')
# CASE12 create in mass_mail composition
# ----------------------------------------
# CASE3: mass_mail with template
# ----------------------------------------
# 1. Mass_mail on pigs and bird, with a default_partner_ids set to check he is correctly added
compose_id = mail_compose.create(cr, uid,
{'subject': 'Forget me subject', 'body': 'Dummy body'},
{'default_composition_mode': 'mass_mail', 'default_model': 'mail.group',
'default_res_id': -1, 'default_use_template': True,
'active_ids': [self.group_pigs_id, group_bird_id] })
'default_res_id': self.group_pigs_id,
'default_template_id': email_template_id,
'default_partner_ids': [p_a_id],
'active_ids': [self.group_pigs_id, self.group_bird_id]})
compose = mail_compose.browse(cr, uid, compose_id)
# Test 'onchange_template_id' with 'use_template' set
values = mail_compose.onchange_template_id(cr, uid, [], compose.use_template, email_template_id, compose.composition_mode, compose.model, compose.res_id)
print values
# self.assertEqual()
# compose.write(values['value'])
values = mail_compose.onchange_use_template(cr, uid, [], not compose.use_template, compose.template_id, compose.composition_mode, compose.model, compose.res_id)
print values
# 2. Perform 'toggle_template', to set use_template and use template_id
mail_compose.toggle_template(cr, uid, [compose_id], {'default_composition_mode': 'comment', 'default_model': 'mail.group'})
compose.refresh()
message_pids = [partner.id for partner in compose.partner_ids]
partner_ids = [p_a_id]
# Test: mail.compose.message: subject, body, content_subtype, partner_ids
self.assertEqual(compose.subject, '${object.name}', 'mail.compose.message subject incorrect')
self.assertEqual(compose.body, '${object.description}', 'mail.compose.message body incorrect')
self.assertEqual(compose.content_subtype, 'html', 'mail.compose.message content_subtype incorrect')
self.assertEqual(set(message_pids), set(partner_ids), 'mail.compose.message partner_ids incorrect')
# Post the comment, get created message
mail_compose.send_mail(cr, uid, [compose_id], {'default_res_id': -1, 'active_ids': [self.group_pigs_id, group_bird_id]})
# 3. Post the comment, get created message
mail_compose.send_mail(cr, uid, [compose_id], {'default_res_id': -1, 'active_ids': [self.group_pigs_id, self.group_bird_id]})
group_pigs.refresh()
group_bird.refresh()
message_pigs = group_pigs.message_ids[0]
@ -130,9 +174,13 @@ class test_message_compose(common.TransactionCase):
# Test: subject, body
self.assertEqual(message_pigs.subject, _subject1, 'mail.message subject on Pigs incorrect')
self.assertEqual(message_bird.subject, _subject2, 'mail.message subject on Bird incorrect')
self.assertEqual(message_pigs.body, _body_text_html1, 'mail.message body on Pigs incorrect')
self.assertEqual(message_bird.body, _body_text_html2, 'mail.message body on Bird incorrect')
# Test: partner_ids
print message_pigs.partner_ids
print message_pigs.partner_ids
self.assertEqual(len(message_pigs.partner_ids), 6, 'mail.message partner_ids incorrect')
self.assertEqual(message_pigs.body, _body_html1, 'mail.message body on Pigs incorrect')
self.assertEqual(message_bird.body, _body_html2, 'mail.message body on Bird incorrect')
# Test: partner_ids: p_a_id (default) + 3 newly created partners
message_pigs_pids = [partner.id for partner in message_pigs.partner_ids]
message_bird_pids = [partner.id for partner in message_bird.partner_ids]
partner_ids = self.res_partner.search(cr, uid, [('email', 'in', ['b@b.b', 'c@c.c', 'd@d.d'])]) + [p_a_id]
self.assertEqual(len(message_pigs_pids), len(partner_ids), 'mail.message on pigs incorrect number of partner_ids')
self.assertEqual(len(message_bird_pids), len(partner_ids), 'mail.message on bird partner_ids incorrect')
self.assertEqual(set(message_pigs_pids), set(partner_ids), 'mail.message on pigs incorrect number of partner_ids')
self.assertEqual(set(message_bird_pids), set(partner_ids), 'mail.message on bird partner_ids incorrect')

View File

@ -19,22 +19,19 @@
#
##############################################################################
import base64
import tools
from osv import osv
from osv import fields
from tools.translate import _
class mail_compose_message(osv.osv_memory):
_inherit = 'mail.compose.message'
_compose_fields = ['body', 'body_html', 'subject', 'partner_ids', 'attachment_ids']
def _get_templates(self, cr, uid, context=None):
if context is None:
context = {}
model = False
email_template_obj= self.pool.get('email.template')
email_template_obj = self.pool.get('email.template')
message_id = context.get('default_parent_id', context.get('message_id', context.get('active_id')))
if context.get('default_composition_mode') == 'reply' and message_id:
@ -54,6 +51,9 @@ class mail_compose_message(osv.osv_memory):
context = {}
result = super(mail_compose_message, self).default_get(cr, uid, fields, context=context)
result['template_id'] = context.get('default_template_id', context.get('mail.compose.template_id', False))
# force html when using templates
if result.get('use_template'):
result['content_subtype'] = 'html'
return result
_columns = {
@ -67,34 +67,50 @@ class mail_compose_message(osv.osv_memory):
- use_template set in mass_mailing: we cannot render, so return the template values
- use_template set: return rendered values """
if use_template and template_id and composition_mode == 'mass_mail':
values = self.pool.get('email.template').read(cr, uid, template_id, self._compose_fields, context)
values = self.pool.get('email.template').read(cr, uid, template_id, ['subject', 'body_html'], context)
values.pop('id')
elif use_template and template_id:
values = self.generate_email_for_composer(cr, uid, template_id, res_id, context=context)
# transform attachments into attachment_ids
values['attachment_ids'] = []
ir_attach_obj = self.pool.get('ir.attachment')
for attach_fname, attach_datas in values.pop('attachments', []):
data_attach = {
'name': attach_fname,
'datas': attach_datas,
'datas_fname': attach_fname,
'res_model': model,
'res_id': res_id,
}
values['attachment_ids'].append(ir_attach_obj.create(cr, uid, data_attach, context=context))
else:
values = self.default_get(cr, uid, self._compose_fields, context=context)
values = self.default_get(cr, uid, ['body', 'body_html', 'subject', 'partner_ids', 'attachment_ids'], context=context)
if values.get('body_html'):
values['body'] = values.pop('body_html')
values.update(use_template=use_template, template_id=template_id)
return {'value': values}
def toggle_template(self, cr, uid, ids, context=None):
""" hit toggle template mode button: calls onchange_use_template to
emulate an on_change, then writes the value to update the form. """
""" hit toggle template mode button: calls onchange_use_template to
emulate an on_change, then writes the values to update the form. """
for record in self.browse(cr, uid, ids, context=context):
onchange_res = self.onchange_use_template(cr, uid, ids, not record.use_template,
record.template_id, record.composition_mode, record.model, record.res_id, context=context)['value']
record.write(onchange_res.get('value', {}))
record.template_id, record.composition_mode, record.model, record.res_id, context=context).get('value', {})
# update partner_ids and attachment_ids
onchange_res['partner_ids'] = [(4, partner_id) for partner_id in onchange_res.pop('partner_ids', [])]
onchange_res['attachment_ids'] = [(4, attachment_id) for attachment_id in onchange_res.pop('attachment_ids', [])]
record.write(onchange_res)
return True
def onchange_use_template(self, cr, uid, ids, use_template, template_id, composition_mode, model, res_id, context=None):
""" onchange_use_template (values: True or False). If use_template is
False, we do like an onchange with template_id False for values """
False, we do as an onchange with template_id False for values """
values = self.onchange_template_id(cr, uid, ids, use_template,
template_id, composition_mode, model, res_id, context=context)
# force html when using templates
if use_template:
values['content_subtype'] = 'html'
values['value']['content_subtype'] = 'html'
return values
def save_as_template(self, cr, uid, ids, context=None):
@ -112,7 +128,7 @@ class mail_compose_message(osv.osv_memory):
values = {
'name': template_name,
'subject': record.subject or False,
'body': record.body or False,
'body_html': record.body or False,
'model_id': model_id or False,
'attachment_ids': [(6, 0, [att.id for att in record.attachment_ids])]
}
@ -127,61 +143,29 @@ class mail_compose_message(osv.osv_memory):
def generate_email_for_composer(self, cr, uid, template_id, res_id, context=None):
""" Call email_template.generate_email(), get fields relevant for
mail.compose.message, transform email_cc and email_to into partner_ids """
fields = ['body', 'body_html', 'subject', 'email_to', 'email_cc', 'attachment_ids']
template_values = self.pool.get('email.template').generate_email(cr, uid, template_id, res_id, context=context)
values = {field: template_values[field] for field in fields if template_values.get(field)}
# filter template values
fields = ['body', 'body_html', 'subject', 'email_to', 'email_cc', 'attachments']
values = dict((field, template_values[field]) for field in fields if template_values.get(field))
values['body'] = values.pop('body_html', '')
# transform email_to, email_cc into partner_ids
values['partner_ids'] = []
mails = tools.email_split(values.pop('email_to', '') + ' ' + values.pop('email_cc', ''))
for mail in mails:
partner_search_ids = self.pool.get('res.partner').search(cr, uid, [('email', 'ilike', mail)], context=context)
if partner_search_ids:
values['partner_ids'].append((4, partner_search_ids[0]))
else:
partner_id = self.pool.get('res.partner').name_create(cr, uid, mail, context=context)[0]
partner = self.pool.get('res.partner').browse(cr, uid, partner_id, context=context)
values['partner_ids'].append((4, partner_id))
# transform attachments into attachment_ids
values['attachment_ids'] = []
for attach_fname, attach_datas in template_values.get('attachments', []):
data_attach = {
'name': attach_fname,
'datas': attach_datas,
'datas_fname': attach_fname,
'res_model': model,
'res_id': res_id,
}
values['attachment_ids'].append((0, 0, data_attach))
partner_id = self.pool.get('res.partner').find_or_create(cr, uid, mail, context=context)
values['partner_ids'].append(partner_id)
return values
def render_message(self, cr, uid, wizard, model, res_id, context=None):
def render_message(self, cr, uid, wizard, res_id, context=None):
""" Generate an email from the template for given (model, res_id) pair.
This method is meant to be inherited by email_template that will
produce a more complete dictionary, with email_to, ...
"""
# render the template to get the email
fields = ['body', 'body_html', 'subject', 'email_to', 'email_cc', 'partner_ids', 'attachment_ids']
template_values = self.pool.get('email.template').generate_email(cr, uid, wizard.template_id, res_id, context=context)
template_values = {field: template_values[field] for field in fields if template_values.get(field)}
# transform email_to, email_cc into partner_ids
partner_ids = []
mails = tools.email_split(template_values.pop('email_to', '') + ' ' + template_values.pop('email_cc', ''))
for mail in mails:
partner_search_ids = self.pool.get('res.partner').search(cr, uid, [('email', 'ilike', mail)], context=context)
if partner_search_ids:
partner_ids.append((4, partner_search_ids[0]))
else:
partner_id = self.pool.get('res.partner').name_create(cr, uid, mail, context=context)[0]
partner = self.pool.get('res.partner').browse(cr, uid, partner_id, context=context)
partner_ids.append((4, partner_id))
# generate the composer email
values = self.generate_email_for_composer(cr, uid, wizard.template_id, res_id, context=context)
# get values to return
email_dict = super(mail_compose_message, self).render_message(cr, uid, wizard, model, res_id, context)
email_dict.update(template_values, partner_ids=partner_ids)
email_dict = super(mail_compose_message, self).render_message(cr, uid, wizard, res_id, context)
email_dict.update(values)
return email_dict
def render_template(self, cr, uid, template, model, res_id, context=None):

View File

@ -42,10 +42,12 @@
<xpath expr="//button[@class='oe_mail_compose_message_attachment']" position="before">
<button icon="/email_template/static/src/img/email_template.png"
type="object" name="toggle_template" string=""
help="Use a message template"/>
help="Use a message template"
attrs="{'invisible':[('content_subtype','!=','html')]}"/>
<button icon="/email_template/static/src/img/email_template_save.png"
type="object" name="save_as_template" string=""
help="Save as a new template"/>
help="Save as a new template"
attrs="{'invisible':[('content_subtype','!=','html')]}"/>
</xpath>
</data>
</field>