[FIX] event_sale: workaround for broken view.
[odoo/odoo.git] / addons / event_sale / models / event.py
1 # -*- coding: utf-8 -*-
2
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
7
8
9 class event_event(models.Model):
10     _inherit = 'event.event'
11
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')
20
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)]})
24
25     @api.model
26     def _default_tickets(self):
27         try:
28             product = self.env.ref('event_sale.product_product_event')
29             return [{
30                 'name': _('Subscription'),
31                 'product_id': product.id,
32                 'price': 0,
33             }]
34         except ValueError:
35             return self.env['event.event.ticket']
36
37     @api.one
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)
41
42
43 class event_ticket(models.Model):
44     _name = 'event.event.ticket'
45     _description = 'Event Ticket'
46
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)
57
58     @api.model
59     def _default_product_id(self):
60         try:
61             product = self.env['ir.model.data'].get_object('event_sale', 'product_product_event')
62             return product.id
63         except ValueError:
64             return False
65
66     @api.one
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
75
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.
78     """
79     price_reduce = fields.Float("Price Reduce", compute="_get_price_reduce", store=False,
80                                 digits=dp.get_precision('Product Price'))
81     @api.one
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
87     """
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
94         return res
95
96     _columns = {
97         'price_reduce': old_fields.function(_get_price_reduce, type='float', string='Price Reduce',
98                                             digits_compute=dp.get_precision('Product Price')),
99     }
100
101     # seats fields
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)
107
108     @api.multi
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
113         for ticket in self:
114             ticket.seats_unconfirmed = ticket.seats_reserved = ticket.seats_used = ticket.seats_available = 0
115         # aggregate registrations by ticket and by state
116         if self.ids:
117             state_field = {
118                 'draft': 'seats_unconfirmed',
119                 'open': 'seats_reserved',
120                 'done': 'seats_used',
121             }
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
126                     """
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
132         for ticket in self:
133             if ticket.seats_max > 0:
134                 ticket.seats_available = ticket.seats_max - (ticket.seats_reserved + ticket.seats_used)
135
136     @api.one
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')
141
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}}
146
147
148 class event_registration(models.Model):
149     _inherit = 'event.registration'
150
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')
153
154     @api.one
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')
159
160     @api.one
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':
166                 res = False
167         return res
168
169     @api.model
170     def create(self, vals):
171         res = super(event_registration, self).create(vals)
172         if res.origin:
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)
178         return res