# -*- coding: utf-8 -*-
-##############################################################################
-#
-# OpenERP, Open Source Management Solution
-# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Affero General Public License as
-# published by the Free Software Foundation, either version 3 of the
-# License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Affero General Public License for more details.
-#
-# You should have received a copy of the GNU Affero General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-#
-##############################################################################
-import event_sale
+import models
# -*- coding: utf-8 -*-
-##############################################################################
-#
-# OpenERP, Open Source Management Solution
-# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Affero General Public License as
-# published by the Free Software Foundation, either version 3 of the
-# License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Affero General Public License for more details.
-#
-# You should have received a copy of the GNU Affero General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-#
-##############################################################################
-
{
'name': 'Events Sales',
- 'version': '0.1',
+ 'version': '1.1',
'category': 'Tools',
- 'website' : 'https://www.odoo.com/page/events',
+ 'website': 'https://www.odoo.com/page/events',
'description': """
Creating registration with sale orders.
=======================================
'author': 'OpenERP SA',
'depends': ['event', 'sale_crm'],
'data': [
- 'event_sale_view.xml',
+ 'views/event.xml',
+ 'views/product.xml',
+ 'views/sale_order.xml',
'event_sale_data.xml',
'event_sale_report.xml',
'views/report_registrationbadge.xml',
'installable': True,
'auto_install': True
}
-# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
<field name="standard_price">1000.0</field>
<field name="uom_id" ref="product.product_uom_unit"/>
<field name="uom_po_id" ref="product.product_uom_unit"/>
- <field name="image">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</field>
+ <field name="image" type="base64" file="event_sale/static/img/event_product-image.jpg"/>
</record>
<record id="event_1_product" model="product.product">
<field name="standard_price">1000.0</field>
<field name="uom_id" ref="product.product_uom_unit"/>
<field name="uom_po_id" ref="product.product_uom_unit"/>
- <field name="image">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</field>
+ <field name="image" type="base64" file="event_sale/static/img/event_product-image.jpg"/>
</record>
<record id="event_2_product" model="product.product">
<field name="standard_price">1000.0</field>
<field name="uom_id" ref="product.product_uom_unit"/>
<field name="uom_po_id" ref="product.product_uom_unit"/>
- <field name="image">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</field>
+ <field name="image" type="base64" file="event_sale/static/img/event_product-image.jpg"/>
</record>
<record id="event.event_3" model="event.event">
+++ /dev/null
-# -*- coding: utf-8 -*-
-##############################################################################
-#
-# OpenERP, Open Source Management Solution
-# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Affero General Public License as
-# published by the Free Software Foundation, either version 3 of the
-# License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Affero General Public License for more details.
-#
-# You should have received a copy of the GNU Affero General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-#
-##############################################################################
-
-from openerp import api
-from openerp.fields import Integer, One2many, Html
-from openerp.osv import fields, osv
-from openerp.tools.translate import _
-
-class product_template(osv.osv):
- _inherit = 'product.template'
- _columns = {
- 'event_ok': fields.boolean('Event Subscription', help='Determine if a product needs to create automatically an event registration at the confirmation of a sales order line.'),
- 'event_type_id': fields.many2one('event.type', 'Type of Event', help='Select event types so when we use this product in sales order lines, it will filter events of this type only.'),
- }
-
- def onchange_event_ok(self, cr, uid, ids, type, event_ok, context=None):
- if event_ok:
- return {'value': {'type': 'service'}}
- return {}
-
-class product(osv.osv):
- _inherit = 'product.product'
- _columns = {
- 'event_ticket_ids': fields.one2many('event.event.ticket', 'product_id', 'Event Tickets'),
- }
-
- def onchange_event_ok(self, cr, uid, ids, type, event_ok, context=None):
- # cannot directly forward to product.template as the ids are theoretically different
- if event_ok:
- return {'value': {'type': 'service'}}
- return {}
-
-
-class sale_order_line(osv.osv):
- _inherit = 'sale.order.line'
- _columns = {
- 'event_id': fields.many2one('event.event', 'Event',
- help="Choose an event and it will automatically create a registration for this event."),
- 'event_ticket_id': fields.many2one('event.event.ticket', 'Event Ticket',
- help="Choose an event ticket and it will automatically create a registration for this event ticket."),
- #those 2 fields are used for dynamic domains and filled by onchange
- 'event_type_id': fields.related('product_id','event_type_id', type='many2one', relation="event.type", string="Event Type"),
- 'event_ok': fields.related('product_id', 'event_ok', string='event_ok', type='boolean'),
- }
-
- def product_id_change(self, cr, uid, ids,
- pricelist,
- product,
- qty=0,
- uom=False,
- qty_uos=0,
- uos=False,
- name='',
- partner_id=False,
- lang=False,
- update_tax=True,
- date_order=False,
- packaging=False,
- fiscal_position=False,
- flag=False, context=None):
- """
- check product if event type
- """
- res = super(sale_order_line,self).product_id_change(cr, uid, ids, pricelist, product, qty=qty, uom=uom, qty_uos=qty_uos, uos=uos, name=name, partner_id=partner_id, lang=lang, update_tax=update_tax, date_order=date_order, packaging=packaging, fiscal_position=fiscal_position, flag=flag, context=context)
- if product:
- product_res = self.pool.get('product.product').browse(cr, uid, product, context=context)
- if product_res.event_ok:
- res['value'].update(event_type_id=product_res.event_type_id.id,
- event_ok=product_res.event_ok)
- else:
- res['value'].update(event_type_id=False,
- event_ok=False)
- return res
-
- def button_confirm(self, cr, uid, ids, context=None):
- '''
- 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)
-
- def onchange_event_ticket_id(self, cr, uid, ids, event_ticket_id=False, context=None):
- price = event_ticket_id and self.pool.get("event.event.ticket").browse(cr, uid, event_ticket_id, context=context).price or False
- return {'value': {'price_unit': price}}
-
-
-class event_event(osv.osv):
- _inherit = 'event.event'
-
- event_ticket_ids = One2many('event.event.ticket', 'event_id', string='Event Ticket',
- default=lambda rec: rec._default_tickets())
- seats_max = Integer(string='Maximum Available Seats',
- help="The maximum registration level is equal to the sum of the maximum registration of event ticket. " +
- "If you have too much registrations you are not able to confirm your event. (0 to ignore this rule )",
- store=True, readonly=True, compute='_compute_seats_max')
-
- badge_back = Html('Badge Back', translate=True, states={'done': [('readonly', True)]})
- badge_innerleft = Html('Badge Innner Left', translate=True, states={'done': [('readonly', True)]})
- badge_innerright = Html('Badge Inner Right', translate=True, states={'done': [('readonly', True)]})
-
- @api.model
- def _default_tickets(self):
- try:
- product = self.env.ref('event_sale.product_product_event')
- return [{
- 'name': _('Subscription'),
- 'product_id': product.id,
- 'price': 0,
- }]
- except ValueError:
- return self.env['event.event.ticket']
-
- @api.one
- @api.depends('event_ticket_ids.seats_max')
- def _compute_seats_max(self):
- self.seats_max = sum(ticket.seats_max for ticket in self.event_ticket_ids)
-
-class event_ticket(osv.osv):
- _name = 'event.event.ticket'
-
- def _get_seats(self, cr, uid, ids, fields, args, context=None):
- """Get reserved, available, reserved but unconfirmed and used seats for each event tickets.
- @return: Dictionary of function field values.
- """
- res = dict([(id, {}) for id in ids])
- for ticket in self.browse(cr, uid, ids, context=context):
- res[ticket.id]['seats_reserved'] = sum(reg.nb_register for reg in ticket.registration_ids if reg.state == "open")
- res[ticket.id]['seats_used'] = sum(reg.nb_register for reg in ticket.registration_ids if reg.state == "done")
- res[ticket.id]['seats_unconfirmed'] = sum(reg.nb_register for reg in ticket.registration_ids if reg.state == "draft")
- res[ticket.id]['seats_available'] = ticket.seats_max - \
- (res[ticket.id]['seats_reserved'] + res[ticket.id]['seats_used']) \
- if ticket.seats_max > 0 else None
- return res
-
- def _is_expired(self, cr, uid, ids, field_name, args, context=None):
- # FIXME: A ticket is considered expired when the deadline is passed. The deadline should
- # be considered in the timezone of the event, not the timezone of the user!
- # Until we add a TZ on the event we'll use the context's current date, more accurate
- # than using UTC all the time.
- current_date = fields.date.context_today(self, cr, uid, context=context)
- return {ticket.id: ticket.deadline and ticket.deadline < current_date
- for ticket in self.browse(cr, uid, ids, context=context)}
-
-
- _columns = {
- 'name': fields.char('Name', required=True, translate=True),
- 'event_id': fields.many2one('event.event', "Event", required=True, ondelete='cascade'),
- 'product_id': fields.many2one('product.product', 'Product', required=True, domain=[("event_type_id", "!=", False)]),
- 'registration_ids': fields.one2many('event.registration', 'event_ticket_id', 'Registrations'),
- 'deadline': fields.date("Sales End"),
- 'is_expired': fields.function(_is_expired, type='boolean', string='Is Expired'),
- 'price': fields.float('Price'),
- 'seats_max': fields.integer('Maximum Available Seats', oldname='register_max', help="You can for each event define a maximum registration level. If you have too much registrations you are not able to confirm your event. (put 0 to ignore this rule )"),
- 'seats_reserved': fields.function(_get_seats, string='Reserved Seats', type='integer', multi='seats_reserved'),
- 'seats_available': fields.function(_get_seats, string='Available Seats', type='integer', multi='seats_reserved'),
- 'seats_unconfirmed': fields.function(_get_seats, string='Unconfirmed Seat Reservations', type='integer', multi='seats_reserved'),
- 'seats_used': fields.function(_get_seats, string='Number of Participations', type='integer', multi='seats_reserved'),
- }
-
- def _default_product_id(self, cr, uid, context={}):
- imd = self.pool.get('ir.model.data')
- try:
- product = imd.get_object(cr, uid, 'event_sale', 'product_product_event')
- except ValueError:
- return False
- return product.id
-
- _defaults = {
- 'product_id': _default_product_id
- }
-
- def _check_seats_limit(self, cr, uid, ids, context=None):
- for ticket in self.browse(cr, uid, ids, context=context):
- if ticket.seats_max and ticket.seats_available < 0:
- return False
- return True
-
- _constraints = [
- (_check_seats_limit, 'No more available tickets.', ['registration_ids','seats_max']),
- ]
-
- def onchange_product_id(self, cr, uid, ids, product_id=False, context=None):
- price = self.pool.get("product.product").browse(cr, uid, product_id).list_price if product_id else 0
- return {'value': {'price': price}}
-
-
-class event_registration(osv.osv):
- """Event Registration"""
- _inherit= 'event.registration'
- _columns = {
- 'event_ticket_id': fields.many2one('event.event.ticket', 'Event Ticket'),
- }
-
- def _check_ticket_seats_limit(self, cr, uid, ids, context=None):
- for registration in self.browse(cr, uid, ids, context=context):
- if registration.event_ticket_id.seats_max and registration.event_ticket_id.seats_available < 0:
- return False
- return True
-
- _constraints = [
- (_check_ticket_seats_limit, 'No more available tickets.', ['event_ticket_id','nb_register','state']),
- ]
+++ /dev/null
-<?xml version="1.0"?>
-<openerp>
- <data>
-
- <record model="ir.ui.view" id="event_sale_product_template_form">
- <field name="model">product.template</field>
- <field name="inherit_id" ref="product.product_template_form_view" />
- <field name="arch" type="xml">
- <div name="options" position="inside">
- <div>
- <field name="event_ok" on_change="onchange_event_ok(type, event_ok, context)"/>
- <label for="event_ok"/>
- </div>
- </div>
- <field name='type' position="after">
- <field name="event_type_id" attrs="{'invisible': [('event_ok', '=', False)]}"/>
- </field>
- </field>
- </record>
-
- <record model="ir.ui.view" id="view_event_registration_ticket_search">
- <field name="name">event.registration.ticket.search</field>
- <field name="model">event.registration</field>
- <field name="inherit_id" ref="event.view_registration_search" />
- <field name="arch" type="xml">
- <filter name="group_event" position="after">
- <filter string="Ticket Type" domain="[]" context="{'group_by':'event_ticket_id'}"/>
- </filter>
- </field>
- </record>
-
- <record model="ir.ui.view" id="view_event_registration_ticket_tree">
- <field name="name">event.registration.ticket.tree</field>
- <field name="model">event.registration</field>
- <field name="inherit_id" ref="event.view_event_registration_tree" />
- <field name="arch" type="xml">
- <field name="event_id" position="after">
- <field name="event_ticket_id"/>
- </field>
- </field>
- </record>
-
- <record model="ir.ui.view" id="view_event_registration_ticket_form">
- <field name="name">event.registration.ticket.form</field>
- <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_ticket_id" domain="[('event_id', '=', event_id)]"/>
- </field>
- </field>
- </record>
-
- <record model="ir.ui.view" id="event_order_line">
- <field name="name">event.sale.order</field>
- <field name="model">sale.order</field>
- <field name="inherit_id" ref="sale.view_order_form" />
- <field name="arch" type="xml">
- <xpath expr="//field[@name='product_id']" position="after">
- <field name="event_id" domain="['|', ('type','=', False),('type', '=', event_type_id)]" attrs="{'invisible': [('event_ok', '=', False)],'required': [('event_ok', '!=', False)]}"/>
- <field name="event_ticket_id" domain="[('event_id', '=', event_id), ('seats_available', '>', 0)]" attrs="{'invisible': [('event_id', '=', False)]}"
- on_change="onchange_event_ticket_id(event_ticket_id, context)"/>
- <field name="event_type_id" invisible="1"/>
- <field name="event_ok" invisible="1"/>
- </xpath>
- </field>
- </record>
-
- <!-- the presence of 'event user' makes the order lines non-editable -->
- <record id="sale.view_order_form_editable_list" model="ir.ui.view">
- <field name="groups_id" eval="[(4, ref('event.group_event_user'))]"/>
- </record>
-
- <record id="view_event_form" model="ir.ui.view">
- <field name="name">view_event_form</field>
- <field name="model">event.event</field>
- <field name="inherit_id" ref="event.view_event_form"/>
- <field name="arch" type="xml">
- <data>
- <xpath expr="//notebook" position="inside">
- <page string="Ticket Types">
- <field name="event_ticket_ids" context="{'default_name': name}">
- <tree string="Payments" editable="bottom">
- <field name="name"/>
- <field name="product_id" on_change='onchange_product_id(product_id)'/>
- <field name="deadline"/>
- <field name="price"/>
- <field name="seats_max"/>
- <field name="seats_reserved"/>
- <field name="seats_unconfirmed"/>
- </tree>
- </field>
- </page>
- </xpath>
- </data>
- </field>
- </record>
-
- <!-- Edit badge report form -->
- <record id="view_event_form" model="ir.ui.view">
- <field name="name">view_event_form</field>
- <field name="model">event.event</field>
- <field name="inherit_id" ref="event.view_event_form"/>
- <field name="arch" type="xml">
- <data>
- <xpath expr="//notebook" position="inside">
- <page string="Ticket Types">
- <field name="event_ticket_ids" context="{'default_name': name}">
- <tree string="Payments" editable="bottom">
- <field name="name"/>
- <field name="product_id" on_change='onchange_product_id(product_id)'/>
- <field name="deadline"/>
- <field name="price"/>
- <field name="seats_max"/>
- <field name="seats_reserved"/>
- <field name="seats_unconfirmed"/>
- </tree>
- </field>
- </page>
- </xpath>
- </data>
- </field>
- </record>
- </data>
-</openerp>
--- /dev/null
+# -*- coding: utf-8 -*-
+
+import sale_order
+import product
+import event
--- /dev/null
+# -*- coding: utf-8 -*-
+
+from openerp import models, fields, api, _
+from openerp.exceptions import Warning
+
+
+class event_event(models.Model):
+ _inherit = 'event.event'
+
+ event_ticket_ids = fields.One2many(
+ 'event.event.ticket', 'event_id', string='Event Ticket',
+ default=lambda rec: rec._default_tickets())
+ seats_max = fields.Integer(
+ string='Maximum Available Seats',
+ help="The maximum registration level is equal to the sum of the maximum registration of event ticket. " +
+ "If you have too much registrations you are not able to confirm your event. (0 to ignore this rule )",
+ store=True, readonly=True, compute='_compute_seats_max')
+
+ badge_back = fields.Html('Badge Back', translate=True, states={'done': [('readonly', True)]})
+ badge_innerleft = fields.Html('Badge Innner Left', translate=True, states={'done': [('readonly', True)]})
+ badge_innerright = fields.Html('Badge Inner Right', translate=True, states={'done': [('readonly', True)]})
+
+ @api.model
+ def _default_tickets(self):
+ try:
+ product = self.env.ref('event_sale.product_product_event')
+ return [{
+ 'name': _('Subscription'),
+ 'product_id': product.id,
+ 'price': 0,
+ }]
+ except ValueError:
+ return self.env['event.event.ticket']
+
+ @api.one
+ @api.depends('event_ticket_ids.seats_max')
+ def _compute_seats_max(self):
+ self.seats_max = sum(ticket.seats_max for ticket in self.event_ticket_ids)
+
+
+class event_ticket(models.Model):
+ _name = 'event.event.ticket'
+ _description = 'Event Ticket'
+
+ name = fields.Char('Name', required=True, translate=True)
+ event_id = fields.Many2one('event.event', "Event", required=True, ondelete='cascade')
+ product_id = fields.Many2one(
+ 'product.product', 'Product',
+ required=True, domain=[("event_type_id", "!=", False)],
+ default=lambda self: self._default_product_id())
+ registration_ids = fields.One2many('event.registration', 'event_ticket_id', 'Registrations')
+ price = fields.Float('Price')
+ deadline = fields.Date("Sales End")
+ is_expired = fields.Boolean('Is Expired', compute='_is_expired', store=True)
+
+ @api.model
+ def _default_product_id(self):
+ try:
+ product = self.env['ir.model.data'].get_object('event_sale', 'product_product_event')
+ return product.id
+ except ValueError:
+ return False
+
+ @api.one
+ @api.depends('deadline')
+ def _is_expired(self):
+ # FIXME: A ticket is considered expired when the deadline is passed. The deadline should
+ # be considered in the timezone of the event, not the timezone of the user!
+ # Until we add a TZ on the event we'll use the context's current date, more accurate
+ # than using UTC all the time.
+ current_date = fields.Date.context_today(self.with_context({'tz': self.event_id.date_tz}))
+ self.is_expired = self.deadline < current_date
+
+ seats_max = fields.Integer('Maximum Available Seats', help="You can for each event define a maximum registration level. If you have too much registrations you are not able to confirm your event. (put 0 to ignore this rule )")
+ seats_reserved = fields.Integer(string='Reserved Seats', compute='_compute_seats', store=True)
+ seats_available = fields.Integer(string='Available Seats', compute='_compute_seats', store=True)
+ seats_unconfirmed = fields.Integer(string='Unconfirmed Seat Reservations', compute='_compute_seats', store=True)
+ seats_used = fields.Integer(compute='_compute_seats', store=True)
+
+ @api.multi
+ @api.depends('seats_max', 'registration_ids.state', 'registration_ids.nb_register')
+ def _compute_seats(self):
+ """ Determine reserved, available, reserved but unconfirmed and used seats. """
+ # initialize fields to 0
+ for ticket in self:
+ ticket.seats_unconfirmed = ticket.seats_reserved = ticket.seats_used = ticket.seats_available = 0
+ # aggregate registrations by ticket and by state
+ if self.ids:
+ state_field = {
+ 'draft': 'seats_unconfirmed',
+ 'open': 'seats_reserved',
+ 'done': 'seats_used',
+ }
+ query = """ SELECT event_ticket_id, state, sum(nb_register)
+ FROM event_registration
+ WHERE event_ticket_id IN %s AND state IN ('draft', 'open', 'done')
+ GROUP BY event_ticket_id, state
+ """
+ self._cr.execute(query, (tuple(self.ids),))
+ for event_ticket_id, state, num in self._cr.fetchall():
+ ticket = self.browse(event_ticket_id)
+ ticket[state_field[state]] += num
+ # compute seats_available
+ for ticket in self:
+ if ticket.seats_max > 0:
+ ticket.seats_available = ticket.seats_max - (ticket.seats_reserved + ticket.seats_used)
+
+ @api.one
+ @api.constrains('registration_ids', 'seats_max')
+ def _check_seats_limit(self):
+ if self.seats_max and self.seats_available < 0:
+ raise Warning('No more available seats for the ticket')
+
+ @api.onchange('product_id')
+ def onchange_product_id(self):
+ price = self.product_id.list_price if self.product_id else 0
+ return {'value': {'price': price}}
+
+
+class event_registration(models.Model):
+ _inherit = 'event.registration'
+
+ event_ticket_id = fields.Many2one('event.event.ticket', 'Event Ticket')
+
+ @api.one
+ @api.constrains('event_ticket_id', 'nb_register', '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')
--- /dev/null
+# -*- coding: utf-8 -*-
+
+from openerp.osv import fields, osv
+
+
+class product_template(osv.osv):
+ _inherit = 'product.template'
+ _columns = {
+ 'event_ok': fields.boolean('Event Subscription', help='Determine if a product needs to create automatically an event registration at the confirmation of a sales order line.'),
+ 'event_type_id': fields.many2one('event.type', 'Type of Event', help='Select event types so when we use this product in sales order lines, it will filter events of this type only.'),
+ }
+
+ def onchange_event_ok(self, cr, uid, ids, type, event_ok, context=None):
+ if event_ok:
+ return {'value': {'type': 'service'}}
+ return {}
+
+
+class product(osv.osv):
+ _inherit = 'product.product'
+ _columns = {
+ 'event_ticket_ids': fields.one2many('event.event.ticket', 'product_id', 'Event Tickets'),
+ }
+
+ def onchange_event_ok(self, cr, uid, ids, type, event_ok, context=None):
+ """ Redirection, inheritance mechanism hides the method on the model """
+ if event_ok:
+ return {'value': {'type': 'service'}}
+ return {}
--- /dev/null
+# -*- coding: utf-8 -*-
+
+from openerp.osv import fields, osv
+from openerp.tools.translate import _
+
+
+class sale_order_line(osv.osv):
+ _inherit = 'sale.order.line'
+ _columns = {
+ 'event_id': fields.many2one(
+ 'event.event', 'Event',
+ help="Choose an event and it will automatically create a registration for this event."),
+ 'event_ticket_id': fields.many2one(
+ 'event.event.ticket', 'Event Ticket',
+ help="Choose an event ticket and it will automatically create a registration for this event ticket."),
+ # those 2 fields are used for dynamic domains and filled by onchange
+ # TDE: really necessary ? ...
+ 'event_type_id': fields.related('product_id', 'event_type_id', type='many2one', relation="event.type", string="Event Type"),
+ 'event_ok': fields.related('product_id', 'event_ok', string='event_ok', type='boolean'),
+ }
+
+ def product_id_change(self, cr, uid, ids, pricelist, product, qty=0, uom=False,
+ qty_uos=0, uos=False, name='', partner_id=False, lang=False,
+ update_tax=True, date_order=False, packaging=False,
+ fiscal_position=False, flag=False, context=None):
+ """ check product if event type """
+ res = super(sale_order_line, self).product_id_change(cr, uid, ids, pricelist, product, qty=qty, uom=uom, qty_uos=qty_uos, uos=uos, name=name, partner_id=partner_id, lang=lang, update_tax=update_tax, date_order=date_order, packaging=packaging, fiscal_position=fiscal_position, flag=flag, context=context)
+ if product:
+ product_res = self.pool.get('product.product').browse(cr, uid, product, context=context)
+ if product_res.event_ok:
+ res['value'].update(event_type_id=product_res.event_type_id.id,
+ event_ok=product_res.event_ok)
+ else:
+ res['value'].update(event_type_id=False,
+ event_ok=False)
+ return res
+
+ def button_confirm(self, cr, uid, ids, context=None):
+ '''
+ 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)
+
+ 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
+ return {'value': {'price_unit': price}}
--- /dev/null
+<?xml version="1.0"?>
+<openerp>
+ <data>
+
+ <record model="ir.ui.view" id="view_event_registration_ticket_search">
+ <field name="name">event.registration.ticket.search</field>
+ <field name="model">event.registration</field>
+ <field name="inherit_id" ref="event.view_registration_search" />
+ <field name="arch" type="xml">
+ <filter name="group_event" position="after">
+ <filter string="Ticket Type" domain="[]" context="{'group_by':'event_ticket_id'}"/>
+ </filter>
+ </field>
+ </record>
+
+ <record model="ir.ui.view" id="view_event_registration_ticket_tree">
+ <field name="name">event.registration.ticket.tree</field>
+ <field name="model">event.registration</field>
+ <field name="inherit_id" ref="event.view_event_registration_tree" />
+ <field name="arch" type="xml">
+ <field name="event_id" position="after">
+ <field name="event_ticket_id"/>
+ </field>
+ </field>
+ </record>
+
+ <record model="ir.ui.view" id="view_event_registration_ticket_form">
+ <field name="name">event.registration.ticket.form</field>
+ <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_ticket_id" domain="[('event_id', '=', event_id)]"/>
+ </field>
+ </field>
+ </record>
+
+ <record id="view_event_form" model="ir.ui.view">
+ <field name="name">view_event_form</field>
+ <field name="model">event.event</field>
+ <field name="inherit_id" ref="event.view_event_form"/>
+ <field name="arch" type="xml">
+ <data>
+ <xpath expr="//notebook" position="inside">
+ <page string="Ticket Types">
+ <field name="event_ticket_ids" context="{'default_name': name}">
+ <tree string="Payments" editable="bottom">
+ <field name="name"/>
+ <field name="product_id"/>
+ <field name="deadline"/>
+ <field name="price"/>
+ <field name="seats_max"/>
+ <field name="seats_reserved"/>
+ <field name="seats_unconfirmed"/>
+ </tree>
+ </field>
+ </page>
+ </xpath>
+ </data>
+ </field>
+ </record>
+
+ <!-- Edit badge report form -->
+ <record id="view_event_form" model="ir.ui.view">
+ <field name="name">view_event_form</field>
+ <field name="model">event.event</field>
+ <field name="inherit_id" ref="event.view_event_form"/>
+ <field name="arch" type="xml">
+ <data>
+ <xpath expr="//notebook" position="inside">
+ <page string="Ticket Types">
+ <field name="event_ticket_ids" context="{'default_name': name}">
+ <tree string="Payments" editable="bottom">
+ <field name="name"/>
+ <field name="product_id"/>
+ <field name="deadline"/>
+ <field name="price"/>
+ <field name="seats_max"/>
+ <field name="seats_reserved"/>
+ <field name="seats_unconfirmed"/>
+ </tree>
+ </field>
+ </page>
+ </xpath>
+ </data>
+ </field>
+ </record>
+ </data>
+</openerp>
--- /dev/null
+<?xml version="1.0"?>
+<openerp>
+ <data>
+ <record model="ir.ui.view" id="event_sale_product_template_form">
+ <field name="model">product.template</field>
+ <field name="inherit_id" ref="product.product_template_form_view" />
+ <field name="arch" type="xml">
+ <div name="options" position="inside">
+ <div>
+ <field name="event_ok" on_change="onchange_event_ok(type, event_ok, context)"/>
+ <label for="event_ok"/>
+ </div>
+ </div>
+ <field name='type' position="after">
+ <field name="event_type_id" attrs="{'invisible': [('event_ok', '=', False)]}"/>
+ </field>
+ </field>
+ </record>
+ </data>
+</openerp>
--- /dev/null
+<?xml version="1.0"?>
+<openerp>
+ <data>
+ <record model="ir.ui.view" id="event_order_line">
+ <field name="name">event.sale.order</field>
+ <field name="model">sale.order</field>
+ <field name="inherit_id" ref="sale.view_order_form" />
+ <field name="arch" type="xml">
+ <xpath expr="//field[@name='product_id']" position="after">
+ <field name="event_id" domain="['|', ('type','=', False),('type', '=', event_type_id)]" attrs="{'invisible': [('event_ok', '=', False)],'required': [('event_ok', '!=', False)]}"/>
+ <field name="event_ticket_id" domain="[('event_id', '=', event_id), ('seats_available', '>', 0)]" attrs="{'invisible': [('event_id', '=', False)]}"
+ on_change="onchange_event_ticket_id(event_ticket_id, context)"/>
+ <field name="event_type_id" invisible="1"/>
+ <field name="event_ok" invisible="1"/>
+ </xpath>
+ </field>
+ </record>
+
+ <!-- the presence of 'event user' makes the order lines non-editable -->
+ <record id="sale.view_order_form_editable_list" model="ir.ui.view">
+ <field name="groups_id" eval="[(4, ref('event.group_event_user'))]"/>
+ </record>
+ </data>
+</openerp>