2013-08-07 13:03:34 +00:00
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
##############################################################################
|
|
|
|
#
|
|
|
|
# OpenERP, Open Source Management Solution
|
|
|
|
# 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
|
|
|
|
# published by the Free Software Foundation, either version 3 of the
|
|
|
|
# License, or (at your option) any later version
|
|
|
|
#
|
|
|
|
# This program is distributed in the hope that it will be useful,
|
|
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
# GNU Affero General Public License for more details
|
|
|
|
#
|
|
|
|
# You should have received a copy of the GNU Affero General Public License
|
|
|
|
# along with this program. If not, see <http://www.gnu.org/licenses/>
|
|
|
|
#
|
|
|
|
##############################################################################
|
|
|
|
|
2013-09-10 15:29:33 +00:00
|
|
|
from datetime import datetime
|
2013-09-03 14:59:36 +00:00
|
|
|
from dateutil import relativedelta
|
2014-04-01 13:24:54 +00:00
|
|
|
import random
|
2014-04-12 15:33:39 +00:00
|
|
|
import json
|
2014-03-21 17:21:39 +00:00
|
|
|
import urllib
|
|
|
|
import urlparse
|
2013-09-03 14:59:36 +00:00
|
|
|
|
|
|
|
from openerp import tools
|
2014-03-24 17:10:17 +00:00
|
|
|
from openerp.exceptions import Warning
|
2014-03-14 16:51:13 +00:00
|
|
|
from openerp.tools.safe_eval import safe_eval as eval
|
2013-09-12 10:09:09 +00:00
|
|
|
from openerp.tools.translate import _
|
2013-08-07 13:03:34 +00:00
|
|
|
from openerp.osv import osv, fields
|
|
|
|
|
|
|
|
|
2014-03-14 16:51:13 +00:00
|
|
|
class MassMailingCategory(osv.Model):
|
|
|
|
"""Model of categories of mass mailing, i.e. marketing, newsletter, ... """
|
|
|
|
_name = 'mail.mass_mailing.category'
|
|
|
|
_description = 'Mass Mailing Category'
|
2014-04-12 13:01:32 +00:00
|
|
|
_order = 'name'
|
2014-03-14 16:51:13 +00:00
|
|
|
|
|
|
|
_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
|
2014-04-12 13:01:32 +00:00
|
|
|
base."""
|
2014-03-14 16:51:13 +00:00
|
|
|
_name = 'mail.mass_mailing.contact'
|
|
|
|
_description = 'Mass Mailing Contact'
|
2014-04-12 13:01:32 +00:00
|
|
|
_order = 'email'
|
|
|
|
_rec_name = 'email'
|
2014-03-14 16:51:13 +00:00
|
|
|
|
|
|
|
_columns = {
|
2014-04-12 13:01:32 +00:00
|
|
|
'name': fields.char('Name'),
|
2014-03-14 16:51:13 +00:00
|
|
|
'email': fields.char('Email', required=True),
|
2014-04-12 20:31:29 +00:00
|
|
|
'create_date': fields.datetime('Create Date'),
|
2014-03-14 16:51:13 +00:00
|
|
|
'list_id': fields.many2one(
|
|
|
|
'mail.mass_mailing.list', string='Mailing List',
|
2014-04-12 20:31:29 +00:00
|
|
|
ondelete='cascade', required=True,
|
2014-03-14 16:51:13 +00:00
|
|
|
),
|
2014-04-12 13:01:32 +00:00
|
|
|
'opt_out': fields.boolean('Opt Out', help='The contact has chosen not to receive mails anymore from this list'),
|
2014-03-14 16:51:13 +00:00
|
|
|
}
|
|
|
|
|
2014-04-12 15:33:39 +00:00
|
|
|
def _get_latest_list(self, cr, uid, context={}):
|
|
|
|
lid = self.pool.get('mail.mass_mailing.list').search(cr, uid, [], limit=1, order='id desc', context=context)
|
|
|
|
return lid and lid[0] or False
|
2014-04-14 13:11:09 +00:00
|
|
|
|
2014-04-12 15:33:39 +00:00
|
|
|
_defaults = {
|
|
|
|
'list_id': _get_latest_list
|
2014-03-14 16:51:13 +00:00
|
|
|
}
|
|
|
|
|
2014-03-18 16:41:17 +00:00
|
|
|
def name_create(self, cr, uid, name, context=None):
|
|
|
|
name, email = self.pool['res.partner']._parse_partner_name(name, context=context)
|
|
|
|
if name and not email:
|
|
|
|
email = name
|
|
|
|
if email and not name:
|
|
|
|
name = email
|
|
|
|
rec_id = self.create(cr, uid, {'name': name, 'email': email}, context=context)
|
|
|
|
return self.name_get(cr, uid, [rec_id], context)[0]
|
|
|
|
|
2014-03-14 16:51:13 +00:00
|
|
|
|
|
|
|
class MassMailingList(osv.Model):
|
|
|
|
"""Model of a contact list. """
|
|
|
|
_name = 'mail.mass_mailing.list'
|
2014-04-12 13:01:32 +00:00
|
|
|
_order = 'name'
|
|
|
|
_description = 'Mailing List'
|
2014-03-14 16:51:13 +00:00
|
|
|
|
|
|
|
def _get_contact_nbr(self, cr, uid, ids, name, arg, context=None):
|
2014-04-14 13:11:09 +00:00
|
|
|
result = dict.fromkeys(ids, 0)
|
|
|
|
Contacts = self.pool.get('mail.mass_mailing.contact')
|
|
|
|
for group in Contacts.read_group(cr, uid, [('list_id', 'in', ids), ('opt_out', '!=', True)], ['list_id'], ['list_id'], context=context):
|
|
|
|
result[group['list_id'][0]] = group['list_id_count']
|
|
|
|
return result
|
2014-03-14 16:51:13 +00:00
|
|
|
|
|
|
|
_columns = {
|
2014-04-12 13:01:32 +00:00
|
|
|
'name': fields.char('Mailing List', required=True),
|
2014-03-14 16:51:13 +00:00
|
|
|
'contact_nbr': fields.function(
|
|
|
|
_get_contact_nbr, type='integer',
|
2014-04-14 13:11:09 +00:00
|
|
|
string='Number of Contacts',
|
2014-03-14 16:51:13 +00:00
|
|
|
),
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-04-04 15:34:32 +00:00
|
|
|
class MassMailingStage(osv.Model):
|
|
|
|
"""Stage for mass mailing campaigns. """
|
|
|
|
_name = 'mail.mass_mailing.stage'
|
|
|
|
_description = 'Mass Mailing Campaign Stage'
|
2014-04-12 13:01:32 +00:00
|
|
|
_order = 'sequence'
|
2014-04-04 15:34:32 +00:00
|
|
|
|
|
|
|
_columns = {
|
2014-04-12 13:01:32 +00:00
|
|
|
'name': fields.char('Name', required=True, translate=True),
|
2014-04-04 15:34:32 +00:00
|
|
|
'sequence': fields.integer('Sequence'),
|
|
|
|
}
|
|
|
|
|
|
|
|
_defaults = {
|
|
|
|
'sequence': 0,
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-08-07 13:03:34 +00:00
|
|
|
class MassMailingCampaign(osv.Model):
|
2014-03-18 13:04:28 +00:00
|
|
|
"""Model of mass mailing campaigns. """
|
2013-08-07 13:03:34 +00:00
|
|
|
_name = "mail.mass_mailing.campaign"
|
|
|
|
_description = 'Mass Mailing Campaign'
|
|
|
|
|
|
|
|
def _get_statistics(self, cr, uid, ids, name, arg, context=None):
|
|
|
|
""" Compute statistics of the mass mailing campaign """
|
2014-03-17 16:09:19 +00:00
|
|
|
Statistics = self.pool['mail.mail.statistics']
|
2013-08-07 13:03:34 +00:00
|
|
|
results = dict.fromkeys(ids, False)
|
2014-03-17 16:09:19 +00:00
|
|
|
for cid in ids:
|
2014-04-08 12:40:53 +00:00
|
|
|
stat_ids = Statistics.search(cr, uid, [('mass_mailing_campaign_id', '=', cid)], context=context)
|
2014-04-08 11:30:29 +00:00
|
|
|
stats = Statistics.browse(cr, uid, stat_ids, context=context)
|
2014-03-17 16:09:19 +00:00
|
|
|
results[cid] = {
|
2014-04-08 11:30:29 +00:00
|
|
|
'total': len(stats),
|
|
|
|
'failed': len([s for s in stats if not s.scheduled is False and s.sent is False and not s.exception is False]),
|
2014-04-08 12:40:53 +00:00
|
|
|
'scheduled': len([s for s in stats if not s.scheduled is False and s.sent is False and s.exception is False]),
|
2014-04-08 11:30:29 +00:00
|
|
|
'sent': len([s for s in stats if not s.sent is False]),
|
|
|
|
'opened': len([s for s in stats if not s.opened is False]),
|
|
|
|
'replied': len([s for s in stats if not s.replied is False]),
|
|
|
|
'bounced': len([s for s in stats if not s.bounced is False]),
|
2013-08-07 13:03:34 +00:00
|
|
|
}
|
2014-03-17 16:09:19 +00:00
|
|
|
results[cid]['delivered'] = results[cid]['sent'] - results[cid]['bounced']
|
2014-04-04 15:34:32 +00:00
|
|
|
results[cid]['received_ratio'] = 100.0 * results[cid]['delivered'] / (results[cid]['sent'] or 1)
|
|
|
|
results[cid]['opened_ratio'] = 100.0 * results[cid]['opened'] / (results[cid]['sent'] or 1)
|
|
|
|
results[cid]['replied_ratio'] = 100.0 * results[cid]['replied'] / (results[cid]['sent'] or 1)
|
2013-09-03 14:59:36 +00:00
|
|
|
return results
|
|
|
|
|
2013-08-07 13:03:34 +00:00
|
|
|
_columns = {
|
2014-03-17 16:09:19 +00:00
|
|
|
'name': fields.char('Name', required=True),
|
2014-04-04 15:34:32 +00:00
|
|
|
'stage_id': fields.many2one('mail.mass_mailing.stage', 'Stage', required=True),
|
2013-09-13 11:54:08 +00:00
|
|
|
'user_id': fields.many2one(
|
|
|
|
'res.users', 'Responsible',
|
|
|
|
required=True,
|
2013-09-03 14:59:36 +00:00
|
|
|
),
|
2014-04-14 13:11:09 +00:00
|
|
|
'category_ids': fields.many2many(
|
|
|
|
'mail.mass_mailing.category', 'mail_mass_mailing_category_rel',
|
2014-04-12 20:31:29 +00:00
|
|
|
'category_id', 'campaign_id', string='Categories'),
|
2013-09-13 11:54:08 +00:00
|
|
|
'mass_mailing_ids': fields.one2many(
|
|
|
|
'mail.mass_mailing', 'mass_mailing_campaign_id',
|
|
|
|
'Mass Mailings',
|
2013-09-03 14:59:36 +00:00
|
|
|
),
|
2014-04-01 13:24:54 +00:00
|
|
|
'ab_testing': fields.boolean(
|
|
|
|
'AB Testing',
|
|
|
|
help='If checked, recipients will be mailed only once, allowing to send'
|
|
|
|
'various mailings in a single campaign to test the effectiveness'
|
|
|
|
'of the mailings.'),
|
2013-09-10 10:46:23 +00:00
|
|
|
'color': fields.integer('Color Index'),
|
2013-09-03 14:59:36 +00:00
|
|
|
# stat fields
|
2014-03-17 16:09:19 +00:00
|
|
|
'total': fields.function(
|
2014-04-01 13:53:52 +00:00
|
|
|
_get_statistics, string='Total',
|
|
|
|
type='integer', multi='_get_statistics'
|
|
|
|
),
|
|
|
|
'scheduled': fields.function(
|
2014-04-08 11:30:29 +00:00
|
|
|
_get_statistics, string='Scheduled',
|
|
|
|
type='integer', multi='_get_statistics'
|
|
|
|
),
|
|
|
|
'failed': fields.function(
|
|
|
|
_get_statistics, string='Failed',
|
2014-03-17 16:09:19 +00:00
|
|
|
type='integer', multi='_get_statistics'
|
|
|
|
),
|
2013-09-03 14:59:36 +00:00
|
|
|
'sent': fields.function(
|
2014-03-17 16:09:19 +00:00
|
|
|
_get_statistics, string='Sent Emails',
|
2013-09-03 14:59:36 +00:00
|
|
|
type='integer', multi='_get_statistics'
|
|
|
|
),
|
2013-09-10 10:46:23 +00:00
|
|
|
'delivered': fields.function(
|
2014-03-17 16:09:19 +00:00
|
|
|
_get_statistics, string='Delivered',
|
2013-09-10 10:46:23 +00:00
|
|
|
type='integer', multi='_get_statistics',
|
|
|
|
),
|
2013-09-03 14:59:36 +00:00
|
|
|
'opened': fields.function(
|
2014-03-17 16:09:19 +00:00
|
|
|
_get_statistics, string='Opened',
|
2013-09-03 14:59:36 +00:00
|
|
|
type='integer', multi='_get_statistics',
|
|
|
|
),
|
|
|
|
'replied': fields.function(
|
2014-03-17 16:09:19 +00:00
|
|
|
_get_statistics, string='Replied',
|
2013-09-03 14:59:36 +00:00
|
|
|
type='integer', multi='_get_statistics'
|
|
|
|
),
|
|
|
|
'bounced': fields.function(
|
2014-03-17 16:09:19 +00:00
|
|
|
_get_statistics, string='Bounced',
|
2013-09-03 14:59:36 +00:00
|
|
|
type='integer', multi='_get_statistics'
|
|
|
|
),
|
2014-04-04 15:34:32 +00:00
|
|
|
'received_ratio': fields.function(
|
|
|
|
_get_statistics, string='Received Ratio',
|
|
|
|
type='integer', multi='_get_statistics',
|
|
|
|
),
|
|
|
|
'opened_ratio': fields.function(
|
|
|
|
_get_statistics, string='Opened Ratio',
|
|
|
|
type='integer', multi='_get_statistics',
|
|
|
|
),
|
|
|
|
'replied_ratio': fields.function(
|
|
|
|
_get_statistics, string='Replied Ratio',
|
|
|
|
type='integer', multi='_get_statistics',
|
|
|
|
),
|
2013-09-03 14:59:36 +00:00
|
|
|
}
|
|
|
|
|
2014-04-04 15:34:32 +00:00
|
|
|
def _get_default_stage_id(self, cr, uid, context=None):
|
|
|
|
stage_ids = self.pool['mail.mass_mailing.stage'].search(cr, uid, [], limit=1, context=context)
|
2014-04-12 13:01:32 +00:00
|
|
|
return stage_ids and stage_ids[0] or False
|
2014-04-04 15:34:32 +00:00
|
|
|
|
2013-09-13 14:00:43 +00:00
|
|
|
_defaults = {
|
|
|
|
'user_id': lambda self, cr, uid, ctx=None: uid,
|
2014-04-12 15:33:39 +00:00
|
|
|
'stage_id': lambda self, *args: self._get_default_stage_id(*args),
|
2013-09-13 14:00:43 +00:00
|
|
|
}
|
2013-09-13 11:54:08 +00:00
|
|
|
|
2014-04-01 13:24:54 +00:00
|
|
|
def get_recipients(self, cr, uid, ids, model=None, context=None):
|
|
|
|
"""Return the recipints of a mailing campaign. This is based on the statistics
|
|
|
|
build for each mailing. """
|
|
|
|
Statistics = self.pool['mail.mail.statistics']
|
|
|
|
res = dict.fromkeys(ids, False)
|
|
|
|
for cid in ids:
|
|
|
|
domain = [('mass_mailing_campaign_id', '=', cid)]
|
|
|
|
if model:
|
|
|
|
domain += [('model', '=', model)]
|
|
|
|
stat_ids = Statistics.search(cr, uid, domain, context=context)
|
|
|
|
res[cid] = set(stat.res_id for stat in Statistics.browse(cr, uid, stat_ids, context=context))
|
|
|
|
return res
|
|
|
|
|
2013-09-03 14:59:36 +00:00
|
|
|
|
2013-09-13 11:54:08 +00:00
|
|
|
class MassMailing(osv.Model):
|
|
|
|
""" MassMailing models a wave of emails for a mass mailign campaign.
|
|
|
|
A mass mailing is an occurence of sending emails. """
|
2013-09-10 12:11:23 +00:00
|
|
|
|
2013-09-13 11:54:08 +00:00
|
|
|
_name = 'mail.mass_mailing'
|
2014-03-14 16:51:13 +00:00
|
|
|
_description = 'Mass Mailing'
|
2013-09-03 14:59:36 +00:00
|
|
|
# number of periods for tracking mail_mail statistics
|
|
|
|
_period_number = 6
|
2013-09-17 10:35:55 +00:00
|
|
|
_order = 'date DESC'
|
2013-09-03 14:59:36 +00:00
|
|
|
|
2013-09-10 12:11:23 +00:00
|
|
|
def __get_bar_values(self, cr, uid, id, obj, domain, read_fields, value_field, groupby_field, context=None):
|
2013-09-03 14:59:36 +00:00
|
|
|
""" Generic method to generate data for bar chart values using SparklineBarWidget.
|
|
|
|
This method performs obj.read_group(cr, uid, domain, read_fields, groupby_field).
|
|
|
|
|
|
|
|
:param obj: the target model (i.e. crm_lead)
|
|
|
|
:param domain: the domain applied to the read_group
|
|
|
|
:param list read_fields: the list of fields to read in the read_group
|
|
|
|
:param str value_field: the field used to compute the value of the bar slice
|
|
|
|
:param str groupby_field: the fields used to group
|
|
|
|
|
|
|
|
:return list section_result: a list of dicts: [
|
|
|
|
{ 'value': (int) bar_column_value,
|
|
|
|
'tootip': (str) bar_column_tooltip,
|
|
|
|
}
|
|
|
|
]
|
|
|
|
"""
|
2013-09-10 12:11:23 +00:00
|
|
|
date_begin = datetime.strptime(self.browse(cr, uid, id, context=context).date, tools.DEFAULT_SERVER_DATETIME_FORMAT).date()
|
2013-09-03 14:59:36 +00:00
|
|
|
section_result = [{'value': 0,
|
2013-09-10 12:11:23 +00:00
|
|
|
'tooltip': (date_begin + relativedelta.relativedelta(days=i)).strftime('%d %B %Y'),
|
|
|
|
} for i in range(0, self._period_number)]
|
2013-09-03 14:59:36 +00:00
|
|
|
group_obj = obj.read_group(cr, uid, domain, read_fields, groupby_field, context=context)
|
2014-02-19 12:35:05 +00:00
|
|
|
field_col_info = obj._all_columns.get(groupby_field.split(':')[0])
|
|
|
|
pattern = tools.DEFAULT_SERVER_DATE_FORMAT if field_col_info.column._type == 'date' else tools.DEFAULT_SERVER_DATETIME_FORMAT
|
2013-09-03 14:59:36 +00:00
|
|
|
for group in group_obj:
|
2014-02-19 12:35:05 +00:00
|
|
|
group_begin_date = datetime.strptime(group['__domain'][0][2], pattern).date()
|
2013-09-10 12:11:23 +00:00
|
|
|
timedelta = relativedelta.relativedelta(group_begin_date, date_begin)
|
|
|
|
section_result[timedelta.days] = {'value': group.get(value_field, 0), 'tooltip': group.get(groupby_field)}
|
2013-09-03 14:59:36 +00:00
|
|
|
return section_result
|
|
|
|
|
2013-09-17 10:35:55 +00:00
|
|
|
def _get_daily_statistics(self, cr, uid, ids, field_name, arg, context=None):
|
|
|
|
""" Get the daily statistics of the mass mailing. This is done by a grouping
|
|
|
|
on opened and replied fields. Using custom format in context, we obtain
|
|
|
|
results for the next 6 days following the mass mailing date. """
|
2013-09-13 11:54:08 +00:00
|
|
|
obj = self.pool['mail.mail.statistics']
|
2013-09-10 12:11:23 +00:00
|
|
|
res = {}
|
2013-09-03 14:59:36 +00:00
|
|
|
for id in ids:
|
2013-09-10 12:11:23 +00:00
|
|
|
res[id] = {}
|
2013-10-03 08:27:36 +00:00
|
|
|
date_begin = datetime.strptime(self.browse(cr, uid, id, context=context).date, tools.DEFAULT_SERVER_DATETIME_FORMAT)
|
|
|
|
date_end = date_begin + relativedelta.relativedelta(days=self._period_number - 1)
|
|
|
|
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)]
|
2014-04-08 12:40:53 +00:00
|
|
|
res[id]['opened_dayly'] = json.dumps(self.__get_bar_values(cr, uid, id, obj, domain, ['opened'], 'opened_count', 'opened:day', context=context))
|
2013-10-03 08:27:36 +00:00
|
|
|
domain = [('mass_mailing_id', '=', id), ('replied', '>=', date_begin_str), ('replied', '<=', date_end_str)]
|
2014-04-08 12:40:53 +00:00
|
|
|
res[id]['replied_dayly'] = json.dumps(self.__get_bar_values(cr, uid, id, obj, domain, ['replied'], 'replied_count', 'replied:day', context=context))
|
2013-09-03 14:59:36 +00:00
|
|
|
return res
|
|
|
|
|
|
|
|
def _get_statistics(self, cr, uid, ids, name, arg, context=None):
|
|
|
|
""" Compute statistics of the mass mailing campaign """
|
2014-03-17 16:09:19 +00:00
|
|
|
Statistics = self.pool['mail.mail.statistics']
|
2013-09-03 14:59:36 +00:00
|
|
|
results = dict.fromkeys(ids, False)
|
2014-03-17 16:09:19 +00:00
|
|
|
for mid in ids:
|
2014-04-08 11:30:29 +00:00
|
|
|
stat_ids = Statistics.search(cr, uid, [('mass_mailing_id', '=', mid)], context=context)
|
|
|
|
stats = Statistics.browse(cr, uid, stat_ids, context=context)
|
2014-03-17 16:09:19 +00:00
|
|
|
results[mid] = {
|
2014-04-08 11:30:29 +00:00
|
|
|
'total': len(stats),
|
|
|
|
'failed': len([s for s in stats if not s.scheduled is False and s.sent is False and not s.exception is False]),
|
2014-04-08 12:40:53 +00:00
|
|
|
'scheduled': len([s for s in stats if not s.scheduled is False and s.sent is False and s.exception is False]),
|
2014-04-08 11:30:29 +00:00
|
|
|
'sent': len([s for s in stats if not s.sent is False]),
|
|
|
|
'opened': len([s for s in stats if not s.opened is False]),
|
|
|
|
'replied': len([s for s in stats if not s.replied is False]),
|
|
|
|
'bounced': len([s for s in stats if not s.bounced is False]),
|
2013-09-03 14:59:36 +00:00
|
|
|
}
|
2014-03-17 16:09:19 +00:00
|
|
|
results[mid]['delivered'] = results[mid]['sent'] - results[mid]['bounced']
|
2014-03-28 13:59:07 +00:00
|
|
|
results[mid]['received_ratio'] = 100.0 * results[mid]['delivered'] / (results[mid]['sent'] or 1)
|
|
|
|
results[mid]['opened_ratio'] = 100.0 * results[mid]['opened'] / (results[mid]['sent'] or 1)
|
|
|
|
results[mid]['replied_ratio'] = 100.0 * results[mid]['replied'] / (results[mid]['sent'] or 1)
|
2013-09-03 14:59:36 +00:00
|
|
|
return results
|
|
|
|
|
2014-03-18 13:04:28 +00:00
|
|
|
def _get_contact_nbr(self, cr, uid, ids, name, arg, context=None):
|
2014-04-01 13:24:54 +00:00
|
|
|
res = dict.fromkeys(ids, False)
|
2014-03-18 13:04:28 +00:00
|
|
|
for mailing in self.browse(cr, uid, ids, context=context):
|
2014-04-14 13:11:09 +00:00
|
|
|
val = {'contact_nbr': 0, 'contact_ab_nbr': 0} # 'contact_ab_done': 0
|
2014-04-01 13:24:54 +00:00
|
|
|
val['contact_nbr'] = self.pool[mailing.mailing_model].search(
|
2014-04-14 13:11:09 +00:00
|
|
|
cr, uid, eval(mailing.mailing_domain),
|
2014-03-18 13:04:28 +00:00
|
|
|
count=True, context=context
|
|
|
|
)
|
2014-04-14 13:11:09 +00:00
|
|
|
# val['contact_ab_nbr'] = int(val['contact_nbr'] * mailing.contact_ab_pc / 100.0)
|
|
|
|
# if mailing.mass_mailing_campaign_id and mailing.ab_testing:
|
|
|
|
# val['contact_ab_done'] = len(self.pool['mail.mass_mailing.campaign'].get_recipients(cr, uid, [mailing.mass_mailing_campaign_id.id], context=context)[mailing.mass_mailing_campaign_id.id])
|
2014-04-01 13:24:54 +00:00
|
|
|
res[mailing.id] = val
|
2014-03-18 13:04:28 +00:00
|
|
|
return res
|
|
|
|
|
2014-04-07 17:03:46 +00:00
|
|
|
def _get_private_models(self, context=None):
|
2014-04-08 11:30:29 +00:00
|
|
|
return ['res.partner', 'mail.mass_mailing.contact']
|
2014-04-07 17:03:46 +00:00
|
|
|
|
|
|
|
def _get_auto_reply_to_available(self, cr, uid, ids, name, arg, context=None):
|
|
|
|
res = dict.fromkeys(ids, False)
|
|
|
|
for mailing in self.browse(cr, uid, ids, context=context):
|
|
|
|
res[mailing.id] = mailing.mailing_model not in self._get_private_models(context=context)
|
|
|
|
return res
|
2014-04-04 15:03:50 +00:00
|
|
|
|
2014-03-17 17:16:12 +00:00
|
|
|
def _get_mailing_model(self, cr, uid, context=None):
|
2014-03-14 16:51:13 +00:00
|
|
|
return [
|
2014-04-12 23:21:59 +00:00
|
|
|
('res.partner', _('Customers')),
|
|
|
|
('mail.mass_mailing.contact', _('Mailing List'))
|
2014-03-14 16:51:13 +00:00
|
|
|
]
|
|
|
|
|
|
|
|
# indirections for inheritance
|
2014-03-17 17:16:12 +00:00
|
|
|
_mailing_model = lambda self, *args, **kwargs: self._get_mailing_model(*args, **kwargs)
|
2014-03-14 16:51:13 +00:00
|
|
|
|
2013-09-03 14:59:36 +00:00
|
|
|
_columns = {
|
2014-03-14 16:51:13 +00:00
|
|
|
'name': fields.char('Subject', required=True),
|
2014-04-12 23:21:59 +00:00
|
|
|
'email_from': fields.char('From', required=True),
|
2014-03-14 16:51:13 +00:00
|
|
|
'date': fields.datetime('Date'),
|
2014-04-04 15:03:50 +00:00
|
|
|
'body_html': fields.html('Body'),
|
2014-03-14 16:51:13 +00:00
|
|
|
'mass_mailing_campaign_id': fields.many2one(
|
|
|
|
'mail.mass_mailing.campaign', 'Mass Mailing Campaign',
|
2013-08-07 13:03:34 +00:00
|
|
|
ondelete='set null',
|
|
|
|
),
|
2014-04-12 15:33:39 +00:00
|
|
|
'state': fields.selection(
|
2014-04-14 13:11:09 +00:00
|
|
|
[('draft', 'Draft'), ('test', 'Tested'), ('done', 'Sent')],
|
|
|
|
string='Status', required=True,
|
2014-04-01 13:24:54 +00:00
|
|
|
),
|
2013-09-10 15:19:01 +00:00
|
|
|
'color': fields.related(
|
|
|
|
'mass_mailing_campaign_id', 'color',
|
|
|
|
type='integer', string='Color Index',
|
|
|
|
),
|
2014-03-14 16:51:13 +00:00
|
|
|
# mailing options
|
2014-04-12 15:33:39 +00:00
|
|
|
# TODO: simplify these 4 fields
|
2014-04-07 17:03:46 +00:00
|
|
|
'reply_in_thread': fields.boolean('Reply in thread'),
|
|
|
|
'reply_specified': fields.boolean('Specific Reply-To'),
|
|
|
|
'auto_reply_to_available': fields.function(
|
|
|
|
_get_auto_reply_to_available,
|
|
|
|
type='boolean', string='Reply in thread available'
|
|
|
|
),
|
2014-03-14 16:51:13 +00:00
|
|
|
'reply_to': fields.char('Reply To'),
|
2014-04-12 15:33:39 +00:00
|
|
|
# Target Emails
|
2014-04-14 13:11:09 +00:00
|
|
|
'mailing_model': fields.selection(_mailing_model, string='Recipients Model', required=True),
|
2014-04-12 20:31:29 +00:00
|
|
|
'mailing_domain': fields.char('Domain'),
|
2014-03-14 16:51:13 +00:00
|
|
|
'contact_list_ids': fields.many2many(
|
|
|
|
'mail.mass_mailing.list', 'mail_mass_mailing_list_rel',
|
|
|
|
string='Mailing Lists',
|
|
|
|
),
|
2014-04-01 13:24:54 +00:00
|
|
|
'contact_nbr': fields.function(
|
|
|
|
_get_contact_nbr, type='integer', multi='_get_contact_nbr',
|
|
|
|
string='Contact Number'
|
|
|
|
),
|
|
|
|
'contact_ab_pc': fields.integer(
|
|
|
|
'AB Testing percentage',
|
|
|
|
help='Percentage of the contacts that will be mailed. Recipients will be taken randomly.'
|
|
|
|
),
|
2013-09-13 11:54:08 +00:00
|
|
|
# statistics data
|
|
|
|
'statistics_ids': fields.one2many(
|
|
|
|
'mail.mail.statistics', 'mass_mailing_id',
|
2013-09-13 14:00:43 +00:00
|
|
|
'Emails Statistics',
|
2013-08-07 13:03:34 +00:00
|
|
|
),
|
2014-03-17 16:09:19 +00:00
|
|
|
'total': fields.function(
|
2014-03-28 13:59:07 +00:00
|
|
|
_get_statistics, string='Total',
|
|
|
|
type='integer', multi='_get_statistics',
|
|
|
|
),
|
|
|
|
'scheduled': fields.function(
|
2014-03-17 16:09:19 +00:00
|
|
|
_get_statistics, string='Scheduled',
|
2014-03-28 13:59:07 +00:00
|
|
|
type='integer', multi='_get_statistics',
|
2014-03-17 16:09:19 +00:00
|
|
|
),
|
2014-04-08 11:30:29 +00:00
|
|
|
'failed': fields.function(
|
|
|
|
_get_statistics, string='Failed',
|
|
|
|
type='integer', multi='_get_statistics',
|
|
|
|
),
|
2013-08-07 13:03:34 +00:00
|
|
|
'sent': fields.function(
|
2014-03-17 16:09:19 +00:00
|
|
|
_get_statistics, string='Sent',
|
2014-03-28 13:59:07 +00:00
|
|
|
type='integer', multi='_get_statistics',
|
2013-08-07 13:03:34 +00:00
|
|
|
),
|
2013-09-10 10:46:23 +00:00
|
|
|
'delivered': fields.function(
|
2014-03-17 16:09:19 +00:00
|
|
|
_get_statistics, string='Delivered',
|
2013-09-10 10:46:23 +00:00
|
|
|
type='integer', multi='_get_statistics',
|
|
|
|
),
|
2013-09-03 14:59:36 +00:00
|
|
|
'opened': fields.function(
|
2014-03-17 16:09:19 +00:00
|
|
|
_get_statistics, string='Opened',
|
2013-09-03 14:59:36 +00:00
|
|
|
type='integer', multi='_get_statistics',
|
2013-08-07 13:03:34 +00:00
|
|
|
),
|
2013-09-03 14:59:36 +00:00
|
|
|
'replied': fields.function(
|
2014-03-17 16:09:19 +00:00
|
|
|
_get_statistics, string='Replied',
|
2014-03-28 13:59:07 +00:00
|
|
|
type='integer', multi='_get_statistics',
|
2013-08-07 13:03:34 +00:00
|
|
|
),
|
2013-09-03 14:59:36 +00:00
|
|
|
'bounced': fields.function(
|
2014-03-17 16:09:19 +00:00
|
|
|
_get_statistics, string='Bounced',
|
2014-03-28 13:59:07 +00:00
|
|
|
type='integer', multi='_get_statistics',
|
|
|
|
),
|
|
|
|
'received_ratio': fields.function(
|
|
|
|
_get_statistics, string='Received Ratio',
|
|
|
|
type='integer', multi='_get_statistics',
|
|
|
|
),
|
|
|
|
'opened_ratio': fields.function(
|
|
|
|
_get_statistics, string='Opened Ratio',
|
|
|
|
type='integer', multi='_get_statistics',
|
|
|
|
),
|
|
|
|
'replied_ratio': fields.function(
|
|
|
|
_get_statistics, string='Replied Ratio',
|
|
|
|
type='integer', multi='_get_statistics',
|
2013-09-03 14:59:36 +00:00
|
|
|
),
|
2014-03-28 13:59:07 +00:00
|
|
|
# dayly ratio
|
2014-03-14 16:51:13 +00:00
|
|
|
'opened_dayly': fields.function(
|
2014-03-17 16:09:19 +00:00
|
|
|
_get_daily_statistics, string='Opened',
|
2013-09-17 10:35:55 +00:00
|
|
|
type='char', multi='_get_daily_statistics',
|
2014-03-14 16:51:13 +00:00
|
|
|
oldname='opened_monthly',
|
2013-09-03 14:59:36 +00:00
|
|
|
),
|
2014-03-14 16:51:13 +00:00
|
|
|
'replied_dayly': fields.function(
|
2014-03-17 16:09:19 +00:00
|
|
|
_get_daily_statistics, string='Replied',
|
2013-09-17 10:35:55 +00:00
|
|
|
type='char', multi='_get_daily_statistics',
|
2014-03-14 16:51:13 +00:00
|
|
|
oldname='replied_monthly',
|
2013-08-07 13:03:34 +00:00
|
|
|
),
|
|
|
|
}
|
2013-09-10 15:19:01 +00:00
|
|
|
|
|
|
|
_defaults = {
|
2014-03-14 16:51:13 +00:00
|
|
|
'state': 'draft',
|
2013-10-03 08:27:36 +00:00
|
|
|
'date': fields.datetime.now,
|
2014-03-14 16:51:13 +00:00
|
|
|
'email_from': lambda self, cr, uid, ctx=None: self.pool['mail.message']._get_default_from(cr, uid, context=ctx),
|
2014-04-13 07:09:22 +00:00
|
|
|
'mailing_model': 'mail.mass_mailing.contact',
|
2014-04-01 13:24:54 +00:00
|
|
|
'contact_ab_pc': 100,
|
2013-09-10 15:19:01 +00:00
|
|
|
}
|
2013-09-13 11:54:08 +00:00
|
|
|
|
2014-03-14 16:51:13 +00:00
|
|
|
#------------------------------------------------------
|
|
|
|
# Technical stuff
|
|
|
|
#------------------------------------------------------
|
|
|
|
|
2014-04-03 15:23:29 +00:00
|
|
|
def copy_data(self, cr, uid, id, default=None, context=None):
|
|
|
|
if default is None:
|
|
|
|
default = {}
|
|
|
|
mailing = self.browse(cr, uid, id, context=context)
|
|
|
|
default.update({
|
|
|
|
'state': 'draft',
|
|
|
|
'statistics_ids': [],
|
|
|
|
'name': _('%s (duplicate)') % mailing.name,
|
|
|
|
})
|
|
|
|
return super(MassMailing, self).copy_data(cr, uid, id, default, context=context)
|
|
|
|
|
2014-04-11 12:47:32 +00:00
|
|
|
def read_group(self, cr, uid, domain, fields, groupby, offset=0, limit=None, context=None, orderby=False, lazy=True):
|
2014-03-14 16:51:13 +00:00
|
|
|
""" Override read_group to always display all states. """
|
|
|
|
if groupby and groupby[0] == "state":
|
|
|
|
# Default result structure
|
2014-04-14 13:11:09 +00:00
|
|
|
# states = self._get_state_list(cr, uid, context=context)
|
|
|
|
states = [('draft', 'Draft'), ('test', 'Tested'), ('done', 'Sent')]
|
2014-03-14 16:51:13 +00:00
|
|
|
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
|
|
|
|
#------------------------------------------------------
|
|
|
|
|
2014-04-12 23:21:59 +00:00
|
|
|
def on_change_model(self, cr, uid, ids, mailing_model, list_ids, context=None):
|
|
|
|
value = {}
|
|
|
|
if mailing_model=='mail.mass_mailing.contact':
|
|
|
|
if list_ids and list_ids[0][0]==6 and list_ids[0][2]:
|
|
|
|
value['mailing_domain'] = "[('list_id', 'in', ["+','.join(map(str, list_ids[0][2]))+"])]"
|
|
|
|
else:
|
|
|
|
value['mailing_domain'] = "[('list_id', '=', False)]"
|
2014-04-12 23:30:19 +00:00
|
|
|
value['contact_nbr'] = self.pool[mailing_model].search(
|
|
|
|
cr, uid, eval(value['mailing_domain']), count=True, context=context
|
|
|
|
)
|
2014-04-12 23:21:59 +00:00
|
|
|
else:
|
|
|
|
value['mailing_domain'] = False
|
|
|
|
value['contact_nbr'] = 0
|
|
|
|
return {'value': value}
|
2014-04-07 17:03:46 +00:00
|
|
|
|
|
|
|
def on_change_reply_specified(self, cr, uid, ids, reply_specified, reply_in_thread, context=None):
|
|
|
|
if reply_specified == reply_in_thread:
|
|
|
|
return {'value': {'reply_in_thread': not reply_specified}}
|
|
|
|
return {}
|
|
|
|
|
|
|
|
def on_change_reply_in_thread(self, cr, uid, ids, reply_specified, reply_in_thread, context=None):
|
|
|
|
if reply_in_thread == reply_specified:
|
|
|
|
return {'value': {'reply_specified': not reply_in_thread}}
|
|
|
|
return {}
|
|
|
|
|
|
|
|
def on_change_contact_list_ids(self, cr, uid, ids, mailing_model, contact_list_ids, context=None):
|
|
|
|
values = {}
|
|
|
|
list_ids = []
|
|
|
|
for command in contact_list_ids:
|
|
|
|
if command[0] == 6:
|
|
|
|
list_ids += command[2]
|
|
|
|
if list_ids:
|
|
|
|
values['contact_nbr'] = self.pool[mailing_model].search(
|
2014-04-13 20:29:22 +00:00
|
|
|
cr, uid, [('list_id', 'in', list_ids), ('opt_out','!=',1)],
|
2014-04-07 17:03:46 +00:00
|
|
|
count=True, context=context
|
|
|
|
)
|
2014-03-14 16:51:13 +00:00
|
|
|
else:
|
2014-04-13 20:29:22 +00:00
|
|
|
values['contact_nbr'] = 0
|
2014-03-14 16:51:13 +00:00
|
|
|
return {'value': values}
|
|
|
|
|
2014-03-20 17:50:04 +00:00
|
|
|
def action_duplicate(self, cr, uid, ids, context=None):
|
|
|
|
copy_id = None
|
2014-04-03 15:23:29 +00:00
|
|
|
for mid in ids:
|
|
|
|
copy_id = self.copy(cr, uid, mid, context=context)
|
2014-03-20 17:50:04 +00:00
|
|
|
if copy_id:
|
|
|
|
return {
|
|
|
|
'type': 'ir.actions.act_window',
|
|
|
|
'view_type': 'form',
|
|
|
|
'view_mode': 'form',
|
|
|
|
'res_model': 'mail.mass_mailing',
|
|
|
|
'res_id': copy_id,
|
|
|
|
'context': context,
|
|
|
|
}
|
|
|
|
return False
|
|
|
|
|
2014-04-03 12:59:05 +00:00
|
|
|
def action_test_mailing(self, cr, uid, ids, context=None):
|
|
|
|
ctx = dict(context, default_mass_mailing_id=ids[0])
|
2014-03-17 17:16:12 +00:00
|
|
|
return {
|
2014-04-03 12:59:05 +00:00
|
|
|
'name': _('Test Mailing'),
|
2014-03-17 17:16:12 +00:00
|
|
|
'type': 'ir.actions.act_window',
|
2014-04-03 12:59:05 +00:00
|
|
|
'view_mode': 'form',
|
|
|
|
'res_model': 'mail.mass_mailing.test',
|
|
|
|
'target': 'new',
|
2014-03-17 17:16:12 +00:00
|
|
|
'context': ctx,
|
|
|
|
}
|
|
|
|
|
2014-03-18 13:04:28 +00:00
|
|
|
def action_see_recipients(self, cr, uid, ids, context=None):
|
|
|
|
mailing = self.browse(cr, uid, ids[0], context=context)
|
|
|
|
domain = self.pool['mail.mass_mailing.list'].get_global_domain(cr, uid, [c.id for c in mailing.contact_list_ids], context=context)[mailing.mailing_model]
|
|
|
|
return {
|
2014-04-03 15:23:29 +00:00
|
|
|
'name': _('See Recipients'),
|
2014-03-18 13:04:28 +00:00
|
|
|
'type': 'ir.actions.act_window',
|
|
|
|
'view_type': 'form',
|
|
|
|
'view_mode': 'tree,form',
|
|
|
|
'res_model': mailing.mailing_model,
|
2014-03-20 17:04:55 +00:00
|
|
|
'target': 'new',
|
2014-03-18 13:04:28 +00:00
|
|
|
'domain': domain,
|
|
|
|
'context': context,
|
|
|
|
}
|
|
|
|
|
2014-04-07 17:03:46 +00:00
|
|
|
def action_edit_html(self, cr, uid, ids, context=None):
|
2014-04-14 13:11:09 +00:00
|
|
|
# fixme: assert is not correct
|
2014-04-13 16:20:28 +00:00
|
|
|
assert len(ids)==1, "One and only one ID allowed for this action"
|
|
|
|
mail = self.browse(cr, uid, ids[0], context=context)
|
|
|
|
url = '/website_mail/email_designer?model=mail.mass_mailing&res_id=%d&field_body=body_html&field_from=email_form&field_subject=name&template_model=%s' % (ids[0], mail.mailing_model)
|
2014-04-07 17:03:46 +00:00
|
|
|
return {
|
|
|
|
'name': _('Open with Visual Editor'),
|
|
|
|
'type': 'ir.actions.act_url',
|
|
|
|
'url': url,
|
|
|
|
'target': 'self',
|
|
|
|
}
|
|
|
|
|
2014-03-17 17:16:12 +00:00
|
|
|
#------------------------------------------------------
|
|
|
|
# Email Sending
|
|
|
|
#------------------------------------------------------
|
2014-03-14 16:51:13 +00:00
|
|
|
|
2014-03-25 15:41:14 +00:00
|
|
|
def get_recipients_data(self, cr, uid, mailing, res_ids, context=None):
|
|
|
|
# tde todo: notification link ?
|
2014-03-18 16:41:17 +00:00
|
|
|
if mailing.mailing_model == 'mail.mass_mailing.contact':
|
|
|
|
contacts = self.pool['mail.mass_mailing.contact'].browse(cr, uid, res_ids, context=context)
|
2014-03-25 15:41:14 +00:00
|
|
|
return dict((contact.id, {'partner_id': False, 'name': contact.name, 'email': contact.email}) for contact in contacts)
|
2014-03-18 16:41:17 +00:00
|
|
|
else:
|
2014-03-21 17:21:39 +00:00
|
|
|
partners = self.pool['res.partner'].browse(cr, uid, res_ids, context=context)
|
2014-03-25 15:41:14 +00:00
|
|
|
return dict((partner.id, {'partner_id': partner.id, 'name': partner.name, 'email': partner.email}) for partner in partners)
|
|
|
|
|
2014-04-01 13:24:54 +00:00
|
|
|
def get_recipients(self, cr, uid, mailing, context=None):
|
2014-04-14 13:11:09 +00:00
|
|
|
domain = eval(mailing.mailing_domain)
|
|
|
|
# self.pool['mail.mass_mailing.list'].get_global_domain(
|
|
|
|
# cr, uid, [l.id for l in mailing.contact_list_ids], context=context
|
|
|
|
# )[mailing.mailing_model]
|
2014-04-01 13:24:54 +00:00
|
|
|
res_ids = self.pool[mailing.mailing_model].search(cr, uid, domain, context=context)
|
|
|
|
|
|
|
|
# randomly choose a fragment
|
2014-04-13 20:29:22 +00:00
|
|
|
if mailing.contact_ab_pc < 100:
|
2014-04-01 13:24:54 +00:00
|
|
|
topick = mailing.contact_ab_nbr
|
|
|
|
if mailing.mass_mailing_campaign_id and mailing.ab_testing:
|
|
|
|
already_mailed = self.pool['mail.mass_mailing.campaign'].get_recipients(cr, uid, [mailing.mass_mailing_campaign_id.id], context=context)[mailing.mass_mailing_campaign_id.id]
|
|
|
|
else:
|
|
|
|
already_mailed = set([])
|
|
|
|
remaining = set(res_ids).difference(already_mailed)
|
|
|
|
if topick > len(remaining):
|
|
|
|
topick = len(remaining)
|
|
|
|
res_ids = random.sample(remaining, topick)
|
|
|
|
return res_ids
|
|
|
|
|
2014-03-25 16:18:13 +00:00
|
|
|
def get_unsubscribe_url(self, cr, uid, mailing_id, res_id, email, msg=None, context=None):
|
2014-03-25 15:41:14 +00:00
|
|
|
base_url = self.pool.get('ir.config_parameter').get_param(cr, uid, 'web.base.url')
|
|
|
|
url = urlparse.urljoin(
|
|
|
|
base_url, 'mail/mailing/%(mailing_id)s/unsubscribe?%(params)s' % {
|
2014-03-25 16:18:13 +00:00
|
|
|
'mailing_id': mailing_id,
|
2014-03-28 13:59:07 +00:00
|
|
|
'params': urllib.urlencode({'db': cr.dbname, 'res_id': res_id, 'email': email})
|
2014-03-25 15:41:14 +00:00
|
|
|
}
|
|
|
|
)
|
2014-03-28 13:59:07 +00:00
|
|
|
return '<small><a href="%s">%s</a></small>' % (url, msg or 'Click to unsubscribe')
|
2014-03-18 16:41:17 +00:00
|
|
|
|
2014-03-17 17:16:12 +00:00
|
|
|
def send_mail(self, cr, uid, ids, context=None):
|
2014-03-21 17:21:39 +00:00
|
|
|
author_id = self.pool['res.users'].browse(cr, uid, uid, context=context).partner_id.id
|
2014-03-17 17:16:12 +00:00
|
|
|
for mailing in self.browse(cr, uid, ids, context=context):
|
2014-03-25 15:51:27 +00:00
|
|
|
if not mailing.contact_nbr:
|
|
|
|
raise Warning('Please select recipients.')
|
2014-04-07 17:03:46 +00:00
|
|
|
# instantiate an email composer + send emails
|
2014-04-01 13:24:54 +00:00
|
|
|
res_ids = self.get_recipients(cr, uid, mailing, context=context)
|
2014-04-07 17:03:46 +00:00
|
|
|
comp_ctx = dict(context, active_ids=res_ids)
|
|
|
|
composer_values = {
|
|
|
|
'author_id': author_id,
|
|
|
|
'body': mailing.body_html,
|
|
|
|
'subject': mailing.name,
|
|
|
|
'model': mailing.mailing_model,
|
|
|
|
'email_from': mailing.email_from,
|
|
|
|
'record_name': False,
|
|
|
|
'composition_mode': 'mass_mail',
|
|
|
|
'mass_mailing_id': mailing.id,
|
|
|
|
'mailing_list_ids': [(4, l.id) for l in mailing.contact_list_ids],
|
|
|
|
}
|
|
|
|
if mailing.reply_specified:
|
|
|
|
composer_values['reply_to'] = mailing.reply_to
|
|
|
|
composer_id = self.pool['mail.compose.message'].create(cr, uid, composer_values, context=comp_ctx)
|
|
|
|
self.pool['mail.compose.message'].send_mail(cr, uid, [composer_id], context=comp_ctx)
|
2014-04-08 12:40:53 +00:00
|
|
|
self.write(cr, uid, [mailing.id], {'date': fields.datetime.now(), 'state': 'done'}, context=context)
|
2014-03-14 16:51:13 +00:00
|
|
|
return True
|
|
|
|
|
2013-09-13 11:54:08 +00:00
|
|
|
|