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),
41 class event_event(osv.osv):
44 _description = __doc__
45 _inherit = 'crm.case.section'
48 def copy(self, cr, uid, id, default=None, context=None):
49 """ Copy record of Given id
50 @param id: Id of Event Registration type record.
51 @param context: A standard dictionary for contextual values
56 'code': self.pool.get('ir.sequence').get(cr, uid, 'event.event'),
59 return super(event_event, self).copy(cr, uid, id, default=default, context=context)
61 def button_draft(self, cr, uid, ids, context=None):
62 return self.write(cr, uid, ids, {'state': 'draft'}, context=context)
64 def button_cancel(self, cr, uid, ids, context=None):
65 return self.write(cr, uid, ids, {'state': 'cancel'}, context=context)
67 def button_done(self, cr, uid, ids, context=None):
68 return self.write(cr, uid, ids, {'state': 'done'}, context=context)
70 def button_confirm(self, cr, uid, ids, context=None):
71 register_pool = self.pool.get('event.registration')
72 for event in self.browse(cr, uid, ids, context=context):
73 if event.mail_auto_confirm:
74 #send reminder that will confirm the event for all the people that were already confirmed
75 reg_ids = register_pool.search(cr, uid, [
76 ('event_id', '=', event.id),
77 ('state', 'not in', ['draft', 'cancel'])])
78 register_pool.mail_user_confirm(cr, uid, reg_ids)
80 return self.write(cr, uid, ids, {'state': 'confirm'})
83 def _get_register(self, cr, uid, ids, fields, args, context=None):
85 Get Confirm or uncofirm register value.
86 @param ids: List of Event registration type's id
87 @param fields: List of function fields(register_current and register_prospect).
88 @param context: A standard dictionary for contextual values
89 @return: Dictionary of function fields value.
91 register_pool = self.pool.get('event.registration')
93 for event in self.browse(cr, uid, ids, context):
96 res[event.id][field] = False
98 if 'register_current' in fields:
100 if 'register_prospect' in fields:
101 state.append('draft')
103 reg_ids = register_pool.search(cr, uid, [
104 ('event_id', '=', event.id),
105 ('state', 'in', state)])
106 if 'register_current' in fields:
107 res[event.id]['register_current'] = len(reg_ids)
108 if 'register_prospect' in fields:
109 res[event.id]['register_prospect'] = len(reg_ids)
114 def write(self, cr, uid, ids, vals, context=None):
116 Writes values in one or several fields.
117 @param ids: List of Event registration type's IDs
118 @param vals: dictionary with values to update.
121 register_pool = self.pool.get('event.registration')
122 res = super(event_event, self).write(cr, uid, ids, vals, context=context)
123 if vals.get('date_begin', False) or vals.get('mail_auto_confirm', False) or vals.get('mail_confirm', False):
124 for event in self.browse(cr, uid, ids, context=context):
125 #change the deadlines of the registration linked to this event
127 if vals.get('date_begin', False):
128 register_values['date_deadline'] = vals['date_begin']
130 #change the description of the registration linked to this event
131 if vals.get('mail_auto_confirm', False):
132 if vals['mail_auto_confirm']:
133 if 'mail_confirm' not in vals:
134 vals['mail_confirm'] = event.mail_confirm
136 vals['mail_confirm'] = False
137 if 'mail_confirm' in vals:
138 register_values['description'] = vals['mail_confirm']
141 reg_ids = register_pool.search(cr, uid, [('event_id', '=', event.id)])
142 register_pool.write(cr, uid, reg_ids, register_values)
146 'type': fields.many2one('event.type', 'Type', help="Type of Event like Seminar, Exhibition, Conference, Training."),
147 'register_max': fields.integer('Maximum Registrations', help="Provide Maximun Number of Registrations"),
148 'register_min': fields.integer('Minimum Registrations', help="Providee Minimum Number of Registrations"),
149 'register_current': fields.function(_get_register, method=True, string='Confirmed Registrations', multi='register_current', help="Total of Open Registrations"),
150 'register_prospect': fields.function(_get_register, method=True, string='Unconfirmed Registrations', multi='register_prospect', help="Total of Prospect Registrations"),
151 'date_begin': fields.datetime('Beginning date', required=True, help="Beginning Date of Event"),
152 'date_end': fields.datetime('Closing date', required=True, help="Closing Date of Event"),
153 '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\'.\
154 \nIf the event is over, the state is set to \'Done\'.\n If event is cancelled the state is set to \'Cancelled\'.'),
155 'mail_auto_registr': fields.boolean('Mail Auto Register', help='Check this box if you want to use the automatic mailing for new registration'),
156 'mail_auto_confirm': fields.boolean('Mail Auto Confirm', help='Check this box if you want ot use the automatic confirmation emailing or the reminder'),
157 'mail_registr': fields.text('Registration Email', help='This email will be sent when someone subscribes to the event.'),
158 '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."),
159 '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."),
160 'note': fields.text('Notes', help="Description or Summary of Event")
165 'code': lambda obj, cr, uid, context: obj.pool.get('ir.sequence').get(cr, uid, 'event.event'),
166 'user_id': lambda obj, cr, uid, context: uid,
171 class event_registration(osv.osv):
172 """Event Registration"""
174 _name= 'event.registration'
175 _description = __doc__
176 _inherit = 'crm.meeting'
179 'email_cc': fields.text('CC', size=252 , help="These \
180 people will receive a copy of the future communication between partner \
181 and users by email"),
182 'nb_register': fields.integer('Number of Registration', readonly=True, states={'draft': [('readonly', False)]}),
183 'event_id': fields.many2one('event.event', 'Event Related', required=True),
184 "partner_invoice_id": fields.many2one('res.partner', 'Partner Invoiced'),
185 "contact_id": fields.many2one('res.partner.contact', 'Partner Contact'), #TODO: filter only the contacts that have a function into the selected partner_id
186 "unit_price": fields.float('Unit Price'),
187 "badge_title": fields.char('Badge Title', size=128),
188 "badge_name": fields.char('Badge Name', size=128),
189 "badge_partner": fields.char('Badge Partner', size=128),
190 "event_product": fields.char("Product Name", size=128, required=True),
191 "tobe_invoiced": fields.boolean("To be Invoiced"),
192 "invoice_id": fields.many2one("account.invoice", "Invoice"),
193 'date_closed': fields.datetime('Closed', readonly=True),
194 'ref': fields.reference('Reference', selection=crm._links_get, size=128),
195 'ref2': fields.reference('Reference 2', selection=crm._links_get, size=128),
200 'tobe_invoiced': True,
201 'name': 'Registration',
204 def _make_invoice(self, cr, uid, reg, lines, context=None):
205 """ Create Invoice from Invoice lines
206 @param reg : Object of event.registration
207 @param lines: ids of Invoice lines
211 inv_pool = self.pool.get('account.invoice')
212 inv_lines_pool = self.pool.get('account.invoice.line')
214 val_invoice = inv_pool.onchange_partner_id(cr, uid, [], 'out_invoice', reg.partner_invoice_id.id, False, False)
215 val_invoice['value'].update({'partner_id': reg.partner_invoice_id.id})
216 partner_address_id = val_invoice['value']['address_invoice_id']
218 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)
220 l = inv_lines_pool.read(cr, uid, lines)
222 val_invoice['value'].update({
223 'origin': reg.event_product,
225 'invoice_line': [(6, 0, lines)],
228 inv_id = inv_pool.create(cr, uid, val_invoice['value'])
229 inv_pool.button_compute(cr, uid, [inv_id])
230 self._history(cr, uid, [reg], _('Invoiced'))
233 def action_invoice_create(self, cr, uid, ids, grouped=False, date_inv = False, context=None):
234 """ Action of Create Invoice """
239 inv_lines_pool = self.pool.get('account.invoice.line')
240 inv_pool = self.pool.get('account.invoice')
241 product_pool = self.pool.get('product.product')
242 contact_pool = self.pool.get('res.partner.contact')
245 # If date was specified, use it as date invoiced, usefull when invoices are generated this month and put the
246 # last day of the last month as invoice date
248 context['date_inv'] = date_inv
250 for reg in self.browse(cr, uid, ids, context=context):
252 val_invoice = inv_pool.onchange_partner_id(cr, uid, [], 'out_invoice', reg.partner_invoice_id.id, False, False)
254 val_invoice['value'].update({'partner_id': reg.partner_invoice_id.id})
255 partner_address_id = val_invoice['value']['address_invoice_id']
257 if not partner_address_id:
258 raise osv.except_osv(_('Error !'),
259 _("Registered partner doesn't have an address to make the invoice."))
261 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)
262 product = product_pool.browse(cr, uid, reg.event_id.product_id.id, context=context)
263 for tax in product.taxes_id:
264 tax_ids.append(tax.id)
266 vals = value['value']
267 c_name = reg.contact_id and ('-' + contact_pool.name_get(cr, uid, [reg.contact_id.id])[0][1]) or ''
269 'name': reg.event_product + '-' + c_name,
270 'price_unit': reg.unit_price,
271 'quantity': reg.nb_register,
272 'product_id':reg.event_id.product_id.id,
273 'invoice_line_tax_id': [(6, 0, tax_ids)],
275 inv_line_ids = self._create_invoice_lines(cr, uid, [reg.id], vals)
276 invoices.setdefault(reg.partner_id.id, []).append((reg, inv_line_ids))
278 for val in invoices.values():
280 res = self._make_invoice(cr, uid, val[0][0], [v for k , v in val], context=context)
283 self.write(cr, uid, [k.id], {'state': 'done', 'invoice_id': res}, context=context)
287 res = self._make_invoice(cr, uid, k, [v], context=context)
288 self.write(cr, uid, [k.id], {'state': 'done', 'invoice_id': res}, context=context)
291 def check_confirm(self, cr, uid, ids, context=None):
293 Check confirm event register on given id.
294 @param ids: List of Event registration's IDs
295 @param context: A standard dictionary for contextual values
296 @return: Dictionary value which open Confirm registration form.
298 data_pool = self.pool.get('ir.model.data')
300 for registration in self.browse(cr, uid, ids, context=context):
301 total_confirmed = registration.event_id.register_current + registration.nb_register
302 if total_confirmed <= registration.event_id.register_max or registration.event_id.register_max == 0:
303 self.write(cr, uid, [registration.id], {'state': 'open'}, context=context)
304 self.mail_user(cr, uid, [registration.id])
305 self._history(cr, uid, [registration.id], _('Open'))
307 unconfirmed_ids.append(registration.id)
309 view_id = data_pool._get_id(cr, uid, 'event', 'view_event_confirm_registration')
310 view_data = data_pool.browse(cr, uid, view_id)
311 view_id = view_data.res_id
312 context['registration_ids'] = unconfirmed_ids
314 'name': _('Confirm Registration'),
317 'view_mode': 'tree,form',
318 'res_model': 'event.confirm.registration',
319 'views': [(view_id, 'form')],
320 'type': 'ir.actions.act_window',
327 def button_reg_close(self, cr, uid, ids, *args):
328 registrations = self.browse(cr, uid, ids)
329 self._history(cr, uid, registrations, _('Done'))
330 self.write(cr, uid, ids, {'state': 'done', 'date_closed': time.strftime('%Y-%m-%d %H:%M:%S')})
333 def button_reg_cancel(self, cr, uid, ids, *args):
334 registrations = self.browse(cr, uid, ids)
335 self._history(cr, uid, registrations, _('Cancel'))
336 self.write(cr, uid, ids, {'state': 'cancel'})
339 def create(self, cr, uid, values, context=None):
340 """ Overrides orm create method.
342 event = self.pool.get('event.event').browse(cr, uid, values['event_id'], context=context)
344 values['date_deadline']= event.date_begin
345 values['description']= event.mail_confirm
346 res = super(event_registration, self).create(cr, uid, values, context=context)
347 registrations = self.browse(cr, uid, [res], context=context)
348 self._history(cr, uid, registrations, _('Created'))
351 def write(self, cr, uid, ids, values, context=None):
352 if 'event_id' in values:
353 event = self.pool.get('event.event').browse(cr, uid, values['event_id'], context=context)
354 values['date_deadline']= event.date_begin
355 values['description']= event.mail_confirm
356 return super(event_registration, self).write(cr, uid, ids, values, context=context)
359 def mail_user(self, cr, uid, ids, confirm=False, context=None):
366 for reg_id in self.browse(cr, uid, ids):
367 src = reg_id.event_id.reply_to or False
369 if reg_id.email_from:
370 dest += [reg_id.email_from]
372 dest += [reg_id.email_cc]
375 tools.email_send(src, dest,
376 _('Auto Confirmation: [%s] %s') %(reg_id.id, reg_id.name),
377 reg_id.event_id.mail_confirm,
378 openobject_id = reg_id.id)
379 elif reg_id.event_id.mail_auto_confirm or reg_id.event_id.mail_auto_registr:
380 if reg_id.event_id.state in ['draft', 'fixed', 'open', 'confirm', 'running'] and reg_id.event_id.mail_auto_registr:
381 tools.email_send(src, dest,
382 _('Auto Registration: [%s] %s') %(reg_id.id, reg_id.name),
383 reg_id.event_id.mail_registr, openobject_id = reg_id.id)
384 if (reg_id.event_id.state in ['confirm', 'running']) and reg_id.event_id.mail_auto_confirm:
385 tools.email_send(src, dest,
386 _('Auto Confirmation: [%s] %s') %(reg_id.id, reg_id.name),
387 reg_id.event_id.mail_confirm, openobject_id = reg_id.id)
390 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'))
394 def mail_user_confirm(self, cr, uid, ids, context=None):
398 return self.mail_user(cr, uid, ids, confirm=True, context=context)
400 def _create_invoice_lines(self, cr, uid, ids, vals):
401 """ Create account Invoice line for Registration Id.
403 return self.pool.get('account.invoice.line').create(cr, uid, vals)
405 def onchange_badge_name(self, cr, uid, ids, badge_name):
410 data['name'] = 'Registration: ' + badge_name
411 return {'value': data}
413 def onchange_contact_id(self, cr, uid, ids, contact, partner):
419 contact_id = self.pool.get('res.partner.contact').browse(cr, uid, contact)
420 data['badge_name'] = contact_id.name
421 data['badge_title'] = contact_id.title
423 partner_addresses = self.pool.get('res.partner.address').search(cr, uid, [('partner_id', '=', partner)])
424 job_ids = self.pool.get('res.partner.job').search(cr, uid, [('contact_id', '=', contact), ('address_id', 'in', partner_addresses)])
426 data['email_from'] = self.pool.get('res.partner.job').browse(cr, uid, job_ids[0]).email
427 d = self.onchange_badge_name(cr, uid, ids, data['badge_name'])
428 data.update(d['value'])
429 return {'value': data}
431 def onchange_event(self, cr, uid, ids, event_id, partner_invoice_id):
434 return {'value': {'unit_price': False, 'event_product': False}}
435 data_event = self.pool.get('event.event').browse(cr, uid, event_id)
437 if data_event.product_id:
438 if not partner_invoice_id:
439 unit_price=self.pool.get('product.product').price_get(cr, uid, [data_event.product_id.id], context=context)[data_event.product_id.id]
440 return {'value': {'unit_price': unit_price, 'event_product': data_event.product_id.name}}
441 data_partner = self.pool.get('res.partner').browse(cr, uid, partner_invoice_id)
442 context.update({'partner_id': data_partner})
443 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]
444 return {'value': {'unit_price': unit_price, 'event_product': data_event.product_id.name}}
446 return {'value': {'unit_price': False, 'event_product': False}}
448 def onchange_partner_id(self, cr, uid, ids, part, event_id, email=False):
451 data['badge_partner'] = data['contact_id'] = data['partner_invoice_id'] = data['email_from'] = data['badge_title'] = data['badge_name'] = False
453 return {'value': data}
454 data['partner_invoice_id']=part
455 # this calls onchange_partner_invoice_id
456 d = self.onchange_partner_invoice_id(cr, uid, ids, event_id, part)
457 # this updates the dictionary
458 data.update(d['value'])
459 addr = self.pool.get('res.partner').address_get(cr, uid, [part])
461 if addr.has_key('default'):
462 job_ids = self.pool.get('res.partner.job').search(cr, uid, [('address_id', '=', addr['default'])])
464 data['contact_id'] = self.pool.get('res.partner.job').browse(cr, uid, job_ids[0]).contact_id.id
465 d = self.onchange_contact_id(cr, uid, ids, data['contact_id'], part)
466 data.update(d['value'])
467 partner_data = self.pool.get('res.partner').browse(cr, uid, part)
468 data['badge_partner'] = partner_data.name
469 return {'value': data}
471 def onchange_partner_invoice_id(self, cr, uid, ids, event_id, partner_invoice_id):
475 data['unit_price']=False
477 return {'value': data}
478 data_event = self.pool.get('event.event').browse(cr, uid, event_id)
480 if data_event.product_id:
481 if not partner_invoice_id:
482 data['unit_price']=self.pool.get('product.product').price_get(cr, uid, [data_event.product_id.id], context=context)[data_event.product_id.id]
483 return {'value': data}
484 data_partner = self.pool.get('res.partner').browse(cr, uid, partner_invoice_id)
485 context.update({'partner_id': data_partner})
486 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]
487 return {'value': data}
488 return {'value': data}
493 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: