1 # -*- coding: utf-8 -*-
3 from openerp import models, fields, api, _
4 import openerp.addons.decimal_precision as dp
5 from openerp.exceptions import Warning
6 from openerp.osv import fields as old_fields
9 class event_event(models.Model):
10 _inherit = 'event.event'
12 event_ticket_ids = fields.One2many(
13 'event.event.ticket', 'event_id', string='Event Ticket',
14 default=lambda rec: rec._default_tickets(), copy=True)
15 seats_max = fields.Integer(
16 string='Maximum Available Seats',
17 help="The maximum registration level is equal to the sum of the maximum registration of event ticket. " +
18 "If you have too much registrations you are not able to confirm your event. (0 to ignore this rule )",
19 store=True, readonly=True, compute='_compute_seats_max')
21 badge_back = fields.Html('Badge Back', translate=True, states={'done': [('readonly', True)]})
22 badge_innerleft = fields.Html('Badge Innner Left', translate=True, states={'done': [('readonly', True)]})
23 badge_innerright = fields.Html('Badge Inner Right', translate=True, states={'done': [('readonly', True)]})
26 def _default_tickets(self):
28 product = self.env.ref('event_sale.product_product_event')
30 'name': _('Subscription'),
31 'product_id': product.id,
35 return self.env['event.event.ticket']
38 @api.depends('event_ticket_ids.seats_max')
39 def _compute_seats_max(self):
40 self.seats_max = sum(ticket.seats_max for ticket in self.event_ticket_ids)
43 class event_ticket(models.Model):
44 _name = 'event.event.ticket'
45 _description = 'Event Ticket'
47 name = fields.Char('Name', required=True, translate=True)
48 event_id = fields.Many2one('event.event', "Event", required=True, ondelete='cascade')
49 product_id = fields.Many2one(
50 'product.product', 'Product',
51 required=True, domain=[("event_type_id", "!=", False)],
52 default=lambda self: self._default_product_id())
53 registration_ids = fields.One2many('event.registration', 'event_ticket_id', 'Registrations')
54 price = fields.Float('Price', digits=dp.get_precision('Product Price'))
55 deadline = fields.Date("Sales End")
56 is_expired = fields.Boolean('Is Expired', compute='_is_expired', store=True)
59 def _default_product_id(self):
61 product = self.env['ir.model.data'].get_object('event_sale', 'product_product_event')
67 @api.depends('deadline')
68 def _is_expired(self):
69 # FIXME: A ticket is considered expired when the deadline is passed. The deadline should
70 # be considered in the timezone of the event, not the timezone of the user!
71 # Until we add a TZ on the event we'll use the context's current date, more accurate
72 # than using UTC all the time.
73 current_date = fields.Date.context_today(self.with_context({'tz': self.event_id.date_tz}))
74 self.is_expired = self.deadline < current_date
76 # FIXME non-stored fields wont ends up in _columns (and thus _all_columns), which forbid them
77 # to be used in qweb views. Waiting a fix, we create an old function field directly.
79 price_reduce = fields.Float("Price Reduce", compute="_get_price_reduce", store=False,
80 digits=dp.get_precision('Product Price'))
82 @api.depends('price', 'product_id.lst_price', 'product_id.price')
83 def _get_price_reduce(self):
84 product = self.product_id
85 discount = product.lst_price and (product.lst_price - product.price) / product.lst_price or 0.0
86 self.price_reduce = (1.0 - discount) * self.price
88 def _get_price_reduce(self, cr, uid, ids, field_name, arg, context=None):
89 res = dict.fromkeys(ids, 0.0)
90 for ticket in self.browse(cr, uid, ids, context=context):
91 product = ticket.product_id
92 discount = product.lst_price and (product.lst_price - product.price) / product.lst_price or 0.0
93 res[ticket.id] = (1.0 - discount) * ticket.price
97 'price_reduce': old_fields.function(_get_price_reduce, type='float', string='Price Reduce',
98 digits_compute=dp.get_precision('Product Price')),
102 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 )")
103 seats_reserved = fields.Integer(string='Reserved Seats', compute='_compute_seats', store=True)
104 seats_available = fields.Integer(string='Available Seats', compute='_compute_seats', store=True)
105 seats_unconfirmed = fields.Integer(string='Unconfirmed Seat Reservations', compute='_compute_seats', store=True)
106 seats_used = fields.Integer(compute='_compute_seats', store=True)
109 @api.depends('seats_max', 'registration_ids.state')
110 def _compute_seats(self):
111 """ Determine reserved, available, reserved but unconfirmed and used seats. """
112 # initialize fields to 0
114 ticket.seats_unconfirmed = ticket.seats_reserved = ticket.seats_used = ticket.seats_available = 0
115 # aggregate registrations by ticket and by state
118 'draft': 'seats_unconfirmed',
119 'open': 'seats_reserved',
120 'done': 'seats_used',
122 query = """ SELECT event_ticket_id, state, count(event_id)
123 FROM event_registration
124 WHERE event_ticket_id IN %s AND state IN ('draft', 'open', 'done')
125 GROUP BY event_ticket_id, state
127 self._cr.execute(query, (tuple(self.ids),))
128 for event_ticket_id, state, num in self._cr.fetchall():
129 ticket = self.browse(event_ticket_id)
130 ticket[state_field[state]] += num
131 # compute seats_available
133 if ticket.seats_max > 0:
134 ticket.seats_available = ticket.seats_max - (ticket.seats_reserved + ticket.seats_used)
137 @api.constrains('registration_ids', 'seats_max')
138 def _check_seats_limit(self):
139 if self.seats_max and self.seats_available < 0:
140 raise Warning('No more available seats for the ticket')
142 @api.onchange('product_id')
143 def onchange_product_id(self):
144 price = self.product_id.list_price if self.product_id else 0
145 return {'value': {'price': price}}
148 class event_registration(models.Model):
149 _inherit = 'event.registration'
151 event_ticket_id = fields.Many2one('event.event.ticket', 'Event Ticket')
152 # sale_order_line_id = fields.Many2one('sale.order.line', 'Sale Order Line', ondelete='cascade')
155 @api.constrains('event_ticket_id', 'state')
156 def _check_ticket_seats_limit(self):
157 if self.event_ticket_id.seats_max and self.event_ticket_id.seats_available < 0:
158 raise Warning('No more available seats for this ticket')
161 def _check_auto_confirmation(self):
162 res = super(event_registration, self)._check_auto_confirmation()[0]
163 if res and self.origin:
164 orders = self.env['sale.order'].search([('name', '=', self.origin)], limit=1)
165 if orders and orders[0].state == 'draft':
170 def create(self, vals):
171 res = super(event_registration, self).create(vals)
173 message = _("The registration has been created for event %(event_name)s%(ticket)s from sale order %(order)s") % ({
174 'event_name': '<i>%s</i>' % res.event_id.name,
175 'ticket': res.event_ticket_id and _(' with ticket %s') % (('<i>%s</i>') % res.event_ticket_id.name) or '',
176 'order': res.origin})
177 res.message_post(body=message)