[IMP] Changed all module categories, limited number of categories
[odoo/odoo.git] / addons / event / event.py
1 # -*- coding: utf-8 -*-
2 ##############################################################################
3 #
4 #    OpenERP, Open Source Management Solution
5 #    Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
6 #
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.
11 #
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.
16 #
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/>.
19 #
20 ##############################################################################
21
22 import time
23
24 from crm import crm
25 from osv import fields, osv
26 from tools.translate import _
27 import tools
28 import decimal_precision as dp
29
30 class event_type(osv.osv):
31     """ Event Type """
32     _name = 'event.type'
33     _description = __doc__
34     _columns = {
35         'name': fields.char('Event type', size=64, required=True),
36     }
37
38 event_type()
39
40 class event_event(osv.osv):
41     """Event"""
42     _name = 'event.event'
43     _description = __doc__
44     _order = 'date_begin'
45
46     def copy(self, cr, uid, id, default=None, context=None):
47         """ Copy record of Given id
48         @param id: Id of Event record.
49         @param context: A standard dictionary for contextual values
50         """
51         if not default:
52             default = {}
53         default.update({
54             'state': 'draft',
55             'registration_ids': False,
56         })
57         return super(event_event, self).copy(cr, uid, id, default=default, context=context)
58
59     def onchange_product(self, cr, uid, ids, product_id=False):
60         """This function returns value of  product's unit price based on product id.
61         @param self: The object pointer
62         @param cr: the current row, from the database cursor,
63         @param uid: the current user’s ID for security checks,
64         @param ids: List of Event IDs
65         @param product_id: Product's id
66         """
67         if not product_id:
68             return {'value': {'unit_price': False}}
69         else:
70            unit_price=self.pool.get('product.product').price_get(cr, uid, [product_id])[product_id]
71            return {'value': {'unit_price': unit_price}}
72
73     def button_draft(self, cr, uid, ids, context=None):
74         return self.write(cr, uid, ids, {'state': 'draft'}, context=context)
75
76     def button_cancel(self, cr, uid, ids, context=None):
77         return self.write(cr, uid, ids, {'state': 'cancel'}, context=context)
78
79     def button_done(self, cr, uid, ids, context=None):
80         if type(ids) in (int, long,):
81             ids = [ids]
82         return self.write(cr, uid, ids, {'state': 'done'}, context=context)
83
84     def do_confirm(self, cr, uid, ids, context=None):
85         """ Confirm Event and send confirmation email to all register peoples
86         """
87         register_pool = self.pool.get('event.registration')
88         for event in self.browse(cr, uid, ids, context=context):
89             if event.mail_auto_confirm:
90                 #send reminder that will confirm the event for all the people that were already confirmed
91                 reg_ids = register_pool.search(cr, uid, [
92                                ('event_id', '=', event.id),
93                                ('state', 'not in', ['draft', 'cancel'])], context=context)
94                 register_pool.mail_user_confirm(cr, uid, reg_ids)
95
96         return self.write(cr, uid, ids, {'state': 'confirm'}, context=context)
97
98     def button_confirm(self, cr, uid, ids, context=None):
99         """This Function Confirm Event.
100         @param ids: List of Event IDs
101         @param context: A standard dictionary for contextual values
102         @return: True
103         """
104         if context is None:
105             context = {}
106         res = False
107         if type(ids) in (int, long,):
108             ids = [ids]
109         data_pool = self.pool.get('ir.model.data')
110         unconfirmed_ids = []
111         for event in self.browse(cr, uid, ids, context=context):
112             total_confirmed = event.register_current
113             if total_confirmed >= event.register_min or event.register_max == 0:
114                 res = self.do_confirm(cr, uid, [event.id], context=context)
115             else:
116                 unconfirmed_ids.append(event.id)
117         if unconfirmed_ids:
118             view_id = data_pool.get_object_reference(cr, uid, 'event', 'view_event_confirm')
119             view_id = view_id and view_id[1] or False
120             context['event_ids'] = unconfirmed_ids
121             return {
122                 'name': _('Confirm Event'),
123                 'context': context,
124                 'view_type': 'form',
125                 'view_mode': 'tree,form',
126                 'res_model': 'event.confirm',
127                 'views': [(view_id, 'form')],
128                 'type': 'ir.actions.act_window',
129                 'target': 'new',
130                 'context': context,
131                 'nodestroy': True
132             }
133         return res
134
135     def _get_register(self, cr, uid, ids, fields, args, context=None):
136         """Get Confirm or uncofirm register value.
137         @param ids: List of Event registration type's id
138         @param fields: List of function fields(register_current and register_prospect).
139         @param context: A standard dictionary for contextual values
140         @return: Dictionary of function fields value.
141         """
142         register_pool = self.pool.get('event.registration')
143         res = {}
144         for event in self.browse(cr, uid, ids, context=context):
145             res[event.id] = {}
146             for field in fields:
147                 res[event.id][field] = False
148             state = []
149             if 'register_current' in fields:
150                 state += ['open', 'done']
151             if 'register_prospect' in fields:
152                 state.append('draft')
153
154             reg_ids = register_pool.search(cr, uid, [
155                         ('event_id', '=', event.id),
156                        ('state', 'in', state)], context=context)
157
158             number = 0.0
159             if reg_ids:
160                 cr.execute('SELECT SUM(nb_register) FROM event_registration WHERE id IN %s', (tuple(reg_ids),))
161                 number = cr.fetchone()
162
163             if 'register_current' in fields:
164                 res[event.id]['register_current'] = number and number[0] or 0.0
165             if 'register_prospect' in fields:
166                 res[event.id]['register_prospect'] = number and number[0] or 0.0
167         return res
168
169     def write(self, cr, uid, ids, vals, context=None):
170         """
171         Writes values in one or several fields.
172         @param ids: List of Event registration type's IDs
173         @param vals: dictionary with values to update.
174         @return: True
175         """
176         register_pool = self.pool.get('event.registration')
177         res = super(event_event, self).write(cr, uid, ids, vals, context=context)
178         if vals.get('date_begin', False) or vals.get('mail_auto_confirm', False) or vals.get('mail_confirm', False):
179             for event in self.browse(cr, uid, ids, context=context):
180                 #change the deadlines of the registration linked to this event
181                 register_values = {}
182                 if vals.get('date_begin', False):
183                     register_values['date_deadline'] = vals['date_begin']
184
185                 #change the description of the registration linked to this event
186                 if vals.get('mail_auto_confirm', False):
187                     if vals['mail_auto_confirm']:
188                         if 'mail_confirm' not in vals:
189                             vals['mail_confirm'] = event.mail_confirm
190                     else:
191                         vals['mail_confirm'] = False
192                 if 'mail_confirm' in vals:
193                     register_values['description'] = vals['mail_confirm']
194
195                 if register_values:
196                     reg_ids = register_pool.search(cr, uid, [('event_id', '=', event.id)], context=context)
197                     register_pool.write(cr, uid, reg_ids, register_values, context=context)
198         return res
199
200     _columns = {
201         'name': fields.char('Summary', size=64, required=True, translate=True, readonly=False, states={'done': [('readonly', True)]}),
202         'user_id': fields.many2one('res.users', 'Responsible User', readonly=False, states={'done': [('readonly', True)]}),
203         'parent_id': fields.many2one('event.event', 'Parent Event', readonly=False, states={'done': [('readonly', True)]}),
204         'section_id': fields.many2one('crm.case.section', 'Sale Team', readonly=False, states={'done': [('readonly', True)]}),
205         'child_ids': fields.one2many('event.event', 'parent_id', 'Child Events', readonly=False, states={'done': [('readonly', True)]}),
206         'reply_to': fields.char('Reply-To', size=64, readonly=False, states={'done': [('readonly', True)]}, help="The email address put in the 'Reply-To' of all emails sent by OpenERP"),
207         'type': fields.many2one('event.type', 'Type', help="Type of Event like Seminar, Exhibition, Conference, Training.", readonly=False, states={'done': [('readonly', True)]}),
208         'register_max': fields.integer('Maximum Registrations', help="Provide Maximun Number of Registrations", readonly=True, states={'draft': [('readonly', False)]}),
209         'register_min': fields.integer('Minimum Registrations', help="Providee Minimum Number of Registrations", readonly=True, states={'draft': [('readonly', False)]}),
210         'register_current': fields.function(_get_register, method=True, string='Confirmed Registrations', multi='register_current',
211             help="Total of Open and Done Registrations"),
212         'register_prospect': fields.function(_get_register, method=True, string='Unconfirmed Registrations', multi='register_prospect',
213             help="Total of Prospect Registrati./event/event.py:41:ons"),
214         'registration_ids': fields.one2many('event.registration', 'event_id', 'Registrations', readonly=False, states={'done': [('readonly', True)]}),
215         'date_begin': fields.datetime('Beginning date', required=True, help="Beginning Date of Event", readonly=True, states={'draft': [('readonly', False)]}),
216         'date_end': fields.datetime('Closing date', required=True, help="Closing Date of Event", readonly=True, states={'draft': [('readonly', False)]}),
217         'state': fields.selection([
218             ('draft', 'Draft'),
219             ('confirm', 'Confirmed'),
220             ('done', 'Done'),
221             ('cancel', 'Cancelled')],
222             'State', readonly=True, required=True,
223             help='If event is created, the state is \'Draft\'.If event is confirmed for the particular dates the state is set to \'Confirmed\'. If the event is over, the state is set to \'Done\'.If event is cancelled the state is set to \'Cancelled\'.'),
224         'mail_auto_registr': fields.boolean('Mail Auto Register', readonly=False, states={'done': [('readonly', True)]}, help='Check this box if you want to use the automatic mailing for new registration'),
225         'mail_auto_confirm': fields.boolean('Mail Auto Confirm', readonly=False, states={'done': [('readonly', True)]}, help='Check this box if you want ot use the automatic confirmation emailing or the reminder'),
226         'mail_registr': fields.text('Registration Email', readonly=False, states={'done': [('readonly', True)]}, help='This email will be sent when someone subscribes to the event.'),
227         'mail_confirm': fields.text('Confirmation Email', readonly=False, states={'done': [('readonly', True)]}, 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."),
228         'product_id': fields.many2one('product.product', 'Product', required=True, readonly=True, states={'draft': [('readonly', False)]}, help="The invoices of this event registration will be created with this Product. Thus it allows you to set the default label and the accounting info you want by default on these invoices."),
229         'note': fields.text('Notes', help="Description or Summary of Event", readonly=False, states={'done': [('readonly', True)]}),
230         'pricelist_id': fields.many2one('product.pricelist', 'Pricelist', readonly=True, states={'draft': [('readonly', False)]}, help="Pricelist version for current event."),
231         'unit_price': fields.related('product_id', 'list_price', type='float', string='Registration Cost', readonly=True, states={'draft':[('readonly',False)]}, help="This will be the default price used as registration cost when invoicing this event. Note that you can specify for each registration a specific amount if you want to", digits_compute=dp.get_precision('Sale Price')),
232         'main_speaker_id': fields.many2one('res.partner','Main Speaker', readonly=False, states={'done': [('readonly', True)]}, help="Speaker who are giving speech on event."),
233         'speaker_ids': fields.many2many('res.partner', 'event_speaker_rel', 'speaker_id', 'partner_id', 'Other Speakers', readonly=False, states={'done': [('readonly', True)]}),
234         'address_id': fields.many2one('res.partner.address','Location Address', readonly=False, states={'done': [('readonly', True)]}),
235         'speaker_confirmed': fields.boolean('Speaker Confirmed', readonly=False, states={'done': [('readonly', True)]}),
236         'country_id': fields.related('address_id', 'country_id',
237                     type='many2one', relation='res.country', string='Country', readonly=False, states={'done': [('readonly', True)]}),
238         'language': fields.char('Language',size=64, readonly=False, states={'done': [('readonly', True)]}),
239         'note': fields.text('Description', readonly=False, states={'done': [('readonly', True)]}),
240         'company_id': fields.many2one('res.company', 'Company', required=False, change_default=True, readonly=False, states={'done': [('readonly', True)]}),
241     }
242
243     _defaults = {
244         'state': 'draft',
245         'company_id': lambda self,cr,uid,c: self.pool.get('res.company')._company_default_get(cr, uid, 'event.event', context=c),
246         'user_id': lambda obj, cr, uid, context: uid,
247     }
248
249     def _check_recursion(self, cr, uid, ids, context=None):
250         return super(event_event, self)._check_recursion(cr, uid, ids, context=context)
251
252     def _check_closing_date(self, cr, uid, ids, context=None):
253         for event in self.browse(cr, uid, ids, context=context):
254             if event.date_end < event.date_begin:
255                 return False
256         return True
257
258     _constraints = [
259         (_check_recursion, 'Error ! You cannot create recursive event.', ['parent_id']),
260         (_check_closing_date, 'Error ! Closing Date cannot be set before Beginning Date.', ['date_end']),
261     ]
262
263     def do_team_change(self, cr, uid, ids, team_id, context=None):
264         """
265         On Change Callback: when team change, this is call.
266         on this function, take value of reply_to from selected team.
267         """
268         if not team_id:
269             return {}
270         team_pool = self.pool.get('crm.case.section')
271         res = {}
272         team = team_pool.browse(cr, uid, team_id, context=context)
273         if team.reply_to:
274             res = {'value': {'reply_to': team.reply_to}}
275         return res
276
277 event_event()
278
279 class event_registration(osv.osv):
280     """Event Registration"""
281     _name= 'event.registration'
282     _description = __doc__
283     _inherit = 'mailgate.thread'
284
285     def _amount_line(self, cr, uid, ids, field_name, arg, context=None):
286         cur_obj = self.pool.get('res.currency')
287         res = {}
288         for line in self.browse(cr, uid, ids, context=context):
289             price = line.unit_price * line.nb_register
290             pricelist = line.event_id.pricelist_id or line.partner_invoice_id.property_product_pricelist
291             cur = pricelist and pricelist.currency_id or False
292             res[line.id] = cur and cur_obj.round(cr, uid, cur, price) or price
293         return res
294
295     _columns = {
296         'name': fields.char('Summary', size=124,  readonly=True, states={'draft': [('readonly', False)]}),
297         'email_cc': fields.text('CC', size=252, readonly=False, states={'done': [('readonly', True)]}, help="These email addresses will be added to the CC field of all inbound and outbound emails for this record before being sent. Separate multiple email addresses with a comma"),
298         'nb_register': fields.integer('Quantity', required=True, readonly=True, states={'draft': [('readonly', False)]}, help="Number of Registrations or Tickets"),
299         'event_id': fields.many2one('event.event', 'Event', required=True, readonly=True, states={'draft': [('readonly', False)]}),
300         'partner_id': fields.many2one('res.partner', 'Partner', states={'done': [('readonly', True)]}),
301         "partner_invoice_id": fields.many2one('res.partner', 'Partner Invoiced', readonly=True, states={'draft': [('readonly', False)]}),
302         "contact_id": fields.many2one('res.partner.contact', 'Partner Contact', readonly=False, states={'done': [('readonly', True)]}), #TODO: filter only the contacts that have a function into the selected partner_id
303         "unit_price": fields.float('Unit Price', required=True, digits_compute=dp.get_precision('Sale Price'), readonly=True, states={'draft': [('readonly', False)]}),
304         'price_subtotal': fields.function(_amount_line, method=True, string='Subtotal', digits_compute=dp.get_precision('Sale Price'), store=True),
305         "badge_ids": fields.one2many('event.registration.badge', 'registration_id', 'Badges', readonly=False, states={'done': [('readonly', True)]}),
306         "event_product": fields.char("Invoice Name", size=128, readonly=True, states={'draft': [('readonly', False)]}),
307         "tobe_invoiced": fields.boolean("To be Invoiced", readonly=True, states={'draft': [('readonly', False)]}),
308         "invoice_id": fields.many2one("account.invoice", "Invoice", readonly=True),
309         'date_closed': fields.datetime('Closed', readonly=True),
310         'ref': fields.reference('Reference', selection=crm._links_get, size=128),
311         'ref2': fields.reference('Reference 2', selection=crm._links_get, size=128),
312         'email_from': fields.char('Email', size=128, states={'done': [('readonly', True)]}, help="These people will receive email."),
313         'create_date': fields.datetime('Creation Date', readonly=True),
314         'write_date': fields.datetime('Write Date', readonly=True),
315         'description': fields.text('Description', states={'done': [('readonly', True)]}),
316         'message_ids': fields.one2many('mailgate.message', 'res_id', 'Messages', domain=[('model','=',_name)]),
317         'log_ids': fields.one2many('mailgate.message', 'res_id', 'Logs', domain=[('history', '=', False),('model','=',_name)]),
318         'date_deadline': fields.related('event_id','date_end', type='datetime', string="End Date", readonly=True),
319         'date': fields.related('event_id', 'date_begin', type='datetime', string="Start Date", readonly=True),
320         'user_id': fields.many2one('res.users', 'Responsible', states={'done': [('readonly', True)]}),
321         'active': fields.boolean('Active'),
322         'section_id': fields.related('event_id', 'section_id', type='many2one', relation='crm.case.section', string='Sale Team', store=True, readonly=True),
323         'company_id': fields.related('event_id', 'company_id', type='many2one', relation='res.company', string='Company', store=True, readonly=True, states={'draft':[('readonly',False)]}),
324         'state': fields.selection([('open', 'Confirmed'),
325                                     ('draft', 'Unconfirmed'),
326                                     ('cancel', 'Cancelled'),
327                                     ('done', 'Done')], 'State', \
328                                     size=16, readonly=True)
329     }
330     _defaults = {
331         'nb_register': 1,
332         'tobe_invoiced':  True,
333         'state': 'draft',
334         'active': 1,
335         'user_id': lambda self, cr, uid, ctx: uid,
336     }
337
338     def _make_invoice(self, cr, uid, reg, lines, context=None):
339         """ Create Invoice from Invoice lines
340         @param reg: Model of Event Registration
341         @param lines: Ids of Invoice lines
342         """
343         if context is None:
344             context = {}
345         inv_pool = self.pool.get('account.invoice')
346         val_invoice = inv_pool.onchange_partner_id(cr, uid, [], 'out_invoice', reg.partner_invoice_id.id, False, False)
347         val_invoice['value'].update({'partner_id': reg.partner_invoice_id.id})
348         val_invoice['value'].update({
349                 'origin': reg.event_product,
350                 'reference': False,
351                 'invoice_line': [(6, 0, lines)],
352                 'comment': "",
353                 'date_invoice': context.get('date_inv', False)
354             })
355         inv_id = inv_pool.create(cr, uid, val_invoice['value'], context=context)
356         inv_pool.button_compute(cr, uid, [inv_id])
357         self.history(cr, uid, [reg], _('Invoiced'))
358         return inv_id
359
360     def copy(self, cr, uid, id, default=None, context=None):
361         """ Copy record of Given id
362         @param id: Id of Registration record.
363         @param context: A standard dictionary for contextual values
364         """
365         if not default:
366             default = {}
367         default.update({
368             'invoice_id': False,
369         })
370         return super(event_registration, self).copy(cr, uid, id, default=default, context=context)
371
372     def action_invoice_create(self, cr, uid, ids, grouped=False, date_inv = False, context=None):
373         """ Action of Create Invoice """
374         res = False
375         invoices = {}
376         tax_ids=[]
377         new_invoice_ids = []
378         inv_lines_pool = self.pool.get('account.invoice.line')
379         inv_pool = self.pool.get('account.invoice')
380         product_pool = self.pool.get('product.product')
381         contact_pool = self.pool.get('res.partner.contact')
382         if context is None:
383             context = {}
384         # If date was specified, use it as date invoiced, usefull when invoices are generated this month and put the
385         # last day of the last month as invoice date
386         if date_inv:
387             context['date_inv'] = date_inv
388
389         for reg in self.browse(cr, uid, ids, context=context):
390             val_invoice = inv_pool.onchange_partner_id(cr, uid, [], 'out_invoice', reg.partner_invoice_id.id, False, False)
391             val_invoice['value'].update({'partner_id': reg.partner_invoice_id.id})
392             partner_address_id = val_invoice['value']['address_invoice_id']
393             if not partner_address_id:
394                raise osv.except_osv(_('Error !'),
395                         _("Registered partner doesn't have an address to make the invoice."))
396
397             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)
398             product = product_pool.browse(cr, uid, reg.event_id.product_id.id, context=context)
399             for tax in product.taxes_id:
400                 tax_ids.append(tax.id)
401             vals = value['value']
402             c_name = reg.contact_id and ('-' + contact_pool.name_get(cr, uid, [reg.contact_id.id])[0][1]) or ''
403             vals.update({
404                 'name': reg.event_product + '-' + c_name,
405                 'price_unit': reg.unit_price,
406                 'quantity': reg.nb_register,
407                 'product_id':reg.event_id.product_id.id,
408                 'invoice_line_tax_id': [(6, 0, tax_ids)],
409             })
410             inv_line_ids = self._create_invoice_lines(cr, uid, [reg.id], vals)
411             invoices.setdefault(reg.partner_id.id, []).append((reg, inv_line_ids))
412         for val in invoices.values():
413             res = False
414             if grouped:
415                 res = self._make_invoice(cr, uid, val[0][0], [v for k, v in val], context=context)
416
417                 for k, v in val:
418                     self.do_close(cr, uid, [k.id], context={'invoice_id': res})
419
420             else:
421                for k, v in val:
422                    res = self._make_invoice(cr, uid, k, [v], context=context)
423                    self.do_close(cr, uid, [k.id], context={'invoice_id': res})
424             if res: new_invoice_ids.append(res)
425         return new_invoice_ids
426
427     def do_open(self, cr, uid, ids, context=None):
428         """ Open Registration
429         """
430         res = self.write(cr, uid, ids, {'state': 'open'}, context=context)
431         self.mail_user(cr, uid, ids)
432         self.history(cr, uid, ids, _('Open'))
433         return res
434
435     def do_close(self, cr, uid, ids, context=None):
436         """ Close Registration
437         """
438         if context is None:
439             context = {}
440         invoice_id = context.get('invoice_id', False)
441         values = {'state': 'done', 'date_closed': time.strftime('%Y-%m-%d %H:%M:%S')}
442         msg = _('Done')
443         if invoice_id:
444             values['invoice_id'] = invoice_id
445         res = self.write(cr, uid, ids, values)
446         self.history(cr, uid, ids, msg)
447         return res
448
449     def check_confirm(self, cr, uid, ids, context=None):
450         """This Function Open Event Registration and send email to user.
451         @param ids: List of Event registration's IDs
452         @param context: A standard dictionary for contextual values
453         @return: True
454         """
455         if type(ids) in (int, long,):
456             ids = [ids]
457         data_pool = self.pool.get('ir.model.data')
458         unconfirmed_ids = []
459         if context is None:
460             context = {}
461         for registration in self.browse(cr, uid, ids, context=context):
462             total_confirmed = registration.event_id.register_current + registration.nb_register
463             if total_confirmed <= registration.event_id.register_max or registration.event_id.register_max == 0:
464                 self.do_open(cr, uid, [registration.id], context=context)
465             else:
466                 unconfirmed_ids.append(registration.id)
467         if unconfirmed_ids:
468             view_id = data_pool.get_object_reference(cr, uid, 'event', 'view_event_confirm_registration')
469             view_id = view_id and view_id[1] or False
470             context['registration_ids'] = unconfirmed_ids
471             return {
472                 'name': _('Confirm Registration'),
473                 'context': context,
474                 'view_type': 'form',
475                 'view_mode': 'tree,form',
476                 'res_model': 'event.confirm.registration',
477                 'views': [(view_id, 'form')],
478                 'type': 'ir.actions.act_window',
479                 'target': 'new',
480                 'context': context,
481                 'nodestroy': True
482             }
483         return True
484
485     def button_reg_close(self, cr, uid, ids, context=None):
486         """This Function Close Event Registration.
487         """
488         data_pool = self.pool.get('ir.model.data')
489         unclosed_ids = []
490         for registration in self.browse(cr, uid, ids, context=context):
491             if registration.tobe_invoiced and not registration.invoice_id:
492                 unclosed_ids.append(registration.id)
493             else:
494                 self.do_close(cr, uid, [registration.id], context=context)
495         if unclosed_ids:
496             view_id = data_pool.get_object_reference(cr, uid, 'event', 'view_event_make_invoice')
497             view_id = view_id and view_id[1] or False
498             context['active_ids'] = unclosed_ids
499             return {
500                 'name': _('Close Registration'),
501                 'context': context,
502                 'view_type': 'form',
503                 'view_mode': 'tree,form',
504                 'res_model': 'event.make.invoice',
505                 'views': [(view_id, 'form')],
506                 'type': 'ir.actions.act_window',
507                 'target': 'new',
508                 'context': context,
509                 'nodestroy': True
510             }
511         return True
512
513     def button_reg_cancel(self, cr, uid, ids, *args):
514         """This Function Cancel Event Registration.
515         """
516         registrations = self.browse(cr, uid, ids)
517         self.history(cr, uid, registrations, _('Cancel'))
518         return self.write(cr, uid, ids, {'state': 'cancel'})
519
520     def mail_user(self, cr, uid, ids, confirm=False, context=None):
521         """
522         Send email to user
523         """
524
525         for regestration in self.browse(cr, uid, ids, context=context):
526             src = regestration.event_id.reply_to or False
527             email_to = []
528             email_cc = []
529             if regestration.email_from:
530                 email_to = regestration.email_from
531             if regestration.email_cc:
532                 email_cc += [regestration.email_cc]
533             if not (email_to or email_cc):
534                 continue
535             subject = ""
536             body = ""
537             if confirm:
538                 subject = _('Auto Confirmation: [%s] %s') %(regestration.id, regestration.name)
539                 body = regestration.event_id.mail_confirm
540             elif regestration.event_id.mail_auto_confirm or regestration.event_id.mail_auto_registr:
541                 if regestration.event_id.state in ['draft', 'fixed', 'open', 'confirm', 'running'] and regestration.event_id.mail_auto_registr:
542                     subject = _('Auto Registration: [%s] %s') %(regestration.id, regestration.name)
543                     body = regestration.event_id.mail_registr
544                 if (regestration.event_id.state in ['confirm', 'running']) and regestration.event_id.mail_auto_confirm:
545                     subject = _('Auto Confirmation: [%s] %s') %(regestration.id, regestration.name)
546                     body = regestration.event_id.mail_confirm
547             if subject or body:
548                 tools.email_send(src, email_to, subject, body, email_cc=email_cc, openobject_id=regestration.id)
549                 self.history(cr, uid, [regestration], subject, history = True, \
550                         email=email_to, details=body, \
551                         subjec=subject, email_from=src, \
552                         email_cc=', '.join(email_cc))
553
554         return True
555
556     def mail_user_confirm(self, cr, uid, ids, context=None):
557         """
558         Send email to user
559         """
560         return self.mail_user(cr, uid, ids, confirm=True, context=context)
561
562     def _create_invoice_lines(self, cr, uid, ids, vals):
563         """ Create account Invoice line for Registration Id.
564         """
565         return self.pool.get('account.invoice.line').create(cr, uid, vals)
566
567     def onchange_contact_id(self, cr, uid, ids, contact, partner):
568
569         """This function returns value of Badge Name, Badge Title based on Partner contact.
570         @param self: The object pointer
571         @param cr: the current row, from the database cursor,
572         @param uid: the current user’s ID for security checks,
573         @param ids: List of Registration IDs
574         @param contact: Patner Contact IDS
575         @param partner: Partner IDS
576         """
577         data ={}
578         if not contact:
579             return data
580         addr_obj = self.pool.get('res.partner.address')
581         job_obj = self.pool.get('res.partner.job')
582
583         if partner:
584             partner_addresses = addr_obj.search(cr, uid, [('partner_id', '=', partner)])
585             job_ids = job_obj.search(cr, uid, [('contact_id', '=', contact), ('address_id', 'in', partner_addresses)])
586             if job_ids:
587                 data['email_from'] = job_obj.browse(cr, uid, job_ids[0]).email
588         return {'value': data}
589
590     def onchange_event(self, cr, uid, ids, event_id, partner_invoice_id):
591         """This function returns value of Product Name, Unit Price based on Event.
592         @param self: The object pointer
593         @param cr: the current row, from the database cursor,
594         @param uid: the current user’s ID for security checks,
595         @param ids: List of Registration IDs
596         @param event_id: Event ID
597         @param partner_invoice_id: Partner Invoice ID
598         """
599         context = {}
600         if not event_id:
601             return {'value': {'unit_price': False, 'event_product': False}}
602
603         event_obj = self.pool.get('event.event')
604         prod_obj = self.pool.get('product.product')
605         res_obj = self.pool.get('res.partner')
606
607         data_event =  event_obj.browse(cr, uid, event_id)
608         res = {'value': {'unit_price': False,
609                          'event_product': False,
610                          'user_id': False,
611                          'date': data_event.date_begin,
612                          'date_deadline': data_event.date_end,
613                          'description': data_event.note,
614                          'name': data_event.name,
615                          'section_id': data_event.section_id and data_event.section_id.id or False,
616                         }}
617         if data_event.user_id.id:
618             res['value'].update({'user_id': data_event.user_id.id})
619         if data_event.product_id:
620             pricelist_id = data_event.pricelist_id and data_event.pricelist_id.id or False
621             if partner_invoice_id:
622                 partner = res_obj.browse(cr, uid, partner_invoice_id, context=context)
623                 pricelist_id = pricelist_id or partner.property_product_pricelist.id
624             unit_price = prod_obj._product_price(cr, uid, [data_event.product_id.id], False, False, {'pricelist': pricelist_id})[data_event.product_id.id]
625             if not unit_price:
626                 unit_price = data_event.unit_price
627             res['value'].update({'unit_price': unit_price, 'event_product': data_event.product_id.name})
628         return res
629
630     def onchange_partner_id(self, cr, uid, ids, part, event_id, email=False):
631         """This function returns value of Patner Invoice id, Unit Price, badget title based on partner and Event.
632         @param self: The object pointer
633         @param cr: the current row, from the database cursor,
634         @param uid: the current user’s ID for security checks,
635         @param ids: List of Registration IDs
636         @param event_id: Event ID
637         @param partner_invoice_id: Partner Invoice ID
638         """
639         job_obj = self.pool.get('res.partner.job')
640         res_obj = self.pool.get('res.partner')
641
642         data = {}
643         data['contact_id'], data['partner_invoice_id'], data['email_from'] = (False, False, False)
644         if not part:
645             return {'value': data}
646         data['partner_invoice_id'] = part
647         # this calls onchange_partner_invoice_id
648         d = self.onchange_partner_invoice_id(cr, uid, ids, event_id, part)
649         # this updates the dictionary
650         data.update(d['value'])
651         addr = res_obj.address_get(cr, uid, [part])
652         if addr:
653             if addr.has_key('default'):
654                 job_ids = job_obj.search(cr, uid, [('address_id', '=', addr['default'])])
655                 if job_ids:
656                     data['contact_id'] = job_obj.browse(cr, uid, job_ids[0]).contact_id.id
657                     d = self.onchange_contact_id(cr, uid, ids, data['contact_id'], part)
658                     data.update(d['value'])
659         return {'value': data}
660
661     def onchange_partner_invoice_id(self, cr, uid, ids, event_id, partner_invoice_id):
662         """This function returns value of Product unit Price based on Invoiced partner.
663         @param self: The object pointer
664         @param cr: the current row, from the database cursor,
665         @param uid: the current user’s ID for security checks,
666         @param ids: List of Registration IDs
667         @param event_id: Event ID
668         @param partner_invoice_id: Partner Invoice ID
669         """
670         data = {}
671         context = {}
672         event_obj = self.pool.get('event.event')
673         prod_obj = self.pool.get('product.product')
674         res_obj = self.pool.get('res.partner')
675
676         data['unit_price']=False
677         if not event_id:
678             return {'value': data}
679         data_event =  event_obj.browse(cr, uid, event_id, context=context)
680         if data_event.product_id:
681             data['event_product'] = data_event.product_id.name
682             pricelist_id = data_event.pricelist_id and data_event.pricelist_id.id or False
683             if partner_invoice_id:
684                 partner = res_obj.browse(cr, uid, partner_invoice_id, context=context)
685                 pricelist_id = pricelist_id or partner.property_product_pricelist.id
686             unit_price = prod_obj._product_price(cr, uid, [data_event.product_id.id], False, False, {'pricelist': pricelist_id})[data_event.product_id.id]
687             if not unit_price:
688                 unit_price = data_event.unit_price
689             data['unit_price'] = unit_price
690         return {'value': data}
691
692 event_registration()
693
694 class event_registration_badge(osv.osv):
695     _name = 'event.registration.badge'
696     _description = __doc__
697     _columns = {
698         "registration_id": fields.many2one('event.registration', 'Registration', required=True),
699         "title": fields.char('Title', size=128),
700         "name": fields.char('Name', size=128, required=True),
701         "address_id": fields.many2one('res.partner.address', 'Address'),
702     }
703
704 event_registration_badge()
705
706 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: