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