1 # -*- coding: utf-8 -*-
2 ##############################################################################
4 # OpenERP, Open Source Management Solution
5 # Copyright (C) 2010-Today OpenERP SA (<http://www.openerp.com>)
7 # This program is free software: you can redistribute it and/or modify
8 # it under the terms of the GNU General Public License as published by
9 # the Free Software Foundation, either version 3 of the License, or
10 # (at your option) any later version.
12 # This program is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 # GNU General Public License for more details.
17 # You should have received a copy of the GNU General Public License
18 # along with this program. If not, see <http://www.gnu.org/licenses/>
20 ##############################################################################
22 from openerp import tools, SUPERUSER_ID
23 from openerp.osv import osv, fields
26 def _reopen(self, res_id, model):
27 return {'type': 'ir.actions.act_window',
31 'res_model': self._name,
33 # save original model in context, because selecting the list of available
34 # templates requires a model in context
36 'default_model': model,
41 class mail_compose_message(osv.TransientModel):
42 _inherit = 'mail.compose.message'
44 def default_get(self, cr, uid, fields, context=None):
45 """ Override to pre-fill the data when having a template in single-email mode """
48 res = super(mail_compose_message, self).default_get(cr, uid, fields, context=context)
49 if res.get('composition_mode') != 'mass_mail' and context.get('default_template_id') and res.get('model') and res.get('res_id'):
51 self.onchange_template_id(
52 cr, uid, [], context['default_template_id'], res.get('composition_mode'),
53 res.get('model'), res.get('res_id', context.get('active_id')), context=context
59 'template_id': fields.many2one('email.template', 'Use template', select=True),
60 'partner_to': fields.char('To (Partner IDs)',
61 help="Comma-separated list of recipient partners ids (placeholders may be used here)"),
62 'email_to': fields.char('To (Emails)',
63 help="Comma-separated recipient addresses (placeholders may be used here)",),
64 'email_cc': fields.char('Cc (Emails)',
65 help="Carbon copy recipients (placeholders may be used here)"),
68 def send_mail(self, cr, uid, ids, context=None):
69 """ Override of send_mail to duplicate attachments linked to the email.template.
70 Indeed, basic mail.compose.message wizard duplicates attachments in mass
71 mailing mode. But in 'single post' mode, attachments of an email template
72 also have to be duplicated to avoid changing their ownership. """
75 wizard_context = dict(context)
76 for wizard in self.browse(cr, uid, ids, context=context):
77 if wizard.template_id:
78 wizard_context['mail_notify_user_signature'] = False # template user_signature is added when generating body_html
79 wizard_context['mail_auto_delete'] = wizard.template_id.auto_delete # mass mailing: use template auto_delete value -> note, for emails mass mailing only
80 if not wizard.attachment_ids or wizard.composition_mode == 'mass_mail' or not wizard.template_id:
82 new_attachment_ids = []
83 for attachment in wizard.attachment_ids:
84 if attachment in wizard.template_id.attachment_ids:
85 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))
87 new_attachment_ids.append(attachment.id)
88 self.write(cr, uid, wizard.id, {'attachment_ids': [(6, 0, new_attachment_ids)]}, context=context)
89 return super(mail_compose_message, self).send_mail(cr, uid, ids, context=wizard_context)
91 def onchange_template_id(self, cr, uid, ids, template_id, composition_mode, model, res_id, context=None):
92 """ - mass_mailing: we cannot render, so return the template values
93 - normal mode: return rendered values """
94 if template_id and composition_mode == 'mass_mail':
95 fields = ['subject', 'body_html', 'email_from', 'email_to', 'partner_to', 'email_cc', 'reply_to']
96 template = self.pool['email.template'].browse(cr, uid, template_id, context=context)
97 values = dict((field, getattr(template, field)) for field in fields if getattr(template, field))
98 print values, template.user_signature
99 if template.attachment_ids:
100 values['attachment_ids'] = [att.id for att in template.attachment_ids]
101 if template.mail_server_id:
102 values['mail_server_id'] = template.mail_server_id.id
103 if template.user_signature and 'body_html' in values:
104 signature = self.pool.get('res.users').browse(cr, uid, uid, context).signature
105 values['body_html'] = tools.append_content_to_html(values['body_html'], signature)
107 values = self.generate_email_for_composer_batch(cr, uid, template_id, [res_id], context=context)[res_id]
108 # transform attachments into attachment_ids; not attached to the document because this will
109 # be done further in the posting process, allowing to clean database if email not send
110 values['attachment_ids'] = values.pop('attachment_ids', [])
111 ir_attach_obj = self.pool.get('ir.attachment')
112 for attach_fname, attach_datas in values.pop('attachments', []):
114 'name': attach_fname,
115 'datas': attach_datas,
116 'datas_fname': attach_fname,
117 'res_model': 'mail.compose.message',
119 'type': 'binary', # override default_type from context, possibly meant for another model!
121 values['attachment_ids'].append(ir_attach_obj.create(cr, uid, data_attach, context=context))
123 values = self.default_get(cr, uid, ['subject', 'body', 'email_from', 'email_to', 'email_cc', 'partner_to', 'reply_to', 'attachment_ids', 'mail_server_id'], context=context)
125 if values.get('body_html'):
126 values['body'] = values.pop('body_html')
127 return {'value': values}
129 def save_as_template(self, cr, uid, ids, context=None):
130 """ hit save as template button: current form value will be a new
131 template attached to the current document. """
132 email_template = self.pool.get('email.template')
133 ir_model_pool = self.pool.get('ir.model')
134 for record in self.browse(cr, uid, ids, context=context):
135 model_ids = ir_model_pool.search(cr, uid, [('model', '=', record.model)], context=context)
136 model_id = model_ids and model_ids[0] or False
139 model_name = ir_model_pool.browse(cr, uid, model_id, context=context).name
140 template_name = "%s: %s" % (model_name, tools.ustr(record.subject))
142 'name': template_name,
143 'subject': record.subject or False,
144 'body_html': record.body or False,
145 'model_id': model_id or False,
146 'attachment_ids': [(6, 0, [att.id for att in record.attachment_ids])],
148 template_id = email_template.create(cr, uid, values, context=context)
149 # generate the saved template
150 template_values = record.onchange_template_id(template_id, record.composition_mode, record.model, record.res_id)['value']
151 template_values['template_id'] = template_id
152 record.write(template_values)
153 return _reopen(self, record.id, record.model)
155 #------------------------------------------------------
156 # Wizard validation and send
157 #------------------------------------------------------
159 def _get_or_create_partners_from_values(self, cr, uid, rendered_values, context=None):
160 """ Check for email_to, email_cc, partner_to """
162 mails = tools.email_split(rendered_values.pop('email_to', '')) + tools.email_split(rendered_values.pop('email_cc', ''))
164 partner_id = self.pool.get('res.partner').find_or_create(cr, uid, mail, context=context)
165 partner_ids.append(partner_id)
166 partner_to = rendered_values.pop('partner_to', '')
168 # placeholders could generate '', 3, 2 due to some empty field values
169 tpl_partner_ids = [pid for pid in partner_to.split(',') if pid]
170 partner_ids += self.pool['res.partner'].exists(cr, SUPERUSER_ID, tpl_partner_ids, context=context)
173 def generate_email_for_composer_batch(self, cr, uid, template_id, res_ids, context=None, fields=None):
174 """ Call email_template.generate_email(), get fields relevant for
175 mail.compose.message, transform email_cc and email_to into partner_ids """
176 # filter template values
178 fields = ['subject', 'body_html', 'email_from', 'email_to', 'partner_to', 'email_cc', 'reply_to', 'attachment_ids', 'mail_server_id']
179 returned_fields = fields + ['attachments']
180 values = dict.fromkeys(res_ids, False)
182 template_values = self.pool.get('email.template').generate_email_batch(cr, uid, template_id, res_ids, fields=fields, context=context)
183 for res_id in res_ids:
184 res_id_values = dict((field, template_values[res_id][field]) for field in returned_fields if template_values[res_id].get(field))
185 res_id_values['body'] = res_id_values.pop('body_html', '')
187 # transform email_to, email_cc into partner_ids
188 ctx = dict((k, v) for k, v in (context or {}).items() if not k.startswith('default_'))
189 partner_ids = self._get_or_create_partners_from_values(cr, uid, res_id_values, context=ctx)
190 # legacy template behavior: void values do not erase existing values and the
191 # related key is removed from the values dict
193 res_id_values['partner_ids'] = list(partner_ids)
195 values[res_id] = res_id_values
198 def render_message_batch(self, cr, uid, wizard, res_ids, context=None):
199 """ Override to handle templates. """
200 # generate template-based values
201 if wizard.template_id:
202 template_values = self.generate_email_for_composer_batch(
203 cr, uid, wizard.template_id.id, res_ids,
204 fields=['email_to', 'partner_to', 'email_cc', 'attachment_ids', 'mail_server_id'],
207 template_values = dict.fromkeys(res_ids, dict())
208 # generate composer values
209 composer_values = super(mail_compose_message, self).render_message_batch(cr, uid, wizard, res_ids, context)
211 for res_id in res_ids:
212 # remove attachments from template values as they should not be rendered
213 template_values[res_id].pop('attachment_ids', None)
214 # remove some keys from composer that are readonly
215 composer_values[res_id].pop('email_to', None)
216 composer_values[res_id].pop('email_cc', None)
217 composer_values[res_id].pop('partner_to', None)
218 # update template values by composer values
219 template_values[res_id].update(composer_values[res_id])
220 return template_values
222 def render_template_batch(self, cr, uid, template, model, res_ids, context=None, post_process=False):
223 return self.pool.get('email.template').render_template_batch(cr, uid, template, model, res_ids, context=context, post_process=post_process)
225 # Compatibility methods
226 def generate_email_for_composer(self, cr, uid, template_id, res_id, context=None):
227 return self.generate_email_for_composer_batch(cr, uid, template_id, [res_id], context)[res_id]
229 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: