1 # -*- coding: utf-8 -*-
2 ##############################################################################
4 # OpenERP, Open Source Management Solution
5 # Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
7 # This program is free software: you can redistribute it and/or modify
8 # it under the terms of the GNU Affero General Public License as
9 # published by the Free Software Foundation, either version 3 of the
10 # License, or (at your option) any later version.
12 # This program is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 # GNU Affero General Public License for more details.
17 # You should have received a copy of the GNU Affero General Public License
18 # along with this program. If not, see <http://www.gnu.org/licenses/>.
20 ##############################################################################
23 from osv import fields, osv
24 from tools.translate import _
31 class event_type(osv.osv):
34 _description = __doc__
36 'name': fields.char('Event type', size=64, required=True),
40 class event_event(osv.osv):
43 _description = __doc__
44 _inherit = 'crm.case.section'
47 def _get_currency(self, cr, uid, context):
48 user = self.pool.get('res.users').browse(cr, uid, [uid])[0]
50 return user.company_id.currency_id.id
52 return self.pool.get('res.currency').search(cr, uid, [('rate','=',1.0)])[0]
54 def copy(self, cr, uid, id, default=None, context=None):
55 """ Copy record of Given id
56 @param id: Id of Event Registration type record.
57 @param context: A standard dictionary for contextual values
62 'code': self.pool.get('ir.sequence').get(cr, uid, 'event.event'),
65 return super(event_event, self).copy(cr, uid, id, default=default, context=context)
67 def onchange_product(self, cr, uid, ids, product_id):
70 return {'value': {'unit_price': False}}
72 unit_price=self.pool.get('product.product').price_get(cr, uid, [product_id])[product_id]
73 return {'value': {'unit_price': unit_price}}
75 def button_draft(self, cr, uid, ids, context=None):
76 return self.write(cr, uid, ids, {'state': 'draft'}, context=context)
78 def button_cancel(self, cr, uid, ids, context=None):
79 return self.write(cr, uid, ids, {'state': 'cancel'}, context=context)
81 def button_done(self, cr, uid, ids, context=None):
82 return self.write(cr, uid, ids, {'state': 'done'}, context=context)
84 def button_confirm(self, cr, uid, ids, context=None):
85 register_pool = self.pool.get('event.registration')
86 for event in self.browse(cr, uid, ids, context=context):
87 if event.mail_auto_confirm:
88 #send reminder that will confirm the event for all the people that were already confirmed
89 reg_ids = register_pool.search(cr, uid, [
90 ('event_id', '=', event.id),
91 ('state', 'not in', ['draft', 'cancel'])])
92 register_pool.mail_user_confirm(cr, uid, reg_ids)
94 return self.write(cr, uid, ids, {'state': 'confirm'})
97 def _get_register(self, cr, uid, ids, fields, args, context=None):
99 Get Confirm or uncofirm register value.
100 @param ids: List of Event registration type's id
101 @param fields: List of function fields(register_current and register_prospect).
102 @param context: A standard dictionary for contextual values
103 @return: Dictionary of function fields value.
106 register_pool = self.pool.get('event.registration')
108 for event in self.browse(cr, uid, ids, context):
111 res[event.id][field] = False
113 if 'register_current' in fields:
115 if 'register_prospect' in fields:
116 state.append('draft')
118 reg_ids = register_pool.search(cr, uid, [
119 ('event_id', '=', event.id),
120 ('state', 'in', state)])
122 if 'register_current' in fields:
123 res[event.id]['register_current'] = len(reg_ids)
124 if 'register_prospect' in fields:
125 res[event.id]['register_prospect'] = len(reg_ids)
129 def write(self, cr, uid, ids, vals, context=None):
131 Writes values in one or several fields.
132 @param ids: List of Event registration type's IDs
133 @param vals: dictionary with values to update.
136 register_pool = self.pool.get('event.registration')
137 res = super(event_event, self).write(cr, uid, ids, vals, context=context)
138 if vals.get('date_begin', False) or vals.get('mail_auto_confirm', False) or vals.get('mail_confirm', False):
139 for event in self.browse(cr, uid, ids, context=context):
140 #change the deadlines of the registration linked to this event
142 if vals.get('date_begin', False):
143 register_values['date_deadline'] = vals['date_begin']
145 #change the description of the registration linked to this event
146 if vals.get('mail_auto_confirm', False):
147 if vals['mail_auto_confirm']:
148 if 'mail_confirm' not in vals:
149 vals['mail_confirm'] = event.mail_confirm
151 vals['mail_confirm'] = False
152 if 'mail_confirm' in vals:
153 register_values['description'] = vals['mail_confirm']
156 reg_ids = register_pool.search(cr, uid, [('event_id', '=', event.id)])
157 register_pool.write(cr, uid, reg_ids, register_values)
162 'type': fields.many2one('event.type', 'Type', help="Type of Event like Seminar, Exhibition, Conference, Training."),
163 'register_max': fields.integer('Maximum Registrations', help="Provide Maximun Number of Registrations"),
164 'register_min': fields.integer('Minimum Registrations', help="Providee Minimum Number of Registrations"),
165 'register_current': fields.function(_get_register, method=True, string='Confirmed Registrations', multi='register_current', help="Total of Open Registrations"),
166 'register_prospect': fields.function(_get_register, method=True, string='Unconfirmed Registrations', multi='register_prospect', help="Total of Prospect Registrations"),
167 'date_begin': fields.datetime('Beginning date', required=True, help="Beginning Date of Event"),
168 'date_end': fields.datetime('Closing date', required=True, help="Closing Date of Event"),
169 'state': fields.selection([('draft', 'Draft'), ('confirm', 'Confirmed'), ('done', 'Done'), ('cancel', 'Cancelled')], 'State', readonly=True, required=True, help='If event is created, the state is \'Draft\'.\n If event is confirmed for the particular dates the state is set to \'Confirmed\'.\
170 \nIf the event is over, the state is set to \'Done\'.\n If event is cancelled the state is set to \'Cancelled\'.'),
171 'mail_auto_registr': fields.boolean('Mail Auto Register', help='Check this box if you want to use the automatic mailing for new registration'),
172 'mail_auto_confirm': fields.boolean('Mail Auto Confirm', help='Check this box if you want ot use the automatic confirmation emailing or the reminder'),
173 'mail_registr': fields.text('Registration Email', help='This email will be sent when someone subscribes to the event.'),
174 'mail_confirm': fields.text('Confirmation Email', help="This email will be sent when the event gets confimed or when someone subscribes to a confirmed event. This is also the email sent to remind someone about the event."),
175 'product_id': fields.many2one('product.product', 'Product', required=True, help="Product which is provided cost of event. Invoice of event will be created with this Product."),
176 'note': fields.text('Notes', help="Description or Summary of Event"),
177 'currency_id': fields.many2one('res.currency', 'Currency', required=True, readonly=True, states={'draft':[('readonly',False)]}),
178 "unit_price": fields.float('Cost'),
184 # 'code': lambda obj, cr, uid, context: obj.pool.get('ir.sequence').get(cr, uid, 'event.event'),
185 'user_id': lambda obj, cr, uid, context: uid,
186 'currency_id': _get_currency,
192 class event_registration(osv.osv):
193 """Event Registration"""
195 _name= 'event.registration'
196 _description = __doc__
197 _inherit = 'crm.meeting'
200 'email_cc': fields.text('CC', size=252 , help="These \
201 people will receive a copy of the future communication between partner \
202 and users by email"),
203 'nb_register': fields.integer('Number of Registration', readonly=True, states={'draft': [('readonly', False)]}),
204 'event_id': fields.many2one('event.event', 'Event Related', required=True),
205 "partner_invoice_id": fields.many2one('res.partner', 'Partner Invoiced'),
206 "contact_id": fields.many2one('res.partner.contact', 'Partner Contact'), #TODO: filter only the contacts that have a function into the selected partner_id
207 "unit_price": fields.float('Unit Price'),
208 "badge_title": fields.char('Badge Title', size=128),
209 "badge_name": fields.char('Badge Name', size=128),
210 "badge_partner": fields.char('Badge Partner', size=128),
211 "event_product": fields.char("Product Name", size=128, required=True),
212 "tobe_invoiced": fields.boolean("To be Invoiced"),
213 "invoice_id": fields.many2one("account.invoice", "Invoice"),
214 'date_closed': fields.datetime('Closed', readonly=True),
215 'ref': fields.reference('Reference', selection=crm._links_get, size=128),
216 'ref2': fields.reference('Reference 2', selection=crm._links_get, size=128),
217 'message_ids': fields.one2many('mailgate.message', 'res_id', 'Messages', domain=[('history', '=', True),('model','=',_name)]),
218 'log_ids': fields.one2many('mailgate.message', 'res_id', 'Logs', domain=[('history', '=', False),('model','=',_name)]),
219 'currency_id': fields.many2one('res.currency', 'Currency', readonly=True),
223 'tobe_invoiced': True,
224 'name': 'Registration',
225 # 'currency_id': _get_currency,
228 def _make_invoice(self, cr, uid, reg, lines, context=None):
229 """ Create Invoice from Invoice lines
230 @param reg : Object of event.registration
231 @param lines: ids of Invoice lines
235 inv_pool = self.pool.get('account.invoice')
236 inv_lines_pool = self.pool.get('account.invoice.line')
238 val_invoice = inv_pool.onchange_partner_id(cr, uid, [], 'out_invoice', reg.partner_invoice_id.id, False, False)
239 val_invoice['value'].update({'partner_id': reg.partner_invoice_id.id})
240 partner_address_id = val_invoice['value']['address_invoice_id']
242 value = inv_lines_pool.product_id_change(cr, uid, [], reg.event_id.product_id.id, uom =False, partner_id=reg.partner_invoice_id.id, fposition_id=reg.partner_invoice_id.property_account_position.id)
244 l = inv_lines_pool.read(cr, uid, lines)
246 val_invoice['value'].update({
247 'origin': reg.event_product,
249 'invoice_line': [(6, 0, lines)],
252 inv_id = inv_pool.create(cr, uid, val_invoice['value'])
253 inv_pool.button_compute(cr, uid, [inv_id])
254 self._history(cr, uid, [reg], _('Invoiced'))
257 def action_invoice_create(self, cr, uid, ids, grouped=False, date_inv = False, context=None):
258 """ Action of Create Invoice """
263 inv_lines_pool = self.pool.get('account.invoice.line')
264 inv_pool = self.pool.get('account.invoice')
265 product_pool = self.pool.get('product.product')
266 contact_pool = self.pool.get('res.partner.contact')
269 # If date was specified, use it as date invoiced, usefull when invoices are generated this month and put the
270 # last day of the last month as invoice date
272 context['date_inv'] = date_inv
274 for reg in self.browse(cr, uid, ids, context=context):
276 val_invoice = inv_pool.onchange_partner_id(cr, uid, [], 'out_invoice', reg.partner_invoice_id.id, False, False)
278 val_invoice['value'].update({'partner_id': reg.partner_invoice_id.id})
279 partner_address_id = val_invoice['value']['address_invoice_id']
281 if not partner_address_id:
282 raise osv.except_osv(_('Error !'),
283 _("Registered partner doesn't have an address to make the invoice."))
285 value = inv_lines_pool.product_id_change(cr, uid, [], reg.event_id.product_id.id, uom =False, partner_id=reg.partner_invoice_id.id, fposition_id=reg.partner_invoice_id.property_account_position.id)
286 product = product_pool.browse(cr, uid, reg.event_id.product_id.id, context=context)
287 for tax in product.taxes_id:
288 tax_ids.append(tax.id)
290 vals = value['value']
291 c_name = reg.contact_id and ('-' + contact_pool.name_get(cr, uid, [reg.contact_id.id])[0][1]) or ''
293 'name': reg.event_product + '-' + c_name,
294 'price_unit': reg.unit_price,
295 'quantity': reg.nb_register,
296 'product_id':reg.event_id.product_id.id,
297 'invoice_line_tax_id': [(6, 0, tax_ids)],
299 inv_line_ids = self._create_invoice_lines(cr, uid, [reg.id], vals)
300 invoices.setdefault(reg.partner_id.id, []).append((reg, inv_line_ids))
302 for val in invoices.values():
305 res = self._make_invoice(cr, uid, val[0][0], [v for k , v in val], context=context)
308 self.write(cr, uid, [k.id], {'state': 'done', 'invoice_id': res}, context=context)
312 res = self._make_invoice(cr, uid, k, [v], context=context)
313 self.write(cr, uid, [k.id], {'state': 'done', 'invoice_id': res}, context=context)
314 if res: new_invoice_ids.append(res)
316 return new_invoice_ids
318 def check_confirm(self, cr, uid, ids, context=None):
320 Check confirm event register on given id.
321 @param ids: List of Event registration's IDs
322 @param context: A standard dictionary for contextual values
323 @return: Dictionary value which open Confirm registration form.
325 data_pool = self.pool.get('ir.model.data')
327 for registration in self.browse(cr, uid, ids, context=context):
328 total_confirmed = registration.event_id.register_current + registration.nb_register
329 if total_confirmed <= registration.event_id.register_max or registration.event_id.register_max == 0:
330 self.write(cr, uid, [registration.id], {'state': 'open'}, context=context)
331 self.mail_user(cr, uid, [registration.id])
332 self._history(cr, uid, [registration], _('Open'))
334 unconfirmed_ids.append(registration.id)
336 view_id = data_pool._get_id(cr, uid, 'event', 'view_event_confirm_registration')
337 view_data = data_pool.browse(cr, uid, view_id)
338 view_id = view_data.res_id
339 context['registration_ids'] = unconfirmed_ids
341 'name': _('Confirm Registration'),
344 'view_mode': 'tree,form',
345 'res_model': 'event.confirm.registration',
346 'views': [(view_id, 'form')],
347 'type': 'ir.actions.act_window',
354 def button_reg_close(self, cr, uid, ids, *args):
355 registrations = self.browse(cr, uid, ids)
356 self._history(cr, uid, registrations, _('Done'))
357 self.write(cr, uid, ids, {'state': 'done', 'date_closed': time.strftime('%Y-%m-%d %H:%M:%S')})
360 def button_reg_cancel(self, cr, uid, ids, *args):
361 registrations = self.browse(cr, uid, ids)
362 self._history(cr, uid, registrations, _('Cancel'))
363 self.write(cr, uid, ids, {'state': 'cancel'})
366 def create(self, cr, uid, values, context=None):
367 """ Overrides orm create method.
369 event = self.pool.get('event.event').browse(cr, uid, values['event_id'], context=context)
371 values['date_deadline']= event.date_begin
372 values['description']= event.mail_confirm
373 values['currency_id'] = event.currency_id.id
374 res = super(event_registration, self).create(cr, uid, values, context=context)
375 registrations = self.browse(cr, uid, [res], context=context)
376 self._history(cr, uid, registrations, _('Created'))
379 def write(self, cr, uid, ids, values, context=None):
380 if 'event_id' in values:
381 event = self.pool.get('event.event').browse(cr, uid, values['event_id'], context=context)
382 values['date_deadline']= event.date_begin
383 values['description']= event.mail_confirm
384 return super(event_registration, self).write(cr, uid, ids, values, context=context)
386 def mail_user(self, cr, uid, ids, confirm=False, context=None):
393 for reg_id in self.browse(cr, uid, ids):
394 src = reg_id.event_id.reply_to or False
396 if reg_id.email_from:
397 dest += [reg_id.email_from]
399 dest += [reg_id.email_cc]
402 tools.email_send(src, dest,
403 _('Auto Confirmation: [%s] %s') %(reg_id.id, reg_id.name),
404 reg_id.event_id.mail_confirm,
405 openobject_id = reg_id.id)
406 elif reg_id.event_id.mail_auto_confirm or reg_id.event_id.mail_auto_registr:
407 if reg_id.event_id.state in ['draft', 'fixed', 'open', 'confirm', 'running'] and reg_id.event_id.mail_auto_registr:
408 tools.email_send(src, dest,
409 _('Auto Registration: [%s] %s') %(reg_id.id, reg_id.name),
410 reg_id.event_id.mail_registr, openobject_id = reg_id.id)
411 if (reg_id.event_id.state in ['confirm', 'running']) and reg_id.event_id.mail_auto_confirm:
412 tools.email_send(src, dest,
413 _('Auto Confirmation: [%s] %s') %(reg_id.id, reg_id.name),
414 reg_id.event_id.mail_confirm, openobject_id = reg_id.id)
417 raise osv.except_osv(_('Error!'), _('You must define a reply-to address in order to mail the participant. You can do this in the Mailing tab of your event. Note that this is also the place where you can configure your event to not send emails automaticly while registering'))
421 def mail_user_confirm(self, cr, uid, ids, context=None):
425 return self.mail_user(cr, uid, ids, confirm=True, context=context)
427 def _create_invoice_lines(self, cr, uid, ids, vals):
428 """ Create account Invoice line for Registration Id.
430 return self.pool.get('account.invoice.line').create(cr, uid, vals)
432 def onchange_badge_name(self, cr, uid, ids, badge_name):
437 data['name'] = 'Registration: ' + badge_name
438 return {'value': data}
440 def onchange_contact_id(self, cr, uid, ids, contact, partner):
446 contact_id = self.pool.get('res.partner.contact').browse(cr, uid, contact)
447 data['badge_name'] = contact_id.name
448 data['badge_title'] = contact_id.title
450 partner_addresses = self.pool.get('res.partner.address').search(cr, uid, [('partner_id', '=', partner)])
451 job_ids = self.pool.get('res.partner.job').search(cr, uid, [('contact_id', '=', contact), ('address_id', 'in', partner_addresses)])
453 data['email_from'] = self.pool.get('res.partner.job').browse(cr, uid, job_ids[0]).email
454 d = self.onchange_badge_name(cr, uid, ids, data['badge_name'])
455 data.update(d['value'])
456 return {'value': data}
458 def onchange_event(self, cr, uid, ids, event_id, partner_invoice_id):
461 return {'value': {'unit_price': False, 'event_product': False}}
462 data_event = self.pool.get('event.event').browse(cr, uid, event_id)
464 context['currency_id'] = data_event.currency_id.id
466 if data_event.product_id:
467 if not partner_invoice_id:
468 unit_price=self.pool.get('product.product').price_get(cr, uid, [data_event.product_id.id], context=context)[data_event.product_id.id]
469 return {'value': {'unit_price': unit_price, 'event_product': data_event.product_id.name, 'currency_id': data_event.currency_id.id}}
470 data_partner = self.pool.get('res.partner').browse(cr, uid, partner_invoice_id)
471 context.update({'partner_id': data_partner})
472 unit_price = self.pool.get('product.product')._product_price(cr, uid, [data_event.product_id.id], False, False, {'pricelist': data_partner.property_product_pricelist.id})[data_event.product_id.id]
473 return {'value': {'unit_price': unit_price, 'event_product': data_event.product_id.name, 'currency_id': data_event.currency_id.id}}
475 return {'value': {'unit_price': False, 'event_product': False}}
477 def onchange_partner_id(self, cr, uid, ids, part, event_id, email=False):
480 data['badge_partner'] = data['contact_id'] = data['partner_invoice_id'] = data['email_from'] = data['badge_title'] = data['badge_name'] = False
482 return {'value': data}
483 data['partner_invoice_id']=part
484 # this calls onchange_partner_invoice_id
485 d = self.onchange_partner_invoice_id(cr, uid, ids, event_id, part)
486 # this updates the dictionary
487 data.update(d['value'])
488 addr = self.pool.get('res.partner').address_get(cr, uid, [part])
490 if addr.has_key('default'):
491 job_ids = self.pool.get('res.partner.job').search(cr, uid, [('address_id', '=', addr['default'])])
493 data['contact_id'] = self.pool.get('res.partner.job').browse(cr, uid, job_ids[0]).contact_id.id
494 d = self.onchange_contact_id(cr, uid, ids, data['contact_id'], part)
495 data.update(d['value'])
496 partner_data = self.pool.get('res.partner').browse(cr, uid, part)
497 data['badge_partner'] = partner_data.name
498 return {'value': data}
500 def onchange_partner_invoice_id(self, cr, uid, ids, event_id, partner_invoice_id):
504 data['unit_price']=False
506 return {'value': data}
507 data_event = self.pool.get('event.event').browse(cr, uid, event_id)
509 if data_event.product_id:
510 if not partner_invoice_id:
511 data['unit_price']=self.pool.get('product.product').price_get(cr, uid, [data_event.product_id.id], context=context)[data_event.product_id.id]
512 return {'value': data}
513 data_partner = self.pool.get('res.partner').browse(cr, uid, partner_invoice_id)
514 context.update({'partner_id': data_partner})
515 data['unit_price'] = self.pool.get('product.product')._product_price(cr, uid, [data_event.product_id.id], False, False, {'pricelist': data_partner.property_product_pricelist.id})[data_event.product_id.id]
516 return {'value': data}
517 return {'value': data}
521 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: