[IMP] email.template: review/adapt form to 7.0-style + continue refactoring polishing

bzr revid: odo@openerp.com-20120901010907-703t6vx6n99tnyzq
This commit is contained in:
Olivier Dony 2012-09-01 03:09:07 +02:00
parent 761864c11c
commit 9d16f324e9
5 changed files with 102 additions and 152 deletions

View File

@ -29,7 +29,7 @@ from osv import fields
import tools import tools
from tools.translate import _ from tools.translate import _
from tools.html_sanitize import html_sanitize from tools.html_sanitize import html_sanitize
from tools import html2plaintext, append_content_to_html from tools import append_content_to_html
from urllib import quote as quote from urllib import quote as quote
_logger = logging.getLogger(__name__) _logger = logging.getLogger(__name__)
@ -42,7 +42,6 @@ class email_template(osv.osv):
"Templates for sending email" "Templates for sending email"
_name = "email.template" _name = "email.template"
_description = 'Email Templates' _description = 'Email Templates'
_rec_name = 'name' # override mail.message's behavior
def render_template(self, cr, uid, template, model, res_id, context=None): def render_template(self, cr, uid, template, model, res_id, context=None):
"""Render the given template text, replace mako expressions ``${expr}`` """Render the given template text, replace mako expressions ``${expr}``
@ -102,26 +101,31 @@ class email_template(osv.osv):
mod_name = self.pool.get('ir.model').browse(cr, uid, model_id, context).model mod_name = self.pool.get('ir.model').browse(cr, uid, model_id, context).model
return {'value':{'model': mod_name}} return {'value':{'model': mod_name}}
def name_get(self, cr, uid, ids, context=None):
""" Override name_get of mail.message: return directly the template
name, and not the generated name from mail.message.common."""
return [(record.id, record.name) for record in self.browse(cr, uid, ids, context=context)]
_columns = { _columns = {
'name': fields.char('Name', size=250), 'name': fields.char('Name'),
'model_id': fields.many2one('ir.model', 'Related document model'), 'model_id': fields.many2one('ir.model', 'Applies to', help="The kind of document with with this template can be used"),
'model': fields.related('model_id', 'model', type='char', string='Related Document Model', 'model': fields.related('model_id', 'model', type='char', string='Related Document Model',
size=128, select=True, store=True, readonly=True), size=128, select=True, store=True, readonly=True),
'lang': fields.char('Language Selection', size=250, 'lang': fields.char('Language',
help="Optional translation language (ISO code) to select when sending out an email. " help="Optional translation language (ISO code) to select when sending out an email. "
"If not set, the english version will be used. " "If not set, the english version will be used. "
"This should usually be a placeholder expression " "This should usually be a placeholder expression "
"that provides the appropriate language code, e.g. " "that provides the appropriate language code, e.g. "
"${object.partner_id.lang.code}."), "${object.partner_id.lang.code}.",
placeholder="${object.partner_id.lang.code}"),
'user_signature': fields.boolean('Add Signature', 'user_signature': fields.boolean('Add Signature',
help="If checked, the user's signature will be appended to the text version " help="If checked, the user's signature will be appended to the text version "
"of the message"), "of the message"),
'report_name': fields.char('Report Filename', size=200, translate=True, 'subject': fields.char('Subject', translate=True, help="Subject (placeholders may be used here)",),
'email_from': fields.char('From', help="Sender address (placeholders may be used here)"),
'email_to': fields.char('To', help="Comma-separated recipient addresses (placeholders may be used here)"),
'email_cc': fields.char('Cc', help="Carbon copy recipients (placeholders may be used here)"),
'reply_to': fields.char('Reply-To', help="Preferred response address (placeholders may be used here)"),
'mail_server_id': fields.many2one('ir.mail_server', 'Outgoing Mail Server', readonly=False,
help="Optional preferred server for outgoing mails. If not set, the highest "
"priority one will be used."),
'body_html': fields.text('Body', translate=True, help="Rich-text/HTML version of the message (placeholders may be used here)"),
'report_name': fields.char('Report Filename', translate=True,
help="Name to use for the generated report file (may contain placeholders)\n" help="Name to use for the generated report file (may contain placeholders)\n"
"The extension can be omitted and will then come from the report type."), "The extension can be omitted and will then come from the report type."),
'report_template': fields.many2one('ir.actions.report.xml', 'Optional report to print and attach'), 'report_template': fields.many2one('ir.actions.report.xml', 'Optional report to print and attach'),
@ -130,27 +134,11 @@ class email_template(osv.osv):
"of the related document model"), "of the related document model"),
'ref_ir_value': fields.many2one('ir.values', 'Sidebar Button', readonly=True, 'ref_ir_value': fields.many2one('ir.values', 'Sidebar Button', readonly=True,
help="Sidebar button to open the sidebar action"), help="Sidebar button to open the sidebar action"),
'track_campaign_item': fields.boolean('Resource Tracking',
help="Enable this is you wish to include a special tracking marker "
"in outgoing emails so you can identify replies and link "
"them back to the corresponding resource record. "
"This is useful for CRM leads for example"),
# we need a separate m2m table to avoid ID collisions with the original mail.message entries
'attachment_ids': fields.many2many('ir.attachment', 'email_template_attachment_rel', 'email_template_id', 'attachment_ids': fields.many2many('ir.attachment', 'email_template_attachment_rel', 'email_template_id',
'attachment_id', 'Files to attach', 'attachment_id', 'Attachments',
help="You may attach files to this template, to be added to all " help="You may attach files to this template, to be added to all "
"emails created from this template"), "emails created from this template"),
'auto_delete': fields.boolean('Auto Delete', help="Permanently delete this email after sending it, to save space"), 'auto_delete': fields.boolean('Auto Delete', help="Permanently delete this email after sending it, to save space"),
# Overridden mail.message.common fields to make tooltips more appropriate:
'subject': fields.char('Subject', translate=True, help="Subject (placeholders may be used here)",),
'email_from': fields.char('From', size=128, help="Sender address (placeholders may be used here)"),
'email_to': fields.char('To', size=256, help="Comma-separated recipient addresses (placeholders may be used here)"),
'email_cc': fields.char('Cc', size=256, help="Carbon copy recipients (placeholders may be used here)"),
'reply_to': fields.char('Reply-To', size=250, help="Preferred response address (placeholders may be used here)"),
'mail_server_id': fields.many2one('ir.mail_server', 'Outgoing Mail Server', readonly=False,
help="Optional preferred server for outgoing mails. If not set, the highest "
"priority one will be used."),
'body_html': fields.text('Rich-text Contents', translate=True, help="Rich-text/HTML version of the message (placeholders may be used here)"),
# Fake fields used to implement the placeholder assistant # Fake fields used to implement the placeholder assistant
'model_object_field': fields.many2one('ir.model.fields', string="Field", 'model_object_field': fields.many2one('ir.model.fields', string="Field",
@ -164,12 +152,8 @@ class email_template(osv.osv):
help="When a relationship field is selected as first field, " help="When a relationship field is selected as first field, "
"this field lets you select the target field within the " "this field lets you select the target field within the "
"destination document model (sub-model)."), "destination document model (sub-model)."),
'null_value': fields.char('Null value', help="Optional value to use if the target field is empty", size=128), 'null_value': fields.char('Default Value', help="Optional value to use if the target field is empty"),
'copyvalue': fields.char('Expression', size=256, help="Final placeholder expression, to be copy-pasted in the desired template field."), 'copyvalue': fields.char('Placeholder Expression', help="Final placeholder expression, to be copy-pasted in the desired template field."),
}
_defaults = {
'track_campaign_item': True
} }
def create_action(self, cr, uid, ids, context=None): def create_action(self, cr, uid, ids, context=None):
@ -214,7 +198,7 @@ class email_template(osv.osv):
if template.ref_ir_value: if template.ref_ir_value:
ir_values_obj = self.pool.get('ir.values') ir_values_obj = self.pool.get('ir.values')
ir_values_obj.unlink(cr, uid, template.ref_ir_value.id, context) ir_values_obj.unlink(cr, uid, template.ref_ir_value.id, context)
except: except Exception:
raise osv.except_osv(_("Warning"), _("Deletion of the action record failed.")) raise osv.except_osv(_("Warning"), _("Deletion of the action record failed."))
return True return True

View File

@ -1,90 +1,63 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<openerp> <openerp>
<data> <data>
<record model="ir.ui.view" id="email_template_form"> <record model="ir.ui.view" id="email_template_form">
<field name="name">email.template.form</field> <field name="name">email.template.form</field>
<field name="model">email.template</field> <field name="model">email.template</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<form string="Templates" version="7.0"> <form string="Templates" version="7.0">
<sheet> <sheet>
<group col="4"> <div class="oe_title">
<field name="name" required="1"/> <label for="name" class="oe_edit_only"/><h1><field name="name" required="1"/></h1>
<field name="model_id" required="1" on_change="onchange_model_id(model_id)"/> <h3><label for="model_id"/><field name="model_id" required="1" on_change="onchange_model_id(model_id)" class="oe_inline"/></h3>
<field name="model" invisible="1"/> <field name="model" invisible="1"/>
</group> </div>
<div class="oe_right oe_button_box" name="buttons">
<field name="ref_ir_act_window" invisible="1"/>
<button name="create_action" string="Add context action" type="object"
attrs="{'invisible':[('ref_ir_act_window','!=',False)]}"
help="Display an option on related documents to open a composition wizard with this template"/>
<button name="unlink_action" string="Remove context action" type="object"
attrs="{'invisible':[('ref_ir_act_window','=',False)]}"
help="Remove the contextual action to use this template on related documents"/>
<button name="%(wizard_email_template_preview)d" string="Preview"
type="action" target="new"
context="{'template_id':active_id}"/>
</div>
<notebook> <notebook>
<page string="Email Details"> <page string="Email Details">
<group> <group>
<group string="Addressing">
<field name="email_from" required="1"/> <field name="email_from" required="1"/>
<field name="email_to" required="1"/> <field name="email_to" required="1"/>
<field name="email_cc"/> <field name="email_cc"/>
<field name="reply_to"/> <field name="reply_to"/>
<field name="subject" required="1"/>
<notebook colspan="4">
<page string="Body (HTML)">
<field name="body_html" colspan="4" width="250" height="250" nolabel="1"/>
<label string="Note: This is Raw HTML." colspan="4"/>
</page>
</notebook>
<field name="user_signature"/> <field name="user_signature"/>
<notebook colspan="4"> </group>
<page string="Dynamic Values Builder"> <group string="Dynamic Value Builder" class="oe_edit_only">
<group> <field name="model_object_field" domain="[('model_id','=',model_id),('ttype','!=','one2many'),('ttype','!=','many2many')]" on_change="onchange_sub_model_object_value_field(model_object_field)"/>
<field name="model_object_field"
domain="[('model_id','=',model_id),('ttype','!=','one2many'),('ttype','!=','many2many')]"
on_change="onchange_sub_model_object_value_field(model_object_field)"/>
<field name="sub_object" readonly="1"/> <field name="sub_object" readonly="1"/>
<field name="sub_model_object_field" <field name="sub_model_object_field" domain="[('model_id','=',sub_object),('ttype','!=','one2many'),('ttype','!=','many2many')]" attrs="{'readonly':[('sub_object','=',False)],'required':[('sub_object','!=',False)]}" on_change="onchange_sub_model_object_value_field(model_object_field,sub_model_object_field)"/>
domain="[('model_id','=',sub_object),('ttype','!=','one2many'),('ttype','!=','many2many')]"
attrs="{'readonly':[('sub_object','=',False)],'required':[('sub_object','!=',False)]}"
on_change="onchange_sub_model_object_value_field(model_object_field,sub_model_object_field)"/>
<field name="null_value" on_change="onchange_sub_model_object_value_field(model_object_field,sub_model_object_field,null_value)"/> <field name="null_value" on_change="onchange_sub_model_object_value_field(model_object_field,sub_model_object_field,null_value)"/>
<field name="copyvalue"/> <field name="copyvalue"/>
</group> </group>
</page> <group string="Contents" colspan="2">
</notebook> <field name="subject" required="1"/>
<button name="%(wizard_email_template_preview)d" string="Preview Template" <field name="body_html" width="250" height="450" nolabel="1" colspan="2" placeholder="Email contents (in raw HTML format)"/>
type="action" colspan="4" target="new" icon="gtk-zoom-fit" context="{'template_id':active_id}"/> </group>
</group> </group>
</page> </page>
<page string="Advanced"> <page string="Advanced">
<group colspan="2" col="2">
<group colspan="2" col="2">
<separator string="Sidebar Button" colspan="2"/>
<button name="create_action" string="Add sidebar button" type="object" icon="gtk-execute"
colspan="2" attrs="{'invisible':[('ref_ir_act_window','!=',False)]}"
help="Display a button in the sidebar of related documents to open a composition wizard with this template"
/>
<field name="ref_ir_act_window" attrs="{'invisible':[('ref_ir_act_window','=',False)]}"/>
<field name="ref_ir_value" attrs="{'invisible':[('ref_ir_act_window','=',False)]}"/>
<button name="unlink_action" string="Remove sidebar button" type="object" icon="gtk-delete"
colspan="2" attrs="{'invisible':[('ref_ir_act_window','=',False)]}"
help="Remove the sidebar button currently displayed on related documents"
/>
</group>
<group colspan="2" col="2">
<separator string="Advanced Options" colspan="2"/>
<field name="mail_server_id"/>
<field name="track_campaign_item"/>
<field name="auto_delete"/>
<field name="lang"/>
</group>
</group>
<group colspan="2" col="2">
<separator string="Attachments" colspan="2"/>
<notebook colspan="2">
<page string="Attach Report">
<group> <group>
<field name="report_template" colspan="4" <field name="lang"/>
domain="[('model','=',model)]"/> <field name="mail_server_id"/>
<field name="report_name" colspan="4" /> <field name="auto_delete"/>
</group> <field name="report_template" domain="[('model','=',model)]"/>
</page> <field name="report_name" class="oe_inline"
<page string="Attach existing files"> attrs="{'invisible':[('report_template','=',False)]}"/>
<field name="attachment_ids" colspan="4" nolabel="1" height="350"/> <field name="attachment_ids">
</page> <tree><field name="name"/></tree>
</notebook> </field>
</group> </group>
</page> </page>
</notebook> </notebook>
@ -98,9 +71,9 @@
<field name="model">email.template</field> <field name="model">email.template</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<tree string="Templates"> <tree string="Templates">
<field name="model_id"/>
<field name="mail_server_id" invisible="1"/> <field name="mail_server_id" invisible="1"/>
<field name="name"/> <field name="name"/>
<field name="model_id"/>
<field name="subject"/> <field name="subject"/>
<field name="email_from"/> <field name="email_from"/>
<field name="email_to"/> <field name="email_to"/>

View File

@ -1,5 +1,3 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_email_template,email.template,model_email_template,,1,0,0,0 access_email_template,email.template,model_email_template,,1,1,1,0
access_email_template_system,email.template system,model_email_template,base.group_system,1,1,1,1 access_email_template_system,email.template system,model_email_template,base.group_system,1,1,1,1
access_email_template_manager,email.template,model_email_template,,1,1,1,1
access_email_template_preview_system,email.template.preview system,model_email_template_preview,base.group_system,1,1,1,1

1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_email_template email.template model_email_template 1 0 1 0 1 0
3 access_email_template_system email.template system model_email_template base.group_system 1 1 1 1
access_email_template_manager email.template model_email_template 1 1 1 1
access_email_template_preview_system email.template.preview system model_email_template_preview base.group_system 1 1 1 1

View File

@ -69,25 +69,15 @@ class email_template_preview(osv.osv_memory):
} }
def on_change_res_id(self, cr, uid, ids, res_id, context=None): def on_change_res_id(self, cr, uid, ids, res_id, context=None):
if not res_id: if not res_id: return {}
return {}
vals = {} vals = {}
email_template = self.pool.get('email.template') email_template = self.pool.get('email.template')
template_id = context and context.get('template_id') template_id = context and context.get('template_id')
template = email_template.browse(cr, uid, template_id, context=context)
# FIXME ODO: replace everything below with a call to template.generate_email vals['name'] = template.name
template = email_template.get_email_template(cr, uid, template_id=template_id, record_id=res_id, context=context) mail_values = email_template.generate_email(cr, uid, template_id, res_id, context=context)
model = template.model for k in ('email_from','email_to','email_cc','reply_to','subject','body_html'):
vals['email_to'] = self.render_template(cr, uid, template.email_to, model, res_id, context) vals[k] = mail_values[k]
vals['email_cc'] = self.render_template(cr, uid, template.email_cc, model, res_id, context)
vals['reply_to'] = self.render_template(cr, uid, template.reply_to, model, res_id, context)
vals['subject'] = self.render_template(cr, uid, template.subject, model, res_id, context)
description = self.render_template(cr, uid, template.body_html, model, res_id, context) or ''
if template.user_signature:
signature = self.pool.get('res.users').browse(cr, uid, uid, context).signature
description += '\n' + signature
vals['body_html'] = description
vals['report_name'] = self.render_template(cr, uid, template.report_name, model, res_id, context)
return {'value': vals} return {'value': vals}
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -7,15 +7,20 @@
<field name="model">email_template.preview</field> <field name="model">email_template.preview</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<form string="Email Preview" version="7.0"> <form string="Email Preview" version="7.0">
<group> <div>
<h2>Preview of <field name="name" readonly="1" class="oe_inline"/></h2>
<field name="model_id" invisible="1"/> <field name="model_id" invisible="1"/>
<field name="res_id" on_change="on_change_res_id(res_id, context)"/> <h3>Using sample document
<field name="res_id" on_change="on_change_res_id(res_id, context)" class="oe_inline"/>
</h3>
</div>
<group>
<field name="email_from" readonly="1"/>
<field name="email_to" readonly="1"/> <field name="email_to" readonly="1"/>
<field name="email_cc" readonly="1" attrs="{'invisible':[('email_cc','=',False)]}"/> <field name="email_cc" readonly="1" attrs="{'invisible':[('email_cc','=',False)]}"/>
<field name="reply_to" readonly="1" attrs="{'invisible':[('reply_to','=',False)]}"/> <field name="reply_to" readonly="1" attrs="{'invisible':[('reply_to','=',False)]}"/>
<field name="subject" readonly="1"/> <field name="subject" readonly="1"/>
<field name="body_html" nolabel="1" colspan="4" height="350" width="350" readonly="1" widget="html"/> <field name="body_html" widget="html" readonly="1"/>
<field name="report_name" colspan="4" readonly="1"/>
</group> </group>
</form> </form>
</field> </field>