[IMP] [REF] mass_mailing: first draft for the saas-4 refactoring.

Improved mass mailing form view, that is used as a central point to create new
mailings.
Added concept of contact list (based on partner, or leads (to add)), as well as
contact (a list of name / email to import). Mailings are done un contact list
to simplify the way it works.
Added a kanban view of templates, with a flag to filter only mass mailing templates
(to avoid havign to deal with acknoledgments).
Using campaigns is now an option (a group), mailings can be done without having to
deal with campaigns.
Mailings and campaigns now have a status, used to display their kanban view.

bzr revid: tde@openerp.com-20140314165113-g4gvvifrhr2nfu15
This commit is contained in:
Thibault Delavallée 2014-03-14 17:51:13 +01:00
parent 676189cbf7
commit 08ab922468
14 changed files with 950 additions and 73 deletions

View File

@ -63,7 +63,7 @@ campaigns on any OpenERP document.
'wizard/mail_compose_message_view.xml',
'security/ir.model.access.csv'
],
'demo': ['res_partner_demo.yml'],
'demo': [],
'installable': True,
'auto_install': True,
'images': ['images/1_email_account.jpeg','images/2_email_template.jpeg','images/3_emails.jpeg'],

View File

@ -1,9 +0,0 @@
-
Set opt-out to True on all demo partners
-
!python {model: res.partner}: |
partner_ids = self.search(cr, uid, [])
# assume partners with an external ID come from demo data
ext_ids = self._get_external_ids(cr, uid, partner_ids)
ids_to_update = [k for (k,v) in ext_ids.iteritems() if v]
self.write(cr, uid, ids_to_update, {'opt_out': True})

View File

@ -2,7 +2,7 @@
##############################################################################
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2013-today OpenERP SA (<http://www.openerp.com>)
# Copyright (C) 2013-Today OpenERP SA (<http://www.openerp.com>)
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
@ -22,5 +22,7 @@
import mass_mailing
import mail_mail
import mail_thread
import email_template
import res_config
import wizard
import controllers
import controllers

View File

@ -33,14 +33,18 @@ professional emails and reuse templates in a few clicks.
'depends': [
'mail',
'email_template',
'marketing',
'web_kanban_gauge',
'web_kanban_sparkline',
],
'data': [
'mail_data.xml',
'mass_mailing_data.xml',
'wizard/mail_compose_message_view.xml',
'wizard/mail_mass_mailing_create_segment.xml',
'mass_mailing_view.xml',
'res_config_view.xml',
'email_template.xml',
'security/ir.model.access.csv',
],
'js': [
@ -48,7 +52,8 @@ professional emails and reuse templates in a few clicks.
],
'qweb': [],
'css': [
'static/src/css/mass_mailing.css'
'static/src/css/mass_mailing.css',
'static/src/css/email_template.css'
],
'demo': [
'mass_mailing_demo.xml',

View File

@ -0,0 +1,31 @@
# -*- coding: utf-8 -*-
from openerp.tools.translate import _
from openerp.osv import osv, fields
class EmailTemplate(osv.Model):
"""Add the mass mailing campaign data to mail"""
_name = 'email.template'
_inherit = ['email.template']
_columns = {
'use_in_mass_mailing': fields.boolean('Available for mass mailing campaigns'),
}
def action_new_mailing(self, cr, uid, ids, context=None):
ctx = dict(context)
ctx.update({
'default_template_id': ids[0],
})
return {
'name': _('Create a Mass Mailing'),
'type': 'ir.actions.act_window',
'view_type': 'form',
'view_mode': 'form',
'res_model': 'mail.mass_mailing',
'views': [(False, 'form')],
'view_id': False,
# 'target': 'new',
'context': ctx,
}

View File

@ -0,0 +1,83 @@
<?xml version="1.0"?>
<openerp>
<data>
<!-- Email Templates -->
<record id="view_marketing_settings_mass_mailing" model="ir.ui.view">
<field name="name">email.template.form.mass.mailing</field>
<field name="model">email.template</field>
<field name="inherit_id" ref="email_template.email_template_form"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='model_id']" position="after">
<br /><label for="use_in_mass_mailing"/><field name="use_in_mass_mailing"/>
</xpath>
</field>
</record>
<record id="view_email_template_search_mass_mailing" model="ir.ui.view">
<field name="name">email.template.search.mass.mailing</field>
<field name="model">email.template</field>
<field name="inherit_id" ref="email_template.view_email_template_search"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='model_id']" position="after">
<separator/>
<filter string="Available for Mass Mailing" name="use_in_mass_mailing" domain="[('use_in_mass_mailing', '=', 1)]"
help="Available for use in mass mailing campaigns"/>
</xpath>
</field>
</record>
<record model="ir.ui.view" id="view_email_template_kanban">
<field name="name">email.template.kanban</field>
<field name="model">email.template</field>
<field name="arch" type="xml">
<kanban>
<field name="body_html"/>
<templates>
<t t-name="kanban-box">
<div t-attf-class="oe_kanban_card oe_kanban_global_click oe_kanban_email_template">
<div class="oe_dropdown_toggle oe_dropdown_kanban">
<span class="oe_e">i</span>
<ul class="oe_dropdown_menu">
<t>
<li><a name="action_new_mailing" type="object">New Mailing</a></li>
</t>
<t t-if="widget.view.is_action_enabled('edit')">
<li><a type="edit">Edit</a></li>
</t>
<t t-if="widget.view.is_action_enabled('delete')">
<li><a type="delete">Delete</a></li>
</t>
</ul>
</div>
<div class="oe_kanban_content">
<h3>
<field name="name"/>
</h3>
<div class="html_preview">
<t t-raw="record.body_html.raw_value"/>
</div>
</div>
<div class="oe_clear"></div>
</div>
</t>
</templates>
</kanban>
</field>
</record>
<record model="ir.actions.act_window" id="action_email_template">
<field name="name">Templates</field>
<field name="res_model">email.template</field>
<field name="view_type">form</field>
<field name="view_mode">kanban,tree,form</field>
<field name="context">{'search_default_use_in_mass_mailing': 1}</field>
</record>
<!-- Add Templates in Marketing / Mass mailing menu -->
<menuitem name="Mail Templates" id="menu_email_template"
parent="mass_mailing_campaign" sequence="3"
action="action_email_template"/>
</data>
</openerp>

View File

@ -23,10 +23,151 @@ from datetime import datetime
from dateutil import relativedelta
from openerp import tools
from openerp.tools.safe_eval import safe_eval as eval
from openerp.tools.translate import _
from openerp.osv import osv, fields
class MassMailingCategory(osv.Model):
"""Model of categories of mass mailing, i.e. marketing, newsletter, ... """
_name = 'mail.mass_mailing.category'
_description = 'Mass Mailing Category'
_columns = {
'name': fields.char('Name', required=True),
}
class MassMailingContact(osv.Model):
"""Model of a contact. This model is different from the partner model
because it holds only some basic information: name, email. The purpose is to
be able to deal with large contact list to email without bloating the partner
database. """
_name = 'mail.mass_mailing.contact'
_description = 'Mass Mailing Contact'
_columns = {
'name': fields.char('Name', required=True),
'email': fields.char('Email', required=True),
'list_id': fields.many2one(
'mail.mass_mailing.list', string='Mailing List',
required=True, ondelete='cascade',
),
'opt_out': fields.boolean('Opt Out', help='The contact has chosen not to receive news anymore from this mailing list'),
}
class MassMailingList(osv.Model):
"""Model of a contact list. """
_name = 'mail.mass_mailing.list'
_description = 'Contact List'
def default_get(self, cr, uid, fields, context=None):
"""Override default_get to handle active_domain coming from the list view. """
res = super(MassMailingList, self).default_get(cr, uid, fields, context=context)
if 'domain' in fields and 'active_domain' in context:
res['domain'] = '%s' % context['active_domain']
res['model'] = context.get('active_model', 'res.partner')
return res
def _get_contact_nbr(self, cr, uid, ids, name, arg, context=None):
"""Compute the number of contacts linked to the mailing list. """
results = dict.fromkeys(ids, 0)
for contact_list in self.browse(cr, uid, ids, context=context):
if contact_list.model == 'mail.mass_mailing.contact':
results[contact_list.id] = len(contact_list.contact_ids)
else:
domain = self.compute_domain(cr, uid, [contact_list.id], context=context)
results[contact_list.id] = self.pool[contact_list.model].search(cr, uid, domain, count=True, context=context)
return results
def _get_model_list(self, cr, uid, context=None):
return [
('res.partner', 'Customers'),
('mail.mass_mailing.contact', 'Mailing Contacts')
]
# indirections for inheritance
_model_list = lambda self, *args, **kwargs: self._get_model_list(*args, **kwargs)
_columns = {
'name': fields.char('Name', required=True),
'contact_nbr': fields.function(
_get_contact_nbr, type='integer',
string='Contact Number',
),
# contact-based list
'contact_ids': fields.one2many(
'mail.mass_mailing.contact', 'list_id', string='Contacts',
domain=[('opt_out', '=', False)],
),
# filter-based list
'model': fields.selection(
_model_list, type='char', required=True,
string='Applies To'
),
# 'model_id': fields.many2one(
# 'ir.model', string='Related Model',
# domain="[('model', '=', model')]",
# ),
'filter_id': fields.many2one(
'ir.filters', string='Custom Filter',
# domain="[('model_id', '=', model_id)]",
),
'domain': fields.text('Domain'),
}
def on_change_model(self, cr, uid, ids, model, context=None):
values = {}
if model == 'mail.mass_mailing.contact':
values.update(domain=False, filter_id=False)
else:
values.update(filter_id=False)
return {'value': values}
def on_change_filter_id(self, cr, uid, ids, filter_id, context=None):
values = {}
if filter_id:
ir_filter = self.pool['ir.filters'].browse(cr, uid, filter_id, context=context)
values['domain'] = ir_filter.domain
else:
values['domain'] = False
return {'value': values}
def action_see_records(self, cr, uid, ids, context=None):
contact_list = self.browse(cr, uid, ids[0], context=context)
ctx = dict(context)
ctx['search_default_not_opt_out'] = True
return {
'name': _('See Contact List'),
'type': 'ir.actions.act_window',
'view_type': 'form',
'view_mode': 'tree,form',
'res_model': contact_list.model,
'views': [(False, 'tree'), (False, 'form')],
'view_id': False,
'target': 'current',
'context': ctx,
'domain': contact_list.domain,
}
def compute_domain(self, cr, uid, ids, context=None):
domains = []
for contact_list in self.browse(cr, uid, ids, context=context):
domain = eval(contact_list.domain)
if domain:
domain = ['&', ('opt_out', '=', False)] + domain
else:
domain = [('opt_out', '=', False)]
if domain is not False:
domains.append(domain)
if domains:
final_domain = ['|'] * (len(domains) - 1) + [leaf for dom in domains for leaf in dom]
else:
final_domain = domains
return final_domain
class MassMailingCampaign(osv.Model):
"""Model of mass mailing campaigns.
"""
@ -63,6 +204,12 @@ class MassMailingCampaign(osv.Model):
results[campaign.id] = mass_mailing_results
return results
def _get_state_list(self, cr, uid, context=None):
return [('draft', 'Schedule'), ('design', 'Design'), ('done', 'Sent')]
# indirections for inheritance
_state = lambda self, *args, **kwargs: self._get_state_list(*args, **kwargs)
_columns = {
'name': fields.char(
'Campaign Name', required=True,
@ -71,6 +218,12 @@ class MassMailingCampaign(osv.Model):
'res.users', 'Responsible',
required=True,
),
'state': fields.selection(
_state, string='Status', required=True,
),
'category_id': fields.many2one(
'mail.mass_mailing.category', 'Category',
help='Category'),
'mass_mailing_ids': fields.one2many(
'mail.mass_mailing', 'mass_mailing_campaign_id',
'Mass Mailings',
@ -117,8 +270,42 @@ class MassMailingCampaign(osv.Model):
_defaults = {
'user_id': lambda self, cr, uid, ctx=None: uid,
'state': 'draft',
}
#------------------------------------------------------
# Technical stuff
#------------------------------------------------------
def read_group(self, cr, uid, domain, fields, groupby, offset=0, limit=None, context=None, orderby=False):
""" Override read_group to always display all states. """
if groupby and groupby[0] == "state":
# Default result structure
states = self._get_state_list(cr, uid, context=context)
read_group_all_states = [{
'__context': {'group_by': groupby[1:]},
'__domain': domain + [('state', '=', state_value)],
'state': state_value,
'state_count': 0,
} for state_value, state_name in states]
# Get standard results
read_group_res = super(MassMailingCampaign, self).read_group(cr, uid, domain, fields, groupby, offset=offset, limit=limit, context=context, orderby=orderby)
# Update standard results with default results
result = []
for state_value, state_name in states:
res = filter(lambda x: x['state'] == state_value, read_group_res)
if not res:
res = filter(lambda x: x['state'] == state_value, read_group_all_states)
res[0]['state'] = [state_value, state_name]
result.append(res[0])
return result
else:
return super(MassMailingCampaign, self).read_group(cr, uid, domain, fields, groupby, offset=offset, limit=limit, context=context, orderby=orderby)
#------------------------------------------------------
# Actions
#------------------------------------------------------
def launch_mass_mailing_create_wizard(self, cr, uid, ids, context=None):
ctx = dict(context)
ctx.update({
@ -142,7 +329,7 @@ class MassMailing(osv.Model):
A mass mailing is an occurence of sending emails. """
_name = 'mail.mass_mailing'
_description = 'Wave of sending emails'
_description = 'Mass Mailing'
# number of periods for tracking mail_mail statistics
_period_number = 6
_order = 'date DESC'
@ -189,9 +376,9 @@ class MassMailing(osv.Model):
date_begin_str = date_begin.strftime(tools.DEFAULT_SERVER_DATETIME_FORMAT)
date_end_str = date_end.strftime(tools.DEFAULT_SERVER_DATETIME_FORMAT)
domain = [('mass_mailing_id', '=', id), ('opened', '>=', date_begin_str), ('opened', '<=', date_end_str)]
res[id]['opened_monthly'] = self.__get_bar_values(cr, uid, id, obj, domain, ['opened'], 'opened_count', 'opened:day', context=context)
res[id]['opened_dayly'] = self.__get_bar_values(cr, uid, id, obj, domain, ['opened'], 'opened_count', 'opened:day', context=context)
domain = [('mass_mailing_id', '=', id), ('replied', '>=', date_begin_str), ('replied', '<=', date_end_str)]
res[id]['replied_monthly'] = self.__get_bar_values(cr, uid, id, obj, domain, ['replied'], 'replied_count', 'replied:day', context=context)
res[id]['replied_dayly'] = self.__get_bar_values(cr, uid, id, obj, domain, ['replied'], 'replied_count', 'replied:day', context=context)
return res
def _get_statistics(self, cr, uid, ids, name, arg, context=None):
@ -207,22 +394,54 @@ class MassMailing(osv.Model):
}
return results
def _get_mailing_type(self, cr, uid, context=None):
return [
('res.partner', 'Customers'),
('mail.mass_mailing.contact', 'Contacts')
]
def _get_state_list(self, cr, uid, context=None):
return [('draft', 'Schedule'), ('test', 'Tested'), ('done', 'Sent')]
# indirections for inheritance
_mailing_type = lambda self, *args, **kwargs: self._get_mailing_type(*args, **kwargs)
_state = lambda self, *args, **kwargs: self._get_state_list(*args, **kwargs)
_columns = {
'name': fields.char('Name', required=True),
'mass_mailing_campaign_id': fields.many2one(
'mail.mass_mailing.campaign', 'Mass Mailing Campaign',
ondelete='cascade', required=True,
'name': fields.char('Subject', required=True),
'date': fields.datetime('Date'),
'state': fields.selection(
_state, string='Status', required=True,
),
'template_id': fields.many2one(
'email.template', 'Email Template',
domain=[('use_in_mass_mailing', '=', True)],
ondelete='set null',
),
'body_html': fields.related(
'template_id', 'body_html', type='html',
string='Body', readonly='True',
help='Technical field: used only to display a view of the template in the form view',
),
'mass_mailing_campaign_id': fields.many2one(
'mail.mass_mailing.campaign', 'Mass Mailing Campaign',
ondelete='set null',
),
'domain': fields.char('Domain'),
'date': fields.datetime('Date'),
'color': fields.related(
'mass_mailing_campaign_id', 'color',
type='integer', string='Color Index',
),
# mailing options
'email_from': fields.char('From'),
'email_to': fields.char('Send to Emails'),
'reply_to': fields.char('Reply To'),
'mailing_type': fields.selection(_mailing_type, string='Type', required=True),
'contact_list_ids': fields.many2many(
'mail.mass_mailing.list', 'mail_mass_mailing_list_rel',
string='Mailing Lists',
domain="[('model', '=', mailing_type)]",
),
'contact_nbr': fields.integer('Contact Number'),
# statistics data
'statistics_ids': fields.one2many(
'mail.mail.statistics', 'mass_mailing_id',
@ -254,22 +473,159 @@ class MassMailing(osv.Model):
type='integer', multi='_get_statistics'
),
# monthly ratio
'opened_monthly': fields.function(
'opened_dayly': fields.function(
_get_daily_statistics,
string='Opened',
type='char', multi='_get_daily_statistics',
oldname='opened_monthly',
),
'replied_monthly': fields.function(
'replied_dayly': fields.function(
_get_daily_statistics,
string='Replied',
type='char', multi='_get_daily_statistics',
oldname='replied_monthly',
),
}
_defaults = {
'state': 'draft',
'date': fields.datetime.now,
'email_from': lambda self, cr, uid, ctx=None: self.pool['mail.message']._get_default_from(cr, uid, context=ctx),
'mailing_type': 'res.partner',
}
#------------------------------------------------------
# Technical stuff
#------------------------------------------------------
def read_group(self, cr, uid, domain, fields, groupby, offset=0, limit=None, context=None, orderby=False):
""" Override read_group to always display all states. """
if groupby and groupby[0] == "state":
# Default result structure
states = self._get_state_list(cr, uid, context=context)
read_group_all_states = [{
'__context': {'group_by': groupby[1:]},
'__domain': domain + [('state', '=', state_value)],
'state': state_value,
'state_count': 0,
} for state_value, state_name in states]
# Get standard results
read_group_res = super(MassMailing, self).read_group(cr, uid, domain, fields, groupby, offset=offset, limit=limit, context=context, orderby=orderby)
# Update standard results with default results
result = []
for state_value, state_name in states:
res = filter(lambda x: x['state'] == state_value, read_group_res)
if not res:
res = filter(lambda x: x['state'] == state_value, read_group_all_states)
res[0]['state'] = [state_value, state_name]
result.append(res[0])
return result
else:
return super(MassMailing, self).read_group(cr, uid, domain, fields, groupby, offset=offset, limit=limit, context=context, orderby=orderby)
#------------------------------------------------------
# Views & Actions
#------------------------------------------------------
def on_change_mailing_type(self, cr, uid, ids, mailing_type, context=None):
return {'value': {'contact_list_ids': []}}
def on_change_template_id(self, cr, uid, ids, template_id, context=None):
values = {}
if template_id:
template = self.pool['email.template'].browse(cr, uid, template_id, context=context)
if template.email_from:
values['email_from'] = template.email_from
if template.reply_to:
values['reply_to'] = template.reply_to
values['body_html'] = template.body_html
else:
values['email_from'] = self.pool['mail.message']._get_default_from(cr, uid, context=context)
values['reply_to'] = False
values['body_html'] = False
return {'value': values}
def send_mail(self, cr, uid, ids, context=None):
Mail = self.pool['mail.mail']
for mailing in self.browse(cr, uid, ids, context=context):
contact_list_ids = [contact_list.id for contact_list in mailing.contact_list_ids]
# contact-based list: aggregate all contacts
if mailing.mailing_type == 'mail.mass_mailing.list':
res_ids = [contact.id for contact in contact_list.contact_ids for contact_list in mailing.contact_list_ids]
elif mailing.mailing_type == 'res.partner':
domain = self.pool['mail.mass_mailing.list'].compute_domain(cr, uid, contact_list_ids, context=context)
print domain
res_ids = self.pool[contact_list.model].search(cr, uid, domain, context=context)
all_mail_values = self.pool['mail.compose.message'].generate_email_for_composer_batch(
cr, uid, mailing.template_id.id, res_ids,
context=context,
fields=['body_html', 'attachment_ids', 'mail_server_id']
)
for res_id, mail_values in all_mail_values.iteritems():
mail_values.update({
'email_from': mailing.email_from,
'reply_to': mailing.reply_to,
'subject': mailing.name,
'body_html': mail_values.get('body'),
'auto_delete': True,
'statistics_ids': [(0, 0, {
'model': mailing.mailing_type,
'res_id': res_id,
'mass_mailing_id': mailing.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 mailing.mailing_type == 'mail.mass_mailing.list':
contact = self.pool['mail.mass_mailing.contact'].browse(cr, uid, res_id, context=context)
mail_values['email_to'] = '"%s" <%s>' % (contact.name, contact.email)
elif mailing.mailing_type == 'res.partner':
mail_values['recipient_ids'] = [(4, res_id)]
Mail.create(cr, uid, mail_values, context=context)
# todo: handle email_to
return True
def send_mail_to_myself(self, cr, uid, ids, context=None):
Mail = self.pool['mail.mail']
for mailing in self.browse(cr, uid, ids, context=context):
mail_values = {
'email_from': mailing.email_from,
'reply_to': mailing.reply_to,
'email_to': self.pool['res.users'].browse(cr, uid, uid, context=context).email,
'subject': mailing.name,
'body_html': mailing.template_id.body_html,
'auto_delete': True,
}
mail_id = Mail.create(cr, uid, mail_values, context=context)
Mail.send(cr, uid, [mail_id], context=context)
return True
def select_customers(self, cr, uid, ids, context=None):
sid = self.pool['ir.model.data'].xmlid_to_res_id(cr, uid, 'base.view_res_partner_filter')
aid = self.pool['ir.model.data'].xmlid_to_res_id(cr, uid, 'mass_mailing.action_partner_to_mailing_list')
print sid, aid
ctx = dict(context)
ctx['view_manager_highlight'] = [aid]
return {
'name': _('Choose Customers'),
'type': 'ir.actions.act_window',
'view_type': 'form',
'view_mode': 'tree,form',
'res_model': 'res.partner',
# 'views': [(False, 'tree'), (False, 'form')],
'view_id': False,
'search_view_id': sid,
# 'target': 'new',
'context': ctx,
}
class MailMailStats(osv.Model):
""" MailMailStats models the statistics collected about emails. Those statistics

View File

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data noupdate="1">
<!-- After installation of the module, open the related menu -->
<record id="action_client_marketing_menu" model="ir.actions.client">
<field name="name">Open Marketing Menu</field>
<field name="tag">reload</field>
<field name="params" eval="{'menu_id': ref('base.marketing_menu')}"/>
</record>
<record id="base.open_menu" model="ir.actions.todo">
<field name="action_id" ref="action_client_marketing_menu"/>
<field name="state">open</field>
</record>
<!-- Group to manage campaigns -->
<record id="group_mass_mailing_campaign" model="res.groups">
<field name="name">Manage Mass Mailing Campaigns</field>
<field name="category_id" ref="base.module_category_hidden"/>
</record>
</data>
</openerp>

View File

@ -8,16 +8,153 @@
<field name="model_id" ref="base.model_res_partner"/>
<field name="auto_delete" eval="False"/>
<field name="partner_to">${object.id}</field>
<field name="body_html"><![CDATA[<p>Hello</p>]]></field>
<field name="reply_to"><![CDATA[Info <info@yourcompany.example.com>]]></field>
<field name="use_in_mass_mailing" eval="True"/>
<field name="body_html"><![CDATA[<div data-snippet-id="big-picture" style="padding:0px; margin:0px">
<table cellpadding="0" cellspacing="0" style="margin:10px 0px 0px;vertical-align:top;padding:0px;font-family:arial;font-size:12px;color:rgb(51,51,51)">
<tbody>
<tr>
<td style="width:600px" valign="top">
<h2 style="text-align: center; padding:0px 5px">A Punchy Headline</h2>
</td>
</tr>
<tr>
<td style="width:600px" valign="top"><img src="/website/static/src/img/big_picture.png" style="display:block;border:none;min-height:250px;margin:0 auto;" width="500"></td>
</tr>
<tr>
<td style="width:600px" valign="top">
<p style="text-align: center; overflow:hidden"></p>
<h3 style="text-align: center; padding:0px 5px">A Small Subtitle for ${object.name}</h3>
<p></p>
<p style="text-align: center; overflow:hidden">Choose a vibrant image and write an inspiring paragraph about it. It does not have to be long, but it should reinforce your image.</p>
</td>
</tr>
</tbody>
</table>
</div>
<div data-snippet-id="three-columns" style="padding:0px; margin:0px">
<table cellpadding="0" cellspacing="0" style="margin:10px 0px 0px;vertical-align:top;padding:0px;font-family:arial;font-size:12px;color:rgb(51,51,51)">
<tbody>
<tr>
<td style="width:300px" valign="top"><img src="/website/static/src/img/desert_thumb.jpg" style="display:block;border:none;min-height:50px" width="275"></td>
<td style="width:300px" valign="top"><img src="/website/static/src/img/deers_thumb.jpg" style="display:block;border:none;min-height:50px" width="275"></td>
</tr>
<tr>
<td style="width:300px" valign="top">
<h3 style="text-align: center; padding:0px 5px">Feature One</h3>
<p style="overflow:hidden">Choose a vibrant image and write an inspiring paragraph about it. It does not have to be long, but it should reinforce your image.</p>
</td>
<td style="width:300px" valign="top">
<h3 style="text-align: center; padding:0px 5px">Feature Two</h3>
<p style="overflow:hidden">Choose a vibrant image and write an inspiring paragraph about it. It does not have to be long, but it should reinforce your image.</p>
</td>
</tr>
</tbody>
</table>
</div>]]></field>
</record>
<record id="mass_mail_template_2" model="email.template">
<field name="name">Partner Newsletter 2</field>
<field name="model_id" ref="base.model_res_partner"/>
<field name="auto_delete" eval="False"/>
<field name="partner_to">${object.id}</field>
<field name="body_html"><![CDATA[<p>Hello</p>]]></field>
<field name="reply_to"><![CDATA[Info <info@yourcompany.example.com>]]></field>
<field name="use_in_mass_mailing" eval="True"/>
<field name="body_html"><![CDATA[<div data-snippet-id="text-image" style="padding:0px; margin:0px">
<table cellpadding="0" cellspacing="0" style="margin:10px 0px 0px;vertical-align:top;padding:0px 5px;font-family:arial;font-size:12px;color:rgb(51,51,51)">
<tbody>
<tr>
<td style="width:600px" valign="top">
<div style="padding:0px 5px">
<h1 style="text-align: center">Sell Online. Easily.</h1>
<p style="overflow:hidden">Write one sentence to convince visitor about your message.</p>
</div>
</td>
</tr>
</tbody>
</table>
</div>
<div data-snippet-id="hr" style="padding:0px; margin:0px">
<table cellpadding="0" cellspacing="0" style="margin:10px 0px 0px;vertical-align:top;padding:0px;font-family:arial;font-size:12px;color:rgb(51,51,51)">
<tbody>
<tr>
<td style="width:600px" valign="top">
<div style="padding:0px 5px">
<hr style="background-color:rgb(204,204,204);border:medium none;clear:both;display:block;font-size:0px;min-height:1px;line-height:0" width="100%" data-snippet-id="hr"></div>
</td>
</tr>
</tbody>
</table>
</div>
<div data-snippet-id="three-columns" style="padding:0px; margin:0px">
<table cellpadding="0" cellspacing="0" style="margin:10px 0px 0px;vertical-align:top;padding:0px;font-family:arial;font-size:12px;color:rgb(51,51,51)">
<tbody>
<tr>
<td style="width:200px" valign="top"><img src="/website/static/src/img/desert_thumb.jpg" style="display:block;border:none;min-height:50px" width="175"></td>
<td style="width:200px" valign="top"><img src="/website/static/src/img/deers_thumb.jpg" style="display:block;border:none;min-height:50px" width="175"></td>
<td style="width:200px" valign="top"><img src="/website/static/src/img/china_thumb.jpg" style="display:block;border:none;min-height:50px" width="175"></td>
</tr>
<tr>
<td style="width:200px" valign="top">
<h3 style="text-align: center; padding:0px 5px">Feature One</h3>
<p style="overflow:hidden">Choose a vibrant image and write an inspiring paragraph about it. It does not have to be long, but it should reinforce your image.</p>
</td>
<td style="width:200px" valign="top">
<h3 style="text-align: center; padding:0px 5px">Feature Two</h3>
<p style="overflow:hidden">Choose a vibrant image and write an inspiring paragraph about it. It does not have to be long, but it should reinforce your image.</p>
</td>
<td style="width:200px" valign="top">
<h3 style="text-align: center; padding:0px 5px">Feature Three</h3>
<p style="overflow:hidden">Choose a vibrant image and write an inspiring paragraph about it. It does not have to be long, but it should reinforce your image.</p>
</td>
</tr>
</tbody>
</table>
</div>]]></field>
</record>
<!-- Create mailing lists -->
<record id="mass_mail_list_1" model="mail.mass_mailing.list">
<field name="name">Imported Contacts</field>
<field name="model">mail.mass_mailing.contact</field>
</record>
<record id="mass_mail_list_2" model="mail.mass_mailing.list">
<field name="name">Customers</field>
<field name="model">res.partner</field>
<field name="model_id" eval="ref('base.model_res_partner')"/>
<field name="domain">[('customer', '=', True)]</field>
</record>
<!-- Create Contacts -->
<record id="mass_mail_contact_1" model="mail.mass_mailing.contact">
<field name="name">Aristide Antario</field>
<field name="email">aa@example.com</field>
<field name="list_id" eval="ref('mass_mail_list_1')"/>
</record>
<record id="mass_mail_contact_2" model="mail.mass_mailing.contact">
<field name="name">Beverly Bridge</field>
<field name="email">bb@example.com</field>
<field name="list_id" eval="ref('mass_mail_list_1')"/>
</record>
<record id="mass_mail_contact_3" model="mail.mass_mailing.contact">
<field name="name">Carol Cartridge</field>
<field name="email">cc@example.com</field>
<field name="list_id" eval="ref('mass_mail_list_1')"/>
<field name="opt_out" eval="True"/>
</record>
<!-- Create campaign and mailings -->
<record id="mass_mail_campaign_1" model="mail.mass_mailing.campaign">
<field name="name">Partners Newsletter</field>
<field name="user_id" eval="ref('base.user_root')"/>
@ -25,12 +162,14 @@
<record id="mass_mail_1" model="mail.mass_mailing">
<field name="name">First Newsletter</field>
<field name="state">done</field>
<field name="template_id" eval="ref('mass_mail_template_1')"/>
<field name="date" eval="(DateTime.today() - relativedelta(days=3)).strftime('%Y-%m-%d %H:%M:%S')"/>
<field name="date" eval="(DateTime.today() - relativedelta(days=5)).strftime('%Y-%m-%d %H:%M:%S')"/>
<field name="mass_mailing_campaign_id" eval="ref('mass_mail_campaign_1')"/>
</record>
<record id="mass_mail_2" model="mail.mass_mailing">
<field name="name">Second Newsletter</field>
<field name="state">test</field>
<field name="template_id" eval="ref('mass_mail_template_2')"/>
<field name="date" eval="(DateTime.today() - relativedelta(days=3)).strftime('%Y-%m-%d %H:%M:%S')"/>
<field name="mass_mailing_campaign_id" eval="ref('mass_mail_campaign_1')"/>
@ -63,20 +202,5 @@
<field name="bounced" eval="(DateTime.today() - relativedelta(days=3)).strftime('%Y-%m-%d %H:%M:%S')"/>
</record>
<record id="mass_mail_email_2_1" model="mail.mail.statistics">
<field name="mass_mailing_id" eval="ref('mass_mail_2')"/>
<field name="message_id">1111005@OpenERP.com</field>
<field name="opened" eval="(DateTime.today() - relativedelta(days=3)).strftime('%Y-%m-%d %H:%M:%S')"/>
</record>
<record id="mass_mail_email_2_2" model="mail.mail.statistics">
<field name="mass_mailing_id" eval="ref('mass_mail_2')"/>
<field name="message_id">1111006@OpenERP.com</field>
<field name="opened" eval="(DateTime.today() - relativedelta(days=2)).strftime('%Y-%m-%d %H:%M:%S')"/>
</record>
<record id="mass_mail_email_2_3" model="mail.mail.statistics">
<field name="mass_mailing_id" eval="ref('mass_mail_2')"/>
<field name="message_id">1111007@OpenERP.com</field>
</record>
</data>
</openerp>

View File

@ -2,6 +2,147 @@
<openerp>
<data>
<!-- Marketing / Mass Mailing -->
<menuitem name="Mass Mailing" id="mass_mailing_campaign"
parent="base.marketing_menu" sequence="1"/>
<!-- Marketing / Mailing Lists -->
<menuitem name="Contacts" id="mass_mailing_list"
parent="base.marketing_menu" sequence="2"/>
<!-- MASS MAILING CONTACT !-->
<record model="ir.ui.view" id="view_mail_mass_mailing_contact_search">
<field name="name">mail.mass_mailing.contact.search</field>
<field name="model">mail.mass_mailing.contact</field>
<field name="arch" type="xml">
<search string="Mass Mailings">
<field name="name"/>
<field name="email"/>
<field name="list_id"/>
<separator/>
<filter string="Available for Mass Mailing" name="not_opt_out" domain="[('opt_out', '=', False)]"
help="Contact is not opt-out"/>
<group expand="0" string="Group By...">
<filter string="Mailing Lists" name="group_list_id"
context="{'group_by': 'list_id'}"/>
</group>
</search>
</field>
</record>
<record model="ir.ui.view" id="view_mail_mass_mailing_contact_tree">
<field name="name">mail.mass_mailing.contact.tree</field>
<field name="model">mail.mass_mailing.contact</field>
<field name="priority">10</field>
<field name="arch" type="xml">
<tree string="Mass Mailings">
<field name="name"/>
<field name="email"/>
<field name="list_id"/>
<field name="opt_out"/>
</tree>
</field>
</record>
<record model="ir.ui.view" id="view_mail_mass_mailing_contact_form">
<field name="name">mail.mass_mailing.contact.form</field>
<field name="model">mail.mass_mailing.contact</field>
<field name="arch" type="xml">
<form string="Mass Mailing" version="7.0">
<sheet>
<group>
<field name="name"/>
<field name="email"/>
<field name="list_id"/>
<field name="opt_out"/>
</group>
</sheet>
</form>
</field>
</record>
<record id="action_view_mass_mailing_contacts" model="ir.actions.act_window">
<field name="name">Mass Mailing Contacts</field>
<field name="res_model">mail.mass_mailing.contact</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
<field name="context">{'search_default_not_opt_out': 1}</field>
</record>
<menuitem name="Mailing Contacts" id="menu_email_mass_mailing_contacts"
parent="mass_mailing_list" sequence="50"
action="action_view_mass_mailing_contacts"/>
<!-- MASS MAILING LIST !-->
<record model="ir.ui.view" id="view_mail_mass_mailing_list_search">
<field name="name">mail.mass_mailing.list.search</field>
<field name="model">mail.mass_mailing.list</field>
<field name="arch" type="xml">
<search string="Mass Mailings">
<field name="name"/>
<separator/>
</search>
</field>
</record>
<record model="ir.ui.view" id="view_mail_mass_mailing_list_tree">
<field name="name">mail.mass_mailing.list.tree</field>
<field name="model">mail.mass_mailing.list</field>
<field name="priority">10</field>
<field name="arch" type="xml">
<tree string="Contact Lists">
<field name="name"/>
<field name="model"/>
<field name="contact_nbr"/>
</tree>
</field>
</record>
<record model="ir.ui.view" id="view_mail_mass_mailing_list_form">
<field name="name">mail.mass_mailing.list.form</field>
<field name="model">mail.mass_mailing.list</field>
<field name="arch" type="xml">
<form string="Contact List" version="7.0">
<header>
<button name="action_see_records" type="object"
class="oe_highlight" string="See Contacts"/>
</header>
<sheet>
<group>
<field name="name"/>
<label for="contact_nbr"/>
<div>
<field name="contact_nbr" nolabel="1" class="oe_inline"/><span>contacts</span>
</div>
<field name="model" on_change="on_change_model(model, context)"/>
<field name="contact_ids"
attrs="{'invisible': [('model', '!=', 'mail.mass_mailing.contact')]}">
<tree editable='bottom'>
<field name="name"/>
<field name="email"/>
</tree>
</field>
<field name="filter_id"
on_change="on_change_filter_id(filter_id, context)"
attrs="{'invisible': [('model', '=', 'mail.mass_mailing.contact')]}"/>
<field name="domain"
attrs="{'invisible': ['|', ('model', '=', 'mail.mass_mailing.contact'), ('filter_id', '!=', False)]}"/>
</group>
</sheet>
</form>
</field>
</record>
<record id="action_view_mass_mailing_lists" model="ir.actions.act_window">
<field name="name">Contact Lists</field>
<field name="res_model">mail.mass_mailing.list</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
</record>
<menuitem name="Contact Lists" id="menu_email_mass_mailing_lists"
parent="mass_mailing_list" sequence="40"
action="action_view_mass_mailing_lists"/>
<!-- MASS MAILING !-->
<record model="ir.ui.view" id="view_mail_mass_mailing_search">
<field name="name">mail.mass_mailing.search</field>
@ -13,6 +154,7 @@
<field name="template_id"/>
<group expand="0" string="Group By...">
<filter string="Campaign" name="group_mass_mailing_campaign_id"
groups="mass_mailing.group_mass_mailing_campaign"
context="{'group_by': 'mass_mailing_campaign_id'}"/>
<filter string="Template" name="group_template_id"
context="{'group_by': 'template_id'}"/>
@ -32,7 +174,8 @@
<field name="delivered"/>
<field name="opened"/>
<field name="replied"/>
<field name="mass_mailing_campaign_id" invisible="1"/>
<field name="mass_mailing_campaign_id"
groups="mass_mailing.group_mass_mailing_campaign"/>
<field name="template_id" invisible="1"/>
</tree>
</field>
@ -43,19 +186,51 @@
<field name="model">mail.mass_mailing</field>
<field name="arch" type="xml">
<form string="Mass Mailing" version="7.0">
<header>
<button name="send_mail_to_myself" type="object"
class="oe_highlight" string="Send to Myself"/>
<button name="send_mail" type="object"
class="oe_highlight" string="Send to All"/>
<field name="state" widget="statusbar" clickable="True"/>
</header>
<sheet>
<group>
<group>
<field name="name"/>
<field name="mass_mailing_campaign_id" readonly="True"/>
<field name="date" readonly="True"/>
<field name="mass_mailing_campaign_id" groups="mass_mailing.group_mass_mailing_campaign"/>
<label for="template_id"/>
<div style="max-height: 200px; overflow: hidden !important;">
<field name="template_id" string="Select Template" nolabel="1"
on_change="on_change_template_id(template_id, context)"/>
<field name="body_html" class="html_preview" nolabel="1"
attrs="{'invisible': [('template_id', '=', False)]}"/>
</div>
<field name="email_from"/>
<field name="reply_to"/>
<field name="email_to"/>
</group>
<group>
<field name="template_id"/>
<field name="domain"/>
<field name="date"/>
<p>Here be some graphs</p>
</group>
</group>
<group string="Email Statistics">
<group>
<label for="contact_list_ids" string="Recipients"/>
<div>
<field name="contact_nbr" class="oe_inline" readonly="True"/>
<field name="mailing_type" class="oe_inline"
on_change='on_change_mailing_type(mailing_type, context)'/>
<span>selected</span>
<group>
<label for="contact_list_ids" string="Selected Lists"/>
<div>
<field name="contact_list_ids" widget="many2many_tags" nolabel="1"/>
<button string='Create a New List' class="oe_inline oe_link" type='object' name='select_customers'/>
</div>
</group>
</div>
</group>
<!-- <group string="Email Statistics">
<field name="statistics_ids" nolabel="1" colspan="2"/>
<group>
<field name="sent"/>
@ -66,7 +241,7 @@
<field name="delivered"/>
<field name="replied"/>
</group>
</group>
</group> -->
</sheet>
</form>
</field>
@ -76,7 +251,7 @@
<field name="name">mail.mass_mailing.kanban</field>
<field name="model">mail.mass_mailing</field>
<field name="arch" type="xml">
<kanban>
<kanban default_group_by='state'>
<field name='color'/>
<templates>
<t t-name="kanban-box">
@ -87,8 +262,9 @@
<field name="name"/>
</h3>
<p style="margin-left: 10px; margin-top: 8px;">
Sent: <field name="date"/><br />
Campaign: <field name="mass_mailing_campaign_id"/>
<span>Sent:</span><field name="date"/><br />
<span groups="mass_mailing.mass_mailing_campaign_id">Campaign:</span>
<field name="mass_mailing_campaign_id" groups="mass_mailing.mass_mailing_campaign_id"/>
</p>
</div>
<div>
@ -112,11 +288,11 @@
<div>
<div class="oe_sparkline_container">
<h4 class="oe_sparkline_bar_title">Opened</h4><br />
<field name="opened_monthly" widget="sparkline_bar" options="{'height': '50px', 'barWidth': 10, 'barSpacing': 5}"/>
<field name="opened_dayly" widget="sparkline_bar" options="{'height': '50px', 'barWidth': 10, 'barSpacing': 5}"/>
</div>
<div class="oe_sparkline_container">
<h4 class="oe_sparkline_bar_title">Replied</h4><br />
<field name="replied_monthly" widget="sparkline_bar" options="{'height': '50px', 'barWidth': 10, 'barSpacing': 5}"/>
<field name="replied_dayly" widget="sparkline_bar" options="{'height': '50px', 'barWidth': 10, 'barSpacing': 5}"/>
</div>
</div>
</div>
@ -147,6 +323,10 @@
</field>
</record>
<menuitem name="Mass Mailings" id="menu_email_mass_mailings"
parent="mass_mailing_campaign" sequence="2"
action="action_view_mass_mailings"/>
<!-- MASS MAILING CAMPAIGNS !-->
<record model="ir.ui.view" id="view_mail_mass_mailing_campaign_search">
<field name="name">mail.mass_mailing.campaign.search</field>
@ -154,10 +334,13 @@
<field name="arch" type="xml">
<search string="Mass Mailing Campaigns">
<field name="name" string="Campaigns"/>
<field name="category_id"/>
<field name="user_id"/>
<group expand="0" string="Group By...">
<filter string="Responsibles" name="group_user_id"
<filter string="Responsible" name="group_user_id"
context="{'group_by': 'user_id'}"/>
<filter string="Category" name="group_category_id"
context="{'group_by': 'category_id'}"/>
</group>
</search>
</field>
@ -171,6 +354,8 @@
<tree string="Mass Mailing Campaigns">
<field name="name"/>
<field name="user_id"/>
<field name="state"/>
<field name="category_id"/>
</tree>
</field>
</record>
@ -182,14 +367,16 @@
<form string="Mass Mailing Campaign" version="7.0">
<header>
<button name="launch_mass_mailing_create_wizard" type="object"
class="oe_highlight" string="Create a New Mailing"/>
class="oe_highlight" string="New Mailing"/>
<field name="state" widget="statusbar" clickable="True"/>
</header>
<sheet>
<group>
<field name="name"/>
<field name="user_id"/>
<field name="category_id"/>
</group>
<group>
<!-- <group>
<group>
<field name="sent"/>
<field name="opened"/>
@ -199,9 +386,20 @@
<field name="delivered"/>
<field name="replied"/>
</group>
</group>
</group> -->
<group>
<field name="mass_mailing_ids" readonly="1"/>
<field name="mass_mailing_ids" readonly="1" string="Related Mailing(s)">
<tree>
<field name="name"/>
<field name="date"/>
<field name="state"/>
<field name="delivered"/>
<field name="opened"/>
<field name="replied"/>
<field name="bounced"/>
<button name="duplicate_mailing" type="object" string="Duplicate"/>
</tree>
</field>
</group>
</sheet>
</form>
@ -212,7 +410,7 @@
<field name="name">mail.mass_mailing.campaign.kanban</field>
<field name="model">mail.mass_mailing.campaign</field>
<field name="arch" type="xml">
<kanban>
<kanban default_group_by='state'>
<field name="mass_mailing_kanban_ids"/>
<field name='sent'/>
<field name='color'/>
@ -299,6 +497,11 @@
</field>
</record>
<menuitem name="Campaigns" id="menu_email_campaigns"
parent="mass_mailing_campaign" sequence="1"
action="action_view_mass_mailing_campaigns"
groups="mass_mailing.group_mass_mailing_campaign"/>
<!-- MAIL MAIL STATISTICS !-->
<record model="ir.ui.view" id="view_mail_mail_statistics_search">
<field name="name">mail.mail.statistics.search</field>
@ -357,23 +560,25 @@
<field name="view_mode">tree,form</field>
</record>
<!-- Top menu item -->
<menuitem name="Marketing" id="base.marketing_menu" sequence="85" groups="base.group_user"/>
<!-- Add in marketing -->
<menuitem name="Mass Mailing" id="mass_mailing_campaign"
parent="base.marketing_menu" sequence="1"/>
<menuitem name="Campaigns" id="menu_email_campaigns"
parent="mass_mailing_campaign" sequence="1"
action="action_view_mass_mailing_campaigns"/>
<menuitem name="Mass Mailings" id="menu_email_mass_mailings"
parent="mass_mailing_campaign" sequence="2"
action="action_view_mass_mailings"/>
<!-- Add in Technical/Email -->
<menuitem name="Mail Statistics" id="menu_email_statistics"
parent="base.menu_email" sequence="50"
action="action_view_mail_mail_statistics"/>
<!-- Replace the default mass-mailing wizard in base with the composition wizard -->
<act_window name="Partner to Mailing List"
res_model="mail.mass_mailing.list"
src_model="res.partner"
view_mode="form"
multi="True"
target="current"
key2="client_action_multi"
id="action_partner_to_mailing_list"
context="{
'caca': 'prout',
}"/>
</data>
</openerp>

View File

@ -0,0 +1,15 @@
# -*- coding: utf-8 -*-
from openerp.osv import fields, osv
class MassMailingConfiguration(osv.TransientModel):
_name = 'marketing.config.settings'
_inherit = 'marketing.config.settings'
_columns = {
'group_mass_mailing_campaign': fields.boolean(
'Manage Mass Mailing using Campaign',
implied_group='mass_mailing.group_mass_mailing_campaign',
help="""Manage mass mailign using Campaigns"""),
}

View File

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<record id="view_marketing_settings_mass_mailing" model="ir.ui.view">
<field name="name">marketing.config.settings.mass.mailing</field>
<field name="model">marketing.config.settings</field>
<field name="inherit_id" ref="marketing.view_marketing_configuration"/>
<field name="arch" type="xml">
<xpath expr="//div[@name='module_mass_mailing']" position="after">
<div>
<field name="group_mass_mailing_campaign" class="oe_inline"/>
<label for="group_mass_mailing_campaign"/>
</div>
</xpath>
</field>
</record>
</data>
</openerp>

View File

@ -1,4 +1,7 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_mass_mailing_category,mail.mass_mailing.category,model_mail_mass_mailing_category,base.group_user,1,1,1,1
access_mass_mailing_contact,mail.mass_mailing.contact,model_mail_mass_mailing_contact,base.group_user,1,1,1,1
access_mass_mailing_list,mail.mass_mailing.list,model_mail_mass_mailing_list,base.group_user,1,1,1,1
access_mass_mailing_campaign,mail.mass_mailing.campaign,model_mail_mass_mailing_campaign,base.group_user,1,1,1,0
access_mass_mailing_campaign_system,mail.mass_mailing.campaign.system,model_mail_mass_mailing_campaign,base.group_system,1,1,1,1
access_mass_mailing,mail.mass_mailing,model_mail_mass_mailing,base.group_user,1,1,1,0

1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_mass_mailing_category mail.mass_mailing.category model_mail_mass_mailing_category base.group_user 1 1 1 1
3 access_mass_mailing_contact mail.mass_mailing.contact model_mail_mass_mailing_contact base.group_user 1 1 1 1
4 access_mass_mailing_list mail.mass_mailing.list model_mail_mass_mailing_list base.group_user 1 1 1 1
5 access_mass_mailing_campaign mail.mass_mailing.campaign model_mail_mass_mailing_campaign base.group_user 1 1 1 0
6 access_mass_mailing_campaign_system mail.mass_mailing.campaign.system model_mail_mass_mailing_campaign base.group_system 1 1 1 1
7 access_mass_mailing mail.mass_mailing model_mail_mass_mailing base.group_user 1 1 1 0

View File

@ -0,0 +1,19 @@
.openerp .oe_kanban_email_template {
width: 360px;
min-height: 270px !important;
}
.html_preview {
width: 600px;
height: 400px;
-webkit-transform: scale(.50);
-ms-transform: scale(.50);
transform: scale(.50);
-webkit-transform-origin: 0 0;
-ms-transform-origin: 0 0;
transform-origin: 0 0;
border: 2px solid gray;
margin: 0 0px -300px 0;
overflow: hidden !important;
}