[IMP] event: Split Ticket: registration are now for one attendee only.

Registration are now for one attendee only. When buying several seats for an event
you have now one registration for each attendee.

event: nb_register field is removed; as well as unnecessary user_id and it subscribe /
unsubscribe behavior. Also slighly cleaned some views.
event_sale: do not auto confirm registrations linked to a draft sale order. Note: strange
origin is a char field, not a sale_order_id. Added a small wizard to edit attendees
data when confirming a sale order containing event related lines.
website_event: when buying free tickets, ask for attendee details. Added template,
controllers to handle that behavior.
website_event_sale: when buying tickets, ask for attendee details. Events ecommerce
should be better integrated with online events, using inheritance to add details
instead of being very different.
This commit is contained in:
Paramjit Singh Sahota
2014-10-09 10:09:06 +02:00
committed by Thibault Delavallée
parent b7eb97c39e
commit ca862e7b85
28 changed files with 653 additions and 272 deletions
+2
View File
@@ -29,6 +29,8 @@ Key Features
'res_config_view.xml',
'email_template.xml',
'views/event.xml',
'event_report.xml',
'views/report_registrationbadge.xml',
],
'demo': [
'event_demo.xml',
+17 -50
View File
@@ -81,7 +81,7 @@ class event_event(models.Model):
store=True, readonly=True, compute='_compute_seats')
@api.multi
@api.depends('seats_max', 'registration_ids.state', 'registration_ids.nb_register')
@api.depends('seats_max', 'registration_ids.state')
def _compute_seats(self):
""" Determine reserved, available, reserved but unconfirmed and used seats. """
# initialize fields to 0
@@ -94,7 +94,7 @@ class event_event(models.Model):
'open': 'seats_reserved',
'done': 'seats_used',
}
query = """ SELECT event_id, state, sum(nb_register)
query = """ SELECT event_id, state, count(event_id)
FROM event_registration
WHERE event_id IN %s AND state IN ('draft', 'open', 'done')
GROUP BY event_id, state
@@ -110,7 +110,7 @@ class event_event(models.Model):
# Registration fields
registration_ids = fields.One2many(
'event.registration', 'event_id', string='Registrations',
'event.registration', 'event_id', string='Attendees',
readonly=False, states={'done': [('readonly', True)]})
count_registrations = fields.Integer(string='Registrations', compute='_count_registrations')
@@ -245,36 +245,6 @@ class event_event(models.Model):
""" Confirm Event and send confirmation email to all register peoples """
self.confirm_event()
@api.one
def subscribe_to_event(self):
""" Subscribe the current user to a given event """
user = self.env.user
num_of_seats = int(self._context.get('ticket', 1))
regs = self.registration_ids.filtered(lambda reg: reg.user_id == user)
# the subscription is done as SUPERUSER_ID because in case we share the
# kanban view, we want anyone to be able to subscribe
if not regs:
regs = regs.sudo().create({
'event_id': self.id,
'email': user.email,
'name': user.name,
'user_id': user.id,
'nb_register': num_of_seats,
})
else:
regs.write({'nb_register': num_of_seats})
if regs._check_auto_confirmation():
regs.sudo().confirm_registration()
@api.one
def unsubscribe_to_event(self):
""" Unsubscribe the current user from a given event """
# the unsubscription is done as SUPERUSER_ID because in case we share
# the kanban view, we want anyone to be able to unsubscribe
user = self.env.user
regs = self.sudo().registration_ids.filtered(lambda reg: reg.user_id == user)
regs.button_reg_cancel()
@api.onchange('type')
def _onchange_type(self):
if self.type:
@@ -289,35 +259,31 @@ class event_event(models.Model):
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": ['event_date:day'],
"group_by": ['create_date:day'],
}
return res
class event_registration(models.Model):
_name = 'event.registration'
_description = 'Event Registration'
_description = 'Attendee'
_inherit = ['mail.thread', 'ir.needaction_mixin']
_order = 'name, create_date desc'
origin = fields.Char(
string='Source Document', readonly=True,
help="Reference of the sales order which created the registration") # funny we refer sale orders... event is not sale related
nb_register = fields.Integer(
string='Number of Participants', required=True, default=1,
readonly=True, states={'draft': [('readonly', False)]})
help="Reference of the document that created the registration, for example a sale order")
event_id = fields.Many2one(
'event.event', string='Event', required=True,
readonly=True, states={'draft': [('readonly', False)]})
partner_id = fields.Many2one(
'res.partner', string='Partner',
'res.partner', string='Contact',
states={'done': [('readonly', True)]})
date_open = fields.Datetime(string='Registration Date', readonly=True)
date_closed = fields.Datetime(string='Attended Date', readonly=True)
reply_to = fields.Char(string='Reply-to Email', related='event_id.reply_to', readonly=True)
event_begin_date = fields.Datetime(string="Event Start Date", related='event_id.date_begin', readonly=True)
event_end_date = fields.Datetime(string="Event End Date", related='event_id.date_end', readonly=True)
user_id = fields.Many2one('res.users', string='User', states={'done': [('readonly', True)]})
company_id = fields.Many2one(
'res.company', string='Company', related='event_id.company_id',
store=True, readonly=True, states={'draft': [('readonly', False)]})
@@ -327,17 +293,18 @@ class event_registration(models.Model):
string='Status', default='draft', readonly=True, copy=False, track_visibility='onchange')
email = fields.Char(string='Email')
phone = fields.Char(string='Phone')
name = fields.Char(string='Name', select=True)
name = fields.Char(string='Attendee Name', select=True)
@api.one
@api.constrains('event_id', 'state', 'nb_register')
@api.constrains('event_id', 'state')
def _check_seats_limit(self):
if self.event_id.seats_max and \
self.event_id.seats_available < (self.nb_register if self.state == 'draft' else 0):
raise Warning(_('Only %s seats available for this event') % self.event_id.seats_available if self.event_id.seats_available > 0 else _('No more seats available for this event.'))
if self.event_id.seats_max and self.event_id.seats_available < (1 if self.state == 'draft' else 0):
raise Warning(_('No more seats available for this event.'))
@api.one
def _check_auto_confirmation(self):
if self._context.get('registration_force_draft'):
return False
if self.event_id and self.event_id.state == 'confirm' and self.event_id.auto_confirm and self.event_id.seats_available:
return True
return False
@@ -345,7 +312,7 @@ class event_registration(models.Model):
@api.model
def create(self, vals):
res = super(event_registration, self).create(vals)
if res._check_auto_confirmation():
if res._check_auto_confirmation()[0]:
res.sudo().confirm_registration()
return res
@@ -402,6 +369,6 @@ class event_registration(models.Model):
contact_id = self.partner_id.address_get().get('default', False)
if contact_id:
contact = self.env['res.partner'].browse(contact_id)
self.name = contact.name
self.email = contact.email
self.phone = contact.phone
self.name = self.name or contact.name
self.email = self.email or contact.email
self.phone = self.phone or contact.phone
-3
View File
@@ -217,7 +217,6 @@
<field name="phone">003281588558</field>
<field name="event_id" ref="event_1"/>
<field name="partner_id" ref="base.res_partner_2"/>
<field name="nb_register">5</field>
</record>
<record id="reg_1_2" model="event.registration">
@@ -226,7 +225,6 @@
<field name="phone">+ 1 64 61 04 01</field>
<field name="partner_id" ref="base.res_partner_1"/>
<field name="event_id" ref="event_1"/>
<field name="nb_register">10</field>
</record>
<record id="reg_0_2" model="event.registration">
@@ -235,7 +233,6 @@
<field name="phone">+41 21 619 10 04 </field>
<field name="event_id" ref="event_2"/>
<field name="partner_id" ref="base.res_partner_12"/>
<field name="nb_register">5</field>
</record>
</data>
@@ -17,17 +17,14 @@
<field name="header_spacing">0</field>
<field name="dpi">80</field>
</record>
<report
id="action_report_registrationbadge"
model="event.registration"
string="Badge"
report_type="qweb-html"
name="event_sale.report_registrationbadge"
file="event_sale.report_registrationbadge"
/>
<record id="action_report_registrationbadge" model="ir.actions.report.xml">
<field name="paperformat_id" ref="event_sale.paperformat_euro_lowmargin"/>
<report id="action_report_registration_badge" model="event.registration"
string="Badge" report_type="qweb-html"
name="event.report_registration_badge"
file="event.report_registration_badge"/>
<record model="ir.actions.report.xml" id="event.action_report_registration_badge">
<field name="paperformat_id" ref="event.paperformat_euro_lowmargin"/>
</record>
</data>
</openerp>
</openerp>
+14 -32
View File
@@ -46,7 +46,7 @@
<record id="act_event_registration_from_event" model="ir.actions.act_window">
<field name="res_model">event.registration</field>
<field name="view_type">form</field>
<field name="name">Registrations</field>
<field name="name">Attendees</field>
<field name="view_mode">tree,form,calendar,graph</field>
<field name="context">{'search_default_event_id': active_id, 'default_event_id': active_id}</field>
</record>
@@ -75,7 +75,7 @@
class="oe_stat_button oe_inline"
icon="fa-github"
help="Register with this event">
<field name="count_registrations" widget="statinfo" string="Registrations"/>
<field name="count_registrations" widget="statinfo" string="Attendees"/>
</button>
</div>
<group name="main_field_group">
@@ -190,11 +190,9 @@
<h4>
<a name="%(act_event_registration_from_event)d" type="action">
<t t-esc="record.seats_reserved.raw_value" > Attendees</t>
<t t-if="(record.seats_reserved.raw_value + record.seats_unconfirmed.raw_value) > 0 ">&#47;
<t t-esc="record.seats_reserved.raw_value + record.seats_unconfirmed.raw_value"/> Expected
</t>
</a>
<t t-if="record.seats_reserved.raw_value > 0">
<t t-if="(record.seats_reserved.raw_value + record.seats_unconfirmed.raw_value) > 0 ">&#47;
<t t-esc="record.seats_reserved.raw_value + record.seats_unconfirmed.raw_value"/> Expected
<a name="action_event_registration_report" type="object" >&#40;Report&#41;</a>
</t>
</h4>
@@ -273,7 +271,7 @@
<menuitem name="Events" id="menu_event_event" action="action_event_view" parent="event.event_main_menu" />
<!-- EVENTS/REGISTRATIONS/EVENTS -->
<!-- EVENT.REGISTRATION VIEWS -->
<record model="ir.ui.view" id="view_event_registration_tree">
<field name="name">event.registration.tree</field>
<field name="model">event.registration</field>
@@ -284,14 +282,8 @@
<field name="name"/>
<field name="email"/>
<field name="event_id" />
<field name="nb_register"/>
<field name="user_id" invisible="1"/>
<field name="origin"/>
<field name="state"/>
<field name="message_unread" invisible="1"/>
<button name="registration_open" string="Confirm Registration" states="draft" type="object" icon="gtk-apply"/>
<button name="button_reg_close" string="Attended the Event" states="open" type="object" icon="gtk-jump-to"/>
<button name="button_reg_cancel" string="Cancel Registration" states="draft,open" type="object" icon="gtk-cancel"/>
</tree>
</field>
</record>
@@ -309,22 +301,17 @@
<field name="state" nolabel="1" colspan="2" widget="statusbar" statusbar_visible="draft,open,done"/>
</header>
<sheet string="Registration">
<label for="event_id" class="oe_edit_only"/>
<h1>
<field name="event_id" domain="[('state','in',('draft','confirm'))]"/>
</h1>
<group>
<group>
<field name="partner_id" attrs="{'readonly':[('state','!=', 'draft')]}"/>
<group string="Attendee Information">
<field name="name"/>
<field name="phone"/>
<field name="email"/>
<field name="partner_id" attrs="{'readonly':[('state', '!=', 'draft')]}"/>
</group>
<group>
<field name="create_date" groups="base.group_no_one"/>
<group string="Event Information">
<field name="event_id" readonly="1"/>
<field name="date_open" groups="base.group_no_one"/>
<field name="date_closed" groups="base.group_no_one"/>
<field name="nb_register"/>
<field name="user_id" attrs="{'readonly':[('state','!=', 'draft')]}" context="{'default_groups_ref': ['base.group_user', 'base.group_partner_manager', 'event.group_event_user']}"/>
</group>
</group>
</sheet>
@@ -354,7 +341,6 @@
<field name="arch" type="xml">
<graph string="Registration" type="bar">
<field name="event_id" type="row"/>
<field name= "nb_register" type="measure"/>
</graph>
</field>
</record>
@@ -364,15 +350,11 @@
<field name="model">event.registration</field>
<field name="arch" type="xml">
<search string="Event Registration">
<field name="name" string="Participant" filter_domain="['|','|',('name','ilike',self),('email','ilike',self),('origin','ilike',self)]"/>
<field name="id" string="Registration ID"/>
<field name="name" string="Participant" filter_domain="['|', '|', ('name', 'ilike', self), ('email', 'ilike', self), ('origin', 'ilike', self)]"/>
<filter string="Unread Messages" name="message_unread" domain="[('message_unread','=',True)]"/>
<separator/>
<filter string="New" name="draft" domain="[('state','=','draft')]" help="Registrations in unconfirmed state"/>
<filter string="Confirmed" domain="[('state','=','open')]" help="Confirmed registrations"/>
<separator/>
<filter string="My Registrations" help="My Registrations" domain="[('user_id','=',uid)]"/>
<field name="event_id"/>
<field name="user_id"/>
<field name="partner_id"/>
<group expand="0" string="Group By">
<filter string="Responsible" domain="[]" context="{'group_by':'user_id'}"/>
@@ -387,7 +369,7 @@
</record>
<record model="ir.actions.act_window" id="action_registration">
<field name="name">Registrations</field>
<field name="name">Attendees</field>
<field name="res_model">event.registration</field>
<field name="view_type">form</field>
<field name="domain"></field>
@@ -396,7 +378,7 @@
<field name="search_view_id" ref="view_registration_search"/>
</record>
<menuitem name="Registrations"
<menuitem name="Attendees"
id="menu_action_registration" parent="event.event_main_menu"
action="action_registration" groups="event.group_event_manager,event.group_event_user"/>
@@ -29,6 +29,7 @@ class report_event_registration(models.Model):
_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')
@@ -40,7 +41,6 @@ class report_event_registration(models.Model):
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)
user_id_registration = fields.Many2one('res.users', 'Register', readonly=True)
name_registration = fields.Char('Participant / Contact Name', readonly=True)
company_id = fields.Many2one('res.company', 'Company', readonly=True)
@@ -54,14 +54,14 @@ class report_event_registration(models.Model):
e.id::varchar || '/' || coalesce(r.id::varchar,'') AS id,
e.id AS event_id,
e.user_id AS user_id,
r.user_id AS user_id_registration,
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,
sum(r.nb_register) AS nbregistration,
CASE WHEN r.state IN ('draft') THEN r.nb_register ELSE 0 END AS draft_state,
CASE WHEN r.state IN ('open','done') THEN r.nb_register ELSE 0 END AS confirm_state,
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,
e.type AS event_type,
e.seats_max AS seats_max,
e.state AS event_state,
@@ -72,10 +72,8 @@ class report_event_registration(models.Model):
GROUP BY
event_id,
user_id_registration,
r.id,
registration_state,
r.nb_register,
event_type,
e.id,
e.date_begin,
+6 -8
View File
@@ -20,7 +20,7 @@ class TestEventFlow(TestEventCommon):
'name': 'TestEvent',
'date_begin': datetime.datetime.now() + relativedelta(days=-1),
'date_end': datetime.datetime.now() + relativedelta(days=1),
'seats_max': 10,
'seats_max': 2,
})
self.assertEqual(test_event.state, 'confirm', 'Event: auto_confirmation of event failed')
@@ -28,33 +28,30 @@ class TestEventFlow(TestEventCommon):
test_reg1 = self.Registration.sudo(self.user_eventuser).create({
'name': 'TestReg1',
'event_id': test_event.id,
'nb_register': 7,
})
self.assertEqual(test_reg1.state, 'open', 'Event: auto_confirmation of registration failed')
self.assertEqual(test_event.seats_reserved, 7, 'Event: wrong number of reserved seats after confirmed registration')
self.assertEqual(test_event.seats_reserved, 1, 'Event: wrong number of reserved seats after confirmed registration')
test_reg2 = self.Registration.sudo(self.user_eventuser).create({
'name': 'TestReg2',
'event_id': test_event.id,
'nb_register': 3,
})
self.assertEqual(test_reg2.state, 'open', 'Event: auto_confirmation of registration failed')
self.assertEqual(test_event.seats_reserved, 10, 'Event: wrong number of reserved seats after confirmed registration')
self.assertEqual(test_event.seats_reserved, 2, 'Event: wrong number of reserved seats after confirmed registration')
# EventUser create registrations for this event: too much registrations
with self.assertRaises(ValidationError):
self.Registration.sudo(self.user_eventuser).create({
'name': 'TestReg3',
'event_id': test_event.id,
'nb_register': 1,
})
# EventUser validates registrations
test_reg1.button_reg_close()
self.assertEqual(test_reg1.state, 'done', 'Event: wrong state of attended registration')
self.assertEqual(test_event.seats_used, 7, 'Event: incorrect number of attendees after closing registration')
self.assertEqual(test_event.seats_used, 1, 'Event: incorrect number of attendees after closing registration')
test_reg2.button_reg_close()
self.assertEqual(test_reg1.state, 'done', 'Event: wrong state of attended registration')
self.assertEqual(test_event.seats_used, 10, 'Event: incorrect number of attendees after closing registration')
self.assertEqual(test_event.seats_used, 2, 'Event: incorrect number of attendees after closing registration')
# EventUser closes the event
test_event.button_done()
@@ -63,6 +60,7 @@ class TestEventFlow(TestEventCommon):
with self.assertRaises(Warning):
test_event.button_cancel()
@mute_logger('openerp.addons.base.ir.ir_model', 'openerp.models')
def test_10_advanced_event_flow(self):
""" Avanced event flow: no auto confirmation, manage minimum / maximum
@@ -0,0 +1,39 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<template id="report_registration_badge">
<t t-call="report.html_container">
<t t-foreach="docs" t-as="o">
<div class="page">
<div class="row" style="border-bottom:1px dashed black;">
<div class="col-xs-6 text-center" style="padding-right:7mm; border-right:1px dashed black; height: 147mm; padding-top: 7mm">
<div class="row">
<div class="col-xs-12">
<span t-if="o.event_id.organizer_id.company_id.logo_web and o.event_id.organizer_id.is_company">
<img t-att-src="'data:image/png;base64,%s' % o.event_id.organizer_id.company_id.logo_web" style="max-height:1cm; max-width:4cm;"/>
</span>
<h4 t-field="o.event_id.name"/>
<h5>( <i class="fa fa-clock-o"></i> <span itemprop="startDate" t-field="o.event_id.date_begin" t-field-options='{"hide_seconds":"True"}'> </span> <i>to</i> <span itemprop="endDate" t-field="o.event_id.date_end" t-field-options='{"hide_seconds":"True"}'> </span> )</h5>
</div>
</div>
<div class="row">
<div class="col-xs-12 text-center">
<small><h3 t-if="o.partner_id.is_company == True" t-field="o.partner_id.name"/><h5 t-field="o.name"/></small>
</div>
</div>
<div class="row">
<div class="col-xs-12 mt32 text-center" style="background: lightgrey;">
<h3>FREE TICKET</h3>
</div>
</div>
</div>
<!-- Inner right -->
<div class="col-xs-6 text-center" style="padding-left:7mm; height: 149mm; padding-top: 2mm;">
</div>
</div>
</div>
</t>
</t>
</template>
</data>
</openerp>
+1
View File
@@ -1,3 +1,4 @@
# -*- coding: utf-8 -*-
import models
import wizard
+1 -1
View File
@@ -25,9 +25,9 @@ this event.
'views/product.xml',
'views/sale_order.xml',
'event_sale_data.xml',
'event_sale_report.xml',
'views/report_registrationbadge.xml',
'security/ir.model.access.csv',
'wizard/event_edit_registration.xml',
],
'demo': ['event_demo.xml'],
'test': ['test/confirm.yml'],
+24 -3
View File
@@ -78,7 +78,7 @@ class event_ticket(models.Model):
seats_used = fields.Integer(compute='_compute_seats', store=True)
@api.multi
@api.depends('seats_max', 'registration_ids.state', 'registration_ids.nb_register')
@api.depends('seats_max', 'registration_ids.state')
def _compute_seats(self):
""" Determine reserved, available, reserved but unconfirmed and used seats. """
# initialize fields to 0
@@ -91,7 +91,7 @@ class event_ticket(models.Model):
'open': 'seats_reserved',
'done': 'seats_used',
}
query = """ SELECT event_ticket_id, state, sum(nb_register)
query = """ SELECT event_ticket_id, state, count(event_id)
FROM event_registration
WHERE event_ticket_id IN %s AND state IN ('draft', 'open', 'done')
GROUP BY event_ticket_id, state
@@ -121,9 +121,30 @@ class event_registration(models.Model):
_inherit = 'event.registration'
event_ticket_id = fields.Many2one('event.event.ticket', 'Event Ticket')
# sale_order_line_id = fields.Many2one('sale.order.line', 'Sale Order Line', ondelete='cascade')
@api.one
@api.constrains('event_ticket_id', 'nb_register', 'state')
@api.constrains('event_ticket_id', 'state')
def _check_ticket_seats_limit(self):
if self.event_ticket_id.seats_max and self.event_ticket_id.seats_available < 0:
raise Warning('No more available seats for this ticket')
@api.one
def _check_auto_confirmation(self):
res = super(event_registration, self)._check_auto_confirmation()[0]
if res and self.origin:
orders = self.env['sale.order'].search([('name', '=', self.origin)], limit=1)
if orders and orders[0].state == 'draft':
res = False
return res
@api.model
def create(self, vals):
res = super(event_registration, self).create(vals)
if res.origin:
message = _("The registration has been created for event %(event_name)s%(ticket)s from sale order %(order)s") % ({
'event_name': '<i>%s</i>' % res.event_id.name,
'ticket': res.event_ticket_id and _(' with ticket %s') % (('<i>%s</i>') % res.event_ticket_id.name) or '',
'order': res.origin})
res.message_post(body=message)
return res
+41 -25
View File
@@ -1,7 +1,21 @@
# -*- coding: utf-8 -*-
from openerp import api
from openerp.osv import fields, osv
from openerp.tools.translate import _
class sale_order(osv.osv):
_inherit = "sale.order"
def action_button_confirm(self, cr, uid, ids, context=None):
# TDE note: This method works on a list of one id (see sale/sale.py) so working on ids[0] seems safe.
res = super(sale_order, self).action_button_confirm(cr, uid, ids, context=context)
redirect_to_event_registration = any(line.event_id for order in self.browse(cr, uid, ids, context=context) for line in order.order_line)
if redirect_to_event_registration:
event_ctx = dict(context, default_sale_order_id=ids[0])
return self.pool.get('ir.actions.act_window').for_xml_id(cr, uid, 'event_sale', 'action_sale_order_event_registration', event_ctx)
else:
return res
class sale_order_line(osv.osv):
@@ -35,34 +49,36 @@ class sale_order_line(osv.osv):
event_ok=False)
return res
@api.multi
def _update_registrations(self):
""" Create or update registrations linked to a sale 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
and create new one for missing one. """
registrations = self.env['event.registration'].search([('origin', 'in', list(set([so.name for line in self for so in line.order_id if line.event_id])))])
for so_line in [l for l in self if l.event_id]:
existing_registrations = [r for r in registrations if r.event_id == so_line.event_id and r.origin == so_line.order_id.name]
for registration in existing_registrations:
registration.write({'state': 'open'})
for count in range(int(so_line.product_uom_qty) - len(existing_registrations)):
self.env['event.registration'].create({
'event_id': so_line.event_id.id,
'event_ticket_id': so_line.event_ticket_id.id,
'partner_id': so_line.order_id.partner_id.id,
'origin': so_line.order_id.name,
})
return True
def button_confirm(self, cr, uid, ids, context=None):
""" Override confirmation of the sale order line in order to create
or update the possible event registrations linked to the sale. """
'''
create registration with sales order
'''
context = dict(context or {})
registration_obj = self.pool.get('event.registration')
for order_line in self.browse(cr, uid, ids, context=context):
if order_line.event_id:
dic = {
'name': order_line.order_id.partner_invoice_id.name,
'partner_id': order_line.order_id.partner_id.id,
'nb_register': int(order_line.product_uom_qty),
'email': order_line.order_id.partner_id.email,
'phone': order_line.order_id.partner_id.phone,
'origin': order_line.order_id.name,
'event_id': order_line.event_id.id,
'event_ticket_id': order_line.event_ticket_id and order_line.event_ticket_id.id or None,
}
if order_line.event_ticket_id:
message = _("The registration has been created for event <i>%s</i> with the ticket <i>%s</i> from the Sale Order %s. ") % (order_line.event_id.name, order_line.event_ticket_id.name, order_line.order_id.name)
else:
message = _("The registration has been created for event <i>%s</i> from the Sale Order %s. ") % (order_line.event_id.name, order_line.order_id.name)
context.update({'mail_create_nolog': True})
registration_id = registration_obj.create(cr, uid, dic, context=context)
registration_obj.message_post(cr, uid, [registration_id], body=message, context=context)
return super(sale_order_line, self).button_confirm(cr, uid, ids, context=context)
res = super(sale_order_line, self).button_confirm(cr, uid, ids, context=context)
self._update_registrations(cr, uid, ids, context=context)
return res
def onchange_event_ticket_id(self, cr, uid, ids, event_ticket_id=False, context=None):
price = event_ticket_id and self.pool["event.event.ticket"].browse(cr, uid, event_ticket_id, context=context).price or False
@@ -1,3 +1,3 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_event_event_ticket_user,event.event.ticket.user,event_sale.model_event_event_ticket,event.group_event_user,1,0,0,0
access_event_event_ticket_admin,event.event.ticket.admin,event_sale.model_event_event_ticket,event.group_event_manager,1,1,1,1
access_event_event_ticket_admin,event.event.ticket.admin,event_sale.model_event_event_ticket,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
2 access_event_event_ticket_user event.event.ticket.user event_sale.model_event_event_ticket event.group_event_user 1 0 0 0
3 access_event_event_ticket_admin event.event.ticket.admin event_sale.model_event_event_ticket event.group_event_manager 1 1 1 1
+13 -7
View File
@@ -34,21 +34,27 @@
name: sale order line
event_id: event
-
I confirm the sale order
In the event registration I add some attendee detail lines. i choose event product
-
!workflow {model: sale.order, ref: order1, action: order_confirm}
!record {model: registration.editor, id: attendee_detail}:
sale_order_id: order1
event_registration_ids:
- event_id: event
name: 'Administrator'
email: 'abc@example.com'
-
I check if the sale order is confirmed
I click apply to create attendees
-
!assert {model: sale.order, id: order1}:
- state == 'manual'
!python {model: registration.editor}: |
self.action_make_registration(cr, uid, ref('attendee_detail'))
-
I check if a registration is created
-
!python {model: event.registration}: |
from openerp.osv import osv
from openerp.tools.translate import _
order_id = ref('order1')
order = self.pool.get('sale.order').browse(cr, uid,order_id)
registration_ids = self.search(cr,uid,[('origin','=',order.name)])
registration_ids = self.search(cr,uid,[('origin', '=', order.name)])
if registration_ids == []:
raise osv.except_osv(_('Error!'),_("The registration is not created."))
+3 -1
View File
@@ -20,6 +20,7 @@
<field name="arch" type="xml">
<field name="event_id" position="after">
<field name="event_ticket_id"/>
<field name="origin"/>
</field>
</field>
</record>
@@ -29,8 +30,9 @@
<field name="model">event.registration</field>
<field name="inherit_id" ref="event.view_event_registration_form" />
<field name="arch" type="xml">
<field name="user_id" position="after">
<field name="event_id" position="after">
<field name="event_ticket_id" domain="[('event_id', '=', event_id)]"/>
<field name="origin"/>
</field>
</field>
</record>
@@ -1,52 +1,39 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<template id="report_registrationbadge">
<template id="event.report_registration_badge">
<t t-call="report.html_container">
<t t-foreach="docs" t-as="o">
<div class="page">
<div class="row">
<!-- Inner right -->
<div class="col-xs-6 text-center" style="padding-left:7mm; border-left:1px dashed black; height: 149mm; -webkit-transform:rotate(180deg); padding-top: 7mm">
<div>
<div class="row">
<div class="col-xs-12">
<div>
<span t-if="o.event_id.organizer_id.company_id.logo_web and o.event_id.organizer_id.is_company">
<img t-att-src="'data:image/png;base64,%s' % o.event_id.organizer_id.company_id.logo_web" style="max-height:1cm; max-width:4cm;"/>
</span>
<div>
<h5 t-field="o.event_id.name"/>
</div>
<div>
<h5>June 4th - 6th , 2014</h5>
</div>
</div>
</div>
<div class="row">
<div class="col-xs-12">
<span t-if="o.event_id.organizer_id.company_id.logo_web and o.event_id.organizer_id.is_company">
<img t-att-src="'data:image/png;base64,%s' % o.event_id.organizer_id.company_id.logo_web" style="max-height:1cm; max-width:4cm;"/>
</span>
<h5 t-field="o.event_id.name"/>
<h5>( <i class="fa fa-clock-o"></i> <span itemprop="startDate" t-field="o.event_id.date_begin" t-field-options='{"hide_seconds":"True"}'> </span> <i>to</i> <span itemprop="endDate" t-field="o.event_id.date_end" t-field-options='{"hide_seconds":"True"}'> </span> )</h5>
</div>
<div class="row">
<div class="col-xs-12 text-center">
<t t-if="o.event_ticket_id">
<div>
<strong><span t-field="o.event_ticket_id"/></strong>
</div>
<div class="col-xs-12 text-center">
<t t-if="o.event_ticket_id">
<div>
<strong><span t-field="o.event_ticket_id"/></strong>
</div>
</t>
<div>
<t t-if="o.partner_id.is_company == True">
<small>
<h3 t-field="o.partner_id.name"/>
<h5 t-field="o.name"/>
</small>
</t>
<div>
<t t-if="o.partner_id.is_company == True">
<small>
<h3 t-field="o.partner_id.name"/>
<h5 t-field="o.name"/>
</small>
</t>
</div>
</div>
</div>
<br/>
<div class="row">
<div class="col-xs-12 mt32 text-center" style="background: lightgrey;">
<h3>Status</h3>
</div>
</div>
<div class="col-xs-12 mt32 text-center" style="background: lightgrey;">
<h3>Status</h3>
</div>
</div>
</div>
+1
View File
@@ -0,0 +1 @@
import event_edit_registration
@@ -0,0 +1,75 @@
# -*- coding: utf-8 -*-
from openerp import models, fields, api
class SaleOrderEventRegistration(models.TransientModel):
_name = "registration.editor"
sale_order_id = fields.Many2one('sale.order', 'Sale Order', required=True)
event_registration_ids = fields.One2many('registration.editor.line', 'editor_id', string='Registrations to Edit')
@api.model
def default_get(self, fields):
res = super(SaleOrderEventRegistration, self).default_get(fields)
if not res.get('sale_order_id'):
sale_order_id = res.get('sale_order_id', self._context.get('active_id'))
res['sale_order_id'] = sale_order_id
sale_order = self.env['sale.order'].browse(res.get('sale_order_id'))
registrations = self.env['event.registration'].search([('origin', '=', sale_order.name)])
attendee_list = []
for so_line in [l for l in sale_order.order_line if l.event_id]:
existing_registrations = [r for r in registrations if r.event_id == so_line.event_id]
for reg in existing_registrations:
attendee_list.append({
'event_id': reg.event_id.id,
'event_ticket_id': reg.event_ticket_id.id,
'registration_id': reg.id,
'name': reg.name,
'email': reg.email,
'phone': reg.phone,
})
for count in range(int(so_line.product_uom_qty) - len(existing_registrations)):
attendee_list.append({
'event_id': so_line.event_id.id,
'event_ticket_id': so_line.event_ticket_id.id,
})
res['event_registration_ids'] = attendee_list
return res
@api.multi
def action_make_registration(self):
Registration = self.env['event.registration']
for wizard in self:
for wiz_registration in wizard.event_registration_ids:
if wiz_registration.registration_id:
wiz_registration.registration_id.write(wiz_registration.get_registration_data()[0])
else:
Registration.create(wiz_registration.get_registration_data()[0])
return {'type': 'ir.actions.act_window_close'}
class RegistrationEditorLine(models.TransientModel):
"""Event Registration"""
_name = "registration.editor.line"
editor_id = fields.Many2one('registration.editor')
event_id = fields.Many2one('event.event', string='Event', required=True)
registration_id = fields.Many2one('event.registration', 'Original Registration')
event_ticket_id = fields.Many2one('event.event.ticket', string='Event Ticket')
email = fields.Char(string='Email')
phone = fields.Char(string='Phone')
name = fields.Char(string='Name', select=True)
@api.one
def get_registration_data(self):
return {
'event_id': self.event_id.id,
'event_ticket_id': self.event_ticket_id.id,
'partner_id': self.editor_id.sale_order_id.partner_id.id,
'name': self.name or self.editor_id.sale_order_id.partner_id.name,
'phone': self.phone or self.editor_id.sale_order_id.partner_id.phone,
'email': self.email or self.editor_id.sale_order_id.partner_id.email,
'origin': self.editor_id.sale_order_id.name,
}
@@ -0,0 +1,43 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<record id="view_event_registration_editor_form" model="ir.ui.view">
<field name="name">registration.editor.form</field>
<field name="model">registration.editor</field>
<field name="arch" type="xml">
<form string="Registration">
<p>Before confirming <field name="sale_order_id" readonly="1" class="oe_inline"/>
please give details about the registrations</p>
<field name="event_registration_ids">
<tree string="Registration" editable="top" create="false" delete="false">
<field name="event_id" readonly='1'/>
<field name="registration_id" readonly='1'/>
<field name="event_ticket_id" domain="[('event_id', '=', event_id)]" readonly='1'/>
<field name="name"/>
<field name="email"/>
<field name="phone"/>
</tree>
</field>
<footer>
<button string="Apply" name="action_make_registration" type="object" class="oe_highlight"/>
or
<button string="Cancel" class="oe_link" special="cancel"/>
</footer>
</form>
</field>
</record>
<record id="action_sale_order_event_registration" model="ir.actions.act_window">
<field name="name">Event Registrations</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">registration.editor</field>
<field name="view_type">form</field>
<field name="view_mode">form</field>
<field name="view_id" ref="view_event_registration_editor_form"/>
<field name="target">new</field>
<field name="context">{'default_sale_order_id': context.get('default_sale_order_id')}</field>
</record>
</data>
</openerp>
@@ -83,4 +83,4 @@ class TransferPaymentTransaction(osv.Model):
def _transfer_form_validate(self, cr, uid, tx, data, context=None):
_logger.info('Validated transfer payment for tx %s: set as pending' % (tx.reference))
return tx.write({'state': 'pending'})
return tx.write({'state': 'done'})
+48 -1
View File
@@ -4,9 +4,10 @@ import time
import werkzeug.urls
from datetime import datetime, timedelta
from dateutil.relativedelta import relativedelta
from collections import OrderedDict
from openerp import http
from openerp import tools
from openerp import tools, SUPERUSER_ID
from openerp.addons.website.models.website import slug
from openerp.http import request
from openerp.tools.translate import _
@@ -195,6 +196,7 @@ class website_event(http.Controller):
'name': event_name,
'date_begin': date_begin.strftime('%Y-%m-%d'),
'date_end': (date_begin + timedelta(days=(1))).strftime('%Y-%m-%d'),
'seats_available': 1000,
}
event_id = Event.create(request.cr, request.uid, vals, context=context)
event = Event.browse(request.cr, request.uid, event_id, context=context)
@@ -225,3 +227,48 @@ class website_event(http.Controller):
"event": event,
"url": event.website_url})
return request.website.render("website_event.country_events_list", result)
def _process_tickets_details(self, data):
nb_register = int(data.get('nb_register-0', 0))
if nb_register:
return [{'id': 0, 'name': 'Subscription', 'quantity': nb_register, 'price': 0}]
return []
@http.route(['/event/<model("event.event"):event>/registration/new'], type='json', auth="public", methods=['POST'], website=True)
def registration_new(self, event, **post):
tickets = self._process_tickets_details(post)
if not tickets:
return request.redirect("/event/%s" % slug(event))
return request.website._render("website_event.registration_attendee_details", {'tickets': tickets, 'event': event})
def _process_registration_details(self, details):
''' Process data posted from the attendee details form. '''
registrations = {}
for key, value in details.iteritems():
counter, field_name = key.split('-', 1)
registrations.setdefault(counter, dict())[field_name] = value
return registrations.values()
@http.route(['/event/<model("event.event"):event>/registration/confirm'], type='http', auth="public", methods=['POST'], website=True)
def registration_confirm(self, event, **post):
cr, uid, context = request.cr, request.uid, request.context
Registration = request.registry['event.registration']
registrations = self._process_registration_details(post)
registration_ids = []
user = request.registry.get('res.users').browse(cr, uid, uid, context=context)
for registration in registrations:
registration_ids.append(
Registration.create(cr, SUPERUSER_ID, {
'name': registration.get('name', user.name),
'phone': registration.get('phone', user.phone),
'email': registration.get('email', user.email),
'partner_id': user.partner_id.id,
'event_id': event.id,
}, context=context))
attendees = Registration.browse(cr, uid, registration_ids, context=context)
return request.website.render("website_event.registration_complete", {
'attendees': attendees,
'event': event,
})
+6 -3
View File
@@ -4,6 +4,7 @@ from openerp import models, fields, api, _
# from openerp.osv import osv, fields
from openerp import SUPERUSER_ID
from openerp.models import NewId
# from openerp.tools.translate import _
import re
@@ -31,11 +32,13 @@ class event(models.Model):
@api.one
@api.depends('name')
def _website_url(self):
self.website_url = "/event/" + slug(self)
if isinstance(self.id, NewId):
self.website_url = ''
else:
self.website_url = "/event/" + slug(self)
@api.one
def _default_hashtag(self):
self.twitter_hashtag = re.sub("[- \\.\\(\\)\\@\\#\\&]+", "", self.env.user.company_id.name).lower()
return re.sub("[- \\.\\(\\)\\@\\#\\&]+", "", self.env.user.company_id.name).lower()
show_menu = fields.Boolean('Has Dedicated Menu', compute='_get_show_menu', inverse='_set_show_menu')
menu_id = fields.Many2one('website.menu', 'Event Menu')
@@ -0,0 +1,23 @@
$(document).ready(function () {
// Catch registration form event, because of JS for attendee details
$('#registration_form .a-submit')
.off('click')
.removeClass('a-submit')
.click(function (ev) {
ev.preventDefault();
ev.stopPropagation();
var $form = $(ev.currentTarget).closest('form');
var post = {};
$("select").each(function() {
post[$(this)[0].name] = $(this).val();
});
openerp.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');
});
});
});
});
@@ -5,6 +5,7 @@
<template id="event_script" inherit_id="website.assets_frontend" name="Country Events Snippet Script">
<xpath expr="/t" position="inside">
<script type="text/javascript" src="/website_event/static/src/js/website_geolocation.js"></script>
<script type="text/javascript" src="/website_event/static/src/js/website_event.js"></script>
</xpath>
</template>
@@ -289,6 +290,9 @@
<template id="event_description_full">
<t t-call="website_event.event_details">
<div class="col-md-8">
<t t-call="website_event.registration_template"/>
<div class="clearfix"/>
<hr/>
<div itemprop="description" t-field="event.description"></div>
<div class="clearfix"/>
<ul class="media-list" id="comment">
@@ -367,6 +371,145 @@
</t>
</template>
<!-- Registration Templates -->
<template id="registration_template">
<form id="registration_form" t-attf-action="/event/#{slug(event)}/registration/new" method="post">
<table itemprop="offers" class="table table-striped">
<thead>
<tr>
<th>Ticket Type</th>
<th style="min-width: 100px">End of Subscription</th>
<th style="min-width: 100px">Price</th>
<th></th>
<th>Quantity</th>
</tr>
</thead>
<tbody>
<tr>
<td>Event Subscription</td>
<td>
<t t-if="event.date_begin">
<span t-field="event.date_begin"/>
</t>
<t t-if="not event.date_begin">
<span>Unlimited</span>
</t>
</td>
<td>Free</td>
<td></td>
<td>
<select t-if="event.seats_available" name="nb_register-0" class="form-control">
<t t-foreach="range(0, event.seats_available > 9 and 10 or event.seats_available+1)" t-as="nb">
<option t-esc="nb"/>
</t>
</select>
<span t-if="not event.seats_available">Sold Out</span>
</td>
</tr>
</tbody>
</table>
<t t-if="event.seats_available">
<button type="submit" t-if="event.seats_available" class="btn btn-primary btn-lg pull-right a-submit" t-attf-id="#{event.id}">Register Now</button>
</t>
</form>
</template>
<template id="registration_attendee_details" name="Registration Attendee Details">
<div id="modal_attendees_registration" class="modal fade" tabindex="-1" role="dialog">
<div class="modal-dialog modal-lg">
<form id="attendee_registration" t-attf-action="/event/#{slug(event)}/registration/confirm" method="post">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">x</button>
<h4 class="modal-title" id="myModalLabel"><strong>Attendees</strong></h4>
</div>
<div class="modal-body">
<div class="container">
<t t-set="counter" t-value="0"/>
<t t-foreach="tickets" t-as="ticket">
<t t-foreach="range(1, ticket['quantity'] + 1)" t-as="att_counter">
<t t-set="counter" t-value="counter + 1"/>
<div>
<h4><strong>Ticket #<t t-raw="counter"/>: <t t-esc="ticket['name']"/> (
<t t-if="ticket['price'] > 0"><t t-esc="ticket['price']"/><t t-esc="website.pricelist_id.currency_id.symbol"/></t>
<t t-if="ticket['price'] == 0">Free</t>
)</strong></h4><hr/>
</div>
<div class="row">
<div class="col-md-4"><strong>Name</strong></div>
<div class="col-md-4"><strong>Phone</strong></div>
<div class="col-md-4"><strong>Email</strong></div>
</div>
<div class="row">
<div class="col-md-4"><input class='form-control input-sm' type='text' t-attf-name="#{counter}-name"/></div>
<div class="col-md-4"><input class='form-control input-sm' type='tel' t-attf-name="#{counter}-phone"/></div>
<div class="col-md-4"><input class='form-control input-sm' type='email' t-attf-name="#{counter}-email"/></div>
<input class='hidden' type='text' t-attf-name="#{counter}-ticket_id" t-attf-value="#{ticket['id']}"/>
</div><hr/>
</t>
<t t-set="counter" t-value="counter + ticket['quantity']"/>
</t>
</div>
</div>
<div class="modal-footer">
<div class="pull-left">
<button type="submit" class="btn btn-primary">Continue</button> or
<a class="js_goto_event"> Cancel Registration</a>
</div>
</div>
</div>
</form>
</div>
</div>
</template>
<template id="registration_complete" name="Registration Completed">
<t t-call="website.layout">
<div class="container">
<h3>We are glad to confirm your subscription to our event</h3>
<div class="row">
<div class="col-md-3 mt16">
<h4>Event Details</h4>
</div>
<div class="col-md-9 mt16">
<h4><a t-attf-href="/event/#{slug(event)}"><t t-esc="event.name"/></a></h4>
<i class="fa fa-clock-o"/> <span itemprop="startDate" t-field="event.date_begin" t-field-options='{"hide_seconds":"True"}'> </span> <i>to</i> <span itemprop="endDate" t-field="event.date_end" t-field-options='{"hide_seconds":"True"}'> </span>
<div itemprop="location" class="mt16 mb8" t-field="event.address_id" t-field-options='{
"widget": "contact",
"fields": ["address", "phone", "mobile", "fax", "email"]
}'/>
</div>
<div class="col-md-3 mt16">
<h4>Your subscription</h4>
</div>
<div class="col-md-9 mt16">
<table class='table table-bordered table-striped'>
<thead>
<tr>
<th>Reference</th>
<th>Name</th>
<th>E-mail</th>
<th>Phone</th>
</tr>
</thead>
<tbody>
<t t-foreach="attendees" t-as="attendee">
<tr>
<td><t t-esc="attendee.id"/></td>
<td><i class="fa fa-user"></i> <t t-if='attendee.name'><t t-esc="attendee.name"/></t><t t-if='not attendee.name'>N/A</t></td>
<td><i class="fa fa-envelope"></i> <t t-if='attendee.email'><t t-esc="attendee.email"/></t><t t-if='not attendee.email'>N/A</t></td>
<td><i class="fa fa-phone"></i> <t t-if='attendee.phone'><t t-esc="attendee.phone"/></t><t t-if='not attendee.phone'>N/A</t></td>
</tr>
</t>
</tbody>
</table>
</div>
</div>
</div>
</t>
</template>
<!-- Snippets -->
<template id="country_events" name="Country Events" inherit_id="website.snippets">
<xpath expr="//div[@id='snippet_content']" position="inside">
<div>
@@ -398,6 +541,7 @@
</xpath>
</template>
<!-- Misc templates -->
<template id="country_events_list" name="Country">
<t t-ignore="true">
<t t-if="events">
+1 -1
View File
@@ -2,7 +2,7 @@
{
'name': "Online Event's Tickets",
'category': 'Hidden',
'category': 'Website',
'summary': "Sell Your Event's Tickets",
'website': 'https://www.odoo.com/page/events',
'version': '1.0',
+33 -21
View File
@@ -28,39 +28,51 @@ from openerp.tools.translate import _
class website_event(website_event):
@http.route(['/event/cart/update'], type='http', auth="public", methods=['POST'], website=True)
def cart_update(self, event_id, **post):
cr, uid, context = request.cr, request.uid, request.context
ticket_obj = request.registry.get('event.event.ticket')
sale = False
for key, value in post.items():
quantity = int(value or "0")
if not quantity:
def _process_tickets_details(self, data):
ticket_post = {}
for key, value in data.iteritems():
if not key.startswith('nb_register') or not '-' in key:
continue
sale = True
ticket_id = key.split("-")[0] == 'ticket' and int(key.split("-")[1]) or None
ticket = ticket_obj.browse(cr, SUPERUSER_ID, ticket_id, context=context)
order = request.website.sale_get_order(force_create=1)
order.with_context(event_ticket_id=ticket.id)._cart_update(product_id=ticket.product_id.id, add_qty=quantity)
items = key.split('-')
if len(items) < 2:
continue
ticket_post[int(items[1])] = int(value)
tickets = request.registry['event.event.ticket'].browse(request.cr, request.uid, ticket_post.keys(), request.context)
return [{'id': ticket.id, 'name': ticket.name, 'quantity': ticket_post[ticket.id], 'price': ticket.price} for ticket in tickets if ticket_post[ticket.id]]
@http.route(['/event/<model("event.event"):event>/registration/confirm'], type='http', auth="public", methods=['POST'], website=True)
def registration_confirm(self, event, **post):
cr, uid, context = request.cr, request.uid, request.context
order = request.website.sale_get_order(force_create=1)
registrations = self._process_registration_details(post)
registration_ctx = dict(context, registration_force_draft=True)
for registration in registrations:
ticket = request.registry['event.event.ticket'].browse(cr, SUPERUSER_ID, int(registration['ticket_id']), context=context)
order.with_context(event_ticket_id=ticket.id)._cart_update(product_id=ticket.product_id.id, add_qty=1)
request.registry['event.registration'].create(cr, SUPERUSER_ID, {
'name': registration.get('name'),
'phone': registration.get('phone'),
'email': registration.get('email'),
'event_ticket_id': int(registration['ticket_id']),
'partner_id': order.partner_id.id,
'event_id': event.id,
'origin': order.name,
}, context=registration_ctx)
if not sale:
return request.redirect("/event/%s" % event_id)
return request.redirect("/shop/checkout")
def _add_event(self, event_name="New Event", context={}, **kwargs):
try:
dummy, res_id = request.registry.get('ir.model.data').get_object_reference(request.cr, request.uid, 'event_sale', 'product_product_event')
context['default_event_ticket_ids'] = [[0,0,{
context['default_event_ticket_ids'] = [[0, 0, {
'name': _('Subscription'),
'product_id': res_id,
'deadline' : False,
'deadline': False,
'seats_max': 1000,
'price': 0,
}]]
except ValueError:
pass
return super(website_event, self)._add_event(event_name, context, **kwargs)
@@ -13,24 +13,40 @@
},
{
waitNot: 'a[href*="/event"]:contains("Conference on Business Apps")',
title: "select 2 Standard tickets",
title: "select 1 Standard ticket",
element: 'select:eq(0)',
sampleText: '1',
},
{
title: "select 2 VIP tickets",
waitFor: 'select:eq(0) option:contains(1):selected',
element: 'select:eq(1)',
sampleText: '2',
},
{
title: "select 3 VIP tickets",
waitFor: 'select:eq(0) option:contains(2):selected',
element: 'select:eq(1)',
sampleText: '3',
},
{
title: "Order Now",
waitFor: 'select:eq(1) option:contains(3):selected',
waitFor: 'select:eq(1) option:contains(2):selected',
element: '.btn-primary:contains("Order Now")',
},
{
title: "Add the details of attendees",
waitFor: 'form[id="attendee_registration"] .btn:contains("Continue")',
autoComplete: function (tour) {
$("input[name='1-name']").val("Att1");
$("input[name='1-phone']").val("111 111");
$("input[name='1-email']").val("att1@example.com");
$("input[name='1-name']").val("Att2");
$("input[name='1-phone']").val("222 222");
$("input[name='1-email']").val("att2@example.com");
},
},
{
title: "click in modal on 'Continue' button",
element: '.modal button:contains("Continue")',
},
{
title: "Check the cart",
element: '#top_menu .my_cart_quantity:contains(5)'
element: '#top_menu .my_cart_quantity:contains(3)'
},
{
title: "Check if the cart have 2 order lines and add one VIP ticket",
@@ -39,7 +55,7 @@
},
{
title: "Process Checkout",
waitFor: '#top_menu .my_cart_quantity:contains(6)',
waitFor: '#top_menu .my_cart_quantity:contains(4)',
element: '.btn-primary:contains("Process Checkout")'
},
{
@@ -25,57 +25,61 @@
</xpath>
</template>
<template id="event_description_full" inherit_id="website_event.event_description_full" customize_show="True" name="Event's Ticket form">
<xpath expr="//div[@t-field='event.description']" position="before">
<form t-attf-action="/event/cart/update?event_id=#{ event.id }" method="post" t-if="event.event_ticket_ids">
<table itemprop="offers" class="table table-striped">
<thead>
<tr>
<th>Ticket Type</th>
<th style="min-width: 100px">Sales End</th>
<th style="min-width: 100px">Price</th>
<th></th>
<th>Quantity</th>
</tr>
</thead>
<tbody>
<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">
<div itemprop="name" t-field="ticket.name"/>
<div><small itemprop="description" t-field="ticket.product_id.description_sale"/></div>
</td>
<td><span itemprop="priceValidUntil" t-field="ticket.deadline"/></td>
<td>
<t t-if="ticket.price or editable"><span t-field="ticket.price" t-field-options='{
"widget": "monetary",
"display_currency": "website.pricelist_id.currency_id"
}'/>
<span itemprop="price" style="display:none;" t-esc="ticket.price"/>
<span itemprop="priceCurrency" style="display:none;" t-esc="website.pricelist_id.currency_id.name"/>
<template id="registration_template" inherit_id="website_event.registration_template" customize_show="True" name="Event's Ticket form">
<xpath expr="//tbody" position="replace">
<tbody>
<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">
<div itemprop="name" t-field="ticket.name"/>
<div><small itemprop="description" t-field="ticket.product_id.description_sale"/></div>
</td>
<td>
<t t-if="ticket.deadline">
<span itemprop="priceValidUntil" t-field="ticket.deadline"/>
</t>
<t t-if="not ticket.deadline">
<span>Unlimited</span>
</t>
</td>
<td>
<t t-if="ticket.price or editable"><span t-field="ticket.price" t-field-options='{
"widget": "monetary",
"display_currency": "website.pricelist_id.currency_id"
}'/>
<span itemprop="price" style="display:none;" t-esc="ticket.price"/>
<span itemprop="priceCurrency" style="display:none;" t-esc="website.pricelist_id.currency_id.name"/>
</t>
<t t-if="not ticket.price and not editable">
<span>Free</span>
</t>
</td>
<td>
<span t-if="ticket.seats_max and ((ticket.seats_reserved or 0)*100 / ticket.seats_max)&gt;75" class="text-muted">
<t t-esc="ticket.seats_max - ticket.seats_reserved"/> <span>left</span>
</span>
</td>
<td>
<select t-if="ticket.seats_available" t-attf-name="nb_register-#{ticket.id}" class="form-control">
<t t-foreach="range(0, ticket.seats_available > 9 and 10 or ticket.seats_available+1 )" t-as="nb">
<option t-esc="nb"/>
</t>
<t t-if="not ticket.price and not editable">
<span>Free</span>
</t>
</td>
<td>
<span t-if="ticket.seats_max and ((ticket.seats_reserved or 0)*100 / ticket.seats_max)&gt;75" class="text-muted">
<t t-esc="ticket.seats_max - ticket.seats_reserved"/> <span>left</span>
</span>
</td>
<td>
<select t-if="ticket.seats_available" t-attf-name="ticket-#{ ticket.id }" class="form-control">
<t t-foreach="range(0, ticket.seats_available > 9 and 10 or ticket.seats_available+1 )" t-as="nb"><option t-esc="nb"/></t>
</select>
<span t-if="not ticket.seats_available">Sold Out</span>
</td>
</tr>
</t>
</tbody>
</table>
<button type="submit" class="btn btn-primary btn-lg pull-right" t-if="event.seats_available">Order Now</button>
<div class="clearfix"/>
<hr/>
</select>
<span t-if="not ticket.seats_available">Sold Out</span>
</td>
</tr>
</t>
</tbody>
</xpath>
<xpath expr="//button[@type='submit']" position="replace">
<button type="submit" t-if="event.seats_available" class="btn btn-primary btn-lg pull-right a-submit" t-attf-id="#{event.id}">Order Now</button>
<form t-if="not event.event_ticket_ids">
<div class="alert alert-info">
Event registration not yet started.
<t t-if="uid">
<i class="fa fa-plus-circle"><a t-attf-href="/web#id=#{event.id}&amp;view_type=form&amp;model=event.event"> <em>Configure Event Registration</em></a></i>
</t>
</div>
</form>
</xpath>
</template>