[ADD]: Quote roller module
[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
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         """
46         """
47         if context is None:
48             context = {}
49         res = super(mail_compose_message, self).default_get(cr, uid, fields, context=context)
50         if context.get('default_template_id'):
51             res.update(
52                 self.onchange_template_id(
53                     cr, uid, [], context['default_template_id'], res.get('composition_mode'),
54                     res.get('model'), res.get('res_id', context.get('active_id')), context=context
55                 )['value']
56             )
57         return res
58
59     _columns = {
60         'template_id': fields.many2one('email.template', 'Use template', select=True),
61         'partner_to': fields.char('To (Partner IDs)',
62             help="Comma-separated list of recipient partners ids (placeholders may be used here)"),
63         'email_to': fields.char('To (Emails)',
64             help="Comma-separated recipient addresses (placeholders may be used here)",),
65         'email_cc': fields.char('Cc (Emails)',
66             help="Carbon copy recipients (placeholders may be used here)"),
67     }
68
69     def send_mail(self, cr, uid, ids, context=None):
70         """ Override of send_mail to duplicate attachments linked to the email.template.
71             Indeed, basic mail.compose.message wizard duplicates attachments in mass
72             mailing mode. But in 'single post' mode, attachments of an email template
73             also have to be duplicated to avoid changing their ownership. """
74         if context is None:
75             context = {}
76         wizard_context = dict(context)
77         for wizard in self.browse(cr, uid, ids, context=context):
78             if wizard.template_id:
79                 wizard_context['mail_notify_user_signature'] = False  # template user_signature is added when generating body_html
80                 wizard_context['mail_auto_delete'] = wizard.template_id.auto_delete  # mass mailing: use template auto_delete value -> note, for emails mass mailing only
81             if not wizard.attachment_ids or wizard.composition_mode == 'mass_mail' or not wizard.template_id:
82                 continue
83             new_attachment_ids = []
84             for attachment in wizard.attachment_ids:
85                 if attachment in wizard.template_id.attachment_ids:
86                     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                 else:
88                     new_attachment_ids.append(attachment.id)
89                 self.write(cr, uid, wizard.id, {'attachment_ids': [(6, 0, new_attachment_ids)]}, context=context)
90         return super(mail_compose_message, self).send_mail(cr, uid, ids, context=wizard_context)
91
92     def onchange_template_id(self, cr, uid, ids, template_id, composition_mode, model, res_id, context=None):
93         """ - mass_mailing: we cannot render, so return the template values
94             - normal mode: return rendered values """
95         if template_id and composition_mode == 'mass_mail':
96             fields = ['subject', 'body_html', 'email_from', 'email_to', 'partner_to', 'email_cc', 'reply_to', 'attachment_ids', 'mail_server_id']
97             template_values = self.pool.get('email.template').read(cr, uid, template_id, fields, context)
98             values = dict((field, template_values[field]) for field in fields if template_values.get(field))
99         elif template_id:
100             values = self.generate_email_for_composer_batch(cr, uid, template_id, [res_id], context=context)[res_id]
101             # transform attachments into attachment_ids; not attached to the document because this will
102             # be done further in the posting process, allowing to clean database if email not send
103             values['attachment_ids'] = values.pop('attachment_ids', [])
104             ir_attach_obj = self.pool.get('ir.attachment')
105             for attach_fname, attach_datas in values.pop('attachments', []):
106                 data_attach = {
107                     'name': attach_fname,
108                     'datas': attach_datas,
109                     'datas_fname': attach_fname,
110                     'res_model': 'mail.compose.message',
111                     'res_id': 0,
112                     'type': 'binary',  # override default_type from context, possibly meant for another model!
113                 }
114                 values['attachment_ids'].append(ir_attach_obj.create(cr, uid, data_attach, context=context))
115         else:
116             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)
117         if values.get('body_html'):
118             values['body'] = values.pop('body_html')
119         return {'value': values}
120
121     def save_as_template(self, cr, uid, ids, context=None):
122         """ hit save as template button: current form value will be a new
123             template attached to the current document. """
124         email_template = self.pool.get('email.template')
125         ir_model_pool = self.pool.get('ir.model')
126         for record in self.browse(cr, uid, ids, context=context):
127             model_ids = ir_model_pool.search(cr, uid, [('model', '=', record.model)], context=context)
128             model_id = model_ids and model_ids[0] or False
129             model_name = ''
130             if model_id:
131                 model_name = ir_model_pool.browse(cr, uid, model_id, context=context).name
132             template_name = "%s: %s" % (model_name, tools.ustr(record.subject))
133             values = {
134                 'name': template_name,
135                 'subject': record.subject or False,
136                 'body_html': record.body or False,
137                 'model_id': model_id or False,
138                 'attachment_ids': [(6, 0, [att.id for att in record.attachment_ids])],
139             }
140             template_id = email_template.create(cr, uid, values, context=context)
141             # generate the saved template
142             template_values = record.onchange_template_id(template_id, record.composition_mode, record.model, record.res_id)['value']
143             template_values['template_id'] = template_id
144             record.write(template_values)
145             return _reopen(self, record.id, record.model)
146
147     #------------------------------------------------------
148     # Wizard validation and send
149     #------------------------------------------------------
150
151     def _get_or_create_partners_from_values(self, cr, uid, rendered_values, context=None):
152         """ Check for email_to, email_cc, partner_to """
153         partner_ids = []
154         mails = tools.email_split(rendered_values.pop('email_to', '') + ' ' + rendered_values.pop('email_cc', ''))
155         for mail in mails:
156             partner_id = self.pool.get('res.partner').find_or_create(cr, uid, mail, context=context)
157             partner_ids.append(partner_id)
158         partner_to = rendered_values.pop('partner_to', '')
159         if partner_to:
160             for partner_id in partner_to.split(','):
161                 if partner_id:  # placeholders could generate '', 3, 2 due to some empty field values
162                     partner_ids.append(int(partner_id))
163         return partner_ids
164
165     def generate_email_for_composer_batch(self, cr, uid, template_id, res_ids, context=None):
166         """ Call email_template.generate_email(), get fields relevant for
167             mail.compose.message, transform email_cc and email_to into partner_ids """
168         # filter template values
169         fields = ['subject', 'body_html', 'email_from', 'email_to', 'partner_to', 'email_cc',  'reply_to', 'attachment_ids', 'attachments', 'mail_server_id']
170         values = dict.fromkeys(res_ids, False)
171         template_values = self.pool.get('email.template').generate_email_batch(cr, uid, template_id, res_ids, context=context)
172         for res_id in res_ids:
173             res_id_values = dict((field, template_values[res_id][field]) for field in fields if template_values[res_id].get(field))
174             res_id_values['body'] = res_id_values.pop('body_html', '')
175
176             # transform email_to, email_cc into partner_ids
177             ctx = dict((k, v) for k, v in (context or {}).items() if not k.startswith('default_'))
178             partner_ids = self._get_or_create_partners_from_values(cr, uid, res_id_values, context=ctx)
179             # legacy template behavior: void values do not erase existing values and the
180             # related key is removed from the values dict
181             if partner_ids:
182                 res_id_values['partner_ids'] = list(partner_ids)
183
184             values[res_id] = res_id_values
185         return values
186
187     def render_message_batch(self, cr, uid, wizard, res_ids, context=None):
188         """ Override to handle templates. """
189         # generate template-based values
190         if wizard.template_id:
191             template_values = self.generate_email_for_composer_batch(cr, uid, wizard.template_id.id, res_ids, context=context)
192         else:
193             template_values = dict.fromkeys(res_ids, dict())
194         # generate composer values
195         composer_values = super(mail_compose_message, self).render_message_batch(cr, uid, wizard, res_ids, context)
196
197         for res_id in res_ids:
198             # remove attachments from template values as they should not be rendered
199             template_values[res_id].pop('attachment_ids', None)
200             # remove some keys from composer that are readonly
201             composer_values[res_id].pop('email_to', None)
202             composer_values[res_id].pop('email_cc', None)
203             composer_values[res_id].pop('partner_to', None)
204             # update template values by composer values
205             template_values[res_id].update(composer_values[res_id])
206         return template_values
207
208     def render_template_batch(self, cr, uid, template, model, res_ids, context=None):
209         return self.pool.get('email.template').render_template_batch(cr, uid, template, model, res_ids, context=context)
210
211     # Compatibility methods
212     def generate_email_for_composer(self, cr, uid, template_id, res_id, context=None):
213         return self.generate_email_for_composer_batch(cr, uid, template_id, [res_id], context)[res_id]
214
215 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: