diff --git a/addons/email_template/email_template.py b/addons/email_template/email_template.py
index 08ef3ec6e98..a602a447867 100644
--- a/addons/email_template/email_template.py
+++ b/addons/email_template/email_template.py
@@ -295,8 +295,7 @@ class email_template(osv.osv):
'copyvalue': self.build_expression(field_value.name, False, null_value or False),
'null_value': null_value or False
})
- return {'value':result}
-
+ return {'value': result}
def generate_email(self, cr, uid, template_id, res_id, context=None):
"""Generates an email from the template for given (model, res_id) pair.
@@ -349,11 +348,13 @@ class email_template(osv.osv):
report_name += ext
attachments.append((report_name, result))
+ attachment_ids = []
# Add template attachments
for attach in template.attachment_ids:
- attachments.append((attach.datas_fname, attach.datas))
+ attachment_ids.append(attach.id)
values['attachments'] = attachments
+ values['attachment_ids'] = attachment_ids
return values
def send_mail(self, cr, uid, template_id, res_id, force_send=False, context=None):
@@ -368,28 +369,34 @@ class email_template(osv.osv):
was executed for this message only.
:returns: id of the mail.message that was created
"""
- if context is None: context = {}
+ if context is None:
+ context = {}
mail_mail = self.pool.get('mail.mail')
ir_attachment = self.pool.get('ir.attachment')
+
+ # create a mail_mail based on values, without attachments
values = self.generate_email(cr, uid, template_id, res_id, context=context)
- assert 'email_from' in values, 'email_from is missing or empty after template rendering, send_mail() cannot proceed'
- attachments = values.pop('attachments') or {}
- del values['email_recipients'] # TODO Properly use them.
+ assert values.get('email_from'), 'email_from is missing or empty after template rendering, send_mail() cannot proceed'
+ del values['email_recipients'] # TODO Properly use them.
+ attachment_ids = values.pop('attachment_ids', [])
+ attachments = values.pop('attachments', [])
msg_id = mail_mail.create(cr, uid, values, context=context)
- # link attachments
- attachment_ids = []
- for fname, fcontent in attachments.iteritems():
+
+ # manage attachments
+ for attachment in attachments:
attachment_data = {
- 'name': fname,
- 'datas_fname': fname,
- 'datas': fcontent,
- 'res_model': mail_mail._name,
+ 'name': attachment[0],
+ 'datas_fname': attachment[0],
+ 'datas': attachment[1],
+ 'res_model': 'mail.message',
'res_id': msg_id,
}
context.pop('default_type', None)
attachment_ids.append(ir_attachment.create(cr, uid, attachment_data, context=context))
if attachment_ids:
+ values['attachment_ids'] = [(6, 0, attachment_ids)]
mail_mail.write(cr, uid, msg_id, {'attachment_ids': [(6, 0, attachment_ids)]}, context=context)
+
if force_send:
mail_mail.send(cr, uid, [msg_id], context=context)
return msg_id
diff --git a/addons/email_template/tests/test_mail.py b/addons/email_template/tests/test_mail.py
index b87b6d63000..a4ecb9b6f91 100644
--- a/addons/email_template/tests/test_mail.py
+++ b/addons/email_template/tests/test_mail.py
@@ -48,8 +48,8 @@ class test_message_compose(TestMailBase):
_body_html1 = 'Fans of Pigs, unite !'
_body_html2 = 'I am angry !'
_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')}
+ {'name': 'First', 'datas_fname': 'first.txt', 'datas': base64.b64encode('My first attachment'), 'res_model': 'res.partner', 'res_id': self.partner_admin_id},
+ {'name': 'Second', 'datas_fname': 'second.txt', 'datas': base64.b64encode('My second attachment'), 'res_model': 'res.partner', 'res_id': self.partner_admin_id},
]
_attachments_test = [('first.txt', 'My first attachment'), ('second.txt', 'My second attachment')]
@@ -115,12 +115,20 @@ class test_message_compose(TestMailBase):
self.assertEqual(compose.subject, _subject1, 'mail.compose.message subject incorrect')
self.assertIn(_body_html1, compose.body, 'mail.compose.message body incorrect')
self.assertEqual(set(message_pids), set(partner_ids), 'mail.compose.message partner_ids incorrect')
- # Test: mail.compose.message: attachments
- # Test: mail.message: attachments
+ # Test: mail.compose.message: attachments (owner has not been modified)
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,
+ self.assertEqual(attach.res_model, 'res.partner', 'mail.compose.message attachment res_model through templat was overriden')
+ self.assertEqual(attach.res_id, self.partner_admin_id, 'mail.compose.message attachment res_id incorrect')
+ self.assertIn((attach.datas_fname, base64.b64decode(attach.datas)), _attachments_test,
+ 'mail.message attachment name / data incorrect')
+ # Test: mail.message: attachments
+ mail_compose.send_mail(cr, uid, [compose_id])
+ group_pigs.refresh()
+ message_pigs = group_pigs.message_ids[0]
+ for attach in message_pigs.attachment_ids:
+ self.assertEqual(attach.res_model, 'mail.group', 'mail.compose.message attachment res_model through templat was overriden')
+ self.assertEqual(attach.res_id, self.group_pigs_id, 'mail.compose.message attachment res_id incorrect')
+ self.assertIn((attach.datas_fname, base64.b64decode(attach.datas)), _attachments_test,
'mail.message attachment name / data incorrect')
# ----------------------------------------
diff --git a/addons/email_template/wizard/mail_compose_message.py b/addons/email_template/wizard/mail_compose_message.py
index 255f93998a2..2e051338352 100644
--- a/addons/email_template/wizard/mail_compose_message.py
+++ b/addons/email_template/wizard/mail_compose_message.py
@@ -61,25 +61,43 @@ class mail_compose_message(osv.TransientModel):
'template_id': fields.selection(_get_templates, 'Template', size=-1),
}
+ def send_mail(self, cr, uid, ids, context=None):
+ """ Override of send_mail to duplicate attachments linked to the email.template.
+ Indeed, basic mail.compose.message wizard duplicates attachments in mass
+ mailing mode. But in 'single post' mode, attachments of an email template
+ also have to be duplicated to avoid changing their ownership. """
+ for wizard in self.browse(cr, uid, ids, context=context):
+ if not wizard.attachment_ids or wizard.composition_mode == 'mass_mail' or not wizard.template_id:
+ continue
+ template = self.pool.get('email.template').browse(cr, uid, wizard.template_id, context=context)
+ new_attachment_ids = []
+ for attachment in wizard.attachment_ids:
+ if attachment in template.attachment_ids:
+ new_attachment_ids.append(self.pool.get('ir.attachment').copy(cr, uid, attachment.id, {'res_model': 'mail.compose.message', 'res_id': wizard.id}, context=context))
+ else:
+ new_attachment_ids.append(attachment.id)
+ self.write(cr, uid, wizard.id, {'attachment_ids': [(6, 0, new_attachment_ids)]}, context=context)
+ return super(mail_compose_message, self).send_mail(cr, uid, ids, context=context)
+
def onchange_template_id(self, cr, uid, ids, template_id, composition_mode, model, res_id, context=None):
""" - mass_mailing: we cannot render, so return the template values
- normal mode: return rendered values """
if template_id and composition_mode == 'mass_mail':
- values = self.pool.get('email.template').read(cr, uid, template_id, ['subject', 'body_html'], context)
+ values = self.pool.get('email.template').read(cr, uid, template_id, ['subject', 'body_html', 'attachment_ids'], context)
values.pop('id')
elif template_id:
- # FIXME odo: change the mail generation to avoid attachment duplication
values = self.generate_email_for_composer(cr, uid, template_id, res_id, context=context)
- # transform attachments into attachment_ids
- values['attachment_ids'] = []
+ # transform attachments into attachment_ids; not attached to the document because this will
+ # be done further in the posting process, allowing to clean database if email not send
+ values['attachment_ids'] = values.pop('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,
+ 'res_model': 'mail.compose.message',
+ 'res_id': 0,
'type': 'binary', # override default_type from context, possibly meant for another model!
}
values['attachment_ids'].append(ir_attach_obj.create(cr, uid, data_attach, context=context))
@@ -122,7 +140,7 @@ class mail_compose_message(osv.TransientModel):
mail.compose.message, transform email_cc and email_to into partner_ids """
template_values = self.pool.get('email.template').generate_email(cr, uid, template_id, res_id, context=context)
# filter template values
- fields = ['body_html', 'subject', 'email_to', 'email_recipients', 'email_cc', 'attachments']
+ fields = ['body_html', 'subject', 'email_to', 'email_recipients', 'email_cc', 'attachment_ids', 'attachments']
values = dict((field, template_values[field]) for field in fields if template_values.get(field))
values['body'] = values.pop('body_html', '')
@@ -151,6 +169,8 @@ class mail_compose_message(osv.TransientModel):
values = self.generate_email_for_composer(cr, uid, wizard.template_id, res_id, context=context)
else:
values = {}
+ # remove attachments as they should not be rendered
+ values.pop('attachment_ids', None)
# get values to return
email_dict = super(mail_compose_message, self).render_message(cr, uid, wizard, res_id, context)
values.update(email_dict)
diff --git a/addons/mail/data/mail_data.xml b/addons/mail/data/mail_data.xml
index 3f517ee7858..02cfd626768 100644
--- a/addons/mail/data/mail_data.xml
+++ b/addons/mail/data/mail_data.xml
@@ -27,6 +27,19 @@
1000
+
+ Garbage Collect Mail Attachments
+
+
+ 1
+ weeks
+ -1
+
+ mail.thread
+ _garbage_collect_attachments
+ ()
+
+