event: fix call to _check_recursion, after last commit.
[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 not context:
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):
250         return super(event_event, self)._check_recursion(cr, uid, ids)
251
252     def _check_closing_date(self, cr, uid, ids):
253         for event in self.browse(cr, uid, ids):
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         if context is None:
271             context = {}
272         team_pool = self.pool.get('crm.case.section')
273         res = {}
274         team = team_pool.browse(cr, uid, team_id, context=context)
275         if team.reply_to:
276             res = {'value': {'reply_to': team.reply_to}}
277         return res
278
279 event_event()
280
281 class event_registration(osv.osv):
282     """Event Registration"""
283     _name= 'event.registration'
284     _description = __doc__
285     _inherit = 'mailgate.thread'
286
287     def _amount_line(self, cr, uid, ids, field_name, arg, context=None):
288         cur_obj = self.pool.get('res.currency')
289         res = {}
290         context = context or {}
291         for line in self.browse(cr, uid, ids, context=context):
292             price = line.unit_price * line.nb_register
293             pricelist = line.event_id.pricelist_id or line.partner_invoice_id.property_product_pricelist
294             cur = pricelist and pricelist.currency_id or False
295             res[line.id] = cur and cur_obj.round(cr, uid, cur, price) or price
296         return res
297
298     _columns = {
299         'name': fields.char('Summary', size=124,  readonly=True, states={'draft': [('readonly', False)]}),
300         '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"),
301         'nb_register': fields.integer('Quantity', required=True, readonly=True, states={'draft': [('readonly', False)]}, help="Number of Registrations or Tickets"),
302         'event_id': fields.many2one('event.event', 'Event', required=True, readonly=True, states={'draft': [('readonly', False)]}),
303         'partner_id': fields.many2one('res.partner', 'Partner', states={'done': [('readonly', True)]}),
304         "partner_invoice_id": fields.many2one('res.partner', 'Partner Invoiced', readonly=True, states={'draft': [('readonly', False)]}),
305         "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
306         "unit_price": fields.float('Unit Price', required=True, digits_compute=dp.get_precision('Sale Price'), readonly=True, states={'draft': [('readonly', False)]}),
307         'price_subtotal': fields.function(_amount_line, method=True, string='Subtotal', digits_compute=dp.get_precision('Sale Price'), store=True),
308         "badge_ids": fields.one2many('event.registration.badge', 'registration_id', 'Badges', readonly=False, states={'done': [('readonly', True)]}),
309         "event_product": fields.char("Invoice Name", size=128, readonly=True, states={'draft': [('readonly', False)]}),
310         "tobe_invoiced": fields.boolean("To be Invoiced", readonly=True, states={'draft': [('readonly', False)]}),
311         "invoice_id": fields.many2one("account.invoice", "Invoice", readonly=True),
312         'date_closed': fields.datetime('Closed', readonly=True),
313         'ref': fields.reference('Reference', selection=crm._links_get, size=128),
314         'ref2': fields.reference('Reference 2', selection=crm._links_get, size=128),
315         'email_from': fields.char('Email', size=128, states={'done': [('readonly', True)]}, help="These people will receive email."),
316         'create_date': fields.datetime('Creation Date', readonly=True),
317         'write_date': fields.datetime('Write Date', readonly=True),
318         'description': fields.text('Description', states={'done': [('readonly', True)]}),
319         'message_ids': fields.one2many('mailgate.message', 'res_id', 'Messages', domain=[('model','=',_name)]),
320         'log_ids': fields.one2many('mailgate.message', 'res_id', 'Logs', domain=[('history', '=', False),('model','=',_name)]),
321         'date_deadline': fields.related('event_id','date_end', type='datetime', string="End Date", readonly=True),
322         'date': fields.related('event_id', 'date_begin', type='datetime', string="Start Date", readonly=True),
323         'user_id': fields.many2one('res.users', 'Responsible', states={'done': [('readonly', True)]}),
324         'active': fields.boolean('Active'),
325         'section_id': fields.related('event_id', 'section_id', type='many2one', relation='crm.case.section', string='Sale Team', store=True, readonly=True),
326         'company_id': fields.related('event_id', 'company_id', type='many2one', relation='res.company', string='Company', store=True, readonly=True, states={'draft':[('readonly',False)]}),
327         'state': fields.selection([('open', 'Confirmed'),
328                                     ('draft', 'Unconfirmed'),
329                                     ('cancel', 'Cancelled'),
330                                     ('done', 'Done')], 'State', \
331                                     size=16, readonly=True)
332     }
333     _defaults = {
334         'nb_register': 1,
335         'tobe_invoiced':  True,
336         'state': 'draft',
337         'active': 1,
338         'user_id': lambda self, cr, uid, ctx: uid,
339     }
340
341     def _make_invoice(self, cr, uid, reg, lines, context=None):
342         """ Create Invoice from Invoice lines
343         @param reg: Model of Event Registration
344         @param lines: Ids of Invoice lines
345         """
346         if context is None:
347             context = {}
348         inv_pool = self.pool.get('account.invoice')
349         val_invoice = inv_pool.onchange_partner_id(cr, uid, [], 'out_invoice', reg.partner_invoice_id.id, False, False)
350         val_invoice['value'].update({'partner_id': reg.partner_invoice_id.id})
351         val_invoice['value'].update({
352                 'origin': reg.event_product,
353                 'reference': False,
354                 'invoice_line': [(6, 0, lines)],
355                 'comment': "",
356                 'date_invoice': context.get('date_inv', False)
357             })
358         inv_id = inv_pool.create(cr, uid, val_invoice['value'], context=context)
359         inv_pool.button_compute(cr, uid, [inv_id])
360         self.history(cr, uid, [reg], _('Invoiced'))
361         return inv_id
362
363     def copy(self, cr, uid, id, default=None, context=None):
364         """ Copy record of Given id
365         @param id: Id of Registration record.
366         @param context: A standard dictionary for contextual values
367         """
368         if not default:
369             default = {}
370         default.update({
371             'invoice_id': False,
372         })
373         return super(event_registration, self).copy(cr, uid, id, default=default, context=context)
374
375     def action_invoice_create(self, cr, uid, ids, grouped=False, date_inv = False, context=None):
376         """ Action of Create Invoice """
377         res = False
378         invoices = {}
379         tax_ids=[]
380         new_invoice_ids = []
381         inv_lines_pool = self.pool.get('account.invoice.line')
382         inv_pool = self.pool.get('account.invoice')
383         product_pool = self.pool.get('product.product')
384         contact_pool = self.pool.get('res.partner.contact')
385         if not context:
386             context = {}
387         # If date was specified, use it as date invoiced, usefull when invoices are generated this month and put the
388         # last day of the last month as invoice date
389         if date_inv:
390             context['date_inv'] = date_inv
391
392         for reg in self.browse(cr, uid, ids, context=context):
393             val_invoice = inv_pool.onchange_partner_id(cr, uid, [], 'out_invoice', reg.partner_invoice_id.id, False, False)
394             val_invoice['value'].update({'partner_id': reg.partner_invoice_id.id})
395             partner_address_id = val_invoice['value']['address_invoice_id']
396             if not partner_address_id:
397                raise osv.except_osv(_('Error !'),
398                         _("Registered partner doesn't have an address to make the invoice."))
399
400             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)
401             product = product_pool.browse(cr, uid, reg.event_id.product_id.id, context=context)
402             for tax in product.taxes_id:
403                 tax_ids.append(tax.id)
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         for val in invoices.values():
416             res = False
417             if grouped:
418                 res = self._make_invoice(cr, uid, val[0][0], [v for k, v in val], context=context)
419
420                 for k, v in val:
421                     self.do_close(cr, uid, [k.id], context={'invoice_id': res})
422
423             else:
424                for k, v in val:
425                    res = self._make_invoice(cr, uid, k, [v], context=context)
426                    self.do_close(cr, uid, [k.id], context={'invoice_id': res})
427             if res: new_invoice_ids.append(res)
428         return new_invoice_ids
429
430     def do_open(self, cr, uid, ids, context=None):
431         """ Open Registration
432         """
433         res = self.write(cr, uid, ids, {'state': 'open'}, context=context)
434         self.mail_user(cr, uid, ids)
435         self.history(cr, uid, ids, _('Open'))
436         return res
437
438     def do_close(self, cr, uid, ids, context=None):
439         """ Close Registration
440         """
441         if not context:
442             context = {}
443         invoice_id = context.get('invoice_id', False)
444         values = {'state': 'done', 'date_closed': time.strftime('%Y-%m-%d %H:%M:%S')}
445         msg = _('Done')
446         if invoice_id:
447             values['invoice_id'] = invoice_id
448         res = self.write(cr, uid, ids, values)
449         self.history(cr, uid, ids, msg)
450         return res
451
452     def check_confirm(self, cr, uid, ids, context=None):
453         """This Function Open Event Registration and send email to user.
454         @param ids: List of Event registration's IDs
455         @param context: A standard dictionary for contextual values
456         @return: True
457         """
458         if not context:
459             context = {}
460         if type(ids) in (int, long,):
461             ids = [ids]
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_object_reference(cr, uid, 'event', 'view_event_confirm_registration')
472             view_id = view_id and view_id[1] or False
473             context['registration_ids'] = unconfirmed_ids
474             return {
475                 'name': _('Confirm Registration'),
476                 'context': context,
477                 'view_type': 'form',
478                 'view_mode': 'tree,form',
479                 'res_model': 'event.confirm.registration',
480                 'views': [(view_id, 'form')],
481                 'type': 'ir.actions.act_window',
482                 'target': 'new',
483                 'context': context,
484                 'nodestroy': True
485             }
486         return True
487
488     def button_reg_close(self, cr, uid, ids, context=None):
489         """This Function Close Event Registration.
490         """
491         if not context:
492             context = {}
493         data_pool = self.pool.get('ir.model.data')
494         unclosed_ids = []
495         for registration in self.browse(cr, uid, ids, context=context):
496             if registration.tobe_invoiced and not registration.invoice_id:
497                 unclosed_ids.append(registration.id)
498             else:
499                 self.do_close(cr, uid, [registration.id], context=context)
500         if unclosed_ids:
501             view_id = data_pool.get_object_reference(cr, uid, 'event', 'view_event_make_invoice')
502             view_id = view_id and view_id[1] or False
503             context['active_ids'] = unclosed_ids
504             return {
505                 'name': _('Close Registration'),
506                 'context': context,
507                 'view_type': 'form',
508                 'view_mode': 'tree,form',
509                 'res_model': 'event.make.invoice',
510                 'views': [(view_id, 'form')],
511                 'type': 'ir.actions.act_window',
512                 'target': 'new',
513                 'context': context,
514                 'nodestroy': True
515             }
516         return True
517
518     def button_reg_cancel(self, cr, uid, ids, *args):
519         """This Function Cancel Event Registration.
520         """
521         registrations = self.browse(cr, uid, ids)
522         self.history(cr, uid, registrations, _('Cancel'))
523         return self.write(cr, uid, ids, {'state': 'cancel'})
524
525     def mail_user(self, cr, uid, ids, confirm=False, context=None):
526         """
527         Send email to user
528         """
529         if not context:
530             context = {}
531
532         for regestration in self.browse(cr, uid, ids, context=context):
533             src = regestration.event_id.reply_to or False
534             email_to = []
535             email_cc = []
536             if regestration.email_from:
537                 email_to = regestration.email_from
538             if regestration.email_cc:
539                 email_cc += [regestration.email_cc]
540             if not (email_to or email_cc):
541                 continue
542             subject = ""
543             body = ""
544             if confirm:
545                 subject = _('Auto Confirmation: [%s] %s') %(regestration.id, regestration.name)
546                 body = regestration.event_id.mail_confirm
547             elif regestration.event_id.mail_auto_confirm or regestration.event_id.mail_auto_registr:
548                 if regestration.event_id.state in ['draft', 'fixed', 'open', 'confirm', 'running'] and regestration.event_id.mail_auto_registr:
549                     subject = _('Auto Registration: [%s] %s') %(regestration.id, regestration.name)
550                     body = regestration.event_id.mail_registr
551                 if (regestration.event_id.state in ['confirm', 'running']) and regestration.event_id.mail_auto_confirm:
552                     subject = _('Auto Confirmation: [%s] %s') %(regestration.id, regestration.name)
553                     body = regestration.event_id.mail_confirm
554             if subject or body:
555                 tools.email_send(src, email_to, subject, body, email_cc=email_cc, openobject_id=regestration.id)
556                 self.history(cr, uid, [regestration], subject, history = True, \
557                         email=email_to, details=body, \
558                         subjec=subject, email_from=src, \
559                         email_cc=', '.join(email_cc))
560
561         return True
562
563     def mail_user_confirm(self, cr, uid, ids, context=None):
564         """
565         Send email to user
566         """
567         return self.mail_user(cr, uid, ids, confirm=True, context=context)
568
569     def _create_invoice_lines(self, cr, uid, ids, vals):
570         """ Create account Invoice line for Registration Id.
571         """
572         return self.pool.get('account.invoice.line').create(cr, uid, vals)
573
574     def onchange_contact_id(self, cr, uid, ids, contact, partner):
575
576         """This function returns value of Badge Name, Badge Title based on Partner contact.
577         @param self: The object pointer
578         @param cr: the current row, from the database cursor,
579         @param uid: the current user’s ID for security checks,
580         @param ids: List of Registration IDs
581         @param contact: Patner Contact IDS
582         @param partner: Partner IDS
583         """
584         data ={}
585         if not contact:
586             return data
587         addr_obj = self.pool.get('res.partner.address')
588         job_obj = self.pool.get('res.partner.job')
589
590         if partner:
591             partner_addresses = addr_obj.search(cr, uid, [('partner_id', '=', partner)])
592             job_ids = job_obj.search(cr, uid, [('contact_id', '=', contact), ('address_id', 'in', partner_addresses)])
593             if job_ids:
594                 data['email_from'] = job_obj.browse(cr, uid, job_ids[0]).email
595         return {'value': data}
596
597     def onchange_event(self, cr, uid, ids, event_id, partner_invoice_id):
598         """This function returns value of Product Name, Unit Price based on Event.
599         @param self: The object pointer
600         @param cr: the current row, from the database cursor,
601         @param uid: the current user’s ID for security checks,
602         @param ids: List of Registration IDs
603         @param event_id: Event ID
604         @param partner_invoice_id: Partner Invoice ID
605         """
606         context = {}
607         if not event_id:
608             return {'value': {'unit_price': False, 'event_product': False}}
609
610         event_obj = self.pool.get('event.event')
611         prod_obj = self.pool.get('product.product')
612         res_obj = self.pool.get('res.partner')
613
614         data_event =  event_obj.browse(cr, uid, event_id)
615         res = {'value': {'unit_price': False,
616                          'event_product': False,
617                          'user_id': False,
618                          'date': data_event.date_begin,
619                          'date_deadline': data_event.date_end,
620                          'description': data_event.note,
621                          'name': data_event.name,
622                          'section_id': data_event.section_id and data_event.section_id.id or False,
623                         }}
624         if data_event.user_id.id:
625             res['value'].update({'user_id': data_event.user_id.id})
626         if data_event.product_id:
627             pricelist_id = data_event.pricelist_id and data_event.pricelist_id.id or False
628             if partner_invoice_id:
629                 partner = res_obj.browse(cr, uid, partner_invoice_id, context=context)
630                 pricelist_id = pricelist_id or partner.property_product_pricelist.id
631             unit_price = prod_obj._product_price(cr, uid, [data_event.product_id.id], False, False, {'pricelist': pricelist_id})[data_event.product_id.id]
632             if not unit_price:
633                 unit_price = data_event.unit_price
634             res['value'].update({'unit_price': unit_price, 'event_product': data_event.product_id.name})
635         return res
636
637     def onchange_partner_id(self, cr, uid, ids, part, event_id, email=False):
638         """This function returns value of Patner Invoice id, Unit Price, badget title based on partner and Event.
639         @param self: The object pointer
640         @param cr: the current row, from the database cursor,
641         @param uid: the current user’s ID for security checks,
642         @param ids: List of Registration IDs
643         @param event_id: Event ID
644         @param partner_invoice_id: Partner Invoice ID
645         """
646         job_obj = self.pool.get('res.partner.job')
647         res_obj = self.pool.get('res.partner')
648
649         data = {}
650         data['contact_id'], data['partner_invoice_id'], data['email_from'] = (False, False, False)
651         if not part:
652             return {'value': data}
653         data['partner_invoice_id'] = part
654         # this calls onchange_partner_invoice_id
655         d = self.onchange_partner_invoice_id(cr, uid, ids, event_id, part)
656         # this updates the dictionary
657         data.update(d['value'])
658         addr = res_obj.address_get(cr, uid, [part])
659         if addr:
660             if addr.has_key('default'):
661                 job_ids = job_obj.search(cr, uid, [('address_id', '=', addr['default'])])
662                 if job_ids:
663                     data['contact_id'] = job_obj.browse(cr, uid, job_ids[0]).contact_id.id
664                     d = self.onchange_contact_id(cr, uid, ids, data['contact_id'], part)
665                     data.update(d['value'])
666         return {'value': data}
667
668     def onchange_partner_invoice_id(self, cr, uid, ids, event_id, partner_invoice_id):
669         """This function returns value of Product unit Price based on Invoiced partner.
670         @param self: The object pointer
671         @param cr: the current row, from the database cursor,
672         @param uid: the current user’s ID for security checks,
673         @param ids: List of Registration IDs
674         @param event_id: Event ID
675         @param partner_invoice_id: Partner Invoice ID
676         """
677         data = {}
678         context = {}
679         event_obj = self.pool.get('event.event')
680         prod_obj = self.pool.get('product.product')
681         res_obj = self.pool.get('res.partner')
682
683         data['unit_price']=False
684         if not event_id:
685             return {'value': data}
686         data_event =  event_obj.browse(cr, uid, event_id, context=context)
687         if data_event.product_id:
688             data['event_product'] = data_event.product_id.name
689             pricelist_id = data_event.pricelist_id and data_event.pricelist_id.id or False
690             if partner_invoice_id:
691                 partner = res_obj.browse(cr, uid, partner_invoice_id, context=context)
692                 pricelist_id = pricelist_id or partner.property_product_pricelist.id
693             unit_price = prod_obj._product_price(cr, uid, [data_event.product_id.id], False, False, {'pricelist': pricelist_id})[data_event.product_id.id]
694             if not unit_price:
695                 unit_price = data_event.unit_price
696             data['unit_price'] = unit_price
697         return {'value': data}
698
699 event_registration()
700
701 class event_registration_badge(osv.osv):
702     _name = 'event.registration.badge'
703     _description = __doc__
704     _columns = {
705         "registration_id": fields.many2one('event.registration', 'Registration', required=True),
706         "title": fields.char('Title', size=128),
707         "name": fields.char('Name', size=128, required=True),
708         "address_id": fields.many2one('res.partner.address', 'Address'),
709     }
710
711 event_registration_badge()
712
713 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: