[merge] events

bzr revid: fp@tinyerp.com-20120525072114-x1ylvnbw2k3twbhy
This commit is contained in:
Fabien Pinckaers 2012-05-25 09:21:14 +02:00
commit 3f31dd0d0c
10 changed files with 210 additions and 111 deletions

View File

@ -1,3 +1,4 @@
# -*- coding: utf-8 -*-
##############################################################################
#
@ -52,6 +53,7 @@ Note that:
],
'demo_xml': ['event_demo.xml'],
'test': ['test/process/event_draft2done.yml'],
'js': ['static/src/js/google_map.js'],
'css': ['static/src/css/event.css'],
'installable': True,
'application': True,

View File

@ -103,6 +103,14 @@ class event_event(osv.osv):
if total_confirmed < self.event.register_min or total_confirmed > self.event.register_max and self.event.register_max!=0:
raise osv.except_osv(_('Error!'),_("The total of confirmed registration for the event '%s' does not meet the expected minimum/maximum. You should maybe reconsider those limits before going further") % (self.event.name))
def check_registration_limits_before(self, cr, uid, ids, no_of_registration, context=None):
for event in self.browse(cr, uid, ids, context=context):
available_seats = event.register_avail
if available_seats and no_of_registration > available_seats:
raise osv.except_osv(_('Warning!'),_("Only %d Seats are Available!") % (available_seats))
elif available_seats == 0:
raise osv.except_osv(_('Warning!'),_("No Tickets Available!"))
def confirm_event(self, cr, uid, ids, context=None):
register_pool = self.pool.get('event.registration')
if self.event.email_confirmation_id:
@ -179,7 +187,7 @@ class event_event(osv.osv):
'register_current': fields.function(_get_register, string='Confirmed Registrations', multi='register_numbers'),
'register_avail': fields.function(_get_register, string='Available Registrations', multi='register_numbers',type='integer'),
'register_prospect': fields.function(_get_register, string='Unconfirmed Registrations', multi='register_numbers'),
'register_attended': fields.function(_get_register, string='Attended Registrations', multi='register_numbers'),
'register_attended': fields.function(_get_register, string='# of Participations', multi='register_numbers'),
'registration_ids': fields.one2many('event.registration', 'event_id', 'Registrations', readonly=False, states={'done': [('readonly', True)]}),
'date_begin': fields.datetime('Start Date', required=True, readonly=True, states={'draft': [('readonly', False)]}),
'date_end': fields.datetime('End Date', required=True, readonly=True, states={'draft': [('readonly', False)]}),
@ -195,7 +203,6 @@ class event_event(osv.osv):
'full_name' : fields.function(_name_get_fnc, type="char", string='Name'),
'reply_to': fields.char('Reply-To Email', size=64, readonly=False, states={'done': [('readonly', True)]}, help="The email address of the organizer is likely to be put here, with the effect to be in the 'Reply-To' of the mails sent automatically at event or registrations confirmation. You can also put the email address of your mail gateway if you use one."),
'main_speaker_id': fields.many2one('res.partner','Main Speaker', readonly=False, states={'done': [('readonly', True)]}, help="Speaker who will be giving speech at the event."),
'speaker_ids': fields.many2many('res.partner', 'event_speaker_rel', 'speaker_id', 'partner_id', 'Other Speakers', readonly=False, states={'done': [('readonly', True)]}),
'address_id': fields.many2one('res.partner','Location Address', readonly=False, states={'done': [('readonly', True)]}),
'speaker_confirmed': fields.boolean('Speaker Confirmed', readonly=False, states={'done': [('readonly', True)]}),
'country_id': fields.related('address_id', 'country_id',
@ -203,22 +210,30 @@ class event_event(osv.osv):
'note': fields.text('Description', readonly=False, states={'done': [('readonly', True)]}),
'company_id': fields.many2one('res.company', 'Company', required=False, change_default=True, readonly=False, states={'done': [('readonly', True)]}),
'is_subscribed' : fields.function(_subscribe_fnc, type="boolean", string='Subscribed'),
'city': fields.related('address_id', 'city', type='char', string='City'),
'street': fields.related('address_id', 'street', type='char', string='Street'),
'country_id': fields.related('address_id', 'country_id', relation='res.country', type='many2one', string='Country'),
'state_id': fields.related('address_id', 'state_id', relation="res.country.state", type="many2one", string='Fed. State'),
'zip': fields.related('address_id','zip', type="char", string="Zip"),
}
_defaults = {
'state': 'draft',
'company_id': lambda self,cr,uid,c: self.pool.get('res.company')._company_default_get(cr, uid, 'event.event', context=c),
'user_id': lambda obj, cr, uid, context: uid,
}
def subscribe_to_event(self, cr, uid, ids, context=None):
register_pool = self.pool.get('event.registration')
user_pool = self.pool.get('res.users')
num_of_seats = int(context.get('ticket', 1))
self.check_registration_limits_before(cr, uid, ids, num_of_seats, context=context)
user = user_pool.browse(cr, uid, uid, context=context)
curr_reg_ids = register_pool.search(cr, uid, [('user_id', '=', user.id), ('event_id', '=' , ids[0])])
#the subscription is done with UID = 1 because in case we share the kanban view, we want anyone to be able to subscribe
if not curr_reg_ids:
curr_reg_ids = [register_pool.create(cr, 1, {'event_id': ids[0] ,'email': user.user_email, 'name':user.name, 'user_id': user.id,})]
curr_reg_ids = [register_pool.create(cr, 1, {'event_id': ids[0] ,'email': user.user_email, 'name':user.name, 'user_id': user.id, 'nb_register': num_of_seats})]
else:
register_pool.write(cr, uid, curr_reg_ids, {'nb_register': num_of_seats}, context=context)
return register_pool.confirm_registration(cr, 1, curr_reg_ids, context=context)
def unsubscribe_to_event(self, cr, uid, ids, context=None):
@ -236,7 +251,6 @@ class event_event(osv.osv):
_constraints = [
(_check_closing_date, 'Error ! Closing Date cannot be set before Beginning Date.', ['date_end']),
]
def onchange_event_type(self, cr, uid, ids, type_event, context=None):
if type_event:
type_info = self.pool.get('event.type').browse(cr,uid,type_event,context)
@ -295,6 +309,11 @@ class event_registration(osv.osv):
def registration_open(self, cr, uid, ids, context=None):
""" Open Registration
"""
event_obj = self.pool.get('event.event')
for register in self.browse(cr, uid, ids, context=context):
event_id = register.event_id.id
no_of_registration = register.nb_register
event_obj.check_registration_limits_before(cr, uid, [event_id], no_of_registration, context=context)
res = self.confirm_registration(cr, uid, ids, context=context)
self.mail_user(cr, uid, ids, context=context)
return res
@ -384,5 +403,4 @@ class event_registration(osv.osv):
event_registration()
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -38,16 +38,16 @@
<record id="event_1" model="event.event">
<field name="name">Opera of Verdi</field>
<field eval="time.strftime('%Y-%m-05 18:00:00')" name="date_begin"/>
<field eval="time.strftime('%Y-%m-05 21:00:00')" name="date_end"/>
<field eval="(DateTime.today()+ timedelta(days=1)).strftime('%Y-%m-%d 18:00:00')" name="date_begin"/>
<field eval="(DateTime.today()+ timedelta(days=2)).strftime('%Y-%m-%d 21:00:00')" name="date_end"/>
<field name="type" ref="event_type_1"/>
<field name="register_min">50</field>
<field name="register_max">350</field>
</record>
<record id="event_2" model="event.event">
<field name="name">Conference on ERP Business</field>
<field eval="time.strftime('%Y-%m-05 14:00:00')" name="date_begin"/>
<field eval="time.strftime('%Y-%m-05 16:30:00')" name="date_end"/>
<field eval="(DateTime.today()+ timedelta(days=2)).strftime('%Y-%m-%d 14:00:00')" name="date_begin"/>
<field eval="(DateTime.today()+ timedelta(days=2)).strftime('%Y-%m-%d 16:30:00')" name="date_end"/>
<field name="type" ref="event_type_2"/>
<field name="register_max">200</field>
</record>

View File

@ -50,10 +50,10 @@
<field name="model">event.event</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form layout="manual">
<form string="Events" layout="manual">
<div class="oe_form_topbar">
<button string="Confirm Event" name="button_confirm" states="draft" type="object"/>
<button string="Mark Done" name="button_done" states="confirm" type="object"/>
<button string="Event Ended" name="button_done" states="confirm" type="object"/>
<button string="Set To Draft" name="button_draft" states="cancel,done" type="object"/>
<button string="Cancel Event" name="button_cancel" states="draft,confirm" type="object"/>
<div class="oe_right">
@ -61,19 +61,38 @@
</div>
<div class="oe_clear"/>
</div>
<sheet string="Events" layout="auto">
<group col="6" colspan="4" class="oe_form_header">
<field name="name"/>
<field name="date_begin"/>
<field name="date_end"/>
<sheet layout="auto">
<field name="name" required="1" nolabel="1" class="oe_form_title" colspan="4"/>
<group colspan="4" col="3">
<group colspan="2" class="oe_form_group_label_border" style="margin-top: 20px;">
<field name="type" on_change="onchange_event_type(type,context)"/>
<field name="date_begin"/>
<field name="user_id"/>
<field name="address_id" />
<field name="date_end"/>
<field name="address_id" widget ="many2one_Geo_address"/>
<field name="register_min"/>
<label string=""/>
<field name="street" nolabel="1"/>
<field name="register_max"/>
</group>
<notebook colspan="4">
<page string="Event">
<separator string="Description" colspan="4"/>
<div id="oe_mapbox" class="oe_mapbox"></div>
</group>
<notebook colspan="4">
<page string="Event Description">
<field name="note" colspan="4" nolabel="1"/>
</page>
<page string="Internal Data">
<group class="oe_form_group_label_border" colspan="2" col="2">
<field name="register_current"/>
<field name="register_prospect"/>
<field name="register_attended"/>
</group>
<group class="oe_form_group_label_border" colspan="2" col="2">
<field name="main_speaker_id" domain="[('speaker','=',True)]" context="{'default_speaker':1}"/>
<field name="speaker_confirmed"/>
</group>
<field name="registration_ids" colspan="4" nolabel="1" groups="event.group_event_manager,event.group_event_user">
<tree string="Registration" editable="top">
<field name="name" />
@ -108,30 +127,8 @@
</form>
</field>
</page>
<page string="Speakers">
<field name="main_speaker_id" domain="[('speaker','=',True)]" context="{'default_speaker':1}"/>
<field name="speaker_confirmed"/>
<separator string="Other Speakers" colspan="4"/>
<field name="speaker_ids" domain="[('speaker','=',True)]" context="{'default_speaker':1}" colspan="4" nolabel="1"/>
</page>
<page string="Extra Info">
<group col="2" colspan="2">
<separator string="Registrations" colspan="2"/>
<field name="register_min"/>
<field name="register_max"/>
<field name="register_prospect"/>
<field name="register_current"/>
<field name="register_attended"/>
</group>
<group col="2" colspan="2">
<separator string="Emails" colspan="2"/>
<field name="reply_to"/>
<field name="email_registration_id" domain="[('model_id.model','=','event.registration')]"/>
<field name="email_confirmation_id" domain="[('model_id.model','=','event.registration')]"/>
</group>
</page>
</notebook>
</sheet>
</sheet>
</form>
</field>
</record>
@ -162,9 +159,10 @@
</field>
</record>
<!-- Event Kanban View -->
<record model="ir.ui.view" id="view_event_kanban">
<record model="ir.ui.view" id="view_event_kanban">
<field name="name">event.event.kanban</field>
<field name="model">event.event</field>
<field name="type">kanban</field>
@ -208,7 +206,8 @@
</p>
<t t-if="record.register_avail.raw_value != 0">
<t t-if="!record.is_subscribed.raw_value">
<button type="object" name="subscribe_to_event" class="subscribe_button oe_event_button_subscribe">
<input t-att-id="record.id.raw_value" type="text" name="subscribe" class="no_of_seats" value="1" onchange="document.getElementById('btn_sub' +this.id).setAttribute('data-context',JSON.stringify({'ticket':this.value}))"/>
<button t-att-id="'btn_sub'+record.id.raw_value" type="object" name="subscribe_to_event" class="subscribe_button oe_event_button_subscribe">
<span >Subscribe</span>
</button>
</t>
@ -488,7 +487,7 @@
<field name="view_mode">tree,form,calendar,graph</field>
<field name="context">{}</field>
<field name="search_view_id" ref="view_registration_search"/>
</record>
</record>view_
<menuitem
name="Registrations"

View File

@ -33,68 +33,25 @@ div.oe_fold_column{
padding:0px !important;
}
.oe_event_button_subscribe {
display: inline-block;
border: 1px solid #ababab;
color: #404040;
font-size: 12px;
padding: 3px 10px;
text-align: center;
-o-background-size: 100% 100%;
-moz-background-size: 100% 100%;
-webkit-background-size: auto auto !important;
background-size: 100% 100%;
background: #d8d8d8 none;
background: none, -webkit-gradient(linear, left top, left bottom, from(#efefef), to(#d8d8d8));
background: none, -webkit-linear-gradient(#efefef, #d8d8d8);
background: none, -moz-linear-gradient(#efefef, #d8d8d8);
background: none, -o-linear-gradient(top, #efefef, #d8d8d8);
background: none, -khtml-gradient(linear, left top, left bottom, from(#efefef), to(#d8d8d8));
background: -ms-linear-gradient(top, #efefef, #d8d8d8);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#efefef', endColorstr='#d8d8d8',GradientType=0 );
-moz-border-radius: 3px;
-webkit-border-radius: 3px;
-o-border-radius: 3px;
-ms-border-radius: 3px;
border-radius: 3px;
-moz-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 1px rgba(255, 255, 255, 0.8) inset;
-webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 1px rgba(255, 255, 255, 0.8) inset;
-o-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 1px rgba(255, 255, 255, 0.8) inset;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 1px rgba(255, 255, 255, 0.8) inset;
text-shadow: 0 1px 1px rgba(255, 255, 255, 0.5);
-webkit-font-smoothing: antialiased;
outline: none;
color: white;
background-color: #8a89ba;
background-image: -webkit-gradient(linear, left top, left bottom, from(#8a89ba), to(#807fb4));
background-image: -webkit-linear-gradient(top, #8a89ba, #807fb4);
background-image: -moz-linear-gradient(top, #8a89ba, #807fb4);
background-image: -ms-linear-gradient(top, #8a89ba, #807fb4);
background-image: -o-linear-gradient(top, #8a89ba, #807fb4);
background-image: linear-gradient(to bottom, #8a89ba, #807fb4);
}
.oe_event_button_unsubscribe {
display: inline-block;
border: 1px solid #AAA;
color: #404040;
font-size: 12px;
padding: 3px 10px;
text-align: center;
-o-background-size: 100% 100%;
-moz-background-size: 100% 100%;
-webkit-background-size: auto auto !important;
background-size: 100% 100%;
background: #AAA none;
background: none, -webkit-gradient(linear, left top, left bottom, from(#AAA), to(#AAA));
background: none, -webkit-linear-gradient(#AAA, #AAA);
background: none, -moz-linear-gradient(#AAA, #AAA);
background: none, -o-linear-gradient(top, #AAA, #AAA);
background: none, -khtml-gradient(linear, left top, left bottom, from(#AAA), to(#AAA));
background: -ms-linear-gradient(top, #AAA, #AAA);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#AAA, endColorstr='#AAA',GradientType=0 );
-moz-border-radius: 3px;
-webkit-border-radius: 3px;
-o-border-radius: 3px;
-ms-border-radius: 3px;
border-radius: 3px;
-moz-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 1px rgba(255, 255, 255, 0.8) inset;
-webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 1px rgba(255, 255, 255, 0.8) inset;
-o-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 1px rgba(255, 255, 255, 0.8) inset;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 1px rgba(255, 255, 255, 0.8) inset;
text-shadow: 0 1px 1px rgba(255, 255, 255, 0.5);
-webkit-font-smoothing: antialiased;
outline: none;
color: white;
background-color: #8a89ba;
background-image: -webkit-gradient(linear, left top, left bottom, from(#8a89ba), to(#807fb4));
background-image: -webkit-linear-gradient(top, #8a89ba, #807fb4);
background-image: -moz-linear-gradient(top, #8a89ba, #807fb4);
background-image: -ms-linear-gradient(top, #8a89ba, #807fb4);
background-image: -o-linear-gradient(top, #8a89ba, #807fb4);
background-image: linear-gradient(to bottom, #8a89ba, #807fb4);;
}
.oe_event_button_subscribe:hover {
cursor: pointer;
@ -115,4 +72,50 @@ div.oe_fold_column{
display: inline;
background-color: #DC5F59;
}
.no_of_seats{
width:35px;
}
.oe_event_title{
font-size: 25px;
}
.oe_sub1
{
float:left;
height:50px;
border-right: 1px solid black;
border-color: #DCDCDC;
}
.oe_mapbox
{
position: relative;
float: right;
height:200px;
width:256px;
border: 1px solid #eeeeee;
}
.oe_td_border
{
width: 7em;
padding: 5px;
border-right: 1px solid black;
text-align: right;
border-color: #DCDCDC;
border-spacing:5em
}
.oe_td_date_border
{
border-right:1px solid black;
border-color: #DCDCDC;
}
textarea.field_text
{
width: 765px;
height: 318px;
}
td.oe_form_group_nested
{
padding: 5px;
}

View File

@ -0,0 +1,68 @@
openerp.event = function(instance){
instance.web.form.widgets.add('many2one_Geo_address', 'instance.event.Many2OneAddress');
instance.web.GoogleMapConnector = instance.web.Class.extend({
init: function(){
this.googleMapsLoaded = $.Deferred();
this.map_load();
},
map_load: function() {
var self = this;
if(this.googleMapsLoaded.state() != "pending"){return this.googleMapsLoaded.promise();}
googleMapsCallback = function () {
self.googleMapsLoaded.resolve();
};
$.ajax({
url: "https://maps.googleapis.com/maps/api/js?v=3&callback=googleMapsCallback&sensor=false",
dataType: "script"
}).fail(self.googleMapsLoaded.reject);
return this.googleMapsLoaded.promise();
},
render_map: function(address,$element){
var geocoder = new google.maps.Geocoder();
geocoder.geocode( { 'address': address}, function(results, status){
if (status == google.maps.GeocoderStatus.OK){
var lat = results[0].geometry.location.lat(),lng =results[0].geometry.location.lng();
var myOptions = {
zoom: 17,
center: new google.maps.LatLng(lat,lng),
mapTypeId: google.maps.MapTypeId.ROADMAP
}
return new google.maps.Marker({
map : new google.maps.Map($element,myOptions),
position: new google.maps.LatLng(lat,lng)
});
}
});
},
});
instance.event.Many2OneAddress = instance.web.form.FieldMany2One.extend({
init: function(field_manager, node){
this._super(field_manager, node);
this.map = new instance.web.GoogleMapConnector();
},
get_address:function(value){
var self = this;
if (!value || value.length == 0){
return $.Deferred().reject();
}
(value instanceof Array)?value = parseInt(value[0]):false;
var data = new instance.web.DataSet(this,this.field.relation, this.build_context());
data.read_ids(value,["street","city","country_id"]).done(function(value){
var address = _.str.sprintf(' %(street)s, %(city)s, %(country_id[1])s', value);
self.map.googleMapsLoaded.done(function(){
self.map.render_map(address,document.getElementById("oe_mapbox"));
})
});
},
set_value:function(value){
this._super(value);
this.get_address(value);
},
render_value:function(no_recurse){
this.get_address(this.get("value"));
this._super(no_recurse);
}
});
};

View File

@ -9,6 +9,7 @@
name: event
date_begin: 2012-01-01 19:05:15
date_end: 2012-01-01 20:05:15
register_max: 10
-
I create a registration for the event
-
@ -32,6 +33,15 @@
I confirm the registration1
-
!python {model: event.registration}: |
event_pool = self.pool.get("event.event")
for register in self.browse(cr, uid, [ref("event_registration1")], context):
nb_register = register.nb_register
event_id = register.event_id.id
available_seats = event_pool.check_available_seats(cr, uid, [event_id], context=context)
if available_seats and nb_register > available_seats:
assert available_seats, "seats available."
elif available_seats == 0:
assert available_seats, "No Tickets Available."
self.registration_open(cr, uid, [ref("event_registration1")],context=context)
-
I check that registration is "confirmed"

View File

@ -70,7 +70,6 @@ class sale_order_line(osv.osv):
def button_confirm(self, cr, uid, ids, context=None):
'''
create registration with sale order
'''
registration_obj = self.pool.get('event.registration')
sale_obj = self.pool.get('sale.order')
@ -92,4 +91,3 @@ class sale_order_line(osv.osv):
message = _("The registration %s has been created from the Sale Order %s.") % (registration_id, order_line.order_id.name)
registration_obj.log(cr, uid, registration_id, message)
return super(sale_order_line, self).button_confirm(cr, uid, ids, context=context)

View File

@ -1,3 +1,4 @@
/* ------------------------------ */
/* Wall */
/* ------------------------------ */

View File

@ -132,7 +132,7 @@
</group>
<notebook colspan="5">
<page string="Sales Order">
<field name="partner_id" on_change="onchange_partner_id(partner_id)" domain="[('customer','=',True)]" context="{'search_default_customer':1}" required="1"/>
<field name="partner_id" on_change="onchange_partner_id(partner_id)" domain="[('customer','=',True)]" context="{'search_default_customer':1}" />
<field domain="[('parent_id','=',partner_id)]" name="partner_invoice_id" groups="sale.group_delivery_invoice_address" options='{"quick_create": false}'/>
<field domain="[('parent_id','=',partner_id)]" name="partner_shipping_id" groups="sale.group_delivery_invoice_address" options='{"quick_create": false}'/>
<field domain="[('type','=','sale')]" name="pricelist_id" groups="product.group_sale_pricelist" on_change="onchange_pricelist_id(pricelist_id,order_line)"/>