f2dbfc173c37840d885046efbdba0d85e612e50b
[odoo/odoo.git] / addons / email_template / wizard / mail_compose_message.py
1 # -*- coding: utf-8 -*-
2 ##############################################################################
3 #
4 #    OpenERP, Open Source Management Solution
5 #    Copyright (C) 2010-Today OpenERP SA (<http://www.openerp.com>)
6 #
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.
11 #
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.
16 #
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/>
19 #
20 ##############################################################################
21
22 from openerp import tools, SUPERUSER_ID
23 from openerp.osv import osv, fields
24
25
26 def _reopen(self, res_id, model):
27     return {'type': 'ir.actions.act_window',
28             'view_mode': 'form',
29             'view_type': 'form',
30             'res_id': res_id,
31             'res_model': self._name,
32             'target': 'new',
33             # save original model in context, because selecting the list of available
34             # templates requires a model in context
35             'context': {
36                 'default_model': model,
37             },
38             }
39
40
41 class mail_compose_message(osv.TransientModel):
42     _inherit = 'mail.compose.message'
43
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 """
46         if context is None:
47             context = {}
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'):
50             res.update(
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
54                 )['value']
55             )
56         return res
57
58     _columns = {
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)"),
66     }
67
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. """
73         if context is None:
74             context = {}
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:
81                 continue
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))
86                 else:
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)
90
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)
106         elif template_id:
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', []):
113                 data_attach = {
114                     'name': attach_fname,
115                     'datas': attach_datas,
116                     'datas_fname': attach_fname,
117                     'res_model': 'mail.compose.message',
118                     'res_id': 0,
119                     'type': 'binary',  # override default_type from context, possibly meant for another model!
120                 }
121                 values['attachment_ids'].append(ir_attach_obj.create(cr, uid, data_attach, context=context))
122         else:
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)
124
125         if values.get('body_html'):
126             values['body'] = values.pop('body_html')
127         return {'value': values}
128
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
137             model_name = ''
138             if model_id:
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))
141             values = {
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])],
147             }
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)
154
155     #------------------------------------------------------
156     # Wizard validation and send
157     #------------------------------------------------------
158
159     def _get_or_create_partners_from_values(self, cr, uid, rendered_values, context=None):
160         """ Check for email_to, email_cc, partner_to """
161         partner_ids = []
162         mails = tools.email_split(rendered_values.pop('email_to', '')) + tools.email_split(rendered_values.pop('email_cc', ''))
163         for mail in mails:
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', '')
167         if 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)
171         return partner_ids
172
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
177         if fields is None:
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)
181
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', '')
186
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
192             if partner_ids:
193                 res_id_values['partner_ids'] = list(partner_ids)
194
195             values[res_id] = res_id_values
196         return values
197
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'],
205                 context=context)
206         else:
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)
210
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
221
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)
224
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]
228
229 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: