[MIG] event_sale : migration to new api

This commit is contained in:
Shivam Dudhat
2016-04-28 08:46:06 +02:00
committed by Jérome Maes
parent 60609eaab2
commit 96fb5d41d9
11 changed files with 168 additions and 211 deletions
-1
View File
@@ -29,7 +29,6 @@ this event.
'wizard/event_edit_registration.xml',
],
'demo': ['data/event_demo.xml'],
'test': ['test/confirm.yml'],
'installable': True,
'auto_install': True
}
+3 -7
View File
@@ -1,7 +1,5 @@
<?xml version="1.0"?>
<openerp>
<data>
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="event_0_product" model="product.product">
<field name="name">Open Days in Los Angeles</field>
<field name="event_ok">True</field>
@@ -219,6 +217,4 @@
</div>
]]></field>
</record>
</data>
</openerp>
</odoo>
+2 -2
View File
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<odoo>
<data noupdate="1">
<record id="event_type" model="event.type">
@@ -19,7 +19,7 @@
</record>
</data>
</openerp>
</odoo>
+70 -93
View File
@@ -1,100 +1,76 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from openerp import models, fields, api, _
import openerp.addons.decimal_precision as dp
from openerp.exceptions import ValidationError
from openerp.osv import fields as old_fields
from odoo import api, fields, models, _
from odoo.exceptions import ValidationError
import odoo.addons.decimal_precision as dp
class event_event(models.Model):
class 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(), copy=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:
product = self.env.ref('event_sale.product_product_event', raise_if_not_found=False)
if not product:
return self.env['event.event.ticket']
return [{
'name': _('Subscription'),
'product_id': product.id,
'price': 0,
}]
event_ticket_ids = fields.One2many('event.event.ticket', 'event_id', string='Event Ticket',
default=lambda self: self._default_tickets(), copy=True)
class event_ticket(models.Model):
class EventTicket(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', digits=dp.get_precision('Product Price'))
deadline = fields.Date("Sales End")
is_expired = fields.Boolean('Is Expired', compute='_is_expired')
@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
return self.env.ref('event_sale.product_product_event', raise_if_not_found=False)
@api.one
@api.depends('deadline')
def _is_expired(self):
if self.deadline:
current_date = fields.Date.context_today(self.with_context({'tz': self.event_id.date_tz}))
self.is_expired = self.deadline < current_date
else:
self.is_expired = False
# FIXME non-stored fields wont ends up in _columns (and thus _all_columns), which forbid them
# to be used in qweb views. Waiting a fix, we create an old function field directly.
"""
price_reduce = fields.Float("Price Reduce", compute="_get_price_reduce", store=False,
digits=dp.get_precision('Product Price'))
@api.one
@api.depends('price', 'product_id.lst_price', 'product_id.price')
def _get_price_reduce(self):
product = self.product_id
discount = product.lst_price and (product.lst_price - product.price) / product.lst_price or 0.0
self.price_reduce = (1.0 - discount) * self.price
"""
def _get_price_reduce(self, cr, uid, ids, field_name, arg, context=None):
res = dict.fromkeys(ids, 0.0)
for ticket in self.browse(cr, uid, ids, context=context):
product = ticket.product_id
discount = product.lst_price and (product.lst_price - product.price) / product.lst_price or 0.0
res[ticket.id] = (1.0 - discount) * ticket.price
return res
_columns = {
'price_reduce': old_fields.function(_get_price_reduce, type='float', string='Price Reduce',
digits_compute=dp.get_precision('Product Price')),
}
name = fields.Char(string='Name', required=True, translate=True)
event_id = fields.Many2one('event.event', string="Event", required=True, ondelete='cascade')
product_id = fields.Many2one('product.product', string='Product',
required=True, domain=[("event_type_id", "!=", False)],
default=_default_product_id)
registration_ids = fields.One2many('event.registration', 'event_ticket_id', string='Registrations')
price = fields.Float(string='Price', digits=dp.get_precision('Product Price'))
deadline = fields.Date(string="Sales End")
is_expired = fields.Boolean(string='Is Expired', compute='_compute_is_expired')
price_reduce = fields.Float(string="Price Reduce", compute="_compute_price_reduce", digits=dp.get_precision('Product Price'))
# seats fields
seats_availability = fields.Selection(
[('limited', 'Limited'), ('unlimited', 'Unlimited')],
'Available Seat', required=True, store=True, compute='_compute_seats', default="limited")
seats_max = fields.Integer('Maximum Available Seats',
help="Define the number of available tickets. If you have too much registrations you will "
"not be able to sell tickets anymore. Set 0 to ignore this rule set as unlimited.")
seats_availability = fields.Selection([('limited', 'Limited'), ('unlimited', 'Unlimited')],
string='Available Seat', required=True, store=True, compute='_compute_seats', default="limited")
seats_max = fields.Integer(string='Maximum Available Seats',
help="Define the number of available tickets. If you have too much registrations you will "
"not be able to sell tickets anymore. Set 0 to ignore this rule set as unlimited.")
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
def _compute_is_expired(self):
for record in self:
if record.deadline:
current_date = fields.Date.context_today(record.with_context({'tz': record.event_id.date_tz}))
record.is_expired = record.deadline < current_date
else:
record.is_expired = False
@api.multi
def _compute_price_reduce(self):
for record in self:
product = record.product_id
discount = product.lst_price and (product.lst_price - product.price) / product.lst_price or 0.0
record.price_reduce = (1.0 - discount) * record.price
@api.multi
@api.depends('seats_max', 'registration_ids.state')
def _compute_seats(self):
@@ -115,8 +91,8 @@ class event_ticket(models.Model):
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():
self.env.cr.execute(query, (tuple(self.ids),))
for event_ticket_id, state, num in self.env.cr.fetchall():
ticket = self.browse(event_ticket_id)
ticket[state_field[state]] += num
# compute seats_available
@@ -124,37 +100,38 @@ class event_ticket(models.Model):
if ticket.seats_max > 0:
ticket.seats_available = ticket.seats_max - (ticket.seats_reserved + ticket.seats_used)
@api.one
@api.multi
@api.constrains('registration_ids', 'seats_max')
def _check_seats_limit(self):
if self.seats_max and self.seats_available < 0:
raise ValidationError(_('No more available seats for the ticket'))
for record in self:
if record.seats_max and record.seats_available < 0:
raise ValidationError(_('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}}
def _onchange_product_id(self):
self.price = self.product_id.list_price or 0
class event_registration(models.Model):
class EventRegistration(models.Model):
_inherit = 'event.registration'
event_ticket_id = fields.Many2one('event.event.ticket', 'Event Ticket')
event_ticket_id = fields.Many2one('event.event.ticket', string='Event Ticket')
# in addition to origin generic fields, add real relational fields to correctly
# handle attendees linked to sale orders and their lines
# TDE FIXME: maybe add an onchange on sale_order_id + origin
sale_order_id = fields.Many2one('sale.order', 'Source Sale Order', ondelete='cascade')
sale_order_line_id = fields.Many2one('sale.order.line', 'Sale Order Line', ondelete='cascade')
sale_order_id = fields.Many2one('sale.order', string='Source Sale Order', ondelete='cascade')
sale_order_line_id = fields.Many2one('sale.order.line', string='Sale Order Line', ondelete='cascade')
@api.one
@api.multi
@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 ValidationError(_('No more available seats for this ticket'))
for record in self:
if record.event_ticket_id.seats_max and record.event_ticket_id.seats_available < 0:
raise ValidationError(_('No more available seats for this ticket'))
@api.multi
def _check_auto_confirmation(self):
res = super(event_registration, self)._check_auto_confirmation()
res = super(EventRegistration, self)._check_auto_confirmation()
if res:
orders = self.env['sale.order'].search([('state', '=', 'draft'), ('id', 'in', self.mapped('sale_order_id').ids)], limit=1)
if orders:
@@ -163,7 +140,7 @@ class event_registration(models.Model):
@api.model
def create(self, vals):
res = super(event_registration, self).create(vals)
res = super(EventRegistration, self).create(vals)
if res.origin or res.sale_order_id:
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,
@@ -178,7 +155,7 @@ class event_registration(models.Model):
line_id = registration.get('sale_order_line_id')
if line_id:
registration.setdefault('partner_id', line_id.order_id.partner_id)
att_data = super(event_registration, self)._prepare_attendee_values(registration)
att_data = super(EventRegistration, self)._prepare_attendee_values(registration)
if line_id:
att_data.update({
'event_id': line_id.event_id.id,
+18 -18
View File
@@ -1,29 +1,29 @@
# -*- coding: utf-8 -*-
from openerp.osv import fields, osv
from odoo import api, fields, models
class product_template(osv.osv):
class ProductTemplate(models.Model):
_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 {}
event_ok = fields.Boolean(string='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', string='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.')
@api.onchange('event_ok')
def _onchange_event_ok(self):
if self.event_ok:
self.type = 'service'
class product(osv.osv):
class Product(models.Model):
_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):
event_ticket_ids = fields.One2many('event.event.ticket', 'product_id', string='Event Tickets')
@api.onchange('event_ok')
def _onchange_event_ok(self):
""" Redirection, inheritance mechanism hides the method on the model """
if event_ok:
return {'value': {'type': 'service'}}
return {}
if self.event_ok:
self.type = 'service'
+36 -41
View File
@@ -1,53 +1,48 @@
# -*- coding: utf-8 -*-
from openerp import api
from openerp.osv import fields, osv
from odoo import api, fields, models
class sale_order(osv.osv):
class SaleOrder(models.Model):
_inherit = "sale.order"
def action_confirm(self, cr, uid, ids, context=None):
res = super(sale_order, self).action_confirm(cr, uid, ids, context=context)
for order in self.browse(cr, uid, ids, context=context):
redirect_to_event_registration, so_id = any(line.event_id for line in order.order_line), order.id
order.order_line._update_registrations(confirm=True)
if redirect_to_event_registration:
event_ctx = dict(context, default_sale_order_id=so_id)
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
@api.multi
def action_confirm(self):
self.ensure_one()
res = super(SaleOrder, self).action_confirm()
self.order_line._update_registrations(confirm=True)
if any(self.order_line.filtered(lambda line: line.event_id)):
return self.env['ir.actions.act_window'].with_context(default_sale_order_id=self.id).for_xml_id('event_sale', 'action_sale_order_event_registration')
return res
class sale_order_line(osv.osv):
class SaleOrderLine(models.Model):
_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", readonly=True),
'event_ok': fields.related('product_id', 'event_ok', string='event_ok', type='boolean', readonly=True),
}
def _prepare_order_line_invoice_line(self, cr, uid, line, account_id=False, context=None):
res = super(sale_order_line, self)._prepare_order_line_invoice_line(cr, uid, line, account_id=account_id, context=context)
if line.event_id:
event = self.pool['event.event'].read(cr, uid, line.event_id.id, ['name'], context=context)
res['name'] = '%s: %s' % (res.get('name', ''), event['name'])
event_id = fields.Many2one('event.event', string='Event',
help="Choose an event and it will automatically create a registration for this event.")
event_ticket_id = fields.Many2one('event.event.ticket', string='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.Many2one(related='product_id.event_type_id', string="Event Type")
event_ok = fields.Boolean(related='product_id.event_ok')
@api.multi
def _prepare_invoice_line(self, qty):
self.ensure_one()
res = super(SaleOrderLine, self)._prepare_invoice_line(qty)
if self.event_id:
res['name'] = '%s: %s' % (res.get('name', ''), self.event_id.name)
return res
@api.onchange('product_id')
def product_id_change_event(self):
def _onchange_product_id_event(self):
values = {'event_type_id': False, 'event_ok': False}
if self.product_id.event_ok:
values = dict(event_type_id=self.product_id.event_type_id.id,
event_ok=self.product_id.event_ok)
else:
values = dict(event_type_id=False, event_ok=False)
values['event_type_id'] = self.product_id.event_type_id.id
values['event_ok'] = self.product_id.event_ok
self.update(values)
@api.multi
@@ -58,7 +53,7 @@ class sale_order_line(osv.osv):
and create new one for missing one. """
Registration = self.env['event.registration']
registrations = Registration.search([('sale_order_line_id', 'in', self.ids)])
for so_line in [l for l in self if l.event_id]:
for so_line in self.filtered('event_id'):
existing_registrations = registrations.filtered(lambda self: self.sale_order_line_id.id == so_line.id)
if confirm:
existing_registrations.filtered(lambda self: self.state != 'open').confirm_registration()
@@ -71,10 +66,10 @@ class sale_order_line(osv.osv):
registration = registration_data.pop()
# TDE CHECK: auto confirmation
registration['sale_order_line_id'] = so_line
self.env['event.registration'].with_context(registration_force_draft=True).create(
Registration.with_context(registration_force_draft=True).create(
Registration._prepare_attendee_values(registration))
return True
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}}
@api.onchange('event_ticket_id')
def _onchange_event_ticket_id(self):
self.price_unit = self.event_ticket_id.price
+14 -18
View File
@@ -1,9 +1,7 @@
<?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>
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="view_event_registration_ticket_search" model="ir.ui.view">
<field name="name">event.registration.search.inherit</field>
<field name="model">event.registration</field>
<field name="inherit_id" ref="event.view_registration_search" />
<field name="arch" type="xml">
@@ -13,8 +11,8 @@
</field>
</record>
<record model="ir.ui.view" id="view_event_registration_ticket_tree">
<field name="name">event.registration.ticket.tree</field>
<record id="view_event_registration_ticket_tree" model="ir.ui.view">
<field name="name">event.registration.tree.inherit</field>
<field name="model">event.registration</field>
<field name="inherit_id" ref="event.view_event_registration_tree" />
<field name="arch" type="xml">
@@ -25,8 +23,8 @@
</field>
</record>
<record model="ir.ui.view" id="view_event_registration_ticket_form">
<field name="name">event.registration.ticket.form</field>
<record id="view_event_registration_ticket_form" model="ir.ui.view">
<field name="name">event.registration.form.inherit</field>
<field name="model">event.registration</field>
<field name="inherit_id" ref="event.view_event_registration_form" />
<field name="arch" type="xml">
@@ -42,13 +40,12 @@
</group>
</field>
</record>
<record model="ir.ui.view" id="view_event_form_inherit_ticket">
<field name="name">view_event_form_inherit_tichet</field>
<record id="view_event_form_inherit_ticket" model="ir.ui.view">
<field name="name">event.form.inherit</field>
<field name="model">event.event</field>
<field name="inherit_id" ref="event.view_event_form"/>
<field name="arch" type="xml">
<data>
<xpath expr="//page[@name='registrations']" position="replace">
<page string="Tickets">
<group>
@@ -72,11 +69,10 @@
</field>
</page>
</xpath>
</data>
</field>
</record>
<record model="ir.ui.view" id="event_ticket_form_view">
<record id="event_ticket_form_view" model="ir.ui.view">
<field name="name">event.event.ticket.form</field>
<field name="model">event.event.ticket</field>
<field name="arch" type="xml">
@@ -106,5 +102,5 @@
</form>
</field>
</record>
</data>
</openerp>
</odoo>
+6 -7
View File
@@ -1,13 +1,13 @@
<?xml version="1.0"?>
<openerp>
<data>
<record model="ir.ui.view" id="event_sale_product_template_form">
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="event_sale_product_template_form" model="ir.ui.view">
<field name="name">product.template.form.inherit</field>
<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)"/>
<field name="event_ok" />
<label for="event_ok"/>
</div>
</div>
@@ -16,5 +16,4 @@
</field>
</field>
</record>
</data>
</openerp>
</odoo>
+8 -11
View File
@@ -1,15 +1,13 @@
<?xml version="1.0"?>
<openerp>
<data>
<record model="ir.ui.view" id="event_order_line">
<field name="name">event.sale.order</field>
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="view_sale_order_form_inherit_event" model="ir.ui.view">
<field name="name">sale.order.form.inherit</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='order_line']//form//field[@name='product_id']" position="after">
<field name="event_id" domain="['|', ('event_type_id','=', False),('event_type_id', '=', event_type_id),('date_end','&gt;=',time.strftime('%Y-%m-%d 00:00:00'))]" attrs="{'invisible': [('event_ok', '=', False)],'required': [('event_ok', '!=', False)]}"/>
<field name="event_ticket_id" domain="[('event_id', '=', event_id), '|', ('seats_available', '>', 0), ('seats_availability', '=', 'unlimited')]" attrs="{'invisible': [('event_id', '=', False)], 'required': [('event_id', '!=', False)]}"
on_change="onchange_event_ticket_id(event_ticket_id, context)"/>
<field name="event_ticket_id" domain="[('event_id', '=', event_id), ('seats_available', '>', 0)]" attrs="{'invisible': [('event_id', '=', False)], 'required': [('event_id', '!=', False)]}"/>
<field name="event_type_id" invisible="1"/>
<field name="event_ok" invisible="1"/>
</xpath>
@@ -19,10 +17,9 @@
</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>
</record>
</odoo>
@@ -46,13 +46,13 @@ class SaleOrderEventRegistration(models.TransientModel):
@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])
self.ensure_one()
for registration_line in self.event_registration_ids:
values = registration_line.get_registration_data()
if registration_line.registration_id:
registration_line.registration_id.write(values)
else:
self.env['event.registration'].create(values)
return {'type': 'ir.actions.act_window_close'}
@@ -69,8 +69,9 @@ class RegistrationEditorLine(models.TransientModel):
phone = fields.Char(string='Phone')
name = fields.Char(string='Name', select=True)
@api.one
@api.multi
def get_registration_data(self):
self.ensure_one()
return {
'event_id': self.event_id.id,
'event_ticket_id': self.event_ticket_id.id,
@@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<odoo>
<record id="view_event_registration_editor_form" model="ir.ui.view">
<field name="name">registration.editor.form</field>
@@ -37,6 +36,4 @@
<field name="target">new</field>
<field name="context">{}</field>
</record>
</data>
</openerp>
</odoo>