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