[MERGE] event: ease event configuration and use of tracks

This merge proposes to ease the use and configuration of events as well
as the use of event tracks and track proposals. This is done through
two main modifications

 * first one aims at improving event categories so that they can be used
   as configuration for events. Categories can now define default values
   for automated mailing, ticketing, location management, questions to
   attendees, ... Preconfigured data for event categories are added to
   help user having finely-tuned events;
 * second one aims at improve event track model. Tracks now use dynamic
   stages with automated mailing, as well as kanban state, activities
   and all common chatter features.
This commit is contained in:
Thibault Delavallée
2017-03-03 13:13:33 +01:00
59 changed files with 1715 additions and 1198 deletions
+1 -2
View File
@@ -23,14 +23,13 @@ Key Features
'security/ir.model.access.csv',
'wizard/event_confirm_view.xml',
'views/event_views.xml',
'report/report_event_registration_view.xml',
'report/event_event_templates.xml',
'report/event_event_reports.xml',
'data/email_template_data.xml',
'data/event_data.xml',
'views/event_config_settings_views.xml',
'views/event_templates.xml',
'views/res_partner_views.xml',
'data/email_template_data.xml',
],
'demo': [
'data/event_demo.xml',
+13 -3
View File
@@ -8,9 +8,6 @@
<value>Module Events has been installed</value>
</function>
<!-- Automatic confirmation of events by default -->
<function id="default_auto_confirmation" model="ir.values" name="set_default" eval="('event.config.settings', 'default_auto_confirmation', True)"/>
<!-- Event Mail Scheduler-->
<record model="ir.cron" forcecreate="True" id="event_mail_scheduler">
<field name="name">Event: Mail Scheduler</field>
@@ -24,5 +21,18 @@
<field name="doall" eval="False" />
</record>
<record id="event_type_data_online" model="event.type">
<field name="name">Online</field>
<field name="is_online" eval="True"/>
<field name="auto_confirm" eval="True"/>
<field name="use_mail_schedule" eval="False"/>
</record>
<record id="event_type_data_physical" model="event.type">
<field name="name">Physical Event</field>
<field name="is_online" eval="False"/>
<field name="auto_confirm" eval="True"/>
<field name="use_mail_schedule" eval="False"/>
</record>
</data>
</odoo>
+167 -112
View File
@@ -11,51 +11,11 @@ from dateutil.relativedelta import relativedelta
class EventType(models.Model):
""" Event Type """
_name = 'event.type'
_description = 'Event Type'
name = fields.Char('Event Type', required=True, translate=True)
default_reply_to = fields.Char('Reply To')
default_registration_min = fields.Integer(
'Default Minimum Registration', default=0,
help="It will select this default minimum value when you choose this event")
default_registration_max = fields.Integer(
'Default Maximum Registration', default=0,
help="It will select this default maximum value when you choose this event")
class EventEvent(models.Model):
"""Event"""
_name = 'event.event'
_description = 'Event'
_inherit = ['mail.thread']
_order = 'date_begin'
name = fields.Char(
string='Event Name', translate=True, required=True,
readonly=False, states={'done': [('readonly', True)]})
active = fields.Boolean(default=True, track_visibility="onchange")
user_id = fields.Many2one(
'res.users', string='Responsible',
default=lambda self: self.env.user,
readonly=False, states={'done': [('readonly', True)]})
company_id = fields.Many2one(
'res.company', string='Company', change_default=True,
default=lambda self: self.env['res.company']._company_default_get('event.event'),
required=False, readonly=False, states={'done': [('readonly', True)]})
organizer_id = fields.Many2one(
'res.partner', string='Organizer',
default=lambda self: self.env.user.company_id.partner_id)
event_type_id = fields.Many2one(
'event.type', string='Category',
readonly=False, states={'done': [('readonly', True)]},
oldname='type')
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(), copy=True)
_description = 'Event Category'
@api.model
def _default_event_mail_ids(self):
def _get_default_event_type_mail_ids(self):
return [(0, 0, {
'interval_unit': 'now',
'interval_type': 'after_sub',
@@ -72,6 +32,81 @@ class EventEvent(models.Model):
'template_id': self.env.ref('event.event_reminder')
})]
name = fields.Char('Event Category', required=True, translate=True)
# registration
has_seats_limitation = fields.Boolean(
'Limited Seats', default=False)
default_registration_min = fields.Integer(
'Minimum Registrations', default=0,
help="It will select this default minimum value when you choose this event")
default_registration_max = fields.Integer(
'Maximum Registrations', default=0,
help="It will select this default maximum value when you choose this event")
auto_confirm = fields.Boolean(
'Automatically Confirm Registrations', default=True,
help="Events and registrations will automatically be confirmed"
"upon creation, easing the flow for simple events.")
# location
is_online = fields.Boolean(
'Online Event', help='Online events like webinars do not require a specific location and are hosted online.')
use_timezone = fields.Boolean('Use Default Timezone')
default_timezone = fields.Selection(
'_tz_get', string='Timezone',
default=lambda self: self.env.user.tz)
# communication
use_reply_to = fields.Boolean('Use Default Reply-To')
default_reply_to = fields.Char('Reply To')
use_hashtag = fields.Boolean('Use Default Hashtag')
default_hashtag = fields.Char('Twitter Hashtag')
use_mail_schedule = fields.Boolean(
'Automatically Send Emails', default=True)
event_type_mail_ids = fields.One2many(
'event.type.mail', 'event_type_id', string='Mail Schedule',
copy=False,
default=_get_default_event_type_mail_ids)
@api.onchange('has_seats_limitation')
def _onchange_has_seats_limitation(self):
if not self.has_seats_limitation:
self.default_registration_min = 0
self.default_registration_max = 0
@api.model
def _tz_get(self):
return [(x, x) for x in pytz.all_timezones]
class EventEvent(models.Model):
"""Event"""
_name = 'event.event'
_description = 'Event'
_inherit = ['mail.thread']
_order = 'date_begin'
name = fields.Char(
string='Event Name', translate=True, required=True,
readonly=False, states={'done': [('readonly', True)]})
active = fields.Boolean(default=True)
user_id = fields.Many2one(
'res.users', string='Responsible',
default=lambda self: self.env.user,
track_visibility="onchange",
readonly=False, states={'done': [('readonly', True)]})
company_id = fields.Many2one(
'res.company', string='Company', change_default=True,
default=lambda self: self.env['res.company']._company_default_get('event.event'),
required=False, readonly=False, states={'done': [('readonly', True)]})
organizer_id = fields.Many2one(
'res.partner', string='Organizer',
track_visibility="onchange",
default=lambda self: self.env.user.company_id.partner_id)
event_type_id = fields.Many2one(
'event.type', string='Category',
readonly=False, states={'done': [('readonly', True)]},
oldname='type')
color = fields.Integer('Kanban Color Index')
event_mail_ids = fields.One2many('event.mail', 'event_id', string='Mail Schedule', copy=True)
# Seats and computation
seats_max = fields.Integer(
string='Maximum Attendees Number', oldname='register_max',
@@ -99,6 +134,48 @@ class EventEvent(models.Model):
string='Number of Expected Attendees',
readonly=True, compute='_compute_seats')
# Registration fields
registration_ids = fields.One2many(
'event.registration', 'event_id', string='Attendees',
readonly=False, states={'done': [('readonly', True)]})
# Date fields
date_tz = fields.Selection('_tz_get', string='Timezone', required=True, default=lambda self: self.env.user.tz)
date_begin = fields.Datetime(
string='Start Date', required=True,
track_visibility='onchange', states={'done': [('readonly', True)]})
date_end = fields.Datetime(
string='End Date', required=True,
track_visibility='onchange', states={'done': [('readonly', True)]})
date_begin_located = fields.Char(string='Start Date Located', compute='_compute_date_begin_tz')
date_end_located = fields.Char(string='End Date Located', compute='_compute_date_end_tz')
state = fields.Selection([
('draft', 'Unconfirmed'), ('cancel', 'Cancelled'),
('confirm', 'Confirmed'), ('done', 'Done')],
string='Status', default='draft', readonly=True, required=True, copy=False,
help="If event is created, the status is 'Draft'. If event is confirmed for the particular dates the status is set to 'Confirmed'. If the event is over, the status is set to 'Done'. If event is cancelled the status is set to 'Cancelled'.")
auto_confirm = fields.Boolean(string='Autoconfirm Registrations')
reply_to = fields.Char(
'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.")
is_online = fields.Boolean('Online Event')
address_id = fields.Many2one(
'res.partner', string='Location',
default=lambda self: self.env.user.company_id.partner_id,
readonly=False, states={'done': [('readonly', True)]},
track_visibility="onchange")
country_id = fields.Many2one('res.country', 'Country', related='address_id.country_id', store=True)
twitter_hashtag = fields.Char('Twitter Hashtag')
description = fields.Html(
string='Description', oldname='note', translate=html_translate, sanitize_attributes=False,
readonly=False, states={'done': [('readonly', True)]})
# badge fields
badge_front = fields.Html(string='Badge Front')
badge_back = fields.Html(string='Badge Back')
badge_innerleft = fields.Html(string='Badge Inner Left')
badge_innerright = fields.Html(string='Badge Inner Right')
event_logo = fields.Html(string='Event Logo')
@api.multi
@api.depends('seats_max', 'registration_ids.state')
def _compute_seats(self):
@@ -128,21 +205,6 @@ class EventEvent(models.Model):
event.seats_available = event.seats_max - (event.seats_reserved + event.seats_used)
event.seats_expected = event.seats_unconfirmed + event.seats_reserved + event.seats_used
# Registration fields
registration_ids = fields.One2many(
'event.registration', 'event_id', string='Attendees',
readonly=False, states={'done': [('readonly', True)]})
# Date fields
date_tz = fields.Selection('_tz_get', string='Timezone', required=True, default=lambda self: self.env.user.tz)
date_begin = fields.Datetime(
string='Start Date', required=True,
track_visibility='onchange', states={'done': [('readonly', True)]})
date_end = fields.Datetime(
string='End Date', required=True,
track_visibility='onchange', states={'done': [('readonly', True)]})
date_begin_located = fields.Char(string='Start Date Located', compute='_compute_date_begin_tz')
date_end_located = fields.Char(string='End Date Located', compute='_compute_date_end_tz')
@api.model
def _tz_get(self):
return [(x, x) for x in pytz.all_timezones]
@@ -163,33 +225,51 @@ class EventEvent(models.Model):
else:
self.date_end_located = False
state = fields.Selection([
('draft', 'Unconfirmed'), ('cancel', 'Cancelled'),
('confirm', 'Confirmed'), ('done', 'Done')],
string='Status', default='draft', readonly=True, required=True, copy=False,
help="If event is created, the status is 'Draft'. If event is confirmed for the particular dates the status is set to 'Confirmed'. If the event is over, the status is set to 'Done'. If event is cancelled the status is set to 'Cancelled'.")
auto_confirm = fields.Boolean(string='Confirmation not required', compute='_compute_auto_confirm')
@api.onchange('event_type_id')
def _onchange_type(self):
if self.event_type_id:
self.seats_min = self.event_type_id.default_registration_min
self.seats_max = self.event_type_id.default_registration_max
if self.event_type_id.default_registration_max:
self.seats_availability = 'limited'
if self.event_type_id.auto_confirm:
self.auto_confirm = self.event_type_id.auto_confirm
if self.event_type_id.use_reply_to:
self.reply_to = self.event_type_id.default_reply_to
if self.event_type_id.use_reply_to:
self.twitter_hashtag = self.event_type_id.default_hashtag
if self.event_type_id.use_timezone:
self.date_tz = self.event_type_id.default_timezone
self.is_online = self.event_type_id.is_online
if self.event_type_id.event_type_mail_ids:
self.event_mail_ids = [(5, 0, 0)] + [{
'template_id': line.template_id,
'interval_nbr': line.interval_nbr,
'interval_unit': line.interval_unit,
'interval_type': line.interval_type}
for line in self.event_type_id.event_type_mail_ids]
@api.constrains('seats_min', 'seats_max', 'seats_availability')
def _check_seats_min_max(self):
if any(event.seats_availability == 'limited' and event.seats_min > event.seats_max for event in self):
raise ValidationError(_('Maximum attendees number should be greater than minimum attendees number.'))
@api.constrains('seats_max', 'seats_available')
def _check_seats_limit(self):
if any(event.seats_availability == 'limited' and event.seats_max and event.seats_available < 0 for event in self):
raise ValidationError(_('No more available seats.'))
@api.one
def _compute_auto_confirm(self):
self.auto_confirm = self.env['ir.values'].get_default('event.config.settings', 'default_auto_confirmation')
reply_to = fields.Char(
'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', 'Country', related='address_id.country_id', store=True)
description = fields.Html(
string='Description', oldname='note', translate=html_translate, sanitize_attributes=False,
readonly=False, states={'done': [('readonly', True)]})
# badge fields
badge_front = fields.Html(string='Badge Front')
badge_back = fields.Html(string='Badge Back')
badge_innerleft = fields.Html(string='Badge Inner Left')
badge_innerright = fields.Html(string='Badge Inner Right')
event_logo = fields.Html(string='Event Logo')
@api.constrains('date_begin', 'date_end')
def _check_closing_date(self):
if self.date_end < self.date_begin:
raise ValidationError(_('Closing Date cannot be set before Beginning Date.'))
@api.multi
@api.depends('name', 'date_begin', 'date_end')
@@ -203,18 +283,6 @@ class EventEvent(models.Model):
result.append((event.id, '%s (%s)' % (event.name, ' - '.join(dates))))
return result
@api.one
@api.constrains('seats_max', 'seats_available')
def _check_seats_limit(self):
if self.seats_availability == 'limited' and self.seats_max and self.seats_available < 0:
raise ValidationError(_('No more available seats.'))
@api.one
@api.constrains('date_begin', 'date_end')
def _check_closing_date(self):
if self.date_end < self.date_begin:
raise ValidationError(_('Closing Date cannot be set before Beginning Date.'))
@api.model
def create(self, vals):
res = super(EventEvent, self).create(vals)
@@ -251,22 +319,6 @@ class EventEvent(models.Model):
def button_confirm(self):
self.state = 'confirm'
@api.onchange('event_type_id')
def _onchange_type(self):
if self.event_type_id:
self.seats_min = self.event_type_id.default_registration_min
self.seats_max = self.event_type_id.default_registration_max
self.reply_to = self.event_type_id.default_reply_to
@api.multi
def action_event_registration_report(self):
res = self.env['ir.actions.act_window'].for_xml_id('event', 'action_report_event_registration')
res['context'] = {
"search_default_event_id": self.id,
"group_by": ['create_date:day'],
}
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):
@@ -278,6 +330,7 @@ class EventRegistration(models.Model):
_description = 'Attendee'
_inherit = ['mail.thread']
_order = 'name, create_date desc'
_mail_mass_mailing = _('Event Attendees')
origin = fields.Char(
string='Source Document', readonly=True,
@@ -361,10 +414,12 @@ class EventRegistration(models.Model):
def button_reg_close(self):
""" Close Registration """
today = fields.Datetime.now()
if self.event_id.date_begin <= today:
if self.event_id.date_begin <= today and self.event_id.state == 'confirm':
self.write({'state': 'done', 'date_closed': today})
elif self.event_id.state == 'draft':
raise UserError(_("You must wait the event confirmation before doing this action."))
else:
raise UserError(_("You must wait for the starting day of the event to do this action."))
raise UserError(_("You must wait the event starting day before doing this action."))
@api.one
def button_reg_cancel(self):
@@ -9,7 +9,6 @@ class event_config_settings(models.TransientModel):
module_event_sale = fields.Boolean("Tickets")
module_website_event_track = fields.Boolean("Tracks and Agenda")
module_website_event_questions = fields.Boolean("Registration Survey")
default_auto_confirmation = fields.Boolean("Auto Confirmation", default_model='event.config.settings')
module_event_barcode = fields.Boolean("Barcode")
module_website_event = fields.Boolean("Online Events")
module_website_event_sale = fields.Boolean("Online Ticketing")
+30 -2
View File
@@ -15,11 +15,39 @@ _INTERVALS = {
}
class EventTypeMail(models.Model):
""" Template of event.mail to attach to event.type. Those will be copied
upon all events created in that type to ease event creation. """
_name = 'event.type.mail'
_description = 'Mail Scheduling on Event Type'
event_type_id = fields.Many2one(
'event.type', string='Event Type',
ondelete='cascade', required=True)
interval_nbr = fields.Integer('Interval', 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 registration'),
('before_event', 'Before the event'),
('after_event', 'After the event')],
string='Trigger', default="before_event", required=True)
template_id = fields.Many2one(
'mail.template', string='Email Template',
domain=[('model', '=', 'event.registration')], required=True, ondelete='restrict',
help='This field contains the template of the mail that will be automatically sent')
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'
_rec_name = 'event_id'
_description = 'Event Automated Mailing'
event_id = fields.Many2one('event.event', string='Event', required=True, ondelete='cascade')
sequence = fields.Integer('Display order')
@@ -33,9 +61,9 @@ class EventMailScheduler(models.Model):
('after_sub', 'After each registration'),
('before_event', 'Before the event'),
('after_event', 'After the event')],
string='When to Run ', default="before_event", required=True)
string='Trigger ', default="before_event", required=True)
template_id = fields.Many2one(
'mail.template', string='Email to Send',
'mail.template', string='Email Template',
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)
-2
View File
@@ -1,4 +1,2 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
import report_event_registration
@@ -1,71 +0,0 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import api, models, fields
from odoo import tools
class ReportEventRegistration(models.Model):
"""Events Analysis"""
_name = "report.event.registration"
_order = 'event_date desc'
_auto = False
create_date = fields.Datetime('Creation Date', readonly=True)
event_date = fields.Datetime('Event Date', readonly=True)
event_id = fields.Many2one('event.event', 'Event', required=True)
draft_state = fields.Integer(' # No of Draft Registrations')
cancel_state = fields.Integer(' # No of Cancelled Registrations')
confirm_state = fields.Integer(' # No of Confirmed Registrations')
seats_max = fields.Integer('Max Seats')
nbevent = fields.Integer('Number of Events')
nbregistration = fields.Integer('Number of Registrations')
event_type_id = fields.Many2one('event.type', 'Event Type')
registration_state = fields.Selection([('draft', 'Draft'), ('confirm', 'Confirmed'), ('done', 'Attended'), ('cancel', 'Cancelled')], 'Registration State', readonly=True, required=True)
event_state = fields.Selection([('draft', 'Draft'), ('confirm', 'Confirmed'), ('done', 'Done'), ('cancel', 'Cancelled')], 'Event State', readonly=True, required=True)
user_id = fields.Many2one('res.users', 'Event Responsible', readonly=True)
name_registration = fields.Char('Participant / Contact Name', readonly=True)
company_id = fields.Many2one('res.company', 'Company', readonly=True)
@api.model_cr
def init(self):
"""Initialize the sql view for the event registration """
tools.drop_view_if_exists(self.env.cr, 'report_event_registration')
# TOFIX this request won't select events that have no registration
self.env.cr.execute(""" CREATE VIEW report_event_registration AS (
SELECT
e.id::varchar || '/' || coalesce(r.id::varchar,'') AS id,
e.id AS event_id,
e.user_id AS user_id,
r.name AS name_registration,
r.create_date AS create_date,
e.company_id AS company_id,
e.date_begin AS event_date,
count(r.id) AS nbevent,
count(r.event_id) AS nbregistration,
CASE WHEN r.state IN ('draft') THEN count(r.event_id) ELSE 0 END AS draft_state,
CASE WHEN r.state IN ('open','done') THEN count(r.event_id) ELSE 0 END AS confirm_state,
CASE WHEN r.state IN ('cancel') THEN count(r.event_id) ELSE 0 END AS cancel_state,
e.event_type_id AS event_type_id,
e.seats_max AS seats_max,
e.state AS event_state,
r.state AS registration_state
FROM
event_event e
LEFT JOIN event_registration r ON (e.id=r.event_id)
GROUP BY
event_id,
r.id,
registration_state,
event_type_id,
e.id,
e.date_begin,
e.user_id,
event_state,
e.company_id,
e.seats_max,
name_registration
)
""")
@@ -1,70 +0,0 @@
<?xml version="1.0"?>
<odoo>
<data>
<record model ="ir.ui.view" id="report_event_registration_pivot">
<field name="name">report.event.registration.pivot</field>
<field name="model">report.event.registration</field>
<field name="arch" type="xml">
<pivot string="Event on Registration" disable_linking="True">
<field name="event_id" type="row"/>
<field name="event_date" interval="month" type="col"/>
<field name="confirm_state" type="measure"/>
</pivot>
</field>
</record>
<record model ="ir.ui.view" id="report_event_registration_graph">
<field name="name">report.event.registration.graph</field>
<field name="model">report.event.registration</field>
<field name="arch" type="xml">
<graph string="Event on Registration">
<field name="event_id"/>
<field name="event_date" interval="month"/>
<field name="confirm_state" type="measure"/>
</graph>
</field>
</record>
<!-- Event on Registration search view -->
<record model="ir.ui.view" id="view_report_event_registration_search">
<field name="name">report.event.registration.search</field>
<field name="model">report.event.registration</field>
<field name="arch" type="xml">
<search string="Event on Registration">
<filter string="New" domain="[('event_state','=','draft')]" help="Events which are in New state"/>
<filter string="Confirm" domain="[('event_state','=','confirm')]" help="Events which are in confirm state"/>
<separator/>
<field name="event_id" string="Event"/>
<field name="user_id"/>
<group expand="0" string="Extended Filters...">
<field name="event_type_id" widget="selection"/>
<field name="event_date"/>
</group>
<newline/>
<group expand="1" string="Group By">
<filter string="Attendee / Contact" context="{'group_by':'name_registration'}" help="Registration contact"/>
<filter string="Event Type" context="{'group_by':'event_type_id'}"/>
<filter string="Event" name="event" context="{'group_by':'event_id', 'max_reg_event_visible':0}"/>
<filter string="Event State" context="{'group_by':'event_state'}"/>
<filter string="Company" context="{'group_by':'company_id'}" groups="base.group_multi_company"/>
<separator/>
<filter string="Event Month" context="{'group_by':'event_date:month'}" help="Event Beginning Date"/>
</group>
</search>
</field>
</record>
<record model="ir.actions.act_window" id="action_report_event_registration">
<field name="name">Events Analysis</field>
<field name="res_model">report.event.registration</field>
<field name="view_type">form</field>
<field name="view_mode">pivot,graph</field>
<field name="search_view_id" ref="view_report_event_registration_search"/>
<field name="context">{}</field> <!-- force empty -->
</record>
<menuitem name="Events" parent="event.menu_reporting_events" action="action_report_event_registration" id="menu_report_event_registration" sequence="3" groups="event.group_event_manager"/>
</data>
</odoo>
-11
View File
@@ -41,16 +41,5 @@
]
</field>
</record>
<record model="ir.rule" id="report_event_registration_company_rule">
<field name="name">Event/Report Registration: multi-company</field>
<field name="model_id" ref="model_report_event_registration"/>
<field name="global" eval="True"/>
<field name="domain_force">['|',
('company_id', '=', False),
('company_id', 'child_of', [user.company_id.id]),
]
</field>
</record>
</data>
</odoo>
+2 -1
View File
@@ -10,4 +10,5 @@ access_event_mail,event.mail,model_event_mail,event.group_event_user,1,0,0,0
access_event_mail_manager,event.mail manager,model_event_mail,event.group_event_manager,1,1,1,1
access_event_mail_registration,event.mail.registration,model_event_mail_registration,event.group_event_user,1,0,0,0
access_event_mail_registration_manager,event.mail.registration.manager,model_event_mail_registration,event.group_event_manager,1,1,1,1
access_report_event_registration,report.event.registration,model_report_event_registration,event.group_event_user,1,1,1,1
access_event_type_mail_event_user,event.type.mail.event.user,model_event_type_mail,event.group_event_user,1,0,0,0
access_event_type_mail_event_manager,event.type.mail.event.manager,model_event_type_mail,event.group_event_manager,1,1,1,1
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
10 access_event_mail_manager event.mail manager model_event_mail event.group_event_manager 1 1 1 1
11 access_event_mail_registration event.mail.registration model_event_mail_registration event.group_event_user 1 0 0 0
12 access_event_mail_registration_manager event.mail.registration.manager model_event_mail_registration event.group_event_manager 1 1 1 1
13 access_report_event_registration access_event_type_mail_event_user report.event.registration event.type.mail.event.user model_report_event_registration model_event_type_mail event.group_event_user 1 1 0 1 0 1 0
14 access_event_type_mail_event_manager event.type.mail.event.manager model_event_type_mail event.group_event_manager 1 1 1 1
+1 -9
View File
@@ -15,14 +15,10 @@ class TestEventFlow(TestEventCommon):
@mute_logger('odoo.addons.base.ir.ir_model', 'odoo.models')
def test_00_basic_event_auto_confirm(self):
""" Basic event management with auto confirmation """
event_config = self.env['event.config.settings'].sudo(self.user_eventmanager).create({
'default_auto_confirmation': 1
})
event_config.execute()
# EventUser creates a new event: ok
test_event = self.Event.sudo(self.user_eventmanager).create({
'name': 'TestEvent',
'auto_confirm': True,
'date_begin': datetime.datetime.now() + relativedelta(days=-1),
'date_end': datetime.datetime.now() + relativedelta(days=1),
'seats_max': 2,
@@ -66,13 +62,10 @@ class TestEventFlow(TestEventCommon):
with self.assertRaises(UserError):
test_event.button_cancel()
@mute_logger('odoo.addons.base.ir.ir_model', 'odoo.models')
def test_10_advanced_event_flow(self):
""" Avanced event flow: no auto confirmation, manage minimum / maximum
seats, ... """
self.env['ir.values'].set_default('event.config.settings', 'default_auto_confirmation', False)
# EventUser creates a new event: ok
test_event = self.Event.sudo(self.user_eventmanager).create({
'name': 'TestEvent',
@@ -114,7 +107,6 @@ class TestEventFlow(TestEventCommon):
]})
with self.assertRaises(AccessError):
event_config = self.env['event.config.settings'].sudo(self.user_eventmanager).create({
'default_auto_confirmation': 1
})
event_config.execute()
+1 -1
View File
@@ -13,13 +13,13 @@ class TestMailSchedule(TestEventCommon):
@mute_logger('odoo.addons.base.ir.ir_model', 'odoo.models')
def test_00_event_mail_schedule(self):
""" Test mail scheduling for events """
self.env['ir.values'].set_default('event.config.settings', 'default_auto_confirmation', True)
now = fields.datetime.now()
event_date_begin = now + relativedelta(days=1)
event_date_end = now + relativedelta(days=3)
test_event = self.Event.sudo(self.user_eventmanager).create({
'name': 'TestEventMail',
'auto_confirm': True,
'date_begin': event_date_begin,
'date_end': event_date_end,
'seats_max': 10,
@@ -24,14 +24,14 @@
</div>
</div>
</div>
<div class="col-xs-12 col-md-6 o_setting_box" title="Add a navigation menu to your event web pages with an agenda, tracks, a track proposal form, etc.">
<div class="col-xs-12 col-md-6 o_setting_box" title="Add a navigation menu to your event web pages with schedule, tracks, a track proposal form, etc.">
<div class="o_setting_left_pane">
<field name="module_website_event_track"/>
</div>
<div class="o_setting_right_pane">
<label string="Agenda &amp; Tracks" for="module_website_event_track"/>
<label string="Schedule &amp; Tracks" for="module_website_event_track"/>
<div class="text-muted">
Manage &amp; publish an agenda with tracks
Manage &amp; publish a schedule with tracks
</div>
</div>
</div>
@@ -49,7 +49,7 @@
</div>
</div>
</div>
<div class="col-xs-12 col-md-6 o_setting_box">
<div class="col-xs-12 col-md-6 o_setting_box" name="event_settings_website">
<div class="o_setting_left_pane">
<field name="module_website_event_sale"/>
</div>
@@ -60,17 +60,6 @@
</div>
</div>
</div>
<div class="col-xs-12 col-md-6 o_setting_box" id="default_auto_confirmation" title="Uncheck this option to manually manage draft event and draft registration.">
<div class="o_setting_left_pane">
<field name="default_auto_confirmation"/>
</div>
<div class="o_setting_right_pane">
<label for="default_auto_confirmation"/>
<div class="text-muted">
Confirm registrations automatically
</div>
</div>
</div>
</div>
<h2>Attendance</h2>
<div class="row mt16 o_settings_container">
+223 -68
View File
@@ -11,14 +11,135 @@
<field name="name">event.type.form</field>
<field name="model">event.type</field>
<field name="arch" type="xml">
<form string="Event Type">
<sheet>
<group>
<field name="name"/>
<field name="default_reply_to"/>
<field name="default_registration_min"/>
<field name="default_registration_max"/>
</group>
<form string="Event Category">
<sheet>
<div class="oe_title">
<label for="name" class="oe_edit_only"/>
<h1><field name="name"/></h1>
</div>
<h2>Location</h2>
<div class="row mt16 o_settings_container" name="event_type_location">
<div class="col-xs-12 col-md-6 o_setting_box">
<div class="o_setting_left_pane">
<field name="is_online"/>
</div>
<div class="o_setting_right_pane">
<label for="is_online"/>
<div class="row">
<div class="col-md-8 mt16 text-muted">
Online events like webinars do not require a specific location
and are hosted online.
</div>
</div>
</div>
</div>
<div class="col-xs-12 col-md-6 o_setting_box">
<div class="o_setting_left_pane">
<field name="use_timezone"/>
</div>
<div class="o_setting_right_pane">
<label for="use_timezone"/>
<div class="row">
<div class="col-md-8 mt16" attrs="{'invisible': [('use_timezone', '=', False)]}">
<label for="default_timezone"/>
<field name="default_timezone"
attrs="{'required': [('use_timezone', '=', True)]}"/>
</div>
</div>
</div>
</div>
</div>
<h2>Communication</h2>
<div class="row mt16 o_settings_container" name="event_type_communication">
<div class="col-xs-12 col-md-6 o_setting_box">
<div class="o_setting_left_pane">
<field name="use_reply_to"/>
</div>
<div class="o_setting_right_pane">
<label for="use_reply_to"/>
<div class="row">
<div class="col-md-8 mt16" attrs="{'invisible': [('use_reply_to', '=', False)]}">
<label for="default_reply_to"/>
<field name="default_reply_to"
attrs="{'required': [('use_reply_to', '=', True)]}"/>
</div>
</div>
</div>
</div>
<div class="col-xs-12 col-md-6 o_setting_box">
<div class="o_setting_left_pane">
<field name="use_hashtag"/>
</div>
<div class="o_setting_right_pane">
<label for="use_hashtag"/>
<div class="row">
<div class="col-md-8 mt16" attrs="{'invisible': [('use_hashtag', '=', False)]}">
<label for="default_hashtag"/>
<field name="default_hashtag"
attrs="{'required': [('use_hashtag', '=', True)]}"/>
</div>
</div>
</div>
</div>
<div class="col-xs-12 col-md-12 o_setting_box">
<div class="o_setting_left_pane">
<field name="use_mail_schedule"/>
</div>
<div class="o_setting_right_pane">
<label for="use_mail_schedule"/>
<div class="row mt16" attrs="{'invisible': [('use_mail_schedule', '=', False)]}">
<div class="col-md-9">
<field name="event_type_mail_ids">
<tree string="Email Schedule" editable="bottom">
<field name="template_id"/>
<field name="interval_nbr" attrs="{'readonly':[('interval_unit', '=', 'now')]}"/>
<field name="interval_unit"/>
<field name="interval_type"/>
</tree>
</field>
</div>
</div>
</div>
</div>
</div>
<h2>Visibility</h2>
<div class="row mt16 o_settings_container" name="event_type_visibility">
<div class="col-xs-12 col-md-6 o_setting_box" name="event_type_visibility_seats">
<div class="o_setting_left_pane">
<field name="has_seats_limitation"/>
</div>
<div class="o_setting_right_pane">
<label for="has_seats_limitation"/>
<div class="row">
<div class="col-md-8 mt16" attrs="{'invisible': [('has_seats_limitation', '=', False)]}">
<div>
<label for="default_registration_min"/> <field name="default_registration_min"/>
</div>
<div>
<label for="default_registration_max"/> <field name="default_registration_max"/>
</div>
</div>
</div>
</div>
</div>
</div>
<h2>Attendees</h2>
<div class="row mt16 o_settings_container" name="event_type_attendees">
<div class="col-xs-12 col-md-6 o_setting_box" name="event_type_attendees_auto_confirm">
<div class="o_setting_left_pane">
<field name="auto_confirm"/>
</div>
<div class="o_setting_right_pane">
<label for="auto_confirm"/>
<div class="row">
<div class="col-md-8 mt16 text-muted">
Events and registrations will automatically be confirmed
upon creation, easing the flow for simple events.
</div>
</div>
</div>
</div>
</div>
</sheet>
</form>
</field>
@@ -28,14 +149,14 @@
<field name="name">event.type.tree</field>
<field name="model">event.type</field>
<field name="arch" type="xml">
<tree string="Event Type">
<tree string="Event Category">
<field name="name"/>
</tree>
</field>
</record>
<record model="ir.actions.act_window" id="action_event_type">
<field name="name">Event Types</field>
<field name="name">Event Categories</field>
<field name="res_model">event.type</field>
<field name="view_type">form</field>
</record>
@@ -54,6 +175,13 @@
</record>
<!-- EVENT.EVENT VIEWS -->
<record id="event_event_action_pivot" model="ir.actions.act_window" >
<field name="name">Events Analysis</field>
<field name="res_model">event.event</field>
<field name="view_type">form</field>
<field name="view_mode">pivot,graph</field>
</record>
<record model="ir.ui.view" id="view_event_form">
<field name="name">event.event.form</field>
<field name="model">event.event</field>
@@ -69,14 +197,16 @@
<sheet>
<div class="oe_button_box" name="button_box" groups="base.group_user">
<button name="%(event.act_event_registration_from_event)d"
type="action"
class="oe_stat_button oe_event_attendee_button"
icon="fa-users"
help="Register with this event">
type="action"
class="oe_stat_button"
icon="fa-users"
help="Register with this event">
<field name="seats_expected" widget="statinfo" string="Attendees"/>
</button>
<button name="toggle_active" type="object"
class="oe_stat_button" icon="fa-archive">
<button name="toggle_active"
type="object"
class="oe_stat_button"
icon="fa-archive">
<field name="active" widget="boolean_button"
options='{"terminology": "archive"}'/>
</button>
@@ -84,44 +214,44 @@
<div class="oe_title">
<label for="name" class="oe_edit_only"/>
<h1><field name="name" placeholder="Event Name"/></h1>
<field name="is_online" groups="base.group_no_one"/>
<label for="is_online" string="Online" groups="base.group_no_one"/>
</div>
<group name="main_field_group">
<group>
<group>
<field name="address_id" context="{'show_address': 1}" options='{"always_reload": True}'/>
<field name="organizer_id"/>
<field name="address_id"
attrs="{'invisible': [('is_online', '=', True)]}"
context="{'show_address': 1}"
options='{"always_reload": True}'/>
<field name="company_id" groups="base.group_multi_company"/>
<field name="user_id"/>
</group>
<group>
<field name="user_id"/>
<field name="event_type_id" options="{'no_create':True}"/>
<field name="reply_to" string="Contact Email"/>
<field name="twitter_hashtag"/>
<field name="auto_confirm" groups="base.group_no_one"/>
</group>
<group>
<field name="date_begin"/>
<field name="date_end"/>
<field name="date_tz" />
<field name="date_tz"/>
</group>
<group>
<field name="seats_min"/>
<label for="seats_availability"/>
<div>
<field name="seats_availability" widget='radio'/>
<span attrs="{'invisible': [('seats_availability', '=', 'unlimited')]}" class="oe_read_only">
to
</span>
<field name="seats_max" attrs="{'invisible': [('seats_availability', '=', 'unlimited')], 'required': [('seats_availability', '=', 'limited')]}"/>
</div>
</group>
</group>
<notebook>
<page name="registrations" string="Registrations">
<group>
<group>
<field name="seats_min"/>
<label for="seats_availability"/>
<div>
<field name="seats_availability" widget='radio'/>
<span attrs="{'invisible': [('seats_availability', '=', 'unlimited')]}" class="oe_read_only">
to
</span>
<field name="seats_max" attrs="{'invisible': [('seats_availability', '=', 'unlimited')], 'required': [('seats_availability', '=', 'limited')]}"/>
</div>
</group>
<group>
<field name="auto_confirm" groups="base.group_no_one"/>
</group>
</group>
</page>
<page string="Email Schedule">
<group>
<field name="reply_to"/>
</group>
<page string="Email Schedule" name="event_mail_schedule">
<field name="event_mail_ids">
<tree string="Email Schedule" editable="bottom">
<field name="sequence" widget="handle"/>
@@ -211,8 +341,9 @@
<t t-esc="record.seats_expected.raw_value"> Expected attendees </t>
</a>
<t t-if="(record.seats_reserved.raw_value + record.seats_used.raw_value) > 0 "><br/>
<t t-esc="record.seats_reserved.raw_value + record.seats_used.raw_value"/> Confirmed attendees
<a name="action_event_registration_report" type="object" >&#40;stats&#41;</a>
<a name="%(event_event_action_pivot)d" type="action">
<t t-esc="record.seats_reserved.raw_value + record.seats_used.raw_value"/> Confirmed attendees
</a>
</t>
</h4>
</div>
@@ -264,12 +395,23 @@
</field>
</record>
<record id="event_event_view_pivot" model="ir.ui.view" >
<field name="name">event.event.view.pivot</field>
<field name="model">event.event</field>
<field name="arch" type="xml">
<pivot string="Event" disable_linking="True">
<field name="name" type="row"/>
<field name="seats_reserved" type="measure"/>
</pivot>
</field>
</record>
<record model="ir.actions.act_window" id="action_event_view">
<field name="name">Events</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">event.event</field>
<field name="view_type">form</field>
<field name="view_mode">kanban,calendar,tree,form</field>
<field name="view_mode">kanban,calendar,tree,form,pivot</field>
<field name="context">{"search_default_upcoming":1}</field>
<field name="search_view_id" ref="view_event_search"/>
<field name="help" type="html"><p class="oe_view_nocontent_create">
@@ -291,6 +433,12 @@
view_type="form"/>
<menuitem name="Events" id="menu_event_event" action="action_event_view" parent="event.event_main_menu" />
<menuitem name="Events"
id="event_event_menu_pivot_report"
action="event_event_action_pivot"
sequence="3"
parent="event.menu_reporting_events"
groups="event.group_event_manager"/>
<!-- EVENT.REGISTRATION VIEWS -->
<record model="ir.ui.view" id="view_event_registration_tree">
@@ -328,10 +476,10 @@
<sheet string="Registration">
<group>
<group string="Attendee" name="attendee">
<field name="partner_id" attrs="{'readonly':[('state', '!=', 'draft')]}"/>
<field name="name"/>
<field name="phone"/>
<field name="email"/>
<field name="partner_id" attrs="{'readonly':[('state', '!=', 'draft')]}"/>
</group>
<group string="Event Information" name="event">
<field name="event_id" attrs="{'readonly': [('state', '!=', 'draft')]}"/>
@@ -423,28 +571,35 @@
<field name="model">event.mail</field>
<field name="arch" type="xml">
<form string="Event Mail Scheduler">
<group>
<field name="event_id"/>
<field name="template_id"/>
<field name="mail_sent"/>
</group>
<group>
<field name="interval_nbr" attrs="{'readonly':[('interval_unit', '=', 'now')]}"/>
<field name="interval_unit"/>
<field name="interval_type"/>
<field name="scheduled_date"/>
</group>
<notebook>
<page string="Registration Mails">
<field name="mail_registration_ids">
<tree string="Registration mail" editable="bottom">
<field name="registration_id"/>
<field name="scheduled_date"/>
<field name="mail_sent"/>
</tree>
</field>
</page>
</notebook>
<sheet>
<group>
<group>
<field name="event_id"/>
<field name="template_id"/>
<field name="mail_sent"/>
</group>
<group>
<label for="interval_nbr"/>
<div class="o_row">
<field name="interval_nbr" attrs="{'invisible': [('interval_unit', '=', 'now')], 'readonly': [('interval_unit', '=', 'now')]}"/>
<field name="interval_unit"/>
</div>
<field name="interval_type"/>
<field name="scheduled_date"/>
</group>
</group>
<notebook>
<page string="Registration Mails">
<field name="mail_registration_ids">
<tree string="Registration mail" editable="bottom">
<field name="registration_id"/>
<field name="scheduled_date"/>
<field name="mail_sent"/>
</tree>
</field>
</page>
</notebook>
</sheet>
</form>
</field>
</record>
+6 -5
View File
@@ -1,11 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data noupdate="1">
<record id="event_type" model="event.type">
<field name="name">Generic Events</field>
</record>
<record id="product_product_event" model="product.product">
<field name="list_price">10.0</field>
<field name="event_ok" eval="True"/>
@@ -17,6 +12,12 @@
<field name="type">service</field>
</record>
<record id="event_type_data_sale" model="event.type">
<field name="name">Ticketing</field>
<field name="auto_confirm" eval="False"/>
<field name="use_mail_schedule" eval="True"/>
<field name="use_ticketing" eval="True"/>
</record>
</data>
</odoo>
+1
View File
@@ -1,5 +1,6 @@
# -*- coding: utf-8 -*-
import account_invoice
import sale_order
import product
import event
@@ -0,0 +1,17 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import api, models
class AccountInvoice(models.Model):
_inherit = 'account.invoice'
@api.multi
def action_invoice_paid(self):
""" When an invoice linked to a sales order selling registrations is
paid confirm attendees. Attendees should indeed not be confirmed before
full payment. """
res = super(AccountInvoice, self).action_invoice_paid()
self.mapped('invoice_line_ids.sale_line_ids')._update_registrations(confirm=True)
return res
+46 -12
View File
@@ -2,31 +2,59 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import api, fields, models, _
from odoo.exceptions import ValidationError
from odoo.exceptions import ValidationError, UserError
import odoo.addons.decimal_precision as dp
class Event(models.Model):
class EventType(models.Model):
_inherit = 'event.type'
_inherit = 'event.event'
def _default_tickets(self):
@api.model
def _get_default_event_ticket_ids(self):
product = self.env.ref('event_sale.product_product_event', raise_if_not_found=False)
if not product:
return self.env['event.event.ticket']
return [{
return False
return [(0, 0, {
'name': _('Registration'),
'product_id': product.id,
'price': 0,
}]
})]
event_ticket_ids = fields.One2many('event.event.ticket', 'event_id', string='Event Ticket',
default=lambda self: self._default_tickets(), copy=True)
use_ticketing = fields.Boolean('Ticketing')
event_ticket_ids = fields.One2many(
'event.event.ticket', 'event_type_id',
string='Tickets', default=_get_default_event_ticket_ids)
@api.onchange('name')
def _onchange_name(self):
if self.name:
self.event_ticket_ids.filtered(lambda ticket: ticket.name == _('Registration')).update({
'name': _('Registration for %s') % self.name
})
class Event(models.Model):
_inherit = 'event.event'
event_ticket_ids = fields.One2many(
'event.event.ticket', 'event_id', string='Event Ticket',
copy=True)
@api.onchange('event_type_id')
def _onchange_type(self):
super(Event, self)._onchange_type()
if self.event_type_id.use_ticketing:
self.event_ticket_ids = [(5, 0, 0)] + [
(0, 0, {
'name': self.name and _('Registration for %s') % self.name or ticket.name,
'product_id': ticket.product_id.id,
'price': ticket.price,
})
for ticket in self.event_type_id.event_ticket_ids]
class EventTicket(models.Model):
_name = 'event.event.ticket'
_description = 'Event Ticket'
@@ -34,7 +62,8 @@ class EventTicket(models.Model):
return self.env.ref('event_sale.product_product_event', raise_if_not_found=False)
name = fields.Char(string='Name', required=True, translate=True)
event_id = fields.Many2one('event.event', string="Event", required=True, ondelete='cascade')
event_type_id = fields.Many2one('event.type', string='Event Category', ondelete='cascade')
event_id = fields.Many2one('event.event', string="Event", ondelete='cascade')
product_id = fields.Many2one('product.product', string='Product',
required=True, domain=[("event_ok", "=", True)],
default=_default_product_id)
@@ -115,6 +144,11 @@ class EventTicket(models.Model):
if record.seats_max and record.seats_available < 0:
raise ValidationError(_('No more available seats for the ticket'))
@api.constrains('event_type_id', 'event_id')
def _constrains_event(self):
if any(ticket.event_type_id and ticket.event_id for ticket in self):
raise UserError(_('Ticket should belong to either event category or event but not both'))
@api.onchange('product_id')
def _onchange_product_id(self):
self.price = self.product_id.list_price or 0
+3 -3
View File
@@ -10,7 +10,7 @@ class SaleOrder(models.Model):
def action_confirm(self):
self.ensure_one()
res = super(SaleOrder, self).action_confirm()
self.order_line._update_registrations(confirm=True)
self.order_line._update_registrations(confirm=False, cancel_to_draft=False)
if any(self.order_line.filtered(lambda line: line.event_id)):
return self.env['ir.actions.act_window'].with_context(default_sale_order_id=self.id).for_xml_id('event_sale', 'action_sale_order_event_registration')
return res
@@ -35,7 +35,7 @@ class SaleOrderLine(models.Model):
return res
@api.multi
def _update_registrations(self, confirm=True, registration_data=None):
def _update_registrations(self, confirm=True, cancel_to_draft=False, registration_data=None):
""" Create or update registrations linked to a sales order line. A sale
order line has a product_uom_qty attribute that will be the number of
registrations linked to this line. This method update existing registrations
@@ -46,7 +46,7 @@ class SaleOrderLine(models.Model):
existing_registrations = registrations.filtered(lambda self: self.sale_order_line_id.id == so_line.id)
if confirm:
existing_registrations.filtered(lambda self: self.state != 'open').confirm_registration()
else:
if cancel_to_draft:
existing_registrations.filtered(lambda self: self.state == 'cancel').do_draft()
for count in range(int(so_line.product_uom_qty) - len(existing_registrations)):
+44 -23
View File
@@ -41,34 +41,55 @@
</field>
</record>
<record id="event_type_view_form_inherit_sale" model="ir.ui.view">
<field name="name">event.type.view.form.inherit.sale</field>
<field name="model">event.type</field>
<field name="inherit_id" ref="event.view_event_type_form"/>
<field name="arch" type="xml">
<div name="event_type_attendees_auto_confirm" position="after">
<div class="col-xs-12 col-md-12 o_setting_box">
<div class="o_setting_left_pane">
<field name="use_ticketing"/>
</div>
<div class="o_setting_right_pane">
<label for="use_ticketing"/>
<div class="row mt16" attrs="{'invisible': [('use_ticketing', '=', False)]}">
<div class="col-md-9">
<field name="event_ticket_ids">
<tree string="Tickets" editable="bottom">
<field name="name"/>
<field name="product_id"/>
<field name="price"/>
</tree>
</field>
</div>
</div>
</div>
</div>
</div>
</field>
</record>
<record id="view_event_form_inherit_ticket" model="ir.ui.view">
<field name="name">event.form.inherit</field>
<field name="model">event.event</field>
<field name="inherit_id" ref="event.view_event_form"/>
<field name="arch" type="xml">
<xpath expr="//page[@name='registrations']" position="replace">
<page string="Tickets">
<group>
<group>
<field name="auto_confirm" invisible="1"/>
<field name="seats_min"/>
<field name="seats_availability" widget='radio'/>
<field name="seats_max" attrs="{'invisible': [('seats_availability', '=', 'unlimited')], 'required': [('seats_availability', '=', 'limited')]}"/>
</group>
</group>
<field name="event_ticket_ids" context="{'default_name': name}">
<tree string="Tickets" editable="bottom">
<field name="name"/>
<field name="product_id" context="{'default_event_ok':1}"/>
<field name="deadline"/>
<field name="price"/>
<field name="seats_max"/>
<field name="seats_reserved" readonly="1"/>
<field name="seats_unconfirmed" readonly="1"/>
</tree>
</field>
</page>
</xpath>
<page name="event_mail_schedule" position="before">
<page string="Tickets">
<field name="event_ticket_ids" context="{'default_name': name}">
<tree string="Tickets" editable="bottom">
<field name="name"/>
<field name="product_id" context="{'default_event_ok':1}"/>
<field name="deadline"/>
<field name="price"/>
<field name="seats_max"/>
<field name="seats_reserved" readonly="1"/>
<field name="seats_unconfirmed" readonly="1"/>
</tree>
</field>
</page>
</page>
</field>
</record>
@@ -55,7 +55,7 @@ class RegistrationEditor(models.TransientModel):
self.env['event.registration'].create(values)
if self.env.context.get('active_model') == 'sale.order':
for order in self.env['sale.order'].browse(self.env.context.get('active_ids', [])):
order.order_line._update_registrations(confirm=True)
order.order_line._update_registrations(confirm=False)
return {'type': 'ir.actions.act_window_close'}
+2
View File
@@ -734,6 +734,8 @@ class MailThread(models.AbstractModel):
recipient_ids.add(record.partner_id.id)
elif 'email_from' in self._fields and record.email_from:
email_to = record.email_from
elif 'partner_email' in self._fields and record.partner_email:
email_to = record.partner_email
elif 'email' in self._fields:
email_to = record.email
res[record.id] = {'partner_ids': list(recipient_ids), 'email_to': email_to, 'email_cc': email_cc}
+1 -1
View File
@@ -10,7 +10,7 @@ Create Awesome Event Pages
### Get rid of old WYSIWYG editors
Create beautiful event pages by drag & droping well designed *'Building Blocks'*. Publish event photos, speakers, agenda, etc.
Create beautiful event pages by drag & droping well designed *'Building Blocks'*. Publish event photos, speakers, schedule, etc.
Odoo's unique *'edit inline'* approach makes website creation surprisingly easy. "Want to introduce a speaker? to change the price of a ticket? to update a banner? promote sponsors?" just click and change.
+6 -6
View File
@@ -4,22 +4,22 @@
'name': 'Online Events',
'category': 'Marketing',
'sequence': 135,
'summary': 'Schedule, Promote and Sell Events',
'summary': 'Publish Events and Manage Online Registrations on your Website',
'website': 'https://www.odoo.com/page/website-builder',
'description': """
Online Events
""",
'depends': ['website', 'website_partner', 'website_mail', 'event'],
'data': [
'data/website_event_data.xml',
'data/event_data.xml',
'views/event_config_settings_views.xml',
'views/website_event_templates.xml',
'views/website_event_views.xml',
'views/event_templates.xml',
'views/event_views.xml',
'security/ir.model.access.csv',
'security/website_event_security.xml',
'security/event_security.xml',
],
'demo': [
'data/website_event_demo.xml'
'data/event_demo.xml'
],
'application': True,
}
+44 -38
View File
@@ -6,14 +6,18 @@ from odoo import api, fields, models, _
from odoo.addons.website.models.website import slug
class EventType(models.Model):
_name = 'event.type'
_inherit = ['event.type']
website_menu = fields.Boolean(
'Display a dedicated menu on Website')
class Event(models.Model):
_name = 'event.event'
_inherit = ['event.event', 'website.seo.metadata', 'website.published.mixin']
def _default_hashtag(self):
return re.sub("[- \\.\\(\\)\\@\\#\\&]+", "", self.env.user.company_id.name).lower()
twitter_hashtag = fields.Char('Twitter Hashtag', default=_default_hashtag)
website_published = fields.Boolean(track_visibility='onchange')
website_message_ids = fields.One2many(
'mail.message', 'res_id',
@@ -25,9 +29,10 @@ class Event(models.Model):
)
is_participating = fields.Boolean("Is Participating", compute="_compute_is_participating")
show_menu = fields.Boolean('Dedicated Menu', compute='_get_show_menu', inverse='_set_show_menu',
help="Creates menus Introduction, Location and Register on the page "
" of the event on the website.", store=True)
website_menu = fields.Boolean(
'Dedicated Menu', compute='_compute_website_menu', inverse='_set_website_menu',
help="Creates menus Introduction, Location and Register on the page "
" of the event on the website.", store=True)
menu_id = fields.Many2one('website.menu', 'Event Menu')
def _compute_is_participating(self):
@@ -46,46 +51,47 @@ class Event(models.Model):
if event.id: # avoid to perform a slug on a not yet saved record in case of an onchange.
event.website_url = '/event/%s' % slug(event)
@api.multi
def _get_new_menu_pages(self):
""" Retuns a list of tuple ('Page name', 'relative page url') for the event """
@api.onchange('event_type_id')
def _onchange_type(self):
super(Event, self)._onchange_type()
if self.event_type_id:
self.website_menu = self.event_type_id.website_menu
def _get_menu_entries(self):
self.ensure_one()
todo = [
(_('Introduction'), 'website_event.template_intro'),
(_('Location'), 'website_event.template_location')
return [
(_('Introduction'), False, 'website_event.template_intro'),
(_('Location'), False, 'website_event.template_location'),
(_('Register'), '/event/%s/register' % slug(self), False),
]
result = []
for name, path in todo:
complete_name = name + ' ' + self.name
newpath = self.env['website'].new_page(complete_name, path, ispage=False)
url = "/event/" + slug(self) + "/page/" + newpath
result.append((name, url))
result.append((_('Register'), '/event/%s/register' % slug(self)))
return result
@api.multi
def _set_show_menu(self):
def _set_website_menu(self):
for event in self:
if event.menu_id and not event.show_menu:
if event.menu_id and not event.website_menu:
event.menu_id.unlink()
elif event.show_menu and not event.menu_id:
root_menu = self.env['website.menu'].create({'name': event.name})
to_create_menus = event._get_new_menu_pages()
seq = 0
for name, url in to_create_menus:
self.env['website.menu'].create({
'name': name,
'url': url,
'parent_id': root_menu.id,
'sequence': seq,
})
seq += 1
event.menu_id = root_menu
elif event.website_menu:
if not event.menu_id:
root_menu = self.env['website.menu'].create({'name': event.name})
event.menu_id = root_menu
for sequence, (name, url, xml_id) in enumerate(self._get_menu_entries()):
existing_pages = event.menu_id.child_id.mapped('name')
if name not in existing_pages:
if not url:
newpath = self.env['website'].new_page(name + ' ' + self.name, xml_id, ispage=False)
url = "/event/" + slug(self) + "/page/" + newpath
self.env['website.menu'].create({
'name': name,
'url': url,
'parent_id': event.menu_id.id,
'sequence': sequence,
})
@api.multi
def _get_show_menu(self):
def _compute_website_menu(self):
for event in self:
event.show_menu = bool(event.menu_id)
event.website_menu = bool(event.menu_id)
@api.multi
def google_map_img(self, zoom=8, width=298, height=298):
@@ -1,7 +1,7 @@
<section class="oe_container">
<div class="oe_row oe_spaced">
<h2 class="oe_slogan" style="color:#875A7B;">Create your own events</h2>
<h3 class="oe_slogan">Organize, publish, promote and sell.</h3>
<h3 class="oe_slogan">Organize, publish and promote.</h3>
<div class="oe_span12">
<div class="oe_demo oe_picture oe_screenshot">
<img src="event_sc_00.png">
@@ -15,7 +15,7 @@
<h2 class="oe_slogan" style="color:#875A7B;">Host events that resonates with your audience</h2>
<h3 class="oe_slogan">Easily create live or online events</h3>
<p class="oe_mt32">
One platform to manage it all. Odoo Events covers all aspects of an event manager's work: organization, visibility, promotion and sale. Use it with any kind of event, including conferences, meetings, seminars, training and webinars.
One platform to manage it all. Odoo Events covers all aspects of an event manager's work: organization, visibility, promotion. Use it with any kind of event, including conferences, meetings, seminars, training and webinars.
</p>
</div>
</section>
@@ -51,7 +51,7 @@
</div>
<div class="oe_span3 text-center">
<span class="fa fa-2x fa-calendar"/>
<p class="oe_mt16">Automatically display your event&apos;s agenda in a clear, classy design on your website.</p>
<p class="oe_mt16">Automatically display your event&apos;s schedule in a clear, classy design on your website.</p>
</div>
<div class="oe_span3 text-center">
<span class="fa fa-2x fa-search"/>
@@ -69,9 +69,9 @@
<div class="oe_span6">
<img class="oe_picture oe_screenshot" src="sponsors.png" style="margin-left: -1px;">
<h2 class="oe_slogan oe_mt32" style="text-align: left; color:#875A7B;">Get sponsors to come to you</h2>
<h3 class="oe_slogan" style="text-align: left;">Sell sponsorship, promote your sponsors</h3>
<h3 class="oe_slogan" style="text-align: left;">Promote your sponsors</h3>
<p class="oe_mt32 text-justify">
Easily manage existing and new sponsors with Odoo Events. Add sponsors to your events and publish sponsors per level (e.g., gold) on the bottom of every page of the event. Sell sponsorship packages online through Odoo eCommerce.</p>
Easily manage existing and new sponsors with Odoo Events. Add sponsors to your events and publish sponsors per level (e.g., gold) on the bottom of every page of the event.</p>
</div>
<div class="oe_span6">
<img class="oe_picture oe_screenshot" src="website_seo.png" style="margin-left: -1px;">
@@ -83,22 +83,16 @@
</div>
</section>
<section class="oe_container oe_dark">
<section class="oe_container">
<div class="oe_row oe_spaced">
<h2 class="oe_slogan" style="color:#875A7B;">Total promotion tools</h2>
<h3 class="oe_slogan">Promote events efficiently on all channels</h3>
<div class="oe_span6">
<img class="oe_picture oe_screenshot" src="event_promote.png" style="margin-left: -1px;">
<h2 class="oe_slogan oe_mt32" style="text-align: left; color:#875A7B;">Total promotion tools</h2>
<h3 class="oe_slogan" style="text-align: left;">Promote events efficiently on all channels</h3>
<p class="oe_mt32 text-justify">
Segment your audience, leverage social media and email marketing to promote your events to the right audience. Odoo Events&apos; smooth integration with countless Odoo apps simplifies promotion to the extreme. Setup automated campaigns for attendees, or automatically send timely emails to registrants. Optimize conversions with ad-hoc landing pages for your different marketing campaigns.
</p>
<img class="oe_picture oe_screenshot" src="event_promote.png">
</div>
<div class="oe_span6">
<img class="oe_picture oe_screenshot" src="event_sell.png" style="margin-left: -1px;">
<h2 class="oe_slogan oe_mt32" style="text-align: left; color:#875A7B;">Sell tickets online</h2>
<h3 class="oe_slogan" style="text-align: left;">Automate the registration and payment process</h3>
<p class="oe_mt32 text-justify">
Manage registrations and sell tickets online to your events. Choose whether it is a free event or whether attendees need to register for a fee. Pick the paying method -pay online with a credit card or with the invoice. Define special conditions such as early-bird prices, member benefits or extra services with multiple tickets. All you need to boost your event attendance.
Segment your audience, leverage social media and email marketing to promote your events to the right audience. Odoo Events&apos; smooth integration with countless Odoo apps simplifies promotion to the extreme. Setup automated campaigns for attendees, or automatically send timely emails to registrants. Optimize conversions with ad-hoc landing pages for your different marketing campaigns.
</p>
</div>
</div>
@@ -26,13 +26,21 @@ var EventRegistrationForm = Widget.extend({
$("#registration_form select").each(function() {
post[$(this).attr('name')] = $(this).val();
});
return ajax.jsonRpc($form.attr('action'), 'call', post).then(function (modal) {
var $modal = $(modal);
$modal.appendTo($form).modal();
$modal.on('click', '.js_goto_event', function () {
$modal.modal('hide');
var tickets_ordered = _.some(_.map(post, function(value, key) { return parseInt(value) }));
if (! tickets_ordered) {
return $('#registration_form table').after(
'<div class="alert alert-info">Please select at least one ticket.</div>'
);
}
else {
return ajax.jsonRpc($form.attr('action'), 'call', post).then(function (modal) {
var $modal = $(modal);
$modal.appendTo($form).modal();
$modal.on('click', '.js_goto_event', function () {
$modal.modal('hide');
});
});
});
}
},
});
@@ -1,12 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="event_config_settings_view_form_inherit_website_event" model="ir.ui.view">
<field name="name">event.config.settings.form.inherit.website.event</field>
<record id="event_config_settings_view_form_inherit_website" model="ir.ui.view">
<field name="name">event.config.settings.view.form.inherit.website</field>
<field name="model">event.config.settings</field>
<field name="inherit_id" ref="event.event_config_settings_view_form"/>
<field name="arch" type="xml">
<div id="default_auto_confirmation" position="before">
<div name="event_settings_website" position="after">
<div class="col-xs-12 col-md-6 o_setting_box">
<div class="o_setting_left_pane">
<field name="module_website_event_questions"/>
@@ -438,7 +438,12 @@
<td>
<select t-if="event.seats_available or event.seats_availability == 'unlimited'" name="nb_register-0" class="form-control">
<t t-foreach="range(0, (event.seats_availability == 'unlimited' or event.seats_available > 9) and 10 or event.seats_available+1)" t-as="nb">
<option t-esc="nb"/>
<t t-if="nb == 1">
<option t-esc="nb" selected="selected"/>
</t>
<t t-if="nb != 1">
<option t-esc="nb"/>
</t>
</t>
</select>
<span t-if="event.seats_availability == 'limited' and not event.seats_available">Sold Out</span>
@@ -0,0 +1,60 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="event_type_view_form_inherit_website" model="ir.ui.view">
<field name="name">event.type.view.form.inherit.website</field>
<field name="model">event.type</field>
<field name="inherit_id" ref="event.view_event_type_form"/>
<field name="arch" type="xml">
<div name="event_type_visibility_seats" position="after">
<div class="col-xs-12 col-md-6 o_setting_box" name="event_type_visibility_website">
<div class="o_setting_left_pane">
<field name="website_menu"/>
</div>
<div class="o_setting_right_pane">
<label for="website_menu"/>
<div class="row">
<div class="col-md-8 mt16 text-muted">
Check this option to have menus for your event on the
website: registrations, schedule, map, ...
</div>
</div>
</div>
</div>
</div>
</field>
</record>
<record id="event_event_view_form_inherit_website" model="ir.ui.view">
<field name="name">event.event.view.form.inherit.website</field>
<field name="model">event.event</field>
<field name="inherit_id" ref="event.view_event_form"/>
<field name="arch" type="xml">
<button name="toggle_active" position="before">
<field name="website_url" invisible="1"/>
<button name="website_publish_button"
type="object"
class="oe_stat_button"
icon="fa-globe">
<field name="website_published" widget="website_button"/>
</button>
</button>
<label for="is_online" position="after">
<field name="website_menu"/>
<label for="website_menu" string="Website Menu"/>
</label>
<xpath expr="//button[@name='button_done']" position="before">
<button name="action_open_badge_editor"
type="object"
states="confirm"
string="Edit Badges"
class="oe_highlight"/>
<button name="action_open_badge_editor"
type="object"
states="done"
string="Edit Badges"/>
</xpath>
</field>
</record>
</odoo>
@@ -1,34 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record model="ir.ui.view" id="view_event_sale_form">
<field name="name">event.event.website.form</field>
<field name="model">event.event</field>
<field name="inherit_id" ref="event.view_event_form"/>
<field name="arch" type="xml">
<!-- add state field in header -->
<button name="toggle_active" position="before">
<field name="website_url" invisible="1"/>
<button class="oe_stat_button" name="website_publish_button"
type="object" icon="fa-globe">
<field name="website_published" widget="website_button"/>
</button>
</button>
<xpath expr="//field[@name='organizer_id']" position="after">
<field name="twitter_hashtag"/>
</xpath>
<xpath expr="//button[@name='button_done']" position="before">
<button name="action_open_badge_editor"
type="object"
states="confirm"
string="Edit Badges"
class="oe_highlight"/>
<button name="action_open_badge_editor"
type="object"
states="done"
string="Edit Badges"/>
</xpath>
</field>
</record>
</odoo>
@@ -7,13 +7,13 @@
'version': '1.0',
'depends': ['website_event'],
'data': [
'views/website_event_questions_backend.xml',
'views/website_event_questions_templates.xml',
'views/event_views.xml',
'views/event_templates.xml',
'report/report_event_question_view.xml',
'security/ir.model.access.csv',
],
'demo': [
'data/demo.xml',
'data/event_demo.xml',
],
'installable': True,
}
+35 -2
View File
@@ -1,7 +1,17 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import fields, models
from odoo import api, fields, models, _
from odoo.exceptions import UserError
class EventType(models.Model):
_inherit = 'event.type'
use_questions = fields.Boolean('Questions to Attendees')
question_ids = fields.One2many(
'event.question', 'event_type_id',
string='Questions', copy=True)
class EventEvent(models.Model):
@@ -14,6 +24,23 @@ class EventEvent(models.Model):
specific_question_ids = fields.One2many('event.question', 'event_id', 'Specific Questions',
domain=[('is_individual', '=', True)])
@api.onchange('event_type_id')
def _onchange_type(self):
super(EventEvent, self)._onchange_type()
if self.event_type_id.use_questions and self.event_type_id.question_ids:
self.question_ids = [(5, 0, 0)] + [
(0, 0, {
'title': question.title,
'sequence': question.sequence,
'is_individual': question.is_individual,
'answer_ids': [(0, 0, {
'name': answer.name,
'sequence': answer.sequence,
}) for answer in question.answer_ids]
})
for question in self.event_type_id.question_ids
]
class EventRegistrationAnswer(models.Model):
''' This m2m table has to be explicitly instanciated as we need unique ids
@@ -41,13 +68,19 @@ class EventQuestion(models.Model):
_order = 'sequence,id'
title = fields.Char(required=True, translate=True)
event_id = fields.Many2one('event.event', required=True, ondelete='cascade')
event_type_id = fields.Many2one('event.type', 'Event Type', ondelete='cascade')
event_id = fields.Many2one('event.event', 'Event', ondelete='cascade')
answer_ids = fields.One2many('event.answer', 'question_id', "Answers", required=True, copy=True)
sequence = fields.Integer(default=10)
is_individual = fields.Boolean('Ask each attendee',
help="If True, this question will be asked for every attendee of a reservation. If "
"not it will be asked only once and its value propagated to every attendees.")
@api.constrains('event_type_id', 'event_id')
def _constrains_event(self):
if any(question.event_type_id and question.event_id for question in self):
raise UserError(_('Question should belong to either event category or event but not both'))
class EventAnswer(models.Model):
_name = 'event.answer'
@@ -31,10 +31,33 @@
</field>
</record>
<record id="event_type_view_form_inherit_question" model="ir.ui.view">
<field name="name">event.type.view.form.inherit.question</field>
<field name="model">event.type</field>
<field name="inherit_id" ref="website_event.event_type_view_form_inherit_website"/>
<field name="arch" type="xml">
<div name="event_type_attendees_auto_confirm" position="after">
<div class="col-xs-12 col-md-12 o_setting_box">
<div class="o_setting_left_pane">
<field name="use_questions"/>
</div>
<div class="o_setting_right_pane">
<label for="use_questions"/>
<div class="row mt16" attrs="{'invisible': [('use_ticketing', '=', False)]}">
<div class="col-md-9">
<field name="question_ids"/>
</div>
</div>
</div>
</div>
</div>
</field>
</record>
<record model="ir.ui.view" id="view_event_form_inherit_question">
<field name="name">event.form.inherit.question</field>
<field name="name">event.event.view.form.inherit.question</field>
<field name="model">event.event</field>
<field name="inherit_id" ref="event.view_event_form"/>
<field name="inherit_id" ref="website_event.event_event_view_form_inherit_website"/>
<field name="arch" type="xml">
<data>
<xpath expr="//notebook" position="inside">
+3 -2
View File
@@ -3,7 +3,7 @@
{
'name': "Online Event's Tickets",
'category': 'Marketing',
'summary': "Sell Your Event's Tickets",
'summary': "Manage Events and Sell Tickets Online",
'website': 'https://www.odoo.com/page/events',
'description': """
Online Event's Tickets
@@ -12,7 +12,8 @@ Online Event's Tickets
""",
'depends': ['website_event', 'event_sale', 'website_sale'],
'data': [
'views/website_event_sale_templates.xml',
'data/event_data.xml',
'views/event_templates.xml',
'security/ir.model.access.csv',
'security/website_event_sale_security.xml',
],
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data noupdate="1">
<record id="event_sale.event_type_data_sale" model="event.type">
<field name="name">Sell Online</field>
<field name="website_menu" eval="True"/>
</record>
</data>
</odoo>
@@ -92,7 +92,7 @@ class SaleOrder(models.Model):
# adding attendees
elif ticket and new_qty > old_qty:
line = OrderLine.browse(values['line_id'])
line._update_registrations(confirm=False, registration_data=kwargs.get('registration_data', []))
line._update_registrations(confirm=False, cancel_to_draft=True, registration_data=kwargs.get('registration_data', []))
# add in return values the registrations, to display them on website (or not)
values['attendee_ids'] = self.env['event.registration'].search([('sale_order_line_id', '=', line.id), ('state', '!=', 'cancel')]).ids
return values
@@ -25,6 +25,7 @@
</xpath>
<xpath expr="//tbody" position="replace">
<tbody>
<t t-set="ticket_count" t-value="len([ticket for ticket in event.event_ticket_ids if not ticket.is_expired])"/>
<t t-foreach="event.event_ticket_ids" t-as="ticket">
<tr itemscope="itemscope" itemtype="http://data-vocabulary.org/Offer" t-if="not ticket.is_expired">
<td itemscope="itemscope" itemtype="http://data-vocabulary.org/Product">
@@ -74,7 +75,12 @@
<t t-set="seats_max_event" t-value="(event.seats_availability == 'unlimited' or event.seats_available > 9) and 10 or event.seats_available + 1"/>
<t t-set="seats_max" t-value="min(seats_max_ticket, seats_max_event)"/>
<t t-foreach="range(0, seats_max)" t-as="nb">
<option t-esc="nb"/>
<t t-if="ticket_count == 1 and nb == 1">
<option t-esc="nb" selected="selected"/>
</t>
<t t-if="ticket_count != 1 or nb != 1">
<option t-esc="nb"/>
</t>
</t>
</select>
<span t-if="(not event.seats_available and event.seats_availability == 'limited') or (ticket.seats_availability == 'limited' and not ticket.seats_available)">Sold Out</span>
@@ -84,8 +90,16 @@
</tbody>
</xpath>
<xpath expr="//button[@type='submit']" position="replace">
<t t-set="ticket_buy" t-value="any(ticket for ticket in event.event_ticket_ids if not ticket.is_expired and ticket.price)"/>
<button type="submit" t-if="event.state == 'confirm' and (event.seats_available or event.seats_availability == 'unlimited')"
class="btn btn-primary btn-lg pull-right a-submit" t-attf-id="#{event.id}">Order Now</button>
class="btn btn-primary btn-lg pull-right a-submit" t-attf-id="#{event.id}">
<t t-if="ticket_buy">
Order Now
</t>
<t t-if="not ticket_buy">
Register Now
</t>
</button>
</xpath>
<xpath expr="//form[@id='registration_form']" position="attributes">
<attribute name="t-if">event.event_ticket_ids</attribute>
@@ -93,6 +107,12 @@
</template>
<template id="cart" inherit_id="website_sale.cart_lines" name="Hide product reduction for event tickets">
<xpath expr="//td[@class='td-product_name']/div/a" position="attributes">
<attribute name="t-attf-href"/>
<attribute name="t-att-href">
line.event_id and ('/event/%s/register' % slug(line.event_id)) or ('/shop/product/%s' % slug(line.product_id.product_tmpl_id))
</attribute>
</xpath>
<xpath expr="//del" position="attributes">
<attribute name="t-attf-class" separator=" " add="#{line.event_id and 'hidden' or ''}"/>
</xpath>
+5 -5
View File
@@ -22,14 +22,14 @@ Adds support for:
'depends': ['website_event'],
'data': [
'security/ir.model.access.csv',
'security/website_event_track_security.xml',
'data/website_event_track_data.xml',
'views/website_event_track_templates.xml',
'views/website_event_track_views.xml',
'security/event_track_security.xml',
'data/event_data.xml',
'data/event_track_data.xml',
'views/event_track_templates.xml',
'views/event_track_views.xml',
'views/event_views.xml',
],
'demo': [
'data/event_demo.xml',
'data/website_event_track_demo.xml'
],
}
+4 -10
View File
@@ -65,7 +65,7 @@ class WebsiteEventTrackController(http.Controller):
'dates': dates
}
@http.route(['''/event/<model("event.event", "[('show_tracks','=',1)]"):event>/agenda'''], type='http', auth="public", website=True)
@http.route(['''/event/<model("event.event", "[('website_track','=',1)]"):event>/agenda'''], type='http', auth="public", website=True)
def event_agenda(self, event, tag=None, **post):
days_tracks = collections.defaultdict(lambda: [])
for track in event.track_ids.sorted(lambda track: (track.date, bool(track.location_id))):
@@ -79,22 +79,16 @@ class WebsiteEventTrackController(http.Controller):
tracks_by_days[day] = tracks
days[day] = self._prepare_calendar(event, tracks)
speakers = {}
for track in event.sudo().track_ids:
speakers_name = u" – ".join(track.speaker_ids.mapped('name'))
speakers[track.id] = speakers_name
return request.render("website_event_track.agenda", {
'event': event,
'days': days,
'tracks_by_days': tracks_by_days,
'speakers': speakers,
'tag': tag
})
@http.route([
'''/event/<model("event.event", "[('show_tracks','=',1)]"):event>/track''',
'''/event/<model("event.event", "[('show_tracks','=',1)]"):event>/track/tag/<model("event.track.tag"):tag>'''
'''/event/<model("event.event", "[('website_track','=',1)]"):event>/track''',
'''/event/<model("event.event", "[('website_track','=',1)]"):event>/track/tag/<model("event.track.tag"):tag>'''
], type='http', auth="public", website=True)
def event_tracks(self, event, tag=None, **post):
searches = {}
@@ -114,7 +108,7 @@ class WebsiteEventTrackController(http.Controller):
}
return request.render("website_event_track.tracks", values)
@http.route(['''/event/<model("event.event", "[('show_track_proposal','=',1)]"):event>/track_proposal'''], type='http', auth="public", website=True)
@http.route(['''/event/<model("event.event", "[('website_track_proposal','=',1)]"):event>/track_proposal'''], type='http', auth="public", website=True)
def event_track_proposal(self, event, **post):
return request.render("website_event_track.event_track_proposal", {'event': event})
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data noupdate="1">
<record id="event_type_data_tracks" model="event.type">
<field name="name">Conference</field>
<field name="auto_confirm" eval="True"/>
<field name="use_mail_schedule" eval="True"/>
<field name="website_menu" eval="True"/>
<field name="website_track" eval="True"/>
<field name="website_track_proposal" eval="True"/>
</record>
</data>
</odoo>
+387 -63
View File
@@ -1,75 +1,399 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="event_track_tag1" model="event.track.tag">
<field name="name">Technical</field>
</record>
<record id="event_track_tag2" model="event.track.tag">
<field name="name">Business</field>
</record>
<record id="event_track_tag3" model="event.track.tag">
<field name="name">Lightning Talks</field>
</record>
<record id="event_track_tag4" model="event.track.tag">
<field name="name">Round Table</field>
</record>
<!--
This should be done at the end so that the menu is complete
-->
<record id="event.event_0" model="event.event">
<field name="show_tracks">True</field>
<field name="show_track_proposal">True</field>
</record>
<record id="event_track_tag1" model="event.track.tag">
<field name="name">Technical</field>
</record>
<record id="event_track_tag2" model="event.track.tag">
<field name="name">Business</field>
</record>
<record id="event_track_tag3" model="event.track.tag">
<field name="name">Lightning Talks</field>
</record>
<record id="event_track_tag4" model="event.track.tag">
<field name="name">Round Table</field>
</record>
<!--
This should be done at the end so that the menu is complete
-->
<record id="event.event_0" model="event.event">
<field name="website_track">True</field>
<field name="website_track_proposal">True</field>
</record>
<!-- Show menu after so that the menu is created with tracks -->
<!-- Show menu after so that the menu is created with tracks -->
<record id="event.event_0" model="event.event">
<field name="show_menu">True</field>
</record>
<record id="event.event_0" model="event.event">
<field name="website_menu">True</field>
</record>
<!-- Sponsorships -->
<!-- Sponsorships -->
<record id="event_sponsor_0" model="event.sponsor">
<field name="event_id" ref="event.event_0"/>
<field name="sponsor_type_id" ref="event_sponsor_type1"/>
<field name="partner_id" ref="base.res_partner_2"/>
<field name="url">http://odoo.com</field>
</record>
<record id="event_sponsor_0" model="event.sponsor">
<field name="event_id" ref="event.event_0"/>
<field name="sponsor_type_id" ref="event_sponsor_type1"/>
<field name="partner_id" ref="base.res_partner_2"/>
<field name="url">http://odoo.com</field>
</record>
<record id="event_sponsor_1" model="event.sponsor">
<field name="event_id" ref="event.event_0"/>
<field name="sponsor_type_id" ref="event_sponsor_type2"/>
<field name="partner_id" ref="base.res_partner_12"/>
<field name="url">http://odoo.com</field>
</record>
<record id="event_sponsor_1" model="event.sponsor">
<field name="event_id" ref="event.event_0"/>
<field name="sponsor_type_id" ref="event_sponsor_type2"/>
<field name="partner_id" ref="base.res_partner_12"/>
<field name="url">http://odoo.com</field>
</record>
<record id="event_sponsor_2" model="event.sponsor">
<field name="event_id" ref="event.event_0"/>
<field name="sponsor_type_id" ref="event_sponsor_type2"/>
<field name="partner_id" ref="base.res_partner_3"/>
</record>
<record id="event_sponsor_2" model="event.sponsor">
<field name="event_id" ref="event.event_0"/>
<field name="sponsor_type_id" ref="event_sponsor_type2"/>
<field name="partner_id" ref="base.res_partner_3"/>
</record>
<record id="event_sponsor_3" model="event.sponsor">
<field name="event_id" ref="event.event_0"/>
<field name="sponsor_type_id" ref="event_sponsor_type3"/>
<field name="partner_id" ref="base.res_partner_4"/>
<field name="url">http://odoo.com</field>
</record>
<record id="event_sponsor_3" model="event.sponsor">
<field name="event_id" ref="event.event_0"/>
<field name="sponsor_type_id" ref="event_sponsor_type3"/>
<field name="partner_id" ref="base.res_partner_4"/>
<field name="url">http://odoo.com</field>
</record>
<!-- Tracks -->
<record id="base.res_partner_address_16" model="res.partner">
<field name="website">http://facebook.com/odoo</field>
<field name="website_description" type="xml">
<p>
Ayaan has in the IT sector <b>since 20 years</b>. He
develops software to help develop websites. He sold his
first company at 30 years old and manage to grow OpenCorp
from 1 to 55 employees mostly by reselling services on
Odoo.
</p><p>
Ayaan is the <b>author of several books</b>, including Amazon best seller
"How Odoo will change the business world!".
</p>
</field>
</record>
<record id="event_track_location5" model="event.track.location">
<field name="name">Le Foyer du lac</field>
</record>
<record id="event_track_location6" model="event.track.location">
<field name="name">Theatre</field>
</record>
<record id="event_track_location7" model="event.track.location">
<field name="name">Lauzelle</field>
</record>
<record id="event_track_location8" model="event.track.location">
<field name="name">Foyer Royal</field>
</record>
<record id="event_track_location9" model="event.track.location">
<field name="name">Biereau</field>
</record>
<record id="event_track_location10" model="event.track.location">
<field name="name">Bruyère</field>
</record>
<record id="event_track1" model="event.track">
<field name="name">How to develop a website module.</field>
<field name="website_published" eval="True"/>
<field name="event_id" ref="event.event_0"/>
<field name="date" eval="time.strftime(str(DateTime.today().year) + '-06-04 06:00:00')"></field>
<field name="location_id" ref="website_event_track.event_track_location5"/>
<field name="duration" eval="1"/>
<field name="partner_id" ref="base.res_partner_2"/>
<field name="color">3</field>
<field name="stage_id" ref="event_track_stage0"/>
<field name="kanban_state">blocked</field>
</record>
<record id="event_track2" model="event.track">
<field name="name">How to integrate hardware materials with the Odoo point of sale.</field>
<field name="website_published" eval="True"/>
<field name="event_id" ref="event.event_0"/>
<field name="date" eval="time.strftime(str(DateTime.today().year) + '-06-04 8:30:00')"></field>
<field name="location_id" ref="website_event_track.event_track_location5"/>
<field name="duration" eval="0.25"/>
<field name="partner_id" ref="base.res_partner_3"/>
<field name="stage_id" ref="event_track_stage1"/>
<field name="kanban_state">done</field>
</record>
<record id="event_track3" model="event.track">
<field name="name">How to develop real time apps, the website live chat module explained.</field>
<field name="website_published" eval="True"/>
<field name="event_id" ref="event.event_0"/>
<field name="date" eval="time.strftime(str(DateTime.today().year) + '-06-04 10:30:00')"></field>
<field name="location_id" ref="website_event_track.event_track_location5"/>
<field name="duration" eval="0.3"/>
<field name="partner_id" ref="base.res_partner_4"/>
<field name="stage_id" ref="event_track_stage1"/>
</record>
<record id="event_track4" model="event.track">
<field name="name">How to develop automated tests in the Odoo web client.</field>
<field name="website_published" eval="True"/>
<field name="event_id" ref="event.event_0"/>
<field name="date" eval="time.strftime(str(DateTime.today().year) + '-06-04 9:00:00')"></field>
<field name="location_id" ref="website_event_track.event_track_location5"/>
<field name="duration" eval="0.5"/>
<field name="partner_id" ref="base.res_partner_2"/>
<field name="stage_id" ref="event_track_stage3"/>
</record>
<record id="event_track5" model="event.track">
<field name="name">The new way to promote your modules in the Apps platform and Odoo website.</field>
<field name="website_published" eval="True"/>
<field name="event_id" ref="event.event_0"/>
<field name="date" eval="time.strftime(str(DateTime.today().year) + '-06-04 6:00:00')"></field>
<field name="location_id" ref="website_event_track.event_track_location6"/>
<field name="duration" eval="0.5"/>
<field name="partner_id" ref="base.res_partner_4"/>
<field name="stage_id" ref="event_track_stage2"/>
</record>
<record id="event_track6" model="event.track">
<field name="name">Detailed roadmap of accounting new modules and improvements for version 8.</field>
<field name="website_published" eval="True"/>
<field name="event_id" ref="event.event_0"/>
<field name="date" eval="time.strftime(str(DateTime.today().year) + '-06-04 6:30:00')"></field>
<field name="location_id" ref="website_event_track.event_track_location6"/>
<field name="duration" eval="0.5"/>
<field name="partner_id" ref="base.res_partner_3"/>
<field name="stage_id" ref="event_track_stage2"/>
</record>
<record id="event_track7" model="event.track">
<field name="name">A technical explanation of Odoo as a CMS and a eCommerce platform for version 8.</field>
<field name="website_published" eval="True"/>
<field name="event_id" ref="event.event_0"/>
<field name="date" eval="time.strftime(str(DateTime.today().year) + '-06-04 8:30:00')"></field>
<field name="location_id" ref="website_event_track.event_track_location6"/>
<field name="duration" eval="1"/>
<field name="partner_id" ref="base.res_partner_1"/>
<field name="stage_id" ref="event_track_stage3"/>
</record>
<record id="event_track8" model="event.track">
<field name="name">Discover Odoo CRM: How to optimize your sales, from leads to sales orders.</field>
<field name="website_published" eval="True"/>
<field name="event_id" ref="event.event_0"/>
<field name="date" eval="time.strftime(str(DateTime.today().year) + '-06-04 6:00:00')"></field>
<field name="location_id" ref="website_event_track.event_track_location7"/>
<field name="duration" eval="0.5"/>
<field name="color">2</field>
<field name="partner_id" ref="base.res_partner_4"/>
<field name="stage_id" ref="event_track_stage3"/>
<field name="kanban_state">blocked</field>
</record>
<record id="event_track9" model="event.track">
<field name="name">How to use Odoo for your HR process: recruitment, leaves management, appraisals, expenses, etc.</field>
<field name="website_published" eval="True"/>
<field name="event_id" ref="event.event_0"/>
<field name="user_id" ref="base.user_root"/>
<field name="date" eval="time.strftime(str(DateTime.today().year) + '-06-04 8:30:00')"></field>
<field name="location_id" ref="website_event_track.event_track_location7"/>
<field name="duration" eval="1"/>
<field name="color">2</field>
<field name="partner_id" ref="base.res_partner_12"/>
<field name="stage_id" ref="event_track_stage3"/>
</record>
<record id="event_track10" model="event.track">
<field name="name">Raising qualitive insights with the survey app</field>
<field name="website_published" eval="True"/>
<field name="event_id" ref="event.event_0"/>
<field name="date" eval="time.strftime(str(DateTime.today().year) + '-06-04 6:30:00')"></field>
<field name="location_id" ref="website_event_track.event_track_location7"/>
<field name="duration" eval="0.5"/>
<field name="color">5</field>
<field name="stage_id" ref="event_track_stage0"/>
</record>
<record id="event_track11" model="event.track">
<field name="name">Discover Odoo Point-of-Sale: Your shop ready to use in 30 minutes.</field>
<field name="website_published" eval="True"/>
<field name="event_id" ref="event.event_0"/>
<field name="date" eval="time.strftime(str(DateTime.today().year) + '-06-04 10:30:00')"></field>
<field name="location_id" ref="website_event_track.event_track_location7"/>
<field name="duration" eval="0.5"/>
<field name="partner_id" ref="base.res_partner_4"/>
<field name="stage_id" ref="event_track_stage1"/>
</record>
<record id="event_track12" model="event.track">
<field name="name">Manage your events with Odoo, the new training modules.</field>
<field name="website_published" eval="True"/>
<field name="event_id" ref="event.event_0"/>
<field name="date" eval="time.strftime(str(DateTime.today().year) + '-06-04 11:00:00')"></field>
<field name="location_id" ref="website_event_track.event_track_location7"/>
<field name="duration" eval="0.5"/>
<field name="partner_id" ref="base.res_partner_2"/>
<field name="stage_id" ref="event_track_stage2"/>
</record>
<record id="event_track13" model="event.track">
<field name="name">Advanced reporting with Google Spreadsheets integration.</field>
<field name="website_published" eval="True"/>
<field name="event_id" ref="event.event_0"/>
<field name="date" eval="time.strftime(str(DateTime.today().year) + '-06-04 6:30:00')"></field>
<field name="location_id" ref="website_event_track.event_track_location8"/>
<field name="duration" eval="0.25"/>
<field name="partner_id" ref="base.res_partner_12"/>
<field name="stage_id" ref="event_track_stage3"/>
</record>
<record id="event_track14" model="event.track">
<field name="name">New Paypal modules (portal, handling, installments).</field>
<field name="website_published" eval="True"/>
<field name="event_id" ref="event.event_0"/>
<field name="date" eval="time.strftime(str(DateTime.today().year) + '-06-04 7:00:00')"></field>
<field name="location_id" ref="website_event_track.event_track_location8"/>
<field name="duration" eval="0.5"/>
<field name="partner_id" ref="base.res_partner_10"/>
<field name="stage_id" ref="event_track_stage3"/>
</record>
<record id="event_track15" model="event.track">
<field name="name">Odoo Mobile for Notes, Meetings and Messages.</field>
<field name="website_published" eval="True"/>
<field name="event_id" ref="event.event_0"/>
<field name="date" eval="time.strftime(str(DateTime.today().year) + '-06-04 10:30:00')"></field>
<field name="location_id" ref="website_event_track.event_track_location8"/>
<field name="duration" eval="0.5"/>
<field name="partner_id" ref="base.res_partner_3"/>
<field name="stage_id" ref="event_track_stage3"/>
</record>
<record id="event_track16" model="event.track">
<field name="name">Odoo as your Enterprise Social Network.</field>
<field name="website_published" eval="True"/>
<field name="event_id" ref="event.event_0"/>
<field name="date" eval="time.strftime(str(DateTime.today().year) + '-06-04 11:00:00')"></field>
<field name="location_id" ref="website_event_track.event_track_location8"/>
<field name="duration" eval="0.5"/>
<field name="partner_id" ref="base.res_partner_12"/>
<field name="stage_id" ref="event_track_stage0"/>
</record>
<record id="event_track17" model="event.track">
<field name="name">The Art of Making an Odoo Demo.</field>
<field name="website_published" eval="True"/>
<field name="event_id" ref="event.event_0"/>
<field name="date" eval="time.strftime(str(DateTime.today().year) + '-06-04 6:00:00')"></field>
<field name="location_id" ref="website_event_track.event_track_location9"/>
<field name="duration" eval="0.5"/>
<field name="partner_id" ref="base.res_partner_10"/>
<field name="stage_id" ref="event_track_stage0"/>
</record>
<record id="event_track18" model="event.track">
<field name="name">How to build your marketing strategy for the purpose of generating leads with Odoo.</field>
<field name="website_published" eval="True"/>
<field name="event_id" ref="event.event_0"/>
<field name="date" eval="time.strftime(str(DateTime.today().year) + '-06-04 8:30:00')"></field>
<field name="location_id" ref="website_event_track.event_track_location9"/>
<field name="duration" eval="0.5"/>
<field name="color">5</field>
<field name="partner_id" ref="base.res_partner_2"/>
<field name="stage_id" ref="event_track_stage1"/>
</record>
<record id="event_track19" model="event.track">
<field name="name">Advanced lead management with Odoo: tips and tricks from the fields</field>
<field name="website_published" eval="True"/>
<field name="event_id" ref="event.event_0"/>
<field name="date" eval="time.strftime(str(DateTime.today().year) + '-06-04 9:00:00')"></field>
<field name="location_id" ref="website_event_track.event_track_location9"/>
<field name="duration" eval="0.5"/>
<field name="color">5</field>
<field name="partner_id" ref="base.res_partner_4"/>
<field name="stage_id" ref="event_track_stage1"/>
</record>
<record id="event_track20" model="event.track">
<field name="name">New Certification Program (valid from Oct. 2013).</field>
<field name="website_published" eval="True"/>
<field name="event_id" ref="event.event_0"/>
<field name="date" eval="time.strftime(str(DateTime.today().year) + '-06-04 10:00:00')"></field>
<field name="location_id" ref="website_event_track.event_track_location9"/>
<field name="duration" eval="0.5"/>
<field name="partner_id" ref="base.res_partner_3"/>
<field name="stage_id" ref="event_track_stage1"/>
</record>
<record id="event_track21" model="event.track">
<field name="name">Recruiting high skilled talents with Odoo HR apps</field>
<field name="website_published" eval="True"/>
<field name="event_id" ref="event.event_0"/>
<field name="date" eval="time.strftime(str(DateTime.today().year) + '-06-04 10:30:00')"></field>
<field name="location_id" ref="website_event_track.event_track_location9"/>
<field name="duration" eval="0.5"/>
<field name="color">7</field>
<field name="stage_id" ref="event_track_stage1"/>
</record>
<record id="event_track22" model="event.track">
<field name="name">Manage your KPIs (recomended to openERP partners).</field>
<field name="website_published" eval="True"/>
<field name="event_id" ref="event.event_0"/>
<field name="date" eval="time.strftime(str(DateTime.today().year) + '-06-04 11:00:00')"></field>
<field name="location_id" ref="website_event_track.event_track_location9"/>
<field name="duration" eval="0.5"/>
<field name="partner_id" ref="base.res_partner_3"/>
<field name="stage_id" ref="event_track_stage0"/>
</record>
<record id="event_track23" model="event.track">
<field name="name">Key Success factors selling Odoo.</field>
<field name="website_published" eval="True"/>
<field name="event_id" ref="event.event_0"/>
<field name="date" eval="time.strftime(str(DateTime.today().year) + '-06-04 7:00:00')"></field>
<field name="location_id" ref="website_event_track.event_track_location9"/>
<field name="duration" eval="0.5"/>
<field name="partner_id" ref="base.res_partner_1"/>
<field name="stage_id" ref="event_track_stage3"/>
</record>
<record id="event_track24" model="event.track">
<field name="name">Merge proposals review, code sprint (entire day).</field>
<field name="website_published" eval="True"/>
<field name="event_id" ref="event.event_0"/>
<field name="date" eval="time.strftime(str(DateTime.today().year) + '-06-04 6:00:00')"></field>
<field name="location_id" ref="website_event_track.event_track_location10"/>
<field name="duration" eval="1.5"/>
<field name="partner_id" ref="base.res_partner_18"/>
<field name="stage_id" ref="event_track_stage3"/>
</record>
<record id="event_track25" model="event.track">
<field name="name">Merge proposals review, code sprint (entire afternoon)</field>
<field name="website_published" eval="True"/>
<field name="event_id" ref="event.event_0"/>
<field name="date" eval="time.strftime(str(DateTime.today().year) + '-06-04 8:30:00')"></field>
<field name="location_id" ref="website_event_track.event_track_location10"/>
<field name="duration" eval="2.5"/>
<field name="partner_id" ref="base.res_partner_18"/>
<field name="stage_id" ref="event_track_stage3"/>
</record>
<record id="event_track27" model="event.track">
<field name="name">Odoo in 2014</field>
<field name="website_published" eval="True"/>
<field name="event_id" ref="event.event_0"/>
<field name="date" eval="time.strftime(str(DateTime.today().year) + '-06-04 04:00:00')"></field>
<field name="duration" eval="1"/>
<field name="partner_id" ref="base.res_partner_1"/>
<field name="stage_id" ref="event_track_stage3"/>
<field name="color">3</field>
</record>
<record id="event_track28" model="event.track">
<field name="name">Odoo Status &amp; Strategy 2014</field>
<field name="website_published" eval="True"/>
<field name="event_id" ref="event.event_0"/>
<field name="date" eval="time.strftime(str(DateTime.today().year) + '-06-04 5:00:00')"></field>
<field name="duration" eval="0.5"/>
<field name="partner_id" ref="base.res_partner_2"/>
<field name="stage_id" ref="event_track_stage2"/>
</record>
<record id="event_track29" model="event.track">
<field name="name">The new marketing strategy.</field>
<field name="website_published" eval="True"/>
<field name="event_id" ref="event.event_0"/>
<field name="date" eval="time.strftime(str(DateTime.today().year) + '-06-04 5:30:00')"></field>
<field name="duration" eval="0.25"/>
<field name="partner_id" ref="base.res_partner_2"/>
<field name="stage_id" ref="event_track_stage2"/>
<field name="color">6</field>
</record>
<record id="event_track30" model="event.track">
<field name="name">Morning break</field>
<field name="website_published" eval="True"/>
<field name="event_id" ref="event.event_0"/>
<field name="date" eval="time.strftime(str(DateTime.today().year) + '-06-04 5:45:00')"></field>
<field name="duration" eval="0.25"/>
<field name="stage_id" ref="event_track_stage1"/>
</record>
<record id="event_track31" model="event.track">
<field name="name">Lunch</field>
<field name="website_published" eval="True"/>
<field name="event_id" ref="event.event_0"/>
<field name="date" eval="time.strftime(str(DateTime.today().year) + '-06-04 7:30:00')"></field>
<field name="duration" eval="1"/>
<field name="stage_id" ref="event_track_stage1"/>
</record>
<!-- Tracks -->
<record id="base.res_partner_address_16" model="res.partner">
<field name="website">http://facebook.com/odoo</field>
<field name="website_description" type="xml">
<p>
Ayaan has in the IT sector <b>since 20 years</b>. He
develops software to help develop websites. He sold his
first company at 30 years old and manage to grow OpenCorp
from 1 to 55 employees mostly by reselling services on
Odoo.
</p><p>
Ayaan is the <b>author of several books</b>, including Amazon best seller
"How Odoo will change the business world!".
</p>
</field>
</record>
</odoo>
@@ -0,0 +1,98 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data noupdate="1">
<!-- Email templates -->
<record id="mail_template_data_track_confirmation" model="mail.template">
<field name="name">Track: Confirmation</field>
<field name="subject">Confirmation of ${object.name}</field>
<field name="model_id" ref="website_event_track.model_event_track"/>
<field name="use_default_to" eval="True"/>
<field name="body_html" type="xml">
<div>
<p>
Dear <t t-esc="object.partner_name"/>
</p><p>
We are pleased to inform you that your proposal ${object.name} has been accepted and confirmed for the event ${object.event_id.name}.
</p><p>
You will find more details here:
<div style="margin-top: 16px;">
<a href="/event/${object.event_id.id}/"
style="padding: 8px 12px; font-size: 12px; color: #FFFFFF; text-decoration: none !important; font-weight: 400; background-color: #875A7B; border: 0px solid #875A7B; border-radius:3px">
View Event
</a>
</div>
</p>
<p>Sincerely,</p>
</div>
</field>
<field name="auto_delete" eval="True"/>
</record>
<record id="event_sponsor_type1" model="event.sponsor.type">
<field name="name">Bronze</field>
<field name="sequence">3</field>
</record>
<record id="event_sponsor_type2" model="event.sponsor.type">
<field name="name">Silver</field>
<field name="sequence">2</field>
</record>
<record id="event_sponsor_type3" model="event.sponsor.type">
<field name="name">Gold</field>
<field name="sequence">1</field>
</record>
<record id="event_track_stage0" model="event.track.stage">
<field name="name">Proposal</field>
<field name="sequence">1</field>
</record>
<record id="event_track_stage1" model="event.track.stage">
<field name="name">Confirmed</field>
<field name="sequence">2</field>
<field name="mail_template_id" ref="mail_template_data_track_confirmation"/>
</record>
<record id="event_track_stage2" model="event.track.stage">
<field name="name">Announced</field>
<field name="sequence">3</field>
</record>
<record id="event_track_stage3" model="event.track.stage">
<field name="name">Published</field>
<field name="sequence">4</field>
<field name="is_done" eval="True"/>
</record>
<record id="event_track_stage4" model="event.track.stage">
<field name="name">Refused</field>
<field name="sequence">5</field>
<field name="fold" eval="True"/>
</record>
<record id="event_track_stage5" model="event.track.stage">
<field name="name">Cancelled</field>
<field name="sequence">6</field>
<field name="fold" eval="True"/>
<field name="is_cancel" eval="True"/>
</record>
<!-- Event-related subtypes for new track / Chatter -->
<record id="mt_event_track" model="mail.message.subtype">
<field name="name">New Track</field>
<field name="res_model">event.event</field>
<field name="description">New Track Created</field>
<field name="default" eval="False"/>
</record>
<!-- Track subtypes -->
<record id="mt_track_blocked" model="mail.message.subtype">
<field name="name">Track Blocked</field>
<field name="res_model">event.track</field>
<field name="default" eval="False"/>
<field name="internal" eval="True"/>
<field name="description">Track blocked</field>
</record>
<record id="mt_track_ready" model="mail.message.subtype">
<field name="name">Track Ready</field>
<field name="res_model">event.track</field>
<field name="default" eval="True"/>
<field name="internal" eval="True"/>
<field name="description">Track Ready for Next Stage</field>
</record>
</data>
</odoo>
@@ -1,27 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data noupdate="1">
<record id="event_sponsor_type1" model="event.sponsor.type">
<field name="name">Bronze</field>
<field name="sequence">3</field>
</record>
<record id="event_sponsor_type2" model="event.sponsor.type">
<field name="name">Silver</field>
<field name="sequence">2</field>
</record>
<record id="event_sponsor_type3" model="event.sponsor.type">
<field name="name">Gold</field>
<field name="sequence">1</field>
</record>
<!-- Event-related subtypes for new track / Chatter -->
<record id="mt_event_track" model="mail.message.subtype">
<field name="name">New Track</field>
<field name="res_model">event.event</field>
<field name="description">New Track Created</field>
<field name="default" eval="False"/>
</record>
</data>
</odoo>
@@ -1,325 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data noupdate="1">
<record id="event_track_location5" model="event.track.location">
<field name="name">Le Foyer du lac</field>
</record>
<record id="event_track_location6" model="event.track.location">
<field name="name">Theatre</field>
</record>
<record id="event_track_location7" model="event.track.location">
<field name="name">Lauzelle</field>
</record>
<record id="event_track_location8" model="event.track.location">
<field name="name">Foyer Royal</field>
</record>
<record id="event_track_location9" model="event.track.location">
<field name="name">Biereau</field>
</record>
<record id="event_track_location10" model="event.track.location">
<field name="name">Bruyère</field>
</record>
<record id="event_track1" model="event.track">
<field name="name">How to develop a website module.</field>
<field name="website_published" eval="True"/>
<field name="event_id" ref="event.event_0"/>
<field name="date" eval="time.strftime(str(DateTime.today().year) + '-06-04 06:00:00')"></field>
<field name="location_id" ref="website_event_track.event_track_location5"/>
<field name="duration" eval="1"/>
<field eval="[(4, ref('base.res_partner_2')),(4, ref('base.res_partner_3'))]" name="speaker_ids"/>
<field name="color">3</field>
<field name="state">draft</field>
</record>
<record id="event_track2" model="event.track">
<field name="name">How to integrate hardware materials with the Odoo point of sale.</field>
<field name="website_published" eval="True"/>
<field name="event_id" ref="event.event_0"/>
<field name="date" eval="time.strftime(str(DateTime.today().year) + '-06-04 8:30:00')"></field>
<field name="location_id" ref="website_event_track.event_track_location5"/>
<field name="duration" eval="0.25"/>
<field eval="[(4, ref('base.res_partner_3'))]" name="speaker_ids"/>
<field name="state">confirmed</field>
</record>
<record id="event_track3" model="event.track">
<field name="name">How to develop real time apps, the website live chat module explained.</field>
<field name="website_published" eval="True"/>
<field name="event_id" ref="event.event_0"/>
<field name="date" eval="time.strftime(str(DateTime.today().year) + '-06-04 10:30:00')"></field>
<field name="location_id" ref="website_event_track.event_track_location5"/>
<field name="duration" eval="0.3"/>
<field eval="[(4, ref('base.res_partner_4'))]" name="speaker_ids"/>
<field name="state">confirmed</field>
</record>
<record id="event_track4" model="event.track">
<field name="name">How to develop automated tests in the Odoo web client.</field>
<field name="website_published" eval="True"/>
<field name="event_id" ref="event.event_0"/>
<field name="date" eval="time.strftime(str(DateTime.today().year) + '-06-04 9:00:00')"></field>
<field name="location_id" ref="website_event_track.event_track_location5"/>
<field name="duration" eval="0.5"/>
<field eval="[(4, ref('base.res_partner_2'))]" name="speaker_ids"/>
<field name="state">published</field>
</record>
<record id="event_track5" model="event.track">
<field name="name">The new way to promote your modules in the Apps platform and Odoo website.</field>
<field name="website_published" eval="True"/>
<field name="event_id" ref="event.event_0"/>
<field name="date" eval="time.strftime(str(DateTime.today().year) + '-06-04 6:00:00')"></field>
<field name="location_id" ref="website_event_track.event_track_location6"/>
<field name="duration" eval="0.5"/>
<field eval="[(4, ref('base.res_partner_4'))]" name="speaker_ids"/>
<field name="state">announced</field>
</record>
<record id="event_track6" model="event.track">
<field name="name">Detailed roadmap of accounting new modules and improvements for version 8.</field>
<field name="website_published" eval="True"/>
<field name="event_id" ref="event.event_0"/>
<field name="date" eval="time.strftime(str(DateTime.today().year) + '-06-04 6:30:00')"></field>
<field name="location_id" ref="website_event_track.event_track_location6"/>
<field name="duration" eval="0.5"/>
<field eval="[(4, ref('base.res_partner_3'))]" name="speaker_ids"/>
<field name="state">announced</field>
</record>
<record id="event_track7" model="event.track">
<field name="name">A technical explanation of Odoo as a CMS and a eCommerce platform for version 8.</field>
<field name="website_published" eval="True"/>
<field name="event_id" ref="event.event_0"/>
<field name="date" eval="time.strftime(str(DateTime.today().year) + '-06-04 8:30:00')"></field>
<field name="location_id" ref="website_event_track.event_track_location6"/>
<field name="duration" eval="1"/>
<field eval="[(4, ref('base.res_partner_1'))]" name="speaker_ids"/>
<field name="state">published</field>
</record>
<record id="event_track8" model="event.track">
<field name="name">Discover Odoo CRM: How to optimize your sales, from leads to sales orders.</field>
<field name="website_published" eval="True"/>
<field name="event_id" ref="event.event_0"/>
<field name="date" eval="time.strftime(str(DateTime.today().year) + '-06-04 6:00:00')"></field>
<field name="location_id" ref="website_event_track.event_track_location7"/>
<field name="duration" eval="0.5"/>
<field name="color">2</field>
<field eval="[(4, ref('base.res_partner_4'))]" name="speaker_ids"/>
<field name="state">published</field>
</record>
<record id="event_track9" model="event.track">
<field name="name">How to use Odoo for your HR process: recruitment, leaves management, appraisals, expenses, etc.</field>
<field name="website_published" eval="True"/>
<field name="event_id" ref="event.event_0"/>
<field name="user_id" ref="base.user_root"/>
<field name="date" eval="time.strftime(str(DateTime.today().year) + '-06-04 8:30:00')"></field>
<field name="location_id" ref="website_event_track.event_track_location7"/>
<field name="duration" eval="1"/>
<field name="color">2</field>
<field eval="[(4, ref('base.res_partner_12'))]" name="speaker_ids"/>
<field name="state">published</field>
</record>
<record id="event_track10" model="event.track">
<field name="name">Raising qualitive insights with the survey app</field>
<field name="website_published" eval="True"/>
<field name="event_id" ref="event.event_0"/>
<field name="date" eval="time.strftime(str(DateTime.today().year) + '-06-04 6:30:00')"></field>
<field name="location_id" ref="website_event_track.event_track_location7"/>
<field name="duration" eval="0.5"/>
<field name="color">5</field>
<field name="state">draft</field>
</record>
<record id="event_track11" model="event.track">
<field name="name">Discover Odoo Point-of-Sale: Your shop ready to use in 30 minutes.</field>
<field name="website_published" eval="True"/>
<field name="event_id" ref="event.event_0"/>
<field name="date" eval="time.strftime(str(DateTime.today().year) + '-06-04 10:30:00')"></field>
<field name="location_id" ref="website_event_track.event_track_location7"/>
<field name="duration" eval="0.5"/>
<field eval="[(4, ref('base.res_partner_4'))]" name="speaker_ids"/>
<field name="state">confirmed</field>
</record>
<record id="event_track12" model="event.track">
<field name="name">Manage your events with Odoo, the new training modules.</field>
<field name="website_published" eval="True"/>
<field name="event_id" ref="event.event_0"/>
<field name="date" eval="time.strftime(str(DateTime.today().year) + '-06-04 11:00:00')"></field>
<field name="location_id" ref="website_event_track.event_track_location7"/>
<field name="duration" eval="0.5"/>
<field eval="[(4, ref('base.res_partner_2')),(4, ref('base.res_partner_12'))]" name="speaker_ids"/>
<field name="state">announced</field>
</record>
<record id="event_track13" model="event.track">
<field name="name">Advanced reporting with Google Spreadsheets integration.</field>
<field name="website_published" eval="True"/>
<field name="event_id" ref="event.event_0"/>
<field name="date" eval="time.strftime(str(DateTime.today().year) + '-06-04 6:30:00')"></field>
<field name="location_id" ref="website_event_track.event_track_location8"/>
<field name="duration" eval="0.25"/>
<field eval="[(4, ref('base.res_partner_12'))]" name="speaker_ids"/>
<field name="state">published</field>
</record>
<record id="event_track14" model="event.track">
<field name="name">New Paypal modules (portal, handling, installments).</field>
<field name="website_published" eval="True"/>
<field name="event_id" ref="event.event_0"/>
<field name="date" eval="time.strftime(str(DateTime.today().year) + '-06-04 7:00:00')"></field>
<field name="location_id" ref="website_event_track.event_track_location8"/>
<field name="duration" eval="0.5"/>
<field eval="[(4, ref('base.res_partner_10'))]" name="speaker_ids"/>
<field name="state">published</field>
</record>
<record id="event_track15" model="event.track">
<field name="name">Odoo Mobile for Notes, Meetings and Messages.</field>
<field name="website_published" eval="True"/>
<field name="event_id" ref="event.event_0"/>
<field name="date" eval="time.strftime(str(DateTime.today().year) + '-06-04 10:30:00')"></field>
<field name="location_id" ref="website_event_track.event_track_location8"/>
<field name="duration" eval="0.5"/>
<field eval="[(4, ref('base.res_partner_3'))]" name="speaker_ids"/>
<field name="state">announced</field>
</record>
<record id="event_track16" model="event.track">
<field name="name">Odoo as your Enterprise Social Network.</field>
<field name="website_published" eval="True"/>
<field name="event_id" ref="event.event_0"/>
<field name="date" eval="time.strftime(str(DateTime.today().year) + '-06-04 11:00:00')"></field>
<field name="location_id" ref="website_event_track.event_track_location8"/>
<field name="duration" eval="0.5"/>
<field eval="[(4, ref('base.res_partner_12'))]" name="speaker_ids"/>
<field name="state">draft</field>
</record>
<record id="event_track17" model="event.track">
<field name="name">The Art of Making an Odoo Demo.</field>
<field name="website_published" eval="True"/>
<field name="event_id" ref="event.event_0"/>
<field name="date" eval="time.strftime(str(DateTime.today().year) + '-06-04 6:00:00')"></field>
<field name="location_id" ref="website_event_track.event_track_location9"/>
<field name="duration" eval="0.5"/>
<field eval="[(4, ref('base.res_partner_10'))]" name="speaker_ids"/>
<field name="state">draft</field>
</record>
<record id="event_track18" model="event.track">
<field name="name">How to build your marketing strategy for the purpose of generating leads with Odoo.</field>
<field name="website_published" eval="True"/>
<field name="event_id" ref="event.event_0"/>
<field name="date" eval="time.strftime(str(DateTime.today().year) + '-06-04 8:30:00')"></field>
<field name="location_id" ref="website_event_track.event_track_location9"/>
<field name="duration" eval="0.5"/>
<field name="color">5</field>
<field eval="[(4, ref('base.res_partner_2'))]" name="speaker_ids"/>
<field name="state">confirmed</field>
</record>
<record id="event_track19" model="event.track">
<field name="name">Advanced lead management with Odoo: tips and tricks from the fields</field>
<field name="website_published" eval="True"/>
<field name="event_id" ref="event.event_0"/>
<field name="date" eval="time.strftime(str(DateTime.today().year) + '-06-04 9:00:00')"></field>
<field name="location_id" ref="website_event_track.event_track_location9"/>
<field name="duration" eval="0.5"/>
<field name="color">5</field>
<field eval="[(4, ref('base.res_partner_4'))]" name="speaker_ids"/>
<field name="state">confirmed</field>
</record>
<record id="event_track20" model="event.track">
<field name="name">New Certification Program (valid from Oct. 2013).</field>
<field name="website_published" eval="True"/>
<field name="event_id" ref="event.event_0"/>
<field name="date" eval="time.strftime(str(DateTime.today().year) + '-06-04 10:00:00')"></field>
<field name="location_id" ref="website_event_track.event_track_location9"/>
<field name="duration" eval="0.5"/>
<field eval="[(4, ref('base.res_partner_3'))]" name="speaker_ids"/>
<field name="state">confirmed</field>
</record>
<record id="event_track21" model="event.track">
<field name="name">Recruiting high skilled talents with Odoo HR apps</field>
<field name="website_published" eval="True"/>
<field name="event_id" ref="event.event_0"/>
<field name="date" eval="time.strftime(str(DateTime.today().year) + '-06-04 10:30:00')"></field>
<field name="location_id" ref="website_event_track.event_track_location9"/>
<field name="duration" eval="0.5"/>
<field name="color">7</field>
<field name="state">confirmed</field>
</record>
<record id="event_track22" model="event.track">
<field name="name">Manage your KPIs (recomended to openERP partners).</field>
<field name="website_published" eval="True"/>
<field name="event_id" ref="event.event_0"/>
<field name="date" eval="time.strftime(str(DateTime.today().year) + '-06-04 11:00:00')"></field>
<field name="location_id" ref="website_event_track.event_track_location9"/>
<field name="duration" eval="0.5"/>
<field eval="[(4, ref('base.res_partner_3'))]" name="speaker_ids"/>
<field name="state">draft</field>
</record>
<record id="event_track23" model="event.track">
<field name="name">Key Success factors selling Odoo.</field>
<field name="website_published" eval="True"/>
<field name="event_id" ref="event.event_0"/>
<field name="date" eval="time.strftime(str(DateTime.today().year) + '-06-04 7:00:00')"></field>
<field name="location_id" ref="website_event_track.event_track_location9"/>
<field name="duration" eval="0.5"/>
<field eval="[(4, ref('base.res_partner_1'))]" name="speaker_ids"/>
<field name="state">announced</field>
</record>
<record id="event_track24" model="event.track">
<field name="name">Merge proposals review, code sprint (entire day).</field>
<field name="website_published" eval="True"/>
<field name="event_id" ref="event.event_0"/>
<field name="date" eval="time.strftime(str(DateTime.today().year) + '-06-04 6:00:00')"></field>
<field name="location_id" ref="website_event_track.event_track_location10"/>
<field name="duration" eval="1.5"/>
<field eval="[(4, ref('base.res_partner_12')),(4, ref('base.res_partner_18'))]" name="speaker_ids"/>
<field name="state">announced</field>
</record>
<record id="event_track25" model="event.track">
<field name="name">Merge proposals review, code sprint (entire afternoon)</field>
<field name="website_published" eval="True"/>
<field name="event_id" ref="event.event_0"/>
<field name="date" eval="time.strftime(str(DateTime.today().year) + '-06-04 8:30:00')"></field>
<field name="location_id" ref="website_event_track.event_track_location10"/>
<field name="duration" eval="2.5"/>
<field eval="[(4, ref('base.res_partner_12')),(4, ref('base.res_partner_18'))]" name="speaker_ids"/>
<field name="state">announced</field>
</record>
<record id="event_track27" model="event.track">
<field name="name">Odoo in 2014</field>
<field name="website_published" eval="True"/>
<field name="event_id" ref="event.event_0"/>
<field name="date" eval="time.strftime(str(DateTime.today().year) + '-06-04 04:00:00')"></field>
<field name="duration" eval="1"/>
<field eval="[(4, ref('base.res_partner_1'))]" name="speaker_ids"/>
<field name="state">published</field>
<field name="color">3</field>
</record>
<record id="event_track28" model="event.track">
<field name="name">Odoo Status &amp; Strategy 2014</field>
<field name="website_published" eval="True"/>
<field name="event_id" ref="event.event_0"/>
<field name="date" eval="time.strftime(str(DateTime.today().year) + '-06-04 5:00:00')"></field>
<field name="duration" eval="0.5"/>
<field eval="[(4, ref('base.res_partner_2'))]" name="speaker_ids"/>
<field name="state">published</field>
</record>
<record id="event_track29" model="event.track">
<field name="name">The new marketing strategy.</field>
<field name="website_published" eval="True"/>
<field name="event_id" ref="event.event_0"/>
<field name="date" eval="time.strftime(str(DateTime.today().year) + '-06-04 5:30:00')"></field>
<field name="duration" eval="0.25"/>
<field eval="[(4, ref('base.res_partner_2'))]" name="speaker_ids"/>
<field name="state">published</field>
<field name="color">6</field>
</record>
<record id="event_track30" model="event.track">
<field name="name">Morning break</field>
<field name="website_published" eval="True"/>
<field name="event_id" ref="event.event_0"/>
<field name="date" eval="time.strftime(str(DateTime.today().year) + '-06-04 5:45:00')"></field>
<field name="duration" eval="0.25"/>
<field name="state">confirmed</field>
</record>
<record id="event_track31" model="event.track">
<field name="name">Lunch</field>
<field name="website_published" eval="True"/>
<field name="event_id" ref="event.event_0"/>
<field name="date" eval="time.strftime(str(DateTime.today().year) + '-06-04 7:30:00')"></field>
<field name="duration" eval="1"/>
<field name="state">confirmed</field>
</record>
</data>
</odoo>
@@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
import website_event_track
import event_track
import event
+55 -32
View File
@@ -5,53 +5,76 @@ from odoo import api, fields, models, _
from odoo.addons.website.models.website import slug
class EventType(models.Model):
_inherit = 'event.type'
website_track = fields.Boolean('Tracks on Website')
website_track_proposal = fields.Boolean('Tracks Proposals on Website')
class Event(models.Model):
_inherit = "event.event"
track_ids = fields.One2many('event.track', 'event_id', 'Tracks')
track_count = fields.Integer('Tracks', compute='_compute_track_count')
sponsor_ids = fields.One2many('event.sponsor', 'event_id', 'Sponsors')
show_track_proposal = fields.Boolean('Tracks Proposals', compute='_get_show_menu', inverse='_set_show_menu', store=True)
show_tracks = fields.Boolean('Show Tracks on Website', compute='_get_show_menu', inverse='_set_show_menu', store=True)
count_tracks = fields.Integer('Tracks', compute='_count_tracks')
sponsor_count = fields.Integer('Sponsors', compute='_compute_sponsor_count')
website_track = fields.Boolean('Tracks on Website', compute='_compute_website_track', inverse='_set_website_menu')
website_track_proposal = fields.Boolean('Proposals on Website', compute='_compute_website_track_proposal', inverse='_set_website_menu')
allowed_track_tag_ids = fields.Many2many('event.track.tag', relation='event_allowed_track_tags_rel', string='Available Track Tags')
tracks_tag_ids = fields.Many2many('event.track.tag', relation='event_track_tags_rel', string='Track Tags', compute='_get_tracks_tag_ids', store=True)
count_sponsor = fields.Integer('# Sponsors', compute='_count_sponsor')
tracks_tag_ids = fields.Many2many(
'event.track.tag', relation='event_track_tags_rel', string='Track Tags',
compute='_compute_tracks_tag_ids', store=True)
@api.multi
def _get_new_menu_pages(self):
self.ensure_one()
result = super(Event, self)._get_new_menu_pages()
if self.show_tracks:
result.append((_('Talks'), '/event/%s/track' % slug(self)))
result.append((_('Agenda'), '/event/%s/agenda' % slug(self)))
if self.show_track_proposal:
result.append((_('Talk Proposals'), '/event/%s/track_proposal' % slug(self)))
return result
@api.multi
def _set_show_menu(self):
def _compute_track_count(self):
data = self.env['event.track'].read_group([('stage_id.is_cancel', '!=', True)], ['event_id'], ['event_id'])
result = dict((data['event_id'][0], data['event_id_count']) for data in data)
for event in self:
# if the number of menu items have changed, then menu items must be regenerated
if event.menu_id:
nbr_menu_items = len(event._get_new_menu_pages())
if nbr_menu_items != len(event.menu_id.child_id):
event.menu_id.unlink()
return super(Event, self)._set_show_menu()
event.track_count = result.get(event.id, 0)
@api.multi
def _count_tracks(self):
track_data = self.env['event.track'].read_group([('state', '!=', 'cancel')], ['event_id', 'state'], ['event_id'])
result = dict((data['event_id'][0], data['event_id_count']) for data in track_data)
def _compute_sponsor_count(self):
data = self.env['event.sponsor'].read_group([], ['event_id'], ['event_id'])
result = dict((data['event_id'][0], data['event_id_count']) for data in data)
for event in self:
event.count_tracks = result.get(event.id, 0)
event.sponsor_count = result.get(event.id, 0)
@api.multi
def _compute_website_track(self):
for event in self:
existing_pages = event.menu_id.child_id.mapped('name')
event.website_track = _('Talks') in existing_pages
@api.multi
def _compute_website_track_proposal(self):
for event in self:
existing_pages = event.menu_id.child_id.mapped('name')
event.website_track_proposal = _('Talk Proposals') in existing_pages
@api.multi
@api.depends('track_ids.tag_ids')
def _get_tracks_tag_ids(self):
def _compute_tracks_tag_ids(self):
for event in self:
event.tracks_tag_ids = event.track_ids.mapped('tag_ids').ids
@api.multi
def _count_sponsor(self):
for event in self:
event.count_sponsor = len(event.sponsor_ids)
@api.onchange('event_type_id')
def _onchange_type(self):
super(Event, self)._onchange_type()
if self.event_type_id:
self.website_track = self.event_type_id.website_track
self.website_track_proposal = self.event_type_id.website_track_proposal
def _get_menu_entries(self):
self.ensure_one()
res = super(Event, self)._get_menu_entries()
if self.website_track:
res += [
(_('Talks'), '/event/%s/track' % slug(self), False),
(_('Agenda'), '/event/%s/agenda' % slug(self), False)]
if self.website_track_proposal:
res += [(_('Talk Proposals'), '/event/%s/track_proposal' % slug(self), False)]
return res
@@ -0,0 +1,195 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import api, fields, models
from odoo.tools.translate import _, html_translate
from odoo.addons.website.models.website import slug
class TrackTag(models.Model):
_name = "event.track.tag"
_description = 'Track Tag'
_order = 'name'
name = fields.Char('Tag')
track_ids = fields.Many2many('event.track', string='Tracks')
color = fields.Integer(string='Color Index', default=10)
_sql_constraints = [
('name_uniq', 'unique (name)', "Tag name already exists !"),
]
class TrackLocation(models.Model):
_name = "event.track.location"
_description = 'Track Location'
name = fields.Char('Room')
class TrackStage(models.Model):
_name = 'event.track.stage'
_description = 'Track Stage'
_order = 'sequence, id'
name = fields.Char(string='Stage Name', required=True, translate=True)
sequence = fields.Integer(string='Sequence', default=1)
mail_template_id = fields.Many2one(
'mail.template', string='Email Template',
domain=[('model', '=', 'event.track')],
help="If set an email will be sent to the customer when the track reaches this step.")
fold = fields.Boolean(
string='Folded in Kanban',
help='This stage is folded in the kanban view when there are no records in that stage to display.')
is_done = fields.Boolean(string='Accepted Stage')
is_cancel = fields.Boolean(string='Canceled Stage')
class Track(models.Model):
_name = "event.track"
_description = 'Event Track'
_order = 'priority, date'
_inherit = ['mail.thread', 'mail.activity.mixin', 'website.seo.metadata', 'website.published.mixin']
_mail_mass_mailing = _('Track Speakers')
@api.model
def _get_default_stage_id(self):
return self.env['event.track.stage'].search([], limit=1).id
name = fields.Char('Title', required=True, translate=True)
active = fields.Boolean(default=True)
user_id = fields.Many2one('res.users', 'Responsible', track_visibility='onchange', default=lambda self: self.env.user)
partner_id = fields.Many2one('res.partner', 'Speaker')
partner_name = fields.Char('Speaker Name')
partner_email = fields.Char('Speaker Email')
partner_phone = fields.Char('Speaker Phone')
partner_biography = fields.Html('Speaker Biography')
tag_ids = fields.Many2many('event.track.tag', string='Tags')
stage_id = fields.Many2one(
'event.track.stage', string='Stage',
index=True, copy=False, default=_get_default_stage_id,
group_expand='_read_group_stage_ids',
required=True, track_visibility='onchange')
kanban_state = fields.Selection([
('normal', 'Grey'),
('done', 'Green'),
('blocked', 'Red')], string='Kanban State',
copy=False, default='normal', required=True, track_visibility='onchange',
help="A track's kanban state indicates special situations affecting it:\n"
" * Grey is the default situation\n"
" * Red indicates something is preventing the progress of this track\n"
" * Green indicates the track is ready to be pulled to the next stage")
description = fields.Html('Track Description', translate=html_translate, sanitize_attributes=False)
date = fields.Datetime('Track Date')
duration = fields.Float('Duration', default=1.5)
location_id = fields.Many2one('event.track.location', 'Room')
event_id = fields.Many2one('event.event', 'Event', required=True)
color = fields.Integer('Color Index')
priority = fields.Selection([
('0', 'Low'), ('1', 'Medium'),
('2', 'High'), ('3', 'Highest')],
'Priority', required=True, default='1')
image = fields.Binary('Image', related='partner_id.image_medium', store=True, attachment=True)
@api.multi
@api.depends('name')
def _compute_website_url(self):
super(Track, self)._compute_website_url()
for track in self:
if not isinstance(track.id, models.NewId):
track.website_url = '/event/%s/track/%s' % (slug(track.event_id), slug(track))
@api.onchange('partner_id')
def _onchange_partner_id(self):
if self.partner_id:
self.partner_name = self.partner_id.name
self.partner_email = self.partner_id.email
self.partner_phone = self.partner_id.phone
self.partner_biography = self.partner_id.website_description
@api.model
def create(self, vals):
track = super(Track, self).create(vals)
track.event_id.message_post_with_view(
'website_event_track.event_track_template_new',
values={'track': track},
subject=track.name,
subtype_id=self.env.ref('website_event_track.mt_event_track').id,
)
return track
@api.multi
def write(self, vals):
if 'stage_id' in vals and 'kanban_state' not in vals:
vals['kanban_state'] = 'normal'
res = super(Track, self).write(vals)
if vals.get('partner_id'):
self.message_subscribe(vals['partner_id'])
return res
@api.model
def _read_group_stage_ids(self, stages, domain, order):
""" Always display all stages """
return stages.search([], order=order)
@api.multi
def _track_template(self, tracking):
res = super(Track, self)._track_template(tracking)
track = self[0]
changes, tracking_value_ids = tracking[track.id]
if 'stage_id' in changes and track.stage_id.mail_template_id:
res['stage_id'] = (track.stage_id.mail_template_id, {'composition_mode': 'mass_mail'})
return res
@api.multi
def _track_subtype(self, init_values):
self.ensure_one()
if 'kanban_state' in init_values and self.kanban_state == 'blocked':
return 'website_event_track.mt_track_blocked'
elif 'kanban_state' in init_values and self.kanban_state == 'done':
return 'website_event_track.mt_track_ready'
return super(Track, self)._track_subtype(init_values)
@api.multi
def message_get_suggested_recipients(self):
recipients = super(Track, self).message_get_suggested_recipients()
for track in self:
if track.partner_email != track.partner_id.email:
track._message_add_suggested_recipient(recipients, email=track.partner_email, reason=_('Speaker Email'))
return recipients
@api.multi
def open_track_speakers_list(self):
return {
'name': _('Speakers'),
'domain': [('id', 'in', self.mapped('partner_id').ids)],
'view_type': 'form',
'view_mode': 'kanban,form',
'res_model': 'res.partner',
'view_id': False,
'type': 'ir.actions.act_window',
}
class SponsorType(models.Model):
_name = "event.sponsor.type"
_description = 'Event Sponsor Type'
_order = "sequence"
name = fields.Char('Sponsor Type', required=True, translate=True)
sequence = fields.Integer('Sequence')
class Sponsor(models.Model):
_name = "event.sponsor"
_description = 'Event Sponsor'
_order = "sequence"
event_id = fields.Many2one('event.event', 'Event', required=True)
sponsor_type_id = fields.Many2one('event.sponsor.type', 'Sponsoring Type', required=True)
partner_id = fields.Many2one('res.partner', 'Sponsor/Customer', required=True)
url = fields.Char('Sponsor Website')
sequence = fields.Integer('Sequence', store=True, related='sponsor_type_id.sequence')
image_medium = fields.Binary(string='Logo', related='partner_id.image_medium', store=True, attachment=True)
@@ -1,152 +0,0 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import api, fields, models
from odoo.tools.translate import _, html_translate
from odoo.addons.website.models.website import slug
class TrackTag(models.Model):
_name = "event.track.tag"
_description = 'Track Tag'
_order = 'name'
name = fields.Char('Tag')
track_ids = fields.Many2many('event.track', string='Tracks')
color = fields.Integer(string='Color Index', default=10)
_sql_constraints = [
('name_uniq', 'unique (name)', "Tag name already exists !"),
]
class TrackLocation(models.Model):
_name = "event.track.location"
_description = 'Track Location'
name = fields.Char('Room')
class Track(models.Model):
_name = "event.track"
_description = 'Event Track'
_order = 'priority, date'
_inherit = ['mail.thread', 'website.seo.metadata', 'website.published.mixin']
name = fields.Char('Title', required=True, translate=True)
active = fields.Boolean(default=True)
user_id = fields.Many2one('res.users', 'Responsible', track_visibility='onchange', default=lambda self: self.env.user)
partner_id = fields.Many2one('res.partner', 'Proposed by')
partner_name = fields.Char('Partner Name')
partner_email = fields.Char('Partner Email')
partner_phone = fields.Char('Partner Phone')
partner_biography = fields.Html('Partner Biography')
speaker_ids = fields.Many2many('res.partner', string='Speakers')
tag_ids = fields.Many2many('event.track.tag', string='Tags')
state = fields.Selection([
('draft', 'Proposal'), ('confirmed', 'Confirmed'), ('announced', 'Announced'), ('published', 'Published'), ('refused', 'Refused'), ('cancel', 'Cancelled')],
'Status', default='draft', required=True, copy=False, track_visibility='onchange')
description = fields.Html('Track Description', translate=html_translate, sanitize_attributes=False)
date = fields.Datetime('Track Date')
duration = fields.Float('Duration', default=1.5)
location_id = fields.Many2one('event.track.location', 'Room')
event_id = fields.Many2one('event.event', 'Event', required=True)
color = fields.Integer('Color Index')
priority = fields.Selection([
('0', 'Low'), ('1', 'Medium'),
('2', 'High'), ('3', 'Highest')],
'Priority', required=True, default='1')
image = fields.Binary('Image', related='speaker_ids.image_medium', store=True, attachment=True)
@api.model
def create(self, vals):
res = super(Track, self).create(vals)
res.message_subscribe(res.speaker_ids.ids)
res.message_post_with_view(
'website_event_track.event_track_template_new',
subject=res.name,
subtype_id=self.env['ir.model.data'].xmlid_to_res_id('website_event_track.mt_event_track'))
return res
@api.multi
def write(self, vals):
if vals.get('state') == 'published':
vals.update({'website_published': True})
res = super(Track, self).write(vals)
if vals.get('speaker_ids'):
self.message_subscribe([speaker['id'] for speaker in self.resolve_2many_commands('speaker_ids', vals['speaker_ids'], ['id'])])
return res
@api.multi
@api.depends('name')
def _compute_website_url(self):
super(Track, self)._compute_website_url()
for track in self:
if not isinstance(track.id, models.NewId):
track.website_url = '/event/%s/track/%s' % (slug(track.event_id), slug(track))
@api.model
def read_group(self, domain, fields, groupby, offset=0, limit=None, orderby=False, lazy=True):
""" Override read_group to always display all states. """
if groupby and groupby[0] == "state":
# Default result structure
states = [('draft', 'Proposal'), ('confirmed', 'Confirmed'), ('announced', 'Announced'), ('published', 'Published'), ('cancel', 'Cancelled')]
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(Track, self).read_group(domain, fields, groupby, offset=offset, limit=limit, 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)
if state_value == 'cancel':
res[0]['__fold'] = True
res[0]['state'] = [state_value, state_name]
result.append(res[0])
return result
else:
return super(Track, self).read_group(domain, fields, groupby, offset=offset, limit=limit, orderby=orderby)
@api.multi
def open_track_speakers_list(self):
self.ensure_one()
return {
'name': _('Speakers'),
'domain': [('id', 'in', [partner.id for partner in self.speaker_ids])],
'view_type': 'form',
'view_mode': 'kanban,form',
'res_model': 'res.partner',
'view_id': False,
'type': 'ir.actions.act_window',
}
class SponsorType(models.Model):
_name = "event.sponsor.type"
_order = "sequence"
name = fields.Char('Sponsor Type', required=True, translate=True)
sequence = fields.Integer('Sequence')
class Sponsor(models.Model):
_name = "event.sponsor"
_order = "sequence"
event_id = fields.Many2one('event.event', 'Event', required=True)
sponsor_type_id = fields.Many2one('event.sponsor.type', 'Sponsoring Type', required=True)
partner_id = fields.Many2one('res.partner', 'Sponsor/Customer', required=True)
url = fields.Char('Sponsor Website')
sequence = fields.Integer('Sequence', store=True, related='sponsor_type_id.sequence')
image_medium = fields.Binary(string='Logo', related='partner_id.image_medium', store=True, attachment=True)
@@ -10,3 +10,5 @@ access_event_track_sponsor_type_manager,event.track.sponsor.type.public,model_ev
access_event_track_sponsor_type_public,event.track.sponsor.type.public,model_event_sponsor_type,,1,0,0,0
access_event_track_sponsor_manager,event.track.sponsor.type.public,model_event_sponsor,event.group_event_manager,1,1,1,1
access_event_track_sponsor_public,event.track.sponsor.public,model_event_sponsor,,1,0,0,0
access_event_track_stage_all,event.track.stage.all,model_event_track_stage,,1,0,0,0
access_event_track_stage_event_manager,event.track.stage.event.manager,model_event_track_stage,event.group_event_manager,1,1,1,1
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
10 access_event_track_sponsor_type_public event.track.sponsor.type.public model_event_sponsor_type 1 0 0 0
11 access_event_track_sponsor_manager event.track.sponsor.type.public model_event_sponsor event.group_event_manager 1 1 1 1
12 access_event_track_sponsor_public event.track.sponsor.public model_event_sponsor 1 0 0 0
13 access_event_track_stage_all event.track.stage.all model_event_track_stage 1 0 0 0
14 access_event_track_stage_event_manager event.track.stage.event.manager model_event_track_stage event.group_event_manager 1 1 1 1
@@ -80,9 +80,10 @@
<t t-if="track">
<a t-attf-href="/event/#{ slug(event) }/track/#{ slug(track) }">
<span t-esc="track and track.name"/>
<span t-if="not track.website_published" class="label label-warning">unpublished</span>
</a>
<div class="text-muted">
<small t-esc="speakers[track.id]"/>
<small t-esc="track.partner_id.sudo().name"/>
</div>
</t>
</td>
@@ -97,7 +98,7 @@
<span t-esc="track.name"/>
</a>
<div class="text-muted">
<small t-esc="speakers[track.id]"/>
<small t-esc="track.partner_id.sudo()"/>
</div>
</td>
</t>
@@ -129,8 +130,8 @@
<small t-if="not track.website_published" class="label label-danger">unpublished</small>
</h3>
<ul class="list-inline mb0">
<li t-if="track.speaker_ids" class="text-muted fa fa-user">
<t t-esc="', '.join([speaker.name for speaker in track.speaker_ids])"></t>
<li t-if="track.partner_id" class="text-muted fa fa-user">
<t t-esc="track.partner_id.sudo().name"/>
</li>
<li t-if="track.date" class="text-muted fa fa-calendar"> <span t-field="track.date" t-options='{"hide_seconds":"True"}'/></li>
<li class="text-muted fa fa-map-marker" t-if="track.location_id">
@@ -224,17 +225,17 @@
</div>
</div>
</section>
<div t-foreach="track.speaker_ids" t-as="speaker" class="well mt32">
<div t-if="track.partner_id" class="well mt32">
<div class="row">
<div class="col-sm-2">
<span t-field="speaker.sudo().image_medium"
<span t-field="track.partner_id.sudo().image_medium"
t-options='{"widget": "image", "class": "img-circle"}'/>
</div><div class="col-sm-10">
<h4 t-field="speaker.name" class="mb4"/>
<div class="fa fa-home mb16" t-if="speaker.website">
<a t-att-href="speaker.website"><span t-field="speaker.website"/></a>
<h4 t-field="track.partner_id.name" class="mb4"/>
<div class="fa fa-home mb16" t-if="track.partner_id.website">
<a t-att-href="track.partner_id.website"><span t-field="track.partner_id.website"/></a>
</div>
<div t-field="speaker.website_description"/>
<div t-field="track.partner_id.website_description"/>
</div>
</div>
</div>
@@ -301,7 +302,7 @@
<h1 class="text-center mb0">Call for Proposals</h1>
<h2 class="text-center text-muted mb32" t-esc="event.name"></h2>
</section>
<section id="forms" t-if="not event.show_track_proposal">
<section id="forms" t-if="not event.website_track_proposal">
<h1>Proposals are closed!</h1>
<p>
This event does not accept proposals.
@@ -332,7 +333,7 @@
</p>
</section>
</div>
<section id="forms" t-if="event.show_track_proposal">
<section id="forms" t-if="event.website_track_proposal">
<form class="form-horizontal mt32 js_website_submit_form" t-attf-action="/event/#{event.id}/track_proposal/post" method="post" enctype="multipart/form-data">
<input type="hidden" name="csrf_token" t-att-value="request.csrf_token()"/>
<div class="form-group">
@@ -448,14 +449,13 @@
<!-- Chatter templates -->
<template id="event_track_template_new">
<h3>New track proposal</h3>
<p>New track proposal <a href="#" t-att-data-oe-model="track._name" t-att-data-oe-id="track.id"> <t t-esc="track.name"/></a></p>
<ul>
<li><b>Proposed By</b>: <t t-esc="object.partner_id.name or object.partner_name or object.partner_email"/></li>
<li><b>Mail</b>: <a t-attf-href="mailto:#{object.partner_email}"><t t-esc="object.partner_email"/></a></li>
<li><b>Phone</b>: <t t-esc="object.partner_phone"/></li>
<li><b>Title</b>: <t t-esc="object.name"/></li>
<li><b>Speakers Biography</b>: <t t-esc="object.partner_biography"/></li>
<li><b>Talk Introduction</b>: <t t-esc="object.description"/></li>
<li><b>Proposed By</b>: <t t-esc="track.partner_name or track.partner_email"/></li>
<li><b>Mail</b>: <a t-attf-href="mailto:#{track.partner_email}"><t t-esc="track.partner_email"/></a></li>
<li><b>Phone</b>: <t t-esc="track.partner_phone"/></li>
<li><b>Speakers Biography</b>: <t t-esc="track.partner_biography"/></li>
<li><b>Talk Introduction</b>: <t t-esc="track.description"/></li>
</ul>
</template>
@@ -6,11 +6,14 @@
<field name="name">event.track.kanban</field>
<field name="model">event.track</field>
<field name="arch" type="xml">
<kanban default_group_by="state">
<kanban default_group_by="stage_id">
<templates>
<field name="color"/>
<field name="speaker_ids"/>
<field name="partner_id"/>
<field name="stage_id"/>
<field name="website_url"/>
<field name="activity_ids"/>
<field name="activity_state"/>
<t t-name="kanban-box">
<div t-attf-class="oe_kanban_color_#{kanban_getcolor(record.color.raw_value)} oe_kanban_card oe_kanban_global_click">
<div class="o_dropdown_kanban dropdown" groups="base.group_user">
@@ -31,16 +34,17 @@
<div>
<t t-if="duration"><field name="duration" widget="float_time"/> hours</t>
</div>
<div class="oe_kanban_bottom_right">
<div class="oe_kanban_bottom_left">
<field name="priority" widget="priority"/>
</div>
<div class="oe_kanban_footer_left">
<t t-foreach="record.speaker_ids.raw_value.slice(0,11)" t-as="speaker">
<img t-att-src="kanban_image('res.partner', 'image_small', speaker)" t-att-data-member_id="speaker" width="30px" height="30px"/>
</t>
<t t-if="record.speaker_ids.raw_value.length > 11 ">
<a name="open_track_speakers_list" type="object"><t t-esc="record.speaker_ids.raw_value.length - 11"> More</t></a>
</t>
<div class="oe_kanban_bottom_right">
<img t-att-src="kanban_image('res.partner', 'image_small', record.partner_id.raw_value)"
t-att-title="record.partner_id.value" width="24" height="24"
class="oe_kanban_avatar pull-right"/>
<div class="pull-left mr4">
<field name="activity_ids" widget="kanban_activity"/>
<field name="kanban_state" widget="kanban_state_selection" groups="base.group_user"/>
</div>
</div>
<div class="oe_clear"/>
</div>
@@ -71,14 +75,26 @@
<field name="name"/>
<field name="event_id"/>
<field name="location_id"/>
<field name="state"/>
<field name="speaker_ids"/>
<field name="stage_id"/>
<field name="partner_id"/>
<filter string="Unread Messages" name="message_needaction" domain="[('message_needaction','=',True)]"/>
<separator/>
<filter string="Archived" name="inactive" domain="[('active','=',False)]"/>
<separator/>
<filter string="My Activities" name="activities_my"
domain="[('activity_ids.user_id', '=', uid)]"/>
<filter string="Today Activities" name="activities_today"
domain="[('activity_ids.date_deadline', '=', context_today().strftime('%Y-%m-%d'))]"/>
<filter string="Upcoming Activities (7 days)" name="activities_week"
domain="['&amp;', ('activity_ids.date_deadline', '&gt;=', context_today().strftime('%Y-%m-%d')),
('activity_ids.date_deadline', '&lt;=', (context_today()+datetime.timedelta(days=7)).strftime('%Y-%m-%d'))
]"/>
<filter string="Overdue Activities" name="activities_overdue"
domain="[('activity_ids.date_deadline', '&lt;', context_today().strftime('%Y-%m-%d'))]"
help="Show all records which has next action date is before today"/>
<group expand="0" string="Group By">
<filter string="Responsible" context="{'group_by': 'user_id'}"/>
<filter string="Status" context="{'group_by':'state'}"/>
<filter string="Stage" context="{'group_by':'stage_id'}"/>
<filter string="Date" context="{'group_by':'date'}"/>
<filter string="Event" context="{'group_by':'event_id'}"/>
</group>
@@ -92,7 +108,7 @@
<field name="arch" type="xml">
<form string="Event Track">
<header>
<field name="state" widget="statusbar" clickable="True"/>
<field name="stage_id" widget="statusbar" clickable="True"/>
</header>
<sheet string="Track">
<div class="oe_button_box" name="button_box">
@@ -124,7 +140,6 @@
<field name="partner_phone"/>
</group>
<group>
<field name="speaker_ids" widget="many2many_tags"/>
<field name="date"/>
<label for="duration"/>
<div>
@@ -137,6 +152,7 @@
</sheet>
<div class="oe_chatter">
<field name="message_follower_ids" widget="mail_followers"/>
<field name="activity_ids" widget="mail_activity"/>
<field name="message_ids" widget="mail_thread"/>
</div>
</form>
@@ -174,7 +190,7 @@
<p class="oe_view_nocontent_create">
Click to add a track.
</p><p>
Tracks define the agenda of your event. These can bea talk, a round table, a meeting, etc.
Tracks define the schedule of your event. These can bea talk, a round table, a meeting, etc.
</p>
</field>
</record>
@@ -184,12 +200,12 @@
<field name="name">Event Tracks</field>
<field name="view_type">form</field>
<field name="view_mode">kanban,tree,form,calendar,graph</field>
<field name="context">{'search_default_event_id': active_id, 'default_event_id': active_id, 'group_by': 'state'}</field>
<field name="context">{'search_default_event_id': active_id, 'default_event_id': active_id, 'group_by': 'stage_id'}</field>
<field name="help" type="html">
<p class="oe_view_nocontent_create">
Click to add a track.
</p><p>
Tracks define the agenda of your event. These can be a talk, a round table, a meeting, etc.
Tracks define the schedule of your event. These can be a talk, a round table, a meeting, etc.
</p>
</field>
</record>
@@ -272,7 +288,8 @@
<menuitem
id="menu_event_sponsor_type"
action="action_event_sponsor_type"
parent="event.menu_event_configuration"/>
parent="event.menu_event_configuration"
groups="base.group_no_one"/>
<!-- EVENT.SPONSOR VIEWS -->
<record model="ir.ui.view" id="view_event_sponsor_tree">
@@ -338,6 +355,74 @@
<menuitem
id="menu_event_track_tag"
action="action_event_track_tag"
parent="event.menu_event_configuration"
groups="base.group_no_one"/>
<!-- EVENTS TRACK STAGES-->
<record id="event_track_stage_view_search" model="ir.ui.view">
<field name="name">event.track.stage.view.search</field>
<field name="model">event.track.stage</field>
<field name="arch" type="xml">
<search string="Track Stage">
<field name="name" string="Track Stages"/>
</search>
</field>
</record>
<record id="event_track_stage_view_form" model="ir.ui.view">
<field name="name">event.track.stage.view.form</field>
<field name="model">event.track.stage</field>
<field name="arch" type="xml">
<form string="Track Stage">
<sheet>
<group>
<group>
<field name="name"/>
<field name="mail_template_id"/>
<field name="sequence" groups="base.group_no_one"/>
</group>
<group>
<field name="fold"/>
<field name="is_done"/>
<field name="is_cancel"/>
</group>
</group>
</sheet>
</form>
</field>
</record>
<record id="event_track_stage_view_tree" model="ir.ui.view">
<field name="name">event.track.stage.view.tree</field>
<field name="model">event.track.stage</field>
<field name="arch" type="xml">
<tree string="Track Stage">
<field name="sequence" widget="handle"/>
<field name="name"/>
<field name="fold"/>
</tree>
</field>
</record>
<record id="event_track_stage_action" model="ir.actions.act_window">
<field name="name">Track Stages</field>
<field name="res_model">event.track.stage</field>
<field name="view_type">form</field>
<field name="view_id" ref="event_track_stage_view_tree"/>
<field name="help" type="html">
<p class="oe_view_nocontent_create">
Click to add a stage in the task pipeline.
</p><p>
Define the steps that will be used in the event from the
creation of the track, up to the closing of the track.
You will use these stages in order to track the progress in
solving an event track.
</p></field>
</record>
<menuitem name="Track Stages"
id="event_track_stage_menu"
action="event_track_stage_action"
parent="event.menu_event_configuration"/>
</odoo>
@@ -1,36 +1,48 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="event_type_view_form_inherit_track" model="ir.ui.view">
<field name="name">event.type.view.form.inherit.track</field>
<field name="model">event.type</field>
<field name="inherit_id" ref="website_event.event_type_view_form_inherit_website"/>
<field name="arch" type="xml">
<xpath expr="//div[@name='event_type_visibility_website']/div[@class='o_setting_right_pane']" position='inside'>
<div class="row mt16">
<label class="col-md-4" for="website_track"/> <field name="website_track"/>
</div>
<div class="row mt16">
<label class="col-md-4" for="website_track_proposal"/> <field name="website_track_proposal"/>
</div>
</xpath>
</field>
</record>
<!-- Events Organisation/CONFIGURATION/EVENTS -->
<record id="view_event_form" model="ir.ui.view">
<field name="name">Event Tracks</field>
<field name="inherit_id" ref="event.view_event_form"/>
<field name="inherit_id" ref="website_event.event_event_view_form_inherit_website"/>
<field name="model">event.event</field>
<field name="arch" type="xml">
<button name="toggle_active" position="before">
<button name="website_publish_button" position="before">
<button name="%(action_event_track_from_event)d"
type="action"
class="oe_stat_button"
icon="fa-inbox"
attrs="{'invisible': [('show_tracks', '=', False), ('show_track_proposal', '=', False)]}">
<field name="count_tracks" widget="statinfo"/>
icon="fa-inbox">
<field name="track_count" widget="statinfo"/>
</button>
<button name="%(action_event_sponsor_from_event)d"
type="action"
class="oe_stat_button"
icon="fa-users">
<field name="count_sponsor" widget="statinfo" string="Sponsors"/>
<field name="sponsor_count" widget="statinfo"/>
</button>
</button>
<xpath expr="//div[@class='oe_title']" position="inside">
<div name="event_checkboxes">
<field name="show_menu"/>
<label for="show_menu"/>
<field name="show_tracks" attrs="{'invisible': [('show_menu', '=', False)]}"/>
<label for="show_tracks" attrs="{'invisible': [('show_menu', '=', False)]}"/>
<field name="show_track_proposal" attrs="{'invisible': [('show_menu', '=', False)]}"/>
<label for="show_track_proposal" attrs="{'invisible': [('show_menu', '=', False)]}"/>
</div>
</xpath>
<label for="website_menu" position="after">
<field name="website_track" attrs="{'invisible': [('website_menu', '=', False)]}"/>
<label for="website_track" string="Tracks on Website" attrs="{'invisible': [('website_menu', '=', False)]}"/>
<field name="website_track_proposal" attrs="{'invisible': [('website_menu', '=', False)]}"/>
<label for="website_track_proposal" string="Track Proposals on Website" attrs="{'invisible': [('website_menu', '=', False)]}"/>
</label>
</field>
</record>
</odoo>