[MERGE] Merged prototyping branch about improving performances
in messaging, especially for mass mailing and mail mail creation. Some things will probably be discarded or improved further, but this work will serve as a basis for the whole mass mailing refactorign about speed. bzr revid: tde@openerp.com-20140314165621-stpmdbq92fbigc3u
This commit is contained in:
commit
fd85a00311
|
@ -55,14 +55,23 @@ class mail_compose_message(osv.TransientModel):
|
|||
)
|
||||
return res
|
||||
|
||||
def get_recipients_data(self, cr, uid, values, context=None):
|
||||
if values['composition_mode'] != 'mass_mail':
|
||||
return super(mail_compose_message, self).get_recipients_data(cr, uid, values, context=context)
|
||||
model, res_id, template_id = values['model'], values['res_id'], values.get('template_id')
|
||||
active_ids = context.get('active_ids', list())
|
||||
if not active_ids or not template_id:
|
||||
return False
|
||||
template = self.pool['email.template'].browse(cr, uid, template_id, context=context)
|
||||
partner_to = self.render_template_batch(cr, uid, template.partner_to, model, active_ids[:3], context=context)
|
||||
partner_ids = [int(data) for key, data in partner_to.iteritems() if data]
|
||||
rec_names = [rec_name[1] for rec_name in self.pool['res.partner'].name_get(cr, SUPERUSER_ID, partner_ids, context=context)]
|
||||
recipients = ', '.join(rec_names)
|
||||
recipients += ' and %d more.' % (len(active_ids) - 3) if len(active_ids) > 3 else '.'
|
||||
return recipients
|
||||
|
||||
_columns = {
|
||||
'template_id': fields.many2one('email.template', 'Use template', select=True),
|
||||
'partner_to': fields.char('To (Partner IDs)',
|
||||
help="Comma-separated list of recipient partners ids (placeholders may be used here)"),
|
||||
'email_to': fields.char('To (Emails)',
|
||||
help="Comma-separated recipient addresses (placeholders may be used here)",),
|
||||
'email_cc': fields.char('Cc (Emails)',
|
||||
help="Carbon copy recipients (placeholders may be used here)"),
|
||||
}
|
||||
|
||||
def send_mail(self, cr, uid, ids, context=None):
|
||||
|
@ -92,7 +101,7 @@ class mail_compose_message(osv.TransientModel):
|
|||
""" - mass_mailing: we cannot render, so return the template values
|
||||
- normal mode: return rendered values """
|
||||
if template_id and composition_mode == 'mass_mail':
|
||||
fields = ['subject', 'body_html', 'email_from', 'email_to', 'partner_to', 'email_cc', 'reply_to', 'attachment_ids', 'mail_server_id']
|
||||
fields = ['subject', 'body_html', 'email_from', 'reply_to', 'attachment_ids', 'mail_server_id']
|
||||
template_values = self.pool.get('email.template').read(cr, uid, template_id, fields, context)
|
||||
values = dict((field, template_values[field]) for field in fields if template_values.get(field))
|
||||
elif template_id:
|
||||
|
|
|
@ -7,22 +7,6 @@
|
|||
<field name="model">mail.compose.message</field>
|
||||
<field name="inherit_id" ref="mail.email_compose_message_wizard_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//field[@name='subject']" position="after">
|
||||
<label string="Template Recipients" for="partner_to"
|
||||
groups="base.group_no_one"
|
||||
attrs="{'invisible':[('composition_mode', '!=', 'mass_mail')]}"/>
|
||||
<div groups="base.group_no_one" name="template_recipients"
|
||||
attrs="{'invisible':[('composition_mode', '!=', 'mass_mail')]}">
|
||||
<group class="oe_grey">
|
||||
<!-- <label string="Partners" for="partner_to"/> -->
|
||||
<field name="partner_to" readonly="1"/>
|
||||
<!-- <label string="Email To" for="email_to"/> -->
|
||||
<field name="email_to" readonly="1"/>
|
||||
<!-- <label string="Email CC" for="email_cc"/> -->
|
||||
<field name="email_cc" readonly="1"/>
|
||||
</group>
|
||||
</div>
|
||||
</xpath>
|
||||
<xpath expr="//footer" position="inside">
|
||||
<group class="oe_right oe_form" col="1">
|
||||
<div>Use template
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
<div>
|
||||
<group string="Status">
|
||||
<field name="auto_delete"/>
|
||||
<field name="notification"/>
|
||||
<field name="type"/>
|
||||
<field name="state"/>
|
||||
<field name="mail_server_id"/>
|
||||
|
|
|
@ -76,6 +76,7 @@ class mail_message(osv.Model):
|
|||
_message_read_more_limit = 1024
|
||||
|
||||
def default_get(self, cr, uid, fields, context=None):
|
||||
# print '\tmail_message: default_get on', fields
|
||||
# protection for `default_type` values leaking from menu action context (e.g. for invoices)
|
||||
if context and context.get('default_type') and context.get('default_type') not in self._columns['type'].selection:
|
||||
context = dict(context, default_type=None)
|
||||
|
@ -86,17 +87,6 @@ class mail_message(osv.Model):
|
|||
return name
|
||||
return name[:self._message_record_name_length] + '...'
|
||||
|
||||
def _get_record_name(self, cr, uid, ids, name, arg, context=None):
|
||||
""" Return the related document name, using name_get. It is done using
|
||||
SUPERUSER_ID, to be sure to have the record name correctly stored. """
|
||||
# TDE note: regroup by model/ids, to have less queries to perform
|
||||
result = dict.fromkeys(ids, False)
|
||||
for message in self.read(cr, uid, ids, ['model', 'res_id'], context=context):
|
||||
if not message.get('model') or not message.get('res_id') or message['model'] not in self.pool:
|
||||
continue
|
||||
result[message['id']] = self.pool[message['model']].name_get(cr, SUPERUSER_ID, [message['res_id']], context=context)[0][1]
|
||||
return result
|
||||
|
||||
def _get_to_read(self, cr, uid, ids, name, arg, context=None):
|
||||
""" Compute if the message is unread by the current user. """
|
||||
res = dict((id, False) for id in ids)
|
||||
|
@ -172,9 +162,7 @@ class mail_message(osv.Model):
|
|||
'child_ids': fields.one2many('mail.message', 'parent_id', 'Child Messages'),
|
||||
'model': fields.char('Related Document Model', size=128, select=1),
|
||||
'res_id': fields.integer('Related Document ID', select=1),
|
||||
'record_name': fields.function(_get_record_name, type='char',
|
||||
store=True, string='Message Record Name',
|
||||
help="Name get of the related document."),
|
||||
'record_name': fields.char('Message Record Name', help="Name get of the related document."),
|
||||
'notification_ids': fields.one2many('mail.notification', 'message_id',
|
||||
string='Notifications', auto_join=True,
|
||||
help='Technical field holding the message notifications. Use notified_partner_ids to access notified partners.'),
|
||||
|
@ -783,6 +771,13 @@ class mail_message(osv.Model):
|
|||
_('The requested operation cannot be completed due to security restrictions. Please contact your system administrator.\n\n(Document type: %s, Operation: %s)') % \
|
||||
(self._description, operation))
|
||||
|
||||
def _get_record_name(self, cr, uid, values, context=None):
|
||||
""" Return the related document name, using name_get. It is done using
|
||||
SUPERUSER_ID, to be sure to have the record name correctly stored. """
|
||||
if not values.get('model') or not values.get('res_id') or values['model'] not in self.pool:
|
||||
return False
|
||||
return self.pool[values['model']].name_get(cr, SUPERUSER_ID, [values['res_id']], context=context)[0][1]
|
||||
|
||||
def _get_reply_to(self, cr, uid, values, context=None):
|
||||
""" Return a specific reply_to: alias of the document through message_get_reply_to
|
||||
or take the email_from
|
||||
|
@ -841,8 +836,12 @@ class mail_message(osv.Model):
|
|||
values['message_id'] = self._get_message_id(cr, uid, values, context=context)
|
||||
if 'reply_to' not in values:
|
||||
values['reply_to'] = self._get_reply_to(cr, uid, values, context=context)
|
||||
if 'record_name' not in values and 'default_record_name' not in context:
|
||||
values['record_name'] = self._get_record_name(cr, uid, values, context=context)
|
||||
|
||||
newid = super(mail_message, self).create(cr, uid, values, context)
|
||||
if not values.get('subtype_id'):
|
||||
return newid
|
||||
self._notify(cr, uid, newid, context=context,
|
||||
force_send=context.get('mail_notify_force_send', True),
|
||||
user_signature=context.get('mail_notify_user_signature', True))
|
||||
|
|
|
@ -507,7 +507,7 @@ openerp.mail = function (session) {
|
|||
}
|
||||
$.when(recipient_done).done(function (partner_ids) {
|
||||
var context = {
|
||||
'default_composition_mode': default_composition_mode,
|
||||
// 'default_composition_mode': default_composition_mode,
|
||||
'default_parent_id': self.id,
|
||||
'default_body': mail.ChatterUtils.get_text2html(self.$el ? (self.$el.find('textarea:not(.oe_compact)').val() || '') : ''),
|
||||
'default_attachment_ids': _.map(self.attachment_ids, function (file) {return file.id;}),
|
||||
|
|
|
@ -68,28 +68,25 @@ class mail_compose_message(osv.TransientModel):
|
|||
if context is None:
|
||||
context = {}
|
||||
result = super(mail_compose_message, self).default_get(cr, uid, fields, context=context)
|
||||
# get some important values from context
|
||||
composition_mode = context.get('default_composition_mode', context.get('mail.compose.message.mode'))
|
||||
model = context.get('default_model', context.get('active_model'))
|
||||
res_id = context.get('default_res_id', context.get('active_id'))
|
||||
message_id = context.get('default_parent_id', context.get('message_id', context.get('active_id')))
|
||||
active_ids = context.get('active_ids')
|
||||
|
||||
# v6.1 compatibility mode
|
||||
result['composition_mode'] = result.get('composition_mode', context.get('mail.compose.message.mode'))
|
||||
result['model'] = result.get('model', context.get('active_model'))
|
||||
result['res_id'] = result.get('res_id', context.get('active_id'))
|
||||
result['parent_id'] = result.get('parent_id', context.get('message_id'))
|
||||
|
||||
# default values according to composition mode - NOTE: reply is deprecated, fall back on comment
|
||||
if result['composition_mode'] == 'reply':
|
||||
result['composition_mode'] = 'comment'
|
||||
vals = {}
|
||||
if 'active_domain' in context: # not context.get() because we want to keep global [] domains
|
||||
result['use_active_domain'] = True
|
||||
result['active_domain'] = '%s' % context.get('active_domain')
|
||||
elif not result.get('active_domain'):
|
||||
result['active_domain'] = ''
|
||||
# get default values according to the composition mode
|
||||
if composition_mode == 'reply':
|
||||
vals = self.get_message_data(cr, uid, message_id, context=context)
|
||||
elif composition_mode == 'comment' and model and res_id:
|
||||
vals = self.get_record_data(cr, uid, model, res_id, context=context)
|
||||
elif composition_mode == 'mass_mail' and model and active_ids:
|
||||
vals = {'model': model, 'res_id': res_id}
|
||||
else:
|
||||
vals = {'model': model, 'res_id': res_id}
|
||||
if composition_mode:
|
||||
vals['composition_mode'] = composition_mode
|
||||
vals['use_active_domain'] = True
|
||||
vals['active_domain'] = '%s' % context.get('active_domain')
|
||||
if result.get('parent_id'):
|
||||
vals.update(self.get_message_data(cr, uid, result.get('parent_id'), context=context))
|
||||
if result['composition_mode'] == 'comment' and result['model'] and result['res_id']:
|
||||
vals.update(self.get_record_data(cr, uid, result['model'], result['res_id'], context=context))
|
||||
result['recipients_data'] = self.get_recipients_data(cr, uid, result, context=context)
|
||||
|
||||
for field in vals:
|
||||
if field in fields:
|
||||
|
@ -102,13 +99,15 @@ class mail_compose_message(osv.TransientModel):
|
|||
# but when creating the mail.message to create the mail.compose.message
|
||||
# access rights issues may rise
|
||||
# We therefore directly change the model and res_id
|
||||
if result.get('model') == 'res.users' and result.get('res_id') == uid:
|
||||
if result['model'] == 'res.users' and result['res_id'] == uid:
|
||||
result['model'] = 'res.partner'
|
||||
result['res_id'] = self.pool.get('res.users').browse(cr, uid, uid).partner_id.id
|
||||
return result
|
||||
|
||||
def _get_composition_mode_selection(self, cr, uid, context=None):
|
||||
return [('comment', 'Comment a document'), ('reply', 'Reply to a message'), ('mass_mail', 'Mass mailing')]
|
||||
return [('comment', 'Post on a document'),
|
||||
('mass_mail', 'Email Mass Mailing'),
|
||||
('mass_post', 'Post on Multiple Documents')]
|
||||
|
||||
_columns = {
|
||||
'composition_mode': fields.selection(
|
||||
|
@ -116,15 +115,15 @@ class mail_compose_message(osv.TransientModel):
|
|||
string='Composition mode'),
|
||||
'partner_ids': fields.many2many('res.partner',
|
||||
'mail_compose_message_res_partner_rel',
|
||||
'wizard_id', 'partner_id', 'Additional contacts'),
|
||||
'wizard_id', 'partner_id', 'Additional Contacts'),
|
||||
'recipients_data': fields.text(string='Recipients Data',
|
||||
help='Helper field used in mass mailing to display a sample of recipients'),
|
||||
'use_active_domain': fields.boolean('Use active domain'),
|
||||
'active_domain': fields.char('Active domain', readonly=True),
|
||||
'post': fields.boolean('Post a copy in the document',
|
||||
help='Post a copy of the message on the document communication history.'),
|
||||
'notify': fields.boolean('Notify followers',
|
||||
help='Notify followers of the document'),
|
||||
help='Notify followers of the document (mass post only)'),
|
||||
'same_thread': fields.boolean('Replies in the document',
|
||||
help='Replies to the messages will go into the selected document.'),
|
||||
help='Replies to the messages will go into the selected document (mass mail only)'),
|
||||
'attachment_ids': fields.many2many('ir.attachment',
|
||||
'mail_compose_message_ir_attachments_rel',
|
||||
'wizard_id', 'attachment_id', 'Attachments'),
|
||||
|
@ -136,8 +135,7 @@ class mail_compose_message(osv.TransientModel):
|
|||
'body': lambda self, cr, uid, ctx={}: '',
|
||||
'subject': lambda self, cr, uid, ctx={}: False,
|
||||
'partner_ids': lambda self, cr, uid, ctx={}: [],
|
||||
'post': False,
|
||||
'notify': False,
|
||||
'notify': True,
|
||||
'same_thread': True,
|
||||
}
|
||||
|
||||
|
@ -169,6 +167,21 @@ class mail_compose_message(osv.TransientModel):
|
|||
not want that feature in the wizard. """
|
||||
return
|
||||
|
||||
def get_recipients_data(self, cr, uid, values, context=None):
|
||||
""" Returns a string explaining the targetted recipients, to ease the use
|
||||
of the wizard. """
|
||||
composition_mode, model, res_id = values['composition_mode'], values['model'], values['res_id']
|
||||
if composition_mode == 'comment' and model and res_id:
|
||||
doc_name = self.pool[model].name_get(cr, uid, [res_id], context=context)
|
||||
return doc_name and 'Followers of %s' % doc_name[0][1] or False
|
||||
elif composition_mode == 'mass_post' and model:
|
||||
active_ids = context.get('active_ids', list())
|
||||
if not active_ids:
|
||||
return False
|
||||
name_gets = [rec_name[1] for rec_name in self.pool[model].name_get(cr, uid, active_ids[:3], context=context)]
|
||||
return 'Followers of selected documents (' + ', '.join(name_gets) + len(active_ids) > 3 and ', ...' or '' + ')'
|
||||
return False
|
||||
|
||||
def get_record_data(self, cr, uid, model, res_id, context=None):
|
||||
""" Returns a defaults-like dict with initial values for the composition
|
||||
wizard when sending an email related to the document record
|
||||
|
@ -179,17 +192,10 @@ class mail_compose_message(osv.TransientModel):
|
|||
:param int res_id: id of the document record this mail is related to
|
||||
"""
|
||||
doc_name_get = self.pool[model].name_get(cr, uid, [res_id], context=context)
|
||||
record_name = False
|
||||
if doc_name_get:
|
||||
record_name = doc_name_get[0][1]
|
||||
values = {
|
||||
'model': model,
|
||||
'res_id': res_id,
|
||||
'record_name': record_name,
|
||||
return {
|
||||
'record_name': doc_name_get and doc_name_get[0][1] or False,
|
||||
'subject': doc_name_get and 'Re: %s' % doc_name_get[0][1] or False,
|
||||
}
|
||||
if record_name:
|
||||
values['subject'] = 'Re: %s' % record_name
|
||||
return values
|
||||
|
||||
def get_message_data(self, cr, uid, message_id, context=None):
|
||||
""" Returns a defaults-like dict with initial values for the composition
|
||||
|
@ -208,23 +214,20 @@ class mail_compose_message(osv.TransientModel):
|
|||
# create subject
|
||||
re_prefix = _('Re:')
|
||||
reply_subject = tools.ustr(message_data.subject or message_data.record_name or '')
|
||||
if not (reply_subject.startswith('Re:') or reply_subject.startswith(re_prefix)) and message_data.subject:
|
||||
if not (reply_subject.startswith('Re:') or reply_subject.startswith(re_prefix)):
|
||||
reply_subject = "%s %s" % (re_prefix, reply_subject)
|
||||
|
||||
# get partner_ids from original message
|
||||
partner_ids = [partner.id for partner in message_data.partner_ids] if message_data.partner_ids else []
|
||||
partner_ids += context.get('default_partner_ids', [])
|
||||
if context.get('is_private',False) and message_data.author_id : #check message is private then add author also in partner list.
|
||||
if context.get('is_private') and message_data.author_id: # check message is private then add author also in partner list.
|
||||
partner_ids += [message_data.author_id.id]
|
||||
# update the result
|
||||
result = {
|
||||
return {
|
||||
'record_name': message_data.record_name,
|
||||
'model': message_data.model,
|
||||
'res_id': message_data.res_id,
|
||||
'parent_id': message_data.id,
|
||||
'subject': reply_subject,
|
||||
'partner_ids': partner_ids,
|
||||
}
|
||||
return result
|
||||
|
||||
#------------------------------------------------------
|
||||
# Wizard validation and send
|
||||
|
@ -235,54 +238,46 @@ class mail_compose_message(osv.TransientModel):
|
|||
email(s), rendering any template patterns on the fly if needed. """
|
||||
if context is None:
|
||||
context = {}
|
||||
import datetime
|
||||
print '--> beginning sending email', datetime.datetime.now()
|
||||
# clean the context (hint: mass mailing sets some default values that
|
||||
# could be wrongly interpreted by mail_mail)
|
||||
context.pop('default_email_to', None)
|
||||
context.pop('default_partner_ids', None)
|
||||
|
||||
active_ids = context.get('active_ids')
|
||||
is_log = context.get('mail_compose_log', False)
|
||||
|
||||
for wizard in self.browse(cr, uid, ids, context=context):
|
||||
mass_mail_mode = wizard.composition_mode == 'mass_mail'
|
||||
mass_mode = wizard.composition_mode in ('mass_mail', 'mass_post')
|
||||
active_model_pool = self.pool[wizard.model if wizard.model else 'mail.thread']
|
||||
if not hasattr(active_model_pool, 'message_post'):
|
||||
context['thread_model'] = wizard.model
|
||||
active_model_pool = self.pool['mail.thread']
|
||||
|
||||
# wizard works in batch mode: [res_id] or active_ids or active_domain
|
||||
if mass_mail_mode and wizard.use_active_domain and wizard.model:
|
||||
if mass_mode and wizard.use_active_domain and wizard.model:
|
||||
res_ids = self.pool[wizard.model].search(cr, uid, eval(wizard.active_domain), context=context)
|
||||
elif mass_mail_mode and wizard.model and active_ids:
|
||||
res_ids = active_ids
|
||||
elif mass_mode and wizard.model and context.get('active_ids'):
|
||||
res_ids = context['active_ids']
|
||||
else:
|
||||
res_ids = [wizard.res_id]
|
||||
|
||||
print '----> before computing values', datetime.datetime.now()
|
||||
all_mail_values = self.get_mail_values(cr, uid, wizard, res_ids, context=context)
|
||||
print '----> after computing values', datetime.datetime.now()
|
||||
|
||||
for res_id, mail_values in all_mail_values.iteritems():
|
||||
if mass_mail_mode and not wizard.post:
|
||||
m2m_attachment_ids = self.pool['mail.thread']._message_preprocess_attachments(
|
||||
cr, uid, mail_values.pop('attachments', []),
|
||||
mail_values.pop('attachment_ids', []),
|
||||
'mail.message', 0,
|
||||
context=context)
|
||||
mail_values['attachment_ids'] = m2m_attachment_ids
|
||||
if not mail_values.get('reply_to'):
|
||||
mail_values['reply_to'] = mail_values['email_from']
|
||||
self.pool.get('mail.mail').create(cr, uid, mail_values, context=context)
|
||||
if wizard.composition_mode == 'mass_mail':
|
||||
self.pool['mail.mail'].create(cr, uid, mail_values, context=context)
|
||||
else:
|
||||
subtype = 'mail.mt_comment'
|
||||
if is_log: # log a note: subtype is False
|
||||
if context.get('mail_compose_log') or (wizard.composition_mode == 'mass_post' and not wizard.notify): # log a note: subtype is False
|
||||
subtype = False
|
||||
elif mass_mail_mode: # mass mail: is a log pushed to recipients unless specified, author not added
|
||||
if not wizard.notify:
|
||||
subtype = False
|
||||
if wizard.composition_mode == 'mass_post':
|
||||
context = dict(context,
|
||||
mail_notify_force_send=False, # do not send emails directly but use the queue instead
|
||||
mail_create_nosubscribe=True) # add context key to avoid subscribing the author
|
||||
active_model_pool.message_post(cr, uid, [res_id], type='comment', subtype=subtype, context=context, **mail_values)
|
||||
|
||||
print '--> finished sending email', datetime.datetime.now()
|
||||
return {'type': 'ir.actions.act_window_close'}
|
||||
|
||||
def get_mail_values(self, cr, uid, wizard, res_ids, context=None):
|
||||
|
@ -303,9 +298,12 @@ class mail_compose_message(osv.TransientModel):
|
|||
'parent_id': wizard.parent_id and wizard.parent_id.id,
|
||||
'partner_ids': [partner.id for partner in wizard.partner_ids],
|
||||
'attachment_ids': [attach.id for attach in wizard.attachment_ids],
|
||||
'author_id': wizard.author_id.id,
|
||||
'email_from': wizard.email_from,
|
||||
}
|
||||
# mass mailing: rendering override wizard static values
|
||||
if mass_mail_mode and wizard.model:
|
||||
# rendered values using template
|
||||
email_dict = rendered_values[res_id]
|
||||
mail_values['partner_ids'] += email_dict.pop('partner_ids', [])
|
||||
# process attachments: should not be encoded before being processed by message_post / mail_mail create
|
||||
|
@ -323,20 +321,38 @@ class mail_compose_message(osv.TransientModel):
|
|||
if email_dict.get('email_from'):
|
||||
mail_values['email_from'] = email_dict.pop('email_from')
|
||||
# replies redirection: mass mailing only
|
||||
if wizard.same_thread and wizard.post:
|
||||
if wizard.same_thread:
|
||||
email_dict.pop('reply_to', None)
|
||||
else:
|
||||
mail_values['reply_to'] = email_dict.pop('reply_to', None)
|
||||
mail_values.update(email_dict)
|
||||
# mass mailing without post: mail_mail values
|
||||
if mass_mail_mode and not wizard.post:
|
||||
|
||||
# value tweaking in mass mailing
|
||||
mail_values['record_name'] = False # avoid browsing the record for an email
|
||||
if wizard.same_thread: # same thread: keep a copy of the message in the chatter to enable the reply redirection
|
||||
mail_values.update(notification=True, model=wizard.model, res_id=res_id)
|
||||
m2m_attachment_ids = self.pool['mail.thread']._message_preprocess_attachments(
|
||||
cr, uid, mail_values.pop('attachments', []),
|
||||
mail_values.pop('attachment_ids', []),
|
||||
'mail.message', 0,
|
||||
context=context)
|
||||
mail_values['attachment_ids'] = m2m_attachment_ids
|
||||
if not mail_values.get('reply_to'):
|
||||
mail_values['reply_to'] = mail_values['email_from']
|
||||
|
||||
# mail_mail values
|
||||
if 'mail_auto_delete' in context:
|
||||
mail_values['auto_delete'] = context.get('mail_auto_delete')
|
||||
mail_values['body_html'] = mail_values.get('body', '')
|
||||
mail_values['recipient_ids'] = [(4, id) for id in mail_values.pop('partner_ids', [])]
|
||||
|
||||
results[res_id] = mail_values
|
||||
return results
|
||||
|
||||
#------------------------------------------------------
|
||||
# Template rendering
|
||||
#------------------------------------------------------
|
||||
|
||||
def render_message_batch(self, cr, uid, wizard, res_ids, context=None):
|
||||
"""Generate template-based values of wizard, for the document records given
|
||||
by res_ids. This method is meant to be inherited by email_template that
|
||||
|
|
|
@ -28,29 +28,35 @@
|
|||
<field name="email_from"
|
||||
attrs="{'invisible':[('composition_mode', '!=', 'mass_mail')]}"/>
|
||||
<field name="subject" placeholder="Subject..." required="True"/>
|
||||
<!-- classic message composer -->
|
||||
<label for="partner_ids" string="Recipients"
|
||||
attrs="{'invisible':[('composition_mode', '=', 'mass_mail')]}"/>
|
||||
<div groups="base.group_user"
|
||||
attrs="{'invisible':[('composition_mode', '=', 'mass_mail')]}">
|
||||
<span attrs="{'invisible':[('model', '=', False)]}">
|
||||
Followers of
|
||||
<field name="record_name" readonly="1" class="oe_inline oe_compose_recipients"/>
|
||||
and
|
||||
<!-- recipients -->
|
||||
<label for="partner_ids" string="Recipients" groups="base.group_user"/>
|
||||
<div groups="base.group_user">
|
||||
<span attrs="{'invisible': [('composition_mode', '!=', 'mass_mail')]}">
|
||||
<strong>Email mass mailing</strong> on
|
||||
<span attrs="{'invisible': [('use_active_domain', '=', True)]}">the selected records</span>
|
||||
<span attrs="{'invisible': [('use_active_domain', '=', False)]}">the current search filter</span>.
|
||||
<br />
|
||||
<span>The following contacts will be mailed: </span>
|
||||
</span>
|
||||
<field name="recipients_data" class="oe_inline oe_compose_recipients" readonly="1"/>
|
||||
<span attrs="{'invisible':['|', ('composition_mode', '!=', 'comment'), ('recipients_data', '=', False)]}">and</span>
|
||||
<field name="partner_ids" widget="many2many_tags_email" placeholder="Add contacts to notify..."
|
||||
context="{'force_email':True, 'show_email':True}"/>
|
||||
context="{'force_email':True, 'show_email':True}"
|
||||
attrs="{'invisible': [('composition_mode', '!=', 'comment')]}"/>
|
||||
</div>
|
||||
<!-- mass post / mass mailing -->
|
||||
<field name="post"
|
||||
attrs="{'invisible':[('composition_mode', '!=', 'mass_mail')]}"/>
|
||||
<!-- mass post -->
|
||||
<field name="notify"
|
||||
attrs="{'invisible':['|', ('post', '!=', True), ('composition_mode', '!=', 'mass_mail')]}"/>
|
||||
<field name="same_thread"
|
||||
attrs="{'invisible':['|', ('composition_mode', '!=', 'mass_mail'), ('post', '=', False)]}"/>
|
||||
<field name="reply_to" placeholder="Email address te redirect replies..."
|
||||
attrs="{'invisible':['|', '&', ('same_thread', '=', True), ('post', '=', True), ('composition_mode', '!=', 'mass_mail')],
|
||||
'required':['&', '|', ('post', '=', False), ('same_thread', '=', False), ('composition_mode', '=', 'mass_mail')]}"/>
|
||||
attrs="{'invisible':['|', ('composition_mode', '!=', 'mass_post')]}"/>
|
||||
<!-- mass mailing -->
|
||||
<label for="same_thread"/>
|
||||
<div>
|
||||
<field name="same_thread"
|
||||
attrs="{'invisible':[('composition_mode', '!=', 'mass_mail')]}"/>
|
||||
(a copy of the message will be added in the Chatter of each document)
|
||||
</div>
|
||||
<field name="reply_to" placeholder="Email address to redirect replies..."
|
||||
attrs="{'invisible':['|', ('same_thread', '=', True), ('composition_mode', '!=', 'mass_mail')],
|
||||
'required':[('same_thread', '!=', True), ('composition_mode', '=', 'mass_mail')]}"/>
|
||||
</group>
|
||||
<field name="body"/>
|
||||
<field name="attachment_ids" widget="many2many_binary" string="Attach a file"/>
|
||||
|
|
Loading…
Reference in New Issue