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.
'res_config_view.xml',
'email_template.xml',
'views/event.xml',
+ 'event_report.xml',
+ 'views/report_registrationbadge.xml',
],
'demo': [
'event_demo.xml',
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
'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
# 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')
""" 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:
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)]})
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
@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
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
<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">
<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">
<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>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<openerp>
+ <data>
+
+ <record id="paperformat_euro_lowmargin" model="report.paperformat">
+ <field name="name">European A4 low margin</field>
+ <field name="default" eval="True" />
+ <field name="format">A4</field>
+ <field name="page_height">0</field>
+ <field name="page_width">0</field>
+ <field name="orientation">Portrait</field>
+ <field name="margin_top">5</field>
+ <field name="margin_bottom">5</field>
+ <field name="margin_left">5</field>
+ <field name="margin_right">5</field>
+ <field name="header_line" eval="False" />
+ <field name="header_spacing">0</field>
+ <field name="dpi">80</field>
+ </record>
+
+ <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>
<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>
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">
<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 ">/
- <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 ">/
+ <t t-esc="record.seats_reserved.raw_value + record.seats_unconfirmed.raw_value"/> Expected
<a name="action_event_registration_report" type="object" >(Report)</a>
</t>
</h4>
<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>
<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>
<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>
<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>
<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'}"/>
</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>
<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"/>
_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')
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)
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,
GROUP BY
event_id,
- user_id_registration,
r.id,
registration_state,
- r.nb_register,
event_type,
e.id,
e.date_begin,
'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')
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()
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
--- /dev/null
+<?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>
# -*- coding: utf-8 -*-
import models
+import wizard
'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'],
+++ /dev/null
-<?xml version="1.0" encoding="utf-8"?>
-<openerp>
- <data>
-
- <record id="paperformat_euro_lowmargin" model="report.paperformat">
- <field name="name">European A4 low margin</field>
- <field name="default" eval="True" />
- <field name="format">A4</field>
- <field name="page_height">0</field>
- <field name="page_width">0</field>
- <field name="orientation">Portrait</field>
- <field name="margin_top">5</field>
- <field name="margin_bottom">5</field>
- <field name="margin_left">5</field>
- <field name="margin_right">5</field>
- <field name="header_line" eval="False" />
- <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"/>
- </record>
-
- </data>
-</openerp>
\ No newline at end of file
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
'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
_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
# -*- 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):
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
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
\ No newline at end of file
+access_event_event_ticket_admin,event.event.ticket.admin,event_sale.model_event_event_ticket,event.group_event_manager,1,1,1,1
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."))
-
<field name="arch" type="xml">
<field name="event_id" position="after">
<field name="event_ticket_id"/>
+ <field name="origin"/>
</field>
</field>
</record>
<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>
<?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>
--- /dev/null
+import event_edit_registration
--- /dev/null
+# -*- 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,
+ }
--- /dev/null
+<?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>
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'})
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 _
'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)
"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,
+ })
# from openerp.osv import osv, fields
from openerp import SUPERUSER_ID
+from openerp.models import NewId
# from openerp.tools.translate import _
import re
@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')
--- /dev/null
+$(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');
+ });
+ });
+ });
+});
<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>
<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">
</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>
</xpath>
</template>
+<!-- Misc templates -->
<template id="country_events_list" name="Country">
<t t-ignore="true">
<t t-if="events">
{
'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',
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):
+ 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
+ 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
- ticket_obj = request.registry.get('event.event.ticket')
+ order = request.website.sale_get_order(force_create=1)
- sale = False
- for key, value in post.items():
- quantity = int(value or "0")
- if not quantity:
- 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)
+ 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)
-
-
-
},
{
waitNot: 'a[href*="/event"]:contains("Conference on Business Apps")',
- title: "select 2 Standard tickets",
+ title: "select 1 Standard ticket",
element: 'select:eq(0)',
- sampleText: '2',
+ sampleText: '1',
},
{
- title: "select 3 VIP tickets",
- waitFor: 'select:eq(0) option:contains(2):selected',
+ title: "select 2 VIP tickets",
+ waitFor: 'select:eq(0) option:contains(1):selected',
element: 'select:eq(1)',
- sampleText: '3',
+ sampleText: '2',
},
{
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",
},
{
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")'
},
{
</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)>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)>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}&view_type=form&model=event.event"> <em>Configure Event Registration</em></a></i>
+ </t>
+ </div>
</form>
</xpath>
</template>