Launchpad automatic translations update.
[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 from crm import crm
29
30 class crm_case_log(osv.osv):
31     _inherit = 'crm.case.log'
32     _description = 'crm.case.log'
33     def create(self, cr, uid, vals, *args, **kwargs):
34             if not 'name' in vals:
35                 vals['name']='Historize'
36             return super(osv.osv,self).create(cr, uid, vals, *args, **kwargs)
37     _defaults = {
38         'user_id': lambda self,cr,uid,context: uid,
39     }
40 crm_case_log()
41
42 class event_type(osv.osv):
43     _name = 'event.type'
44     _description= 'Event type'
45     _columns = {
46         'name': fields.char('Event type', size=64, required=True),
47     }
48 event_type()
49
50 class event(osv.osv):
51     _name = 'event.event'
52     _description = 'Event'
53     _inherits = {'crm.case.section': 'section_id'}
54     _order = 'date_begin'
55
56     def copy(self, cr, uid, id, default=None, context=None):
57         return super(event, self).copy(cr, uid,id, default={'code': self.pool.get('ir.sequence').get(cr, uid, 'event.event'),'state':'draft'})
58
59     def button_draft(self, cr, uid, ids, context={}):
60         return self.write(cr, uid, ids, {'state':'draft'})
61
62     def button_cancel(self, cr, uid, ids, context={}):
63         return self.write(cr, uid, ids, {'state':'cancel'})
64
65     def button_done(self, cr, uid, ids, context={}):
66         return self.write(cr, uid, ids, {'state':'done'})
67
68     def button_confirm(self, cr, uid, ids, context={}):
69         for eve in self.browse(cr, uid, ids):
70             if eve.mail_auto_confirm:
71                 #send reminder that will confirm the event for all the people that were already confirmed
72                 reg_ids = self.pool.get('event.registration').search(cr, uid, [('event_id','=',eve.id),('state','not in',['draft','cancel'])])
73                 if reg_ids:
74                     self.pool.get('event.registration').mail_user_confirm(cr, uid, reg_ids)
75         return self.write(cr, uid, ids, {'state':'confirm'})
76
77     def _get_register(self, cr, uid, ids, name, args, context=None):
78         res={}
79         for event in self.browse(cr, uid, ids, context):
80             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')"""
81             cr.execute(query,(event.section_id.id,))
82             res2 = cr.fetchone()
83             if res2 and res2[0]:
84                 res[event.id] = res2[0]
85             else:
86                 res[event.id] = 0
87         return res
88
89     def _get_prospect(self, cr, uid, ids, name, args, context=None):
90         res={}
91         for event in self.browse(cr, uid, ids, context):
92             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'"""
93             cr.execute(query,(event.section_id.id,))
94             res2 = cr.fetchone()
95             if res2 and res2[0]:
96                 res[event.id] = res2[0]
97             else:
98                 res[event.id] = 0
99         return res
100
101     def write(self, cr, uid, ids,vals, *args, **kwargs):
102         res = super(event,self).write(cr, uid, ids,vals, *args, **kwargs)
103         if 'date_begin' in vals and vals['date_begin']:
104             for eve in self.browse(cr, uid, ids):
105                 #change the deadlines of the registration linked to this event
106                 reg_ids = self.pool.get('event.registration').search(cr, uid, [('event_id','=',eve.id)])
107                 if reg_ids:
108                     self.pool.get('event.registration').write(cr, uid, reg_ids, {'date_deadline':vals['date_begin']})
109
110         #change the description of the registration linked to this event
111         if 'mail_auto_confirm' in vals:
112             if vals['mail_auto_confirm']:
113                 if 'mail_confirm' not in vals:
114                     for eve in self.browse(cr, uid, ids):
115                         vals['mail_confirm'] = eve.mail_confirm
116             else:
117                 vals['mail_confirm']=False
118         if 'mail_confirm' in vals:
119             for eve in self.browse(cr, uid, ids):
120                 reg_ids = self.pool.get('event.registration').search(cr, uid, [('event_id','=',eve.id)])
121                 if reg_ids:
122                     self.pool.get('event.registration').write(cr, uid, reg_ids, {'description':vals['mail_confirm']})
123         return res
124
125     _columns = {
126         'type': fields.many2one('event.type', 'Type'),
127         'section_id': fields.many2one('crm.case.section', 'Case section', required=True),
128         'register_max': fields.integer('Maximum Registrations'),
129         'register_min': fields.integer('Minimum Registrations'),
130         'register_current': fields.function(_get_register, method=True, string='Confirmed Registrations'),
131         'register_prospect': fields.function(_get_prospect, method=True, string='Unconfirmed Registrations'),
132         'date_begin': fields.datetime('Beginning date', required=True),
133         'date_end': fields.datetime('Ending date', required=True),
134         'state': fields.selection([('draft','Draft'),('confirm','Confirmed'),('done','Done'),('cancel','Cancelled')], 'State', readonly=True, required=True,
135                                   help='If event is created, the state is \'Draft\'.\n If event is confirmed for the particular dates the state is set to \'Confirmed\'.\
136                                   \nIf the event is over, the state is set to \'Done\'.\n If event is cancelled the state is set to \'Cancelled\'.'),
137         'mail_auto_registr':fields.boolean('Mail Auto Register',help='Check this box if you want to use the automatic mailing for new registration'),
138         'mail_auto_confirm':fields.boolean('Mail Auto Confirm',help='Check this box if you want ot use the automatic confirmation emailing or the reminder'),
139         'mail_registr':fields.text('Registration Email',help='This email will be sent when someone subscribes to the event.'),
140         '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."),
141         'product_id':fields.many2one('product.product','Product', required=True),
142     }
143
144     _defaults = {
145         'state': lambda *args: 'draft',
146         'code': lambda obj, cr, uid, context: obj.pool.get('ir.sequence').get(cr, uid, 'event.event'),
147         'user_id': lambda self,cr,uid,ctx: uid,
148
149     }
150 event()
151
152 class event_registration(osv.osv):
153
154     def _history(self, cr, uid,ids,keyword, history=False, email=False, context={}):
155         for case in self.browse(cr, uid, ids):
156             if not case.case_id:
157                 return True
158             data = {
159                 'name': keyword,
160                 'som': case.som.id,
161                 'canal_id': case.canal_id.id,
162                 'user_id': uid,
163                 'case_id': case.case_id.id
164             }
165             obj = self.pool.get('crm.case.log')
166             obj.create(cr, uid, data, context)
167         return True
168
169     def button_reg_close(self, cr, uid, ids, *args):
170         self.write(cr, uid, ids, {'state':'done',})
171         self._history(cr, uid, ids, 'Done', history=True)
172         return True
173
174     def button_reg_cancel(self, cr, uid, ids, *args):
175         self.write(cr, uid, ids, {'state':'cancel',})
176         self._history(cr, uid, ids, 'Cancel', history=True)
177         return True
178
179     def create(self, cr, uid, *args, **argv):
180         event = self.pool.get('event.event').browse(cr, uid, args[0]['event_id'], None)
181         args[0]['section_id']= event.section_id.id
182         args[0]['date_deadline']= event.date_begin
183         args[0]['description']= event.mail_confirm
184         res = super(event_registration, self).create(cr, uid, *args, **argv)
185         self._history(cr, uid,[res], 'Created', history=True)
186         return res
187
188     def write(self, cr, uid, *args, **argv):
189         if 'event_id' in args[1]:
190             event = self.pool.get('event.event').browse(cr, uid, args[1]['event_id'], None)
191             args[1]['section_id']= event.section_id.id
192             args[1]['date_deadline']= event.date_begin
193             args[1]['description']= event.mail_confirm
194         return super(event_registration, self).write(cr, uid, *args, **argv)
195
196     def mail_user_confirm(self,cr,uid,ids):
197         reg_ids=self.browse(cr,uid,ids)
198         for reg_id in reg_ids:
199             src = reg_id.event_id.reply_to or False
200             dest = [reg_id.email_from]
201             if reg_id.email_cc:
202                 dest += [reg_id.email_cc]
203             if dest and src:
204                 tools.email_send(src, dest,'Auto Confirmation: '+'['+str(reg_id.id)+']'+' '+reg_id.name, reg_id.event_id.mail_confirm, openobject_id = str(reg_id.case_id.id))
205             if not src:
206                 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'))
207         return False
208
209     def mail_user(self,cr,uid,ids):
210         reg_ids=self.browse(cr,uid,ids)
211         for reg_id in reg_ids:
212             src = reg_id.event_id.reply_to or False
213             dest = [reg_id.email_from]
214             if reg_id.email_cc:
215                 dest += [reg_id.email_cc]
216             if reg_id.event_id.mail_auto_confirm or reg_id.event_id.mail_auto_registr:
217                 if dest and src:
218                     if reg_id.event_id.state in ['draft', 'fixed', 'open','confirm','running'] and reg_id.event_id.mail_auto_registr:
219                         tools.email_send(src, dest,'Auto Registration: '+'['+str(reg_id.id)+']'+' '+reg_id.name, reg_id.event_id.mail_registr, openobject_id = str(reg_id.case_id.id))
220                     if (reg_id.event_id.state in ['confirm','running']) and reg_id.event_id.mail_auto_confirm:
221                         tools.email_send(src, dest,'Auto Confirmation: '+'['+str(reg_id.id)+']'+' '+reg_id.name, reg_id.event_id.mail_confirm, openobject_id = str(reg_id.case_id.id))
222                 if not src:
223                     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'))
224         return False
225
226     def _create_invoice_lines(self, cr, uid, ids, vals):
227         return self.pool.get('account.invoice.line').create(cr, uid,vals )
228
229     _name= 'event.registration'
230     _description = 'Event Registration'
231     _inherits = {'crm.case': 'case_id'}
232     _columns = {
233         'case_id':fields.many2one('crm.case','Case'),
234         'nb_register': fields.integer('Number of Registration', readonly=True, states={'draft':[('readonly',False)]}),
235         'event_id':fields.many2one('event.event', 'Event Related', required=True),
236         "partner_invoice_id":fields.many2one('res.partner', 'Partner Invoiced'),
237         "contact_id":fields.many2one('res.partner.contact', 'Partner Contact'), #TODO: filter only the contacts that have a function into the selected partner_id
238         "unit_price": fields.float('Unit Price'),
239         "badge_title":fields.char('Badge Title',size=128),
240         "badge_name":fields.char('Badge Name',size=128),
241         "badge_partner":fields.char('Badge Partner',size=128),
242         "invoice_label":fields.char("Label Invoice",size=128,required=True),
243         "tobe_invoiced":fields.boolean("To be Invoiced"),
244         "invoice_id":fields.many2one("account.invoice","Invoice"),
245         'date_closed': fields.datetime('Closed', readonly=True),
246         'ref' : fields.reference('Reference', selection=crm._links_get, size=128),
247         'ref2' : fields.reference('Reference 2', selection=crm._links_get, size=128),  
248         'categ_id': fields.many2one('crm.case.categ','Category', domain="[('section_id','=',section_id)]"),
249         'canal_id': fields.many2one('res.partner.canal', 'Channel',help="The channels represent the different communication modes available with the customer." \
250                                                                         " With each commercial opportunity, you can indicate the canall which is this opportunity source."),
251         'som': fields.many2one('res.partner.som', 'State of Mind', help="The minds states allow to define a value scale which represents" \
252                                                                        "the partner mentality in relation to our services.The scale has" \
253                                                                        "to be created with a factor for each level from 0 (Very dissatisfied) to 10 (Extremely satisfied)."),
254                       
255     }
256     _defaults = {
257         'nb_register': lambda *a: 1,
258         'tobe_invoiced' : lambda *a: True,
259         'name': lambda *a: 'Registration',
260         'state': lambda *b: 'draft'
261     }
262
263     def onchange_badge_name(self, cr, uid, ids, badge_name):
264         data ={}
265         if not badge_name:
266             return data
267         data['name'] = 'Registration: ' + badge_name
268         return {'value':data}
269
270     def onchange_contact_id(self, cr, uid, ids, contact, partner):
271         data ={}
272         if not contact:
273             return data
274         contact_id = self.pool.get('res.partner.contact').browse(cr, uid, contact)
275         data['badge_name'] = contact_id.name
276         data['badge_title'] = contact_id.title
277         if partner:
278             partner_addresses = self.pool.get('res.partner.address').search(cr, uid, [('partner_id','=',partner)])
279             job_ids = self.pool.get('res.partner.job').search(cr, uid, [('contact_id','=',contact),('address_id','in',partner_addresses)])
280             if job_ids:
281                 data['email_from'] = self.pool.get('res.partner.job').browse(cr, uid, job_ids[0]).email
282         d = self.onchange_badge_name(cr, uid, ids,data['badge_name'])
283         data.update(d['value'])
284
285         return {'value':data}
286
287     def onchange_event(self, cr, uid, ids, event_id, partner_invoice_id):
288         context={}
289         if not event_id:
290             return {'value':{'unit_price' : False ,'invoice_label' : False }}
291         data_event =  self.pool.get('event.event').browse(cr,uid,event_id)
292         if data_event.product_id:
293             if not partner_invoice_id:
294                 unit_price=self.pool.get('product.product').price_get(cr, uid, [data_event.product_id.id],context=context)[data_event.product_id.id]
295                 return {'value':{'unit_price' : unit_price , 'invoice_label' : data_event.product_id.name}}
296             data_partner = self.pool.get('res.partner').browse(cr,uid,partner_invoice_id)
297             context.update({'partner_id':data_partner})
298             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]
299             return {'value':{'unit_price' :unit_price , 'invoice_label' : data_event.product_id.name}}
300         return {'value':{'unit_price' : False,'invoice_label' : False}}
301
302
303     def onchange_partner_id(self, cr, uid, ids, part, event_id, email=False):
304         data={}
305         data['badge_partner'] = data['contact_id'] = data['partner_invoice_id'] = data['email_from'] = data['badge_title'] = data['badge_name'] = False
306         if not part:
307             return {'value':data}
308         data['partner_invoice_id']=part
309         # this calls onchange_partner_invoice_id
310         d = self.onchange_partner_invoice_id(cr, uid, ids, event_id,part)
311         # this updates the dictionary
312         data.update(d['value'])
313         addr = self.pool.get('res.partner').address_get(cr, uid, [part])
314         if addr:
315             if addr.has_key('default'):
316                 job_ids = self.pool.get('res.partner.job').search(cr, uid, [('address_id','=',addr['default'])])
317                 if job_ids:
318                     data['contact_id'] = self.pool.get('res.partner.job').browse(cr, uid, job_ids[0]).contact_id.id
319                     d = self.onchange_contact_id(cr, uid, ids, data['contact_id'],part)
320                     data.update(d['value'])
321         partner_data = self.pool.get('res.partner').browse(cr, uid, part)
322         data['badge_partner'] = partner_data.name
323         return {'value':data}
324
325     def onchange_partner_invoice_id(self, cr, uid, ids, event_id, partner_invoice_id):
326         data={}
327         context={}
328         data['unit_price']=False
329         if not event_id:
330             return {'value':data}
331         data_event =  self.pool.get('event.event').browse(cr,uid,event_id)
332
333         if data_event.product_id:
334             if not partner_invoice_id:
335                 data['unit_price']=self.pool.get('product.product').price_get(cr, uid, [data_event.product_id.id],context=context)[data_event.product_id.id]
336                 return {'value':data}
337             data_partner = self.pool.get('res.partner').browse(cr,uid,partner_invoice_id)
338             context.update({'partner_id':data_partner})
339             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]
340             return {'value':data}
341         return {'value':data}
342
343     def onchange_categ_id(self, cr, uid, ids, categ, context={}):
344         if not categ:
345             return {'value':{}}
346         cat = self.pool.get('crm.case.categ').browse(cr, uid, categ, context).probability
347         return {'value':{'probability':cat}}
348
349     def _map_ids(self,method,cr, uid, ids, *args, **argv):
350         case_data = self.browse(cr,uid,ids)
351         new_ids=[]
352         for case in case_data:
353             if case.case_id:
354                 new_ids.append(case.case_id.id)
355         return getattr(self.pool.get('crm.case'),method)(cr, uid, new_ids, *args, **argv)
356
357
358     def case_close(self,cr, uid, ids, *args, **argv):
359         return self._map_ids('case_close',cr,uid,ids,*args,**argv)
360     def case_escalate(self,cr, uid, ids, *args, **argv):
361         return self._map_ids('case_escalate',cr,uid,ids,*args,**argv)
362     def case_open(self,cr, uid, ids, *args, **argv):
363         return self._map_ids('case_open',cr,uid,ids,*args,**argv)
364     def case_cancel(self,cr, uid, ids, *args, **argv):
365         return self._map_ids('case_cancel',cr,uid,ids,*args,**argv)
366     def case_pending(self,cr, uid, ids, *args, **argv):
367         return self._map_ids('case_pending',cr,uid,ids,*args,**argv)
368     def case_reset(self,cr, uid, ids, *args, **argv):
369         return self._map_ids('case_reset',cr,uid,ids,*args,**argv)
370     def case_log(self,cr, uid, ids, *args, **argv):
371         return self._map_ids('case_log',cr,uid,ids,*args,**argv)
372     def case_log_reply(self,cr, uid, ids, *args, **argv):
373         return self._map_ids('case_log_reply',cr,uid,ids,*args,**argv)
374     def add_reply(self,cr, uid, ids, *args, **argv):
375         return self._map_ids('add_reply',cr,uid,ids,*args,**argv)
376     def remind_partner(self,cr, uid, ids, *args, **argv):
377         return self._map_ids('remind_partner',cr,uid,ids,*args,**argv)
378     def remind_user(self,cr, uid, ids, *args, **argv):
379         return self._map_ids('remind_user',cr,uid,ids,*args,**argv)
380
381
382 event_registration()
383
384
385
386 class report_event_registration(osv.osv):
387     _name = "report.event.registration"
388     _description = "Events on registrations"
389     _auto = False
390     _columns = {
391         'name': fields.char('Event',size=20),
392         'date_begin': fields.datetime('Beginning date', required=True),
393         'date_end': fields.datetime('Ending date', required=True),
394         'draft_state': fields.integer('Draft Registration',size=20),
395         'confirm_state': fields.integer('Confirm Registration',size=20),
396         'register_max': fields.integer('Maximum Registrations'),
397     }
398     def init(self, cr):
399         cr.execute("""
400             create or replace view report_event_registration as (
401                 select
402                 e.id as id,
403                 c.name as name,
404                 e.date_begin as date_begin,
405                 e.date_end as date_end,
406                 (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,
407                 (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,
408                 e.register_max as register_max
409                 from
410                 event_event e,crm_case_section c
411                 where
412                 e.section_id=c.id
413                 )""")
414
415 report_event_registration()
416
417 class report_event_type_registration(osv.osv):
418     _name = "report.event.type.registration"
419     _description = "Event type on registration"
420     _auto = False
421     _columns = {
422         'name': fields.char('Event Type',size=20),
423         'nbevent':fields.integer('Number Of Events'),
424         'draft_state': fields.integer('Draft Registrations',size=20),
425         'confirm_state': fields.integer('Confirm Registrations',size=20),
426         }
427     def init(self, cr):
428         cr.execute("""
429             create or replace view report_event_type_registration as (
430                 select
431                 count(t.id) as id,
432                 t.name as name,
433                 (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 ,
434                 (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,
435                 count(t.id) as nbevent
436                 from
437                     event_event e
438                 inner join
439                     crm_case_section c1 on (e.section_id=c1.id)
440                 inner join
441                     event_type t on (e.type=t.id)
442                 group by
443                     t.name,t.id
444
445             )""")
446 report_event_type_registration()
447
448
449 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
450