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