diff --git a/addons/event/__init__.py b/addons/event/__init__.py
index 9e0115a7300..bf40e48d681 100644
--- a/addons/event/__init__.py
+++ b/addons/event/__init__.py
@@ -20,6 +20,7 @@
##############################################################################
import event
+import event_mail
import wizard
import report
import res_config
diff --git a/addons/event/email_template.xml b/addons/event/email_template.xml
index d4479bcfc87..4a561d38e72 100644
--- a/addons/event/email_template.xml
+++ b/addons/event/email_template.xml
@@ -1,51 +1,48 @@
-
- Confirmation of the Event
-
- ${(object.user_id.email or object.company_id.email or 'noreply@' + object.company_id.name + '.com')|safe}
- ${object.email|safe}
- Your registration at ${object.event_id.name}
- Hello ${object.name},
- The event ${object.event_id.name} that you registered for is confirmed and will be held from ${object.event_id.date_begin_located.strftime('%Y-%m-%d %H:%M:%S (%Z)')} to ${object.event_id.date_end_located.strftime('%Y-%m-%d %H:%M:%S (%Z)')}.
- For any further information please contact our event department.
- Thank you for your participation!
- Best regards
]]>
+
+
+ Event subscription
+
+ ${(object.event_id.organizer_id.email or object.event_id.user_id.email or '')|safe}
+ ${object.email|safe}
+ Your subscription at ${object.event_id.name}
+ Hello ${object.name},
+We confirm that your subscription to the event ${object.event_id.name} has been recorded.
+You will automatically receive an email providing you more practical information (such as the schedule, the agenda...) as soon as the event is confirmed.
+Thank you for your participation!
+Best regards
]]>
-
-
-
-
- Confirmation of the Registration
-
- ${(object.user_id.email or object.company_id.email or 'noreply@' + object.company_id.name + '.com')|safe}
- ${object.email|safe}
- Your registration at ${object.event_id.name}
- Hello ${object.name},
- We confirm that your registration to the event ${object.event_id.name} has been recorded.
- You will automatically receive an email providing you more practical information (such as the schedule, the agenda...) as soon as the event is confirmed.
- Thank you for your participation!
- Best regards
]]>
+
+ Event: reminder
+
+ ${(object.event_id.organizer_id.email or object.event_id.user_id.email or '')|safe}
+ ${object.partner_id.email or object.email|safe}
+ Reminder of event ${object.event_id.name}
+ Hello ${object.name},
+This is a reminder for ${object.event_id.name} that you registered for is confirmed and will be held from ${object.event_id.date_begin_located} to ${object.event_id.date_end_located}.
+For any further information please contact our event department.
+Thank you for your participation!
+Best regards
]]>
-
-
- default_email_event
- default
-
-
- event.type
-
-
- default_email_registration
- default
-
-
- event.type
+
+ Event: thanks for attending
+
+ ${(object.event_id.organizer_id.email or object.event_id.user_id.email or '')|safe}
+ ${object.partner_id.email or object.email|safe}
+ Thanks for attending ${object.event_id.name}
+ Hello ${object.name},
+We would like to thank you for your presence at our event ${object.event_id.name}.
+
+ % if object.event_id.organizer_id and object.event_id.organizer_id.is_company:
+ The ${object.event_id.organizer_id.name} Team
+ % elif object.event_id.organizer_id:
+ ${object.event_id.organizer_id.name}
+ % endif
+
]]>
diff --git a/addons/event/event.py b/addons/event/event.py
index 5fded7e15c9..603886906e2 100644
--- a/addons/event/event.py
+++ b/addons/event/event.py
@@ -2,7 +2,7 @@
import pytz
-from openerp import models, fields, api, _
+from openerp import _, api, fields, models
from openerp.exceptions import Warning
@@ -11,21 +11,13 @@ class event_type(models.Model):
_name = 'event.type'
_description = 'Event Type'
- name = fields.Char(string='Event Type', required=True)
- default_reply_to = fields.Char(
- string='Default Reply-To',
- help="The email address of the organizer which is put in the 'Reply-To' of all emails sent automatically at event or registrations confirmation. You can also put your email address of your mail gateway if you use one.")
- default_email_event = fields.Many2one(
- 'email.template', string='Event Confirmation Email',
- help="It will select this default confirmation event mail value when you choose this event")
- default_email_registration = fields.Many2one(
- 'email.template', string='Registration Confirmation Email',
- help="It will select this default confirmation registration mail value when you choose this event")
+ name = fields.Char('Event Type', required=True)
+ default_reply_to = fields.Char('Reply To')
default_registration_min = fields.Integer(
- string='Default Minimum Registration', default=0,
+ 'Default Minimum Registration', default=0,
help="It will select this default minimum value when you choose this event")
default_registration_max = fields.Integer(
- string='Default Maximum Registration', default=0,
+ 'Default Maximum Registration', default=0,
help="It will select this default maximum value when you choose this event")
@@ -54,6 +46,15 @@ class event_event(models.Model):
'event.type', string='Category',
readonly=False, states={'done': [('readonly', True)]})
color = fields.Integer('Kanban Color Index')
+ event_mail_ids = fields.One2many('event.mail', 'event_id', string='Mail Schedule', default=lambda self: self._default_event_mail_ids())
+
+ @api.model
+ def _default_event_mail_ids(self):
+ return [(0, 0, {
+ 'interval_unit': 'now',
+ 'interval_type': 'after_sub',
+ 'template_id': self.env['ir.model.data'].xmlid_to_res_id('event.event_subscription')
+ })]
# Seats and computation
seats_max = fields.Integer(
@@ -154,11 +155,6 @@ class event_event(models.Model):
else:
self.date_end_located = False
- @api.one
- @api.depends('address_id')
- def _compute_country(self):
- self.country_id = self.address_id.country_id
-
state = fields.Selection([
('draft', 'Unconfirmed'), ('cancel', 'Cancelled'),
('confirm', 'Confirmed'), ('done', 'Done')],
@@ -170,23 +166,13 @@ class event_event(models.Model):
def _compute_auto_confirm(self):
self.auto_confirm = self.env['ir.values'].get_default('marketing.config.settings', 'auto_confirmation')
- # Mailing
- email_registration_id = fields.Many2one(
- 'email.template', string='Registration Confirmation Email',
- domain=[('model', '=', 'event.registration')],
- help='This field contains the template of the mail that will be automatically sent each time a registration for this event is confirmed.')
- email_confirmation_id = fields.Many2one(
- 'email.template', string='Event Confirmation Email',
- domain=[('model', '=', 'event.registration')],
- help="If you set an email template, each participant will receive this email announcing the confirmation of the event.")
reply_to = fields.Char(
- string='Reply-To Email', readonly=False, states={'done': [('readonly', True)]},
+ 'Reply-To Email', readonly=False, states={'done': [('readonly', True)]},
help="The email address of the organizer is likely to be put here, with the effect to be in the 'Reply-To' of the mails sent automatically at event or registrations confirmation. You can also put the email address of your mail gateway if you use one.")
address_id = fields.Many2one(
'res.partner', string='Location', default=lambda self: self.env.user.company_id.partner_id,
readonly=False, states={'done': [('readonly', True)]})
- country_id = fields.Many2one('res.country', string='Country',
- store=True, compute='_compute_country')
+ country_id = fields.Many2one('res.country', 'Country', related='address_id.country_id', store=True)
description = fields.Html(
string='Description', oldname='note', translate=True,
readonly=False, states={'done': [('readonly', True)]})
@@ -217,7 +203,7 @@ class event_event(models.Model):
def create(self, vals):
res = super(event_event, self).create(vals)
if res.auto_confirm:
- res.confirm_event()
+ res.button_confirm()
return res
@api.one
@@ -236,27 +222,16 @@ class event_event(models.Model):
def button_done(self):
self.state = 'done'
- @api.one
- def confirm_event(self):
- if self.email_confirmation_id:
- # send reminder that will confirm the event for all the people that were already confirmed
- regs = self.registration_ids.filtered(lambda reg: reg.state not in ('draft', 'cancel'))
- regs.mail_user_confirm()
- self.state = 'confirm'
-
@api.one
def button_confirm(self):
- """ Confirm Event and send confirmation email to all register peoples """
- self.confirm_event()
+ self.state = 'confirm'
@api.onchange('type')
def _onchange_type(self):
if self.type:
- self.reply_to = self.type.default_reply_to
- self.email_registration_id = self.type.default_email_registration
- self.email_confirmation_id = self.type.default_email_event
self.seats_min = self.type.default_registration_min
self.seats_max = self.type.default_registration_max
+ self.reply_to = self.type.default_reply_to
@api.multi
def action_event_registration_report(self):
@@ -267,6 +242,11 @@ class event_event(models.Model):
}
return res
+ @api.one
+ def mail_attendees(self, template_id, force_send=False, filter_func=lambda self: True):
+ for attendee in self.registration_ids.filtered(filter_func):
+ self.env['email.template'].browse(template_id).send_mail(attendee.id, force_send=force_send)
+
class event_registration(models.Model):
_name = 'event.registration'
@@ -283,9 +263,8 @@ class event_registration(models.Model):
partner_id = fields.Many2one(
'res.partner', string='Contact',
states={'done': [('readonly', True)]})
- date_open = fields.Datetime(string='Registration Date', readonly=True)
+ date_open = fields.Datetime(string='Registration Date', readonly=True, default=lambda self: fields.datetime.now()) # weird crash is directly now
date_closed = fields.Datetime(string='Attended Date', readonly=True)
- reply_to = fields.Char(string='Reply-to Email', related='event_id.reply_to', readonly=True)
event_begin_date = fields.Datetime(string="Event Start Date", related='event_id.date_begin', readonly=True)
event_end_date = fields.Datetime(string="Event End Date", related='event_id.date_end', readonly=True)
company_id = fields.Many2one(
@@ -315,10 +294,10 @@ class event_registration(models.Model):
@api.model
def create(self, vals):
- res = super(event_registration, self).create(vals)
- if res._check_auto_confirmation()[0]:
- res.sudo().confirm_registration()
- return res
+ registration = super(event_registration, self).create(vals)
+ if registration._check_auto_confirmation():
+ registration.sudo().confirm_registration()
+ return registration
@api.one
def do_draft(self):
@@ -331,12 +310,6 @@ class event_registration(models.Model):
subtype="event.mt_event_registration")
self.state = 'open'
- @api.one
- def registration_open(self):
- """ Open Registration """
- self.confirm_registration()
- self.mail_user()
-
@api.one
def button_reg_close(self):
""" Close Registration """
@@ -350,23 +323,6 @@ class event_registration(models.Model):
def button_reg_cancel(self):
self.state = 'cancel'
- @api.one
- def mail_user(self):
- """Send email to user with email_template when registration is done """
- if self.event_id.state == 'confirm' and self.event_id.email_confirmation_id:
- self.mail_user_confirm()
- else:
- template = self.event_id.email_registration_id
- if template:
- template.send_mail(self.id)
-
- @api.one
- def mail_user_confirm(self):
- """Send email to user when the event is confirmed """
- template = self.event_id.email_confirmation_id
- if template:
- template.send_mail(self.id)
-
@api.onchange('partner_id')
def _onchange_partner(self):
if self.partner_id:
diff --git a/addons/event/event_data.xml b/addons/event/event_data.xml
index 823d6428993..2419132f409 100644
--- a/addons/event/event_data.xml
+++ b/addons/event/event_data.xml
@@ -1,6 +1,7 @@
+
diff --git a/addons/event/event_mail.py b/addons/event/event_mail.py
new file mode 100644
index 00000000000..ea4a9a81e93
--- /dev/null
+++ b/addons/event/event_mail.py
@@ -0,0 +1,111 @@
+# -*- coding: utf-8 -*-
+
+from datetime import datetime
+from dateutil.relativedelta import relativedelta
+
+from openerp import api, fields, models, tools
+
+
+_INTERVALS = {
+ 'hours': lambda interval: relativedelta(hours=interval),
+ 'days': lambda interval: relativedelta(days=interval),
+ 'weeks': lambda interval: relativedelta(days=7*interval),
+ 'months': lambda interval: relativedelta(months=interval),
+ 'now': lambda interval: relativedelta(hours=0),
+}
+
+
+class EventMailScheduler(models.Model):
+ """ Event automated mailing. This model replaces all existing fields and
+ configuration allowing to send emails on events since Odoo 9. A cron exists
+ that periodically checks for mailing to run. """
+ _name = 'event.mail'
+
+ event_id = fields.Many2one('event.event', string='Event', required=True, readonly=True, ondelete='cascade')
+ interval_nbr = fields.Integer('Timing', default=1)
+ interval_unit = fields.Selection([
+ ('now', 'Immediately'),
+ ('hours', 'Hour(s)'), ('days', 'Day(s)'),
+ ('weeks', 'Week(s)'), ('months', 'Month(s)')],
+ string='Unit', default='hours', required=True)
+ interval_type = fields.Selection([
+ ('after_sub', 'After each subscription'),
+ ('before_event', 'Before the event'),
+ ('after_event', 'After the event')],
+ string='When to Run ', default="before_event", required=True)
+ template_id = fields.Many2one(
+ 'email.template', string='Email to Send',
+ domain=[('model', '=', 'event.registration')], required=True, ondelete='restrict',
+ help='This field contains the template of the mail that will be automatically sent')
+ scheduled_date = fields.Datetime('Scheduled Sent Mail', compute='_compute_scheduled_date', store=True)
+ mail_registration_ids = fields.One2many('event.mail.registration', 'scheduler_id')
+ mail_sent = fields.Boolean('Mail Sent on Event')
+ done = fields.Boolean('Sent', compute='_compute_done', store=True)
+
+ @api.one
+ @api.depends('mail_sent', 'interval_type', 'event_id.registration_ids', 'mail_registration_ids')
+ def _compute_done(self):
+ if self.interval_type in ['before_event', 'after_event']:
+ self.done = self.mail_sent
+ else:
+ self.done = len(self.mail_registration_ids) == len(self.event_id.registration_ids) and all(filter(lambda line: line.mail_sent, self.mail_registration_ids))
+
+ @api.one
+ @api.depends('event_id.state', 'event_id.date_begin', 'interval_type', 'interval_unit', 'interval_nbr')
+ def _compute_scheduled_date(self):
+ if self.event_id.state not in ['confirm', 'done']:
+ self.scheduled_date = False
+ else:
+ if self.interval_type == 'after_sub':
+ date, sign = self.event_id.create_date, 1
+ elif self.interval_type == 'before_event':
+ date, sign = self.event_id.date_begin, -1
+ else:
+ date, sign = self.event_id.date_end, 1
+
+ self.scheduled_date = datetime.strptime(date, tools.DEFAULT_SERVER_DATETIME_FORMAT) + _INTERVALS[self.interval_unit](sign * self.interval_nbr)
+
+ @api.one
+ def execute(self):
+ if self.interval_type == 'after_sub':
+ # update registration lines
+ lines = []
+ for registration in filter(lambda item: item not in [mail_reg.registration_id for mail_reg in self.mail_registration_ids], self.event_id.registration_ids):
+ lines.append((0, 0, {'registration_id': registration.id}))
+ if lines:
+ self.write({'mail_registration_ids': lines})
+ # execute scheduler on registrations
+ self.mail_registration_ids.filtered(lambda reg: reg.scheduled_date and reg.scheduled_date <= datetime.strftime(fields.datetime.now(), tools.DEFAULT_SERVER_DATETIME_FORMAT)).execute()
+ else:
+ if not self.mail_sent:
+ self.event_id.mail_attendees(self.template_id.id)
+ self.write({'mail_sent': True})
+ return True
+
+ @api.model
+ def run(self):
+ schedulers = self.search([('done', '=', False), ('scheduled_date', '<=', datetime.strftime(fields.datetime.now(), tools.DEFAULT_SERVER_DATETIME_FORMAT))])
+ return schedulers.execute()
+
+
+class EventMailRegistration(models.Model):
+ _name = 'event.mail.registration'
+ _description = 'Registration Mail Scheduler'
+ _rec_name = 'scheduler_id'
+ _order = 'scheduled_date DESC'
+
+ scheduler_id = fields.Many2one('event.mail', 'Mail Scheduler', required=True, ondelete='cascade')
+ registration_id = fields.Many2one('event.registration', 'Attendee', required=True, ondelete='cascade')
+ scheduled_date = fields.Datetime('Scheduled Time', compute='_compute_scheduled_date', store=True)
+ mail_sent = fields.Boolean('Mail Sent')
+
+ @api.one
+ def execute(self):
+ if self.registration_id.state in ['open', 'done'] and not self.mail_sent:
+ self.scheduler_id.template_id.send_mail(self.registration_id.id)
+ self.write({'mail_sent': True})
+
+ @api.one
+ @api.depends('registration_id', 'scheduler_id.interval_unit', 'scheduler_id.interval_type')
+ def _compute_scheduled_date(self):
+ self.scheduled_date = datetime.strptime(self.registration_id.date_open, tools.DEFAULT_SERVER_DATETIME_FORMAT) + _INTERVALS[self.scheduler_id.interval_unit](self.scheduler_id.interval_nbr)
diff --git a/addons/event/event_view.xml b/addons/event/event_view.xml
index 9371dbe25e9..0991c4bb7af 100644
--- a/addons/event/event_view.xml
+++ b/addons/event/event_view.xml
@@ -16,9 +16,7 @@
-
-
@@ -103,12 +101,17 @@
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
@@ -294,7 +297,7 @@