[FIX] Change the year of the copyright
[odoo/odoo.git] / addons / event / event.py
1 # -*- coding: utf-8 -*-
2 ##############################################################################
3 #    
4 #    OpenERP, Open Source Management Solution
5 #    Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
6 #
7 #    This program is free software: you can redistribute it and/or modify
8 #    it under the terms of the GNU Affero General Public License as
9 #    published by the Free Software Foundation, either version 3 of the
10 #    License, or (at your option) any later version.
11 #
12 #    This program is distributed in the hope that it will be useful,
13 #    but WITHOUT ANY WARRANTY; without even the implied warranty of
14 #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 #    GNU Affero General Public License for more details.
16 #
17 #    You should have received a copy of the GNU Affero General Public License
18 #    along with this program.  If not, see <http://www.gnu.org/licenses/>.     
19 #
20 ##############################################################################
21
22 from osv import fields, osv
23 import time
24 import netsvc
25 import pooler
26 import tools
27 from tools.translate import _
28
29 class crm_case_log(osv.osv):
30     _inherit = 'crm.case.log'
31     _description = 'crm.case.log'
32     def create(self, cr, uid, vals, *args, **kwargs):
33             if not 'name' in vals:
34                 vals['name']='Historize'
35             return super(osv.osv,self).create(cr, uid, vals, *args, **kwargs)
36     _defaults = {
37         'user_id': lambda self,cr,uid,context: uid,
38     }
39 crm_case_log()
40
41 class event_type(osv.osv):
42     _name = 'event.type'
43     _description= 'Event type'
44     _columns = {
45         'name': fields.char('Event type', size=64, required=True),
46     }
47 event_type()
48
49 class event(osv.osv):
50     _name = 'event.event'
51     _description = 'Event'
52     _inherits = {'crm.case.section': 'section_id'}
53     _order = 'date_begin'
54
55     def copy(self, cr, uid, id, default=None, context=None):
56         return super(event, self).copy(cr, uid,id, default={'code': self.pool.get('ir.sequence').get(cr, uid, 'event.event'),'state':'draft'})
57
58     def button_draft(self, cr, uid, ids, context={}):
59         return self.write(cr, uid, ids, {'state':'draft'})
60
61     def button_cancel(self, cr, uid, ids, context={}):
62         return self.write(cr, uid, ids, {'state':'cancel'})
63
64     def button_done(self, cr, uid, ids, context={}):
65         return self.write(cr, uid, ids, {'state':'done'})
66
67     def button_confirm(self, cr, uid, ids, context={}):
68         for eve in self.browse(cr, uid, ids):
69             if eve.mail_auto_confirm:
70                 #send reminder that will confirm the event for all the people that were already confirmed
71                 reg_ids = self.pool.get('event.registration').search(cr, uid, [('event_id','=',eve.id),('state','not in',['draft','cancel'])])
72                 if reg_ids:
73                     self.pool.get('event.registration').mail_user_confirm(cr, uid, reg_ids)
74         return self.write(cr, uid, ids, {'state':'confirm'})
75
76     def _get_register(self, cr, uid, ids, name, args, context=None):
77         res={}
78         for event in self.browse(cr, uid, ids, context):
79             query = """select sum(nb_register) from crm_case c left join crm_case_section s on (c.section_id=s.id) right join event_event e on (e.section_id=s.id) right join event_registration r on (r.case_id=c.id) where e.section_id = %s and c.state in ('open','done')""" % event.section_id.id
80             cr.execute(query)
81             res2 = cr.fetchone()
82             if res2 and res2[0]:
83                 res[event.id] = res2[0]
84             else:
85                 res[event.id] = 0
86         return res
87
88     def _get_prospect(self, cr, uid, ids, name, args, context=None):
89         res={}
90         for event in self.browse(cr, uid, ids, context):
91             query = """select sum(nb_register) from crm_case c left join crm_case_section s on (c.section_id=s.id) right join event_event e on (e.section_id=s.id) right join event_registration r on (r.case_id=c.id) where e.section_id = %s and c.state = 'draft'""" % event.section_id.id
92             cr.execute(query)
93             res2 = cr.fetchone()
94             if res2 and res2[0]:
95                 res[event.id] = res2[0]
96             else:
97                 res[event.id] = 0
98         return res
99
100     def write(self, cr, uid, ids,vals, *args, **kwargs):
101         res = super(event,self).write(cr, uid, ids,vals, *args, **kwargs)
102         if 'date_begin' in vals and vals['date_begin']:
103             for eve in self.browse(cr, uid, ids):
104                 #change the deadlines of the registration linked to this event
105                 reg_ids = self.pool.get('event.registration').search(cr, uid, [('event_id','=',eve.id)])
106                 if reg_ids:
107                     self.pool.get('event.registration').write(cr, uid, reg_ids, {'date_deadline':vals['date_begin']})
108
109         #change the description of the registration linked to this event
110         if 'mail_auto_confirm' in vals:
111             if vals['mail_auto_confirm']:
112                 if 'mail_confirm' not in vals:
113                     for eve in self.browse(cr, uid, ids):
114                         vals['mail_confirm'] = eve.mail_confirm
115             else:
116                 vals['mail_confirm']=False
117         if 'mail_confirm' in vals:
118             for eve in self.browse(cr, uid, ids):
119                 reg_ids = self.pool.get('event.registration').search(cr, uid, [('event_id','=',eve.id)])
120                 if reg_ids:
121                     self.pool.get('event.registration').write(cr, uid, reg_ids, {'description':vals['mail_confirm']})
122         return res
123
124     _columns = {
125         'type': fields.many2one('event.type', 'Type'),
126         'section_id': fields.many2one('crm.case.section', 'Case section', required=True),
127         'register_max': fields.integer('Maximum Registrations'),
128         'register_min': fields.integer('Minimum Registrations'),
129         'register_current': fields.function(_get_register, method=True, string='Confirmed Registrations'),
130         'register_prospect': fields.function(_get_prospect, method=True, string='Unconfirmed Registrations'),
131         'date_begin': fields.datetime('Beginning date', required=True),
132         'date_end': fields.datetime('Ending date', required=True),
133         'state': fields.selection([('draft','Draft'),('confirm','Confirmed'),('done','Done'),('cancel','Cancelled')], 'State', readonly=True, required=True,
134                                   help='If event is created, the state is \'Draft\'.\n If event is confirmed for the particular dates the state is set to \'Confirmed\'.\
135                                   \nIf the event is over, the state is set to \'Done\'.\n If event is cancelled the state is set to \'Cancelled\'.'),
136         'mail_auto_registr':fields.boolean('Mail Auto Register',help='Check this box if you want to use the automatic mailing for new registration'),
137         'mail_auto_confirm':fields.boolean('Mail Auto Confirm',help='Check this box if you want ot use the automatic confirmation emailing or the reminder'),
138         'mail_registr':fields.text('Registration Email',help='This email will be sent when someone subscribes to the event.'),
139         'mail_confirm': fields.text('Confirmation Email', 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."),
140         'product_id':fields.many2one('product.product','Product', required=True),
141     }
142
143     _defaults = {
144         'state': lambda *args: 'draft',
145         'code': lambda obj, cr, uid, context: obj.pool.get('ir.sequence').get(cr, uid, 'event.event'),
146         'user_id': lambda self,cr,uid,ctx: uid,
147
148     }
149 event()
150
151 class event_registration(osv.osv):
152
153     def _history(self, cr, uid,ids,keyword, history=False, email=False, context={}):
154         for case in self.browse(cr, uid, ids):
155             if not case.case_id:
156                 return True
157             data = {
158                 'name': keyword,
159                 'som': case.som.id,
160                 'canal_id': case.canal_id.id,
161                 'user_id': uid,
162                 'case_id': case.case_id.id
163             }
164             obj = self.pool.get('crm.case.log')
165             obj.create(cr, uid, data, context)
166         return True
167
168     def button_reg_close(self, cr, uid, ids, *args):
169         self.write(cr, uid, ids, {'state':'done',})
170         self._history(cr, uid, ids, 'Done', history=True)
171         return True
172
173     def button_reg_cancel(self, cr, uid, ids, *args):
174         self.write(cr, uid, ids, {'state':'cancel',})
175         self._history(cr, uid, ids, 'Cancel', history=True)
176         return True
177
178     def create(self, cr, uid, *args, **argv):
179         event = self.pool.get('event.event').browse(cr, uid, args[0]['event_id'], None)
180         args[0]['section_id']= event.section_id.id
181         args[0]['date_deadline']= event.date_begin
182         args[0]['description']= event.mail_confirm
183         res = super(event_registration, self).create(cr, uid, *args, **argv)
184         self._history(cr, uid,[res], 'Created', history=True)
185         return res
186
187     def write(self, cr, uid, *args, **argv):
188         if 'event_id' in args[1]:
189             event = self.pool.get('event.event').browse(cr, uid, args[1]['event_id'], None)
190             args[1]['section_id']= event.section_id.id
191             args[1]['date_deadline']= event.date_begin
192             args[1]['description']= event.mail_confirm
193         return super(event_registration, self).write(cr, uid, *args, **argv)
194
195     def mail_user_confirm(self,cr,uid,ids):
196         reg_ids=self.browse(cr,uid,ids)
197         for reg_id in reg_ids:
198             src = reg_id.event_id.reply_to or False
199             dest = [reg_id.email_from]
200             if reg_id.email_cc:
201                 dest += [reg_id.email_cc]
202             if dest and src:
203                 tools.email_send(src, dest,'Auto Confirmation: '+'['+str(reg_id.id)+']'+' '+reg_id.name, reg_id.event_id.mail_confirm, tinycrm = str(reg_id.case_id.id))
204             if not src:
205                 raise osv.except_osv(_('Error!'), _('You must define a reply-to address in order to mail the participant. You can do this in the Mailing tab of your event. Note that this is also the place where you can configure your event to not send emails automaticly while registering'))
206         return False
207
208     def mail_user(self,cr,uid,ids):
209         reg_ids=self.browse(cr,uid,ids)
210         for reg_id in reg_ids:
211             src = reg_id.event_id.reply_to or False
212             dest = [reg_id.email_from]
213             if reg_id.email_cc:
214                 dest += [reg_id.email_cc]
215             if reg_id.event_id.mail_auto_confirm or reg_id.event_id.mail_auto_registr:
216                 if dest and src:
217                     if reg_id.event_id.state in ['draft', 'fixed', 'open','confirm','running'] and reg_id.event_id.mail_auto_registr:
218                         tools.email_send(src, dest,'Auto Registration: '+'['+str(reg_id.id)+']'+' '+reg_id.name, reg_id.event_id.mail_registr, tinycrm = str(reg_id.case_id.id))
219                     if (reg_id.event_id.state in ['confirm','running']) and reg_id.event_id.mail_auto_confirm:
220                         tools.email_send(src, dest,'Auto Confirmation: '+'['+str(reg_id.id)+']'+' '+reg_id.name, reg_id.event_id.mail_confirm, tinycrm = str(reg_id.case_id.id))
221                 if not src:
222                     raise osv.except_osv(_('Error!'), _('You must define a reply-to address in order to mail the participant. You can do this in the Mailing tab of your event. Note that this is also the place where you can configure your event to not send emails automaticly while registering'))
223         return False
224
225     def _create_invoice_lines(self, cr, uid, ids, vals):
226         return self.pool.get('account.invoice.line').create(cr, uid,vals )
227
228     _name= 'event.registration'
229     _description = 'Event Registration'
230     _inherits = {'crm.case': 'case_id'}
231     _columns = {
232         'case_id':fields.many2one('crm.case','Case'),
233         'nb_register': fields.integer('Number of Registration', readonly=True, states={'draft':[('readonly',False)]}),
234         'event_id':fields.many2one('event.event', 'Event Related', required=True),
235         "partner_invoice_id":fields.many2one('res.partner', 'Partner Invoiced'),
236         "contact_id":fields.many2one('res.partner.contact', 'Partner Contact'), #TODO: filter only the contacts that have a function into the selected partner_id
237         "unit_price": fields.float('Unit Price'),
238         "badge_title":fields.char('Badge Title',size=128),
239         "badge_name":fields.char('Badge Name',size=128),
240         "badge_partner":fields.char('Badge Partner',size=128),
241         "invoice_label":fields.char("Label Invoice",size=128,required=True),
242         "tobe_invoiced":fields.boolean("To be Invoiced"),
243         "invoice_id":fields.many2one("account.invoice","Invoice"),
244     }
245     _defaults = {
246         'nb_register': lambda *a: 1,
247         'tobe_invoiced' : lambda *a: True,
248         'name': lambda *a: 'Registration',
249         'state': lambda *b: 'draft'
250     }
251
252     def onchange_badge_name(self, cr, uid, ids, badge_name):
253         data ={}
254         if not badge_name:
255             return data
256         data['name'] = 'Registration: ' + badge_name
257         return {'value':data}
258
259     def onchange_contact_id(self, cr, uid, ids, contact, partner):
260         data ={}
261         if not contact:
262             return data
263         contact_id = self.pool.get('res.partner.contact').browse(cr, uid, contact)
264         data['badge_name'] = contact_id.name
265         data['badge_title'] = contact_id.title
266         if partner:
267             partner_addresses = self.pool.get('res.partner.address').search(cr, uid, [('partner_id','=',partner)])
268             job_ids = self.pool.get('res.partner.job').search(cr, uid, [('contact_id','=',contact),('address_id','in',partner_addresses)])
269             if job_ids:
270                 data['email_from'] = self.pool.get('res.partner.job').browse(cr, uid, job_ids[0]).email
271         d = self.onchange_badge_name(cr, uid, ids,data['badge_name'])
272         data.update(d['value'])
273
274         return {'value':data}
275
276     def onchange_event(self, cr, uid, ids, event_id, partner_invoice_id):
277         context={}
278         if not event_id:
279             return {'value':{'unit_price' : False ,'invoice_label' : False }}
280         data_event =  self.pool.get('event.event').browse(cr,uid,event_id)
281         if data_event.product_id:
282             if not partner_invoice_id:
283                 unit_price=self.pool.get('product.product').price_get(cr, uid, [data_event.product_id.id],context=context)[data_event.product_id.id]
284                 return {'value':{'unit_price' : unit_price , 'invoice_label' : data_event.product_id.name}}
285             data_partner = self.pool.get('res.partner').browse(cr,uid,partner_invoice_id)
286             context.update({'partner_id':data_partner})
287             unit_price = self.pool.get('product.product')._product_price(cr, uid, [data_event.product_id.id], False, False, {'pricelist':data_partner.property_product_pricelist.id})[data_event.product_id.id]
288             return {'value':{'unit_price' :unit_price , 'invoice_label' : data_event.product_id.name}}
289         return {'value':{'unit_price' : False,'invoice_label' : False}}
290
291
292     def onchange_partner_id(self, cr, uid, ids, part, event_id, email=False):
293         data={}
294         data['badge_partner'] = data['contact_id'] = data['partner_invoice_id'] = data['email_from'] = data['badge_title'] = data['badge_name'] = False
295         if not part:
296             return {'value':data}
297         data['partner_invoice_id']=part
298         # this calls onchange_partner_invoice_id
299         d = self.onchange_partner_invoice_id(cr, uid, ids, event_id,part)
300         # this updates the dictionary
301         data.update(d['value'])
302         addr = self.pool.get('res.partner').address_get(cr, uid, [part])
303         if addr:
304             if addr.has_key('default'):
305                 job_ids = self.pool.get('res.partner.job').search(cr, uid, [('address_id','=',addr['default'])])
306                 if job_ids:
307                     data['contact_id'] = self.pool.get('res.partner.job').browse(cr, uid, job_ids[0]).contact_id.id
308                     d = self.onchange_contact_id(cr, uid, ids, data['contact_id'],part)
309                     data.update(d['value'])
310         partner_data = self.pool.get('res.partner').browse(cr, uid, part)
311         data['badge_partner'] = partner_data.name
312         return {'value':data}
313
314     def onchange_partner_invoice_id(self, cr, uid, ids, event_id, partner_invoice_id):
315         data={}
316         context={}
317         data['unit_price']=False
318         if not event_id:
319             return {'value':data}
320         data_event =  self.pool.get('event.event').browse(cr,uid,event_id)
321
322         if data_event.product_id:
323             if not partner_invoice_id:
324                 data['unit_price']=self.pool.get('product.product').price_get(cr, uid, [data_event.product_id.id],context=context)[data_event.product_id.id]
325                 return {'value':data}
326             data_partner = self.pool.get('res.partner').browse(cr,uid,partner_invoice_id)
327             context.update({'partner_id':data_partner})
328             data['unit_price'] = self.pool.get('product.product')._product_price(cr, uid, [data_event.product_id.id], False, False, {'pricelist':data_partner.property_product_pricelist.id})[data_event.product_id.id]
329             return {'value':data}
330         return {'value':data}
331
332     def onchange_categ_id(self, cr, uid, ids, categ, context={}):
333         if not categ:
334             return {'value':{}}
335         cat = self.pool.get('crm.case.categ').browse(cr, uid, categ, context).probability
336         return {'value':{'probability':cat}}
337
338     def _map_ids(self,method,cr, uid, ids, *args, **argv):
339         case_data = self.browse(cr,uid,ids)
340         new_ids=[]
341         for case in case_data:
342             if case.case_id:
343                 new_ids.append(case.case_id.id)
344         return getattr(self.pool.get('crm.case'),method)(cr, uid, new_ids, *args, **argv)
345
346
347     def case_close(self,cr, uid, ids, *args, **argv):
348         return self._map_ids('case_close',cr,uid,ids,*args,**argv)
349     def case_escalate(self,cr, uid, ids, *args, **argv):
350         return self._map_ids('case_escalate',cr,uid,ids,*args,**argv)
351     def case_open(self,cr, uid, ids, *args, **argv):
352         return self._map_ids('case_open',cr,uid,ids,*args,**argv)
353     def case_cancel(self,cr, uid, ids, *args, **argv):
354         return self._map_ids('case_cancel',cr,uid,ids,*args,**argv)
355     def case_pending(self,cr, uid, ids, *args, **argv):
356         return self._map_ids('case_pending',cr,uid,ids,*args,**argv)
357     def case_reset(self,cr, uid, ids, *args, **argv):
358         return self._map_ids('case_reset',cr,uid,ids,*args,**argv)
359     def case_log(self,cr, uid, ids, *args, **argv):
360         return self._map_ids('case_log',cr,uid,ids,*args,**argv)
361     def case_log_reply(self,cr, uid, ids, *args, **argv):
362         return self._map_ids('case_log_reply',cr,uid,ids,*args,**argv)
363     def add_reply(self,cr, uid, ids, *args, **argv):
364         return self._map_ids('add_reply',cr,uid,ids,*args,**argv)
365     def remind_partner(self,cr, uid, ids, *args, **argv):
366         return self._map_ids('remind_partner',cr,uid,ids,*args,**argv)
367     def remind_user(self,cr, uid, ids, *args, **argv):
368         return self._map_ids('remind_user',cr,uid,ids,*args,**argv)
369
370
371 event_registration()
372
373
374
375 class report_event_registration(osv.osv):
376     _name = "report.event.registration"
377     _description = "Events on registrations"
378     _auto = False
379     _columns = {
380         'name': fields.char('Event',size=20),
381         'date_begin': fields.datetime('Beginning date', required=True),
382         'date_end': fields.datetime('Ending date', required=True),
383         'draft_state': fields.integer('Draft Registration',size=20),
384         'confirm_state': fields.integer('Confirm Registration',size=20),
385         'register_max': fields.integer('Maximum Registrations'),
386     }
387     def init(self, cr):
388         cr.execute("""
389             create or replace view report_event_registration as (
390                 select
391                 e.id as id,
392                 c.name as name,
393                 e.date_begin as date_begin,
394                 e.date_end as date_end,
395                 (SELECT sum(nb_register) FROM event_registration x , crm_case c  WHERE x.case_id=c.id and c.section_id=e.section_id and state in ('draft')) as draft_state,
396                 (SELECT sum(nb_register) FROM event_registration x , crm_case c  WHERE x.case_id=c.id and c.section_id=e.section_id and state in ('open')) as confirm_state,
397                 e.register_max as register_max
398                 from
399                 event_event e,crm_case_section c
400                 where
401                 e.section_id=c.id
402                 )""")
403
404 report_event_registration()
405
406 class report_event_type_registration(osv.osv):
407     _name = "report.event.type.registration"
408     _description = "Event type on registration"
409     _auto = False
410     _columns = {
411         'name': fields.char('Event Type',size=20),
412         'nbevent':fields.integer('Number Of Events'),
413         'draft_state': fields.integer('Draft Registrations',size=20),
414         'confirm_state': fields.integer('Confirm Registrations',size=20),
415         }
416     def init(self, cr):
417         cr.execute("""
418             create or replace view report_event_type_registration as (
419                 select
420                 count(t.id) as id,
421                 t.name as name,
422                 (select sum(nb_register) from event_registration r , crm_case c , event_event e  where c.section_id=e.section_id and r.case_id=c.id and c.state='draft' and e.type=t.id ) as draft_state ,
423                 (select sum(nb_register) from event_registration r , crm_case c , event_event e  where c.section_id=e.section_id and r.case_id=c.id and c.state='open' and e.type=t.id ) as  confirm_state,
424                 count(t.id) as nbevent
425                 from
426                     event_event e
427                 inner join
428                     crm_case_section c1 on (e.section_id=c1.id)
429                 inner join
430                     event_type t on (e.type=t.id)
431                 group by
432                     t.name,t.id
433
434             )""")
435 report_event_type_registration()
436
437
438 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
439