diff options
| author | Thibault Delavallée <tde@openerp.com> | 2014-10-03 10:23:05 +0200 |
|---|---|---|
| committer | Thibault Delavallée <tde@openerp.com> | 2014-10-03 15:07:45 +0200 |
| commit | 0b42e36da3fba78fd2ea9da3ada6e80dc2be39cb (patch) | |
| tree | 90786d24617ffb6e540b693d68909ce7660e763c /addons | |
| parent | 4c87ccb50fef8107de57185c9a875a538aaa3b07 (diff) | |
[CLEAN] event_sale: lint / cleaned module, migrated event models to the new API.
Diffstat (limited to 'addons')
| -rw-r--r-- | addons/event_sale/__init__.py | 21 | ||||
| -rw-r--r-- | addons/event_sale/__openerp__.py | 29 | ||||
| -rw-r--r-- | addons/event_sale/event_demo.xml | 6 | ||||
| -rw-r--r-- | addons/event_sale/event_sale.py | 242 | ||||
| -rw-r--r-- | addons/event_sale/models/__init__.py | 5 | ||||
| -rw-r--r-- | addons/event_sale/models/event.py | 129 | ||||
| -rw-r--r-- | addons/event_sale/models/product.py | 29 | ||||
| -rw-r--r-- | addons/event_sale/models/sale_order.py | 69 | ||||
| -rw-r--r-- | addons/event_sale/views/event.xml (renamed from addons/event_sale/event_sale_view.xml) | 40 | ||||
| -rw-r--r-- | addons/event_sale/views/product.xml | 20 | ||||
| -rw-r--r-- | addons/event_sale/views/sale_order.xml | 24 |
11 files changed, 287 insertions, 327 deletions
diff --git a/addons/event_sale/__init__.py b/addons/event_sale/__init__.py index 726d2d5c09d..c7b5ac7e1f2 100644 --- a/addons/event_sale/__init__.py +++ b/addons/event_sale/__init__.py @@ -1,22 +1,3 @@ # -*- 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 diff --git a/addons/event_sale/__openerp__.py b/addons/event_sale/__openerp__.py index 6691ad217bd..d2300d05a17 100644 --- a/addons/event_sale/__openerp__.py +++ b/addons/event_sale/__openerp__.py @@ -1,30 +1,10 @@ # -*- 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. ======================================= @@ -41,7 +21,9 @@ this event. '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', @@ -52,4 +34,3 @@ this event. 'installable': True, 'auto_install': True } -# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/addons/event_sale/event_demo.xml b/addons/event_sale/event_demo.xml index 8a55172cd85..9d0ed231897 100644 --- a/addons/event_sale/event_demo.xml +++ b/addons/event_sale/event_demo.xml @@ -12,7 +12,7 @@ <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"> @@ -25,7 +25,7 @@ <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"> @@ -38,7 +38,7 @@ <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"> diff --git a/addons/event_sale/event_sale.py b/addons/event_sale/event_sale.py deleted file mode 100644 index 2d947be63e0..00000000000 --- a/addons/event_sale/event_sale.py +++ /dev/null @@ -1,242 +0,0 @@ -# -*- 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']), - ] diff --git a/addons/event_sale/models/__init__.py b/addons/event_sale/models/__init__.py new file mode 100644 index 00000000000..988d9523f9b --- /dev/null +++ b/addons/event_sale/models/__init__.py @@ -0,0 +1,5 @@ +# -*- coding: utf-8 -*- + +import sale_order +import product +import event diff --git a/addons/event_sale/models/event.py b/addons/event_sale/models/event.py new file mode 100644 index 00000000000..8fc46f5e22b --- /dev/null +++ b/addons/event_sale/models/event.py @@ -0,0 +1,129 @@ +# -*- 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') diff --git a/addons/event_sale/models/product.py b/addons/event_sale/models/product.py new file mode 100644 index 00000000000..476425081e7 --- /dev/null +++ b/addons/event_sale/models/product.py @@ -0,0 +1,29 @@ +# -*- 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 {} diff --git a/addons/event_sale/models/sale_order.py b/addons/event_sale/models/sale_order.py new file mode 100644 index 00000000000..6705f00160a --- /dev/null +++ b/addons/event_sale/models/sale_order.py @@ -0,0 +1,69 @@ +# -*- 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}} diff --git a/addons/event_sale/event_sale_view.xml b/addons/event_sale/views/event.xml index 9c4f265ef4d..dd4c4393bbc 100644 --- a/addons/event_sale/event_sale_view.xml +++ b/addons/event_sale/views/event.xml @@ -2,22 +2,6 @@ <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> @@ -50,26 +34,6 @@ </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> @@ -82,7 +46,7 @@ <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="product_id"/> <field name="deadline"/> <field name="price"/> <field name="seats_max"/> @@ -108,7 +72,7 @@ <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="product_id"/> <field name="deadline"/> <field name="price"/> <field name="seats_max"/> diff --git a/addons/event_sale/views/product.xml b/addons/event_sale/views/product.xml new file mode 100644 index 00000000000..dcb548560e0 --- /dev/null +++ b/addons/event_sale/views/product.xml @@ -0,0 +1,20 @@ +<?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> diff --git a/addons/event_sale/views/sale_order.xml b/addons/event_sale/views/sale_order.xml new file mode 100644 index 00000000000..a85691c0f55 --- /dev/null +++ b/addons/event_sale/views/sale_order.xml @@ -0,0 +1,24 @@ +<?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> |
