Event : Mailing of user corrected \nSale : Report corrected
[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 check_confirm(self, cr, uid, ids, context):
155         mod_obj = self.pool.get('ir.model.data')
156         current_registration = self.browse(cr, uid, [ids[0]])[0]
157         total_confirmed = current_registration.event_id.register_current + current_registration.nb_register
158         if total_confirmed <= current_registration.event_id.register_max or current_registration.event_id.register_max == 0:
159             self.write(cr, uid, [ids[0]], {'state':'open'}, context=context)
160             self._history(cr, uid, [ids[0]], 'Open', history=True)
161             self.mail_user(cr, uid, [ids[0]])
162             return True
163         else:
164             model_data_ids = mod_obj.search(cr,uid,[('model','=','ir.ui.view'),('name','=','view_event_confirm_registration')], context=context)
165             resource_id = mod_obj.read(cr, uid, model_data_ids, fields=['res_id'], context=context)[0]['res_id']
166             context.update({'reg_id': ids[0]})
167             return {
168                 'name': _('Confirm Registration'),
169                 'context': context,
170                 'view_type': 'form',
171                 'view_mode': 'tree,form',
172                 'res_model': 'event.confirm.registration',
173                 'views': [(resource_id,'form')],
174                 'type': 'ir.actions.act_window',
175                 'target': 'new',
176                 'nodestroy': True
177             }
178
179     def _history(self, cr, uid,ids,keyword, history=False, email=False, context={}):
180         for case in self.browse(cr, uid, ids):
181             if not case.case_id:
182                 return True
183             data = {
184                 'name': keyword,
185                 'som': case.som.id,
186                 'canal_id': case.canal_id.id,
187                 'user_id': uid,
188                 'case_id': case.case_id.id
189             }
190             obj = self.pool.get('crm.case.log')
191             obj.create(cr, uid, data, context)
192         return True
193
194     def button_reg_close(self, cr, uid, ids, *args):
195         self.write(cr, uid, ids, {'state':'done',})
196         self._history(cr, uid, ids, 'Done', history=True)
197         return True
198
199     def button_reg_cancel(self, cr, uid, ids, *args):
200         self.write(cr, uid, ids, {'state':'cancel',})
201         self._history(cr, uid, ids, 'Cancel', history=True)
202         return True
203
204     def create(self, cr, uid, *args, **argv):
205         event = self.pool.get('event.event').browse(cr, uid, args[0]['event_id'], None)
206         args[0]['section_id']= event.section_id.id
207         args[0]['date_deadline']= event.date_begin
208         args[0]['description']= event.mail_confirm
209         res = super(event_registration, self).create(cr, uid, *args, **argv)
210         self._history(cr, uid,[res], 'Created', history=True)
211         return res
212
213     def write(self, cr, uid, *args, **argv):
214         if 'event_id' in args[1]:
215             event = self.pool.get('event.event').browse(cr, uid, args[1]['event_id'], None)
216             args[1]['section_id']= event.section_id.id
217             args[1]['date_deadline']= event.date_begin
218             args[1]['description']= event.mail_confirm
219         return super(event_registration, self).write(cr, uid, *args, **argv)
220
221     def mail_user_confirm(self, cr, uid, ids):
222         reg_ids = self.browse(cr,uid,ids)
223         for reg_id in reg_ids:
224             src = reg_id.event_id.reply_to or False
225             dest = []
226             if reg_id.email_from:
227                 dest += [reg_id.email_from]
228             if reg_id.email_cc:
229                 dest += [reg_id.email_cc]
230             if dest and src:
231                 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))
232             if not src:
233                 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'))
234         return False
235
236     def mail_user(self, cr, uid, ids):
237         reg_ids = self.browse(cr, uid, ids)
238         for reg_id in reg_ids:
239             src = reg_id.event_id.reply_to or False
240             dest = []
241             if reg_id.email_from:
242                 dest += [reg_id.email_from]
243             if reg_id.email_cc:
244                 dest += [reg_id.email_cc]
245             if reg_id.event_id.mail_auto_confirm or reg_id.event_id.mail_auto_registr:
246                 if dest and src:
247                     if reg_id.event_id.state in ['draft', 'fixed', 'open','confirm','running'] and reg_id.event_id.mail_auto_registr:
248                         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))
249                     if (reg_id.event_id.state in ['confirm','running']) and reg_id.event_id.mail_auto_confirm:
250                         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))
251                 if not src:
252                     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'))
253         return False
254
255     def _create_invoice_lines(self, cr, uid, ids, vals):
256         return self.pool.get('account.invoice.line').create(cr, uid,vals )
257
258     _name= 'event.registration'
259     _description = 'Event Registration'
260     _inherits = {'crm.case': 'case_id'}
261     _columns = {
262         'case_id':fields.many2one('crm.case','Case'),
263         'nb_register': fields.integer('Number of Registration', readonly=True, states={'draft':[('readonly',False)]}),
264         'event_id':fields.many2one('event.event', 'Event Related', required=True),
265         "partner_invoice_id":fields.many2one('res.partner', 'Partner Invoiced'),
266         "contact_id":fields.many2one('res.partner.contact', 'Partner Contact'), #TODO: filter only the contacts that have a function into the selected partner_id
267         "unit_price": fields.float('Unit Price'),
268         "badge_title":fields.char('Badge Title',size=128),
269         "badge_name":fields.char('Badge Name',size=128),
270         "badge_partner":fields.char('Badge Partner',size=128),
271         "invoice_label":fields.char("Label Invoice",size=128,required=True),
272         "tobe_invoiced":fields.boolean("To be Invoiced"),
273         "invoice_id":fields.many2one("account.invoice","Invoice"),
274         'date_closed': fields.datetime('Closed', readonly=True),
275         'ref' : fields.reference('Reference', selection=crm._links_get, size=128),
276         'ref2' : fields.reference('Reference 2', selection=crm._links_get, size=128),
277         'categ_id': fields.many2one('crm.case.categ','Category', domain="[('section_id','=',section_id)]"),
278         'canal_id': fields.many2one('res.partner.canal', 'Channel',help="The channels represent the different communication modes available with the customer." \
279                                                                         " With each commercial opportunity, you can indicate the canall which is this opportunity source."),
280         'som': fields.many2one('res.partner.som', 'State of Mind', help="The minds states allow to define a value scale which represents" \
281                                                                        "the partner mentality in relation to our services.The scale has" \
282                                                                        "to be created with a factor for each level from 0 (Very dissatisfied) to 10 (Extremely satisfied)."),
283
284     }
285     _defaults = {
286         'nb_register': lambda *a: 1,
287         'tobe_invoiced' : lambda *a: True,
288         'name': lambda *a: 'Registration',
289         'state': lambda *b: 'draft'
290     }
291
292     def onchange_badge_name(self, cr, uid, ids, badge_name):
293         data ={}
294         if not badge_name:
295             return data
296         data['name'] = 'Registration: ' + badge_name
297         return {'value':data}
298
299     def onchange_contact_id(self, cr, uid, ids, contact, partner):
300         data ={}
301         if not contact:
302             return data
303         contact_id = self.pool.get('res.partner.contact').browse(cr, uid, contact)
304         data['badge_name'] = contact_id.name
305         data['badge_title'] = contact_id.title
306         if partner:
307             partner_addresses = self.pool.get('res.partner.address').search(cr, uid, [('partner_id','=',partner)])
308             job_ids = self.pool.get('res.partner.job').search(cr, uid, [('contact_id','=',contact),('address_id','in',partner_addresses)])
309             if job_ids:
310                 data['email_from'] = self.pool.get('res.partner.job').browse(cr, uid, job_ids[0]).email
311         d = self.onchange_badge_name(cr, uid, ids,data['badge_name'])
312         data.update(d['value'])
313
314         return {'value':data}
315
316     def onchange_event(self, cr, uid, ids, event_id, partner_invoice_id):
317         context={}
318         if not event_id:
319             return {'value':{'unit_price' : False ,'invoice_label' : False }}
320         data_event =  self.pool.get('event.event').browse(cr,uid,event_id)
321         if data_event.product_id:
322             if not partner_invoice_id:
323                 unit_price=self.pool.get('product.product').price_get(cr, uid, [data_event.product_id.id],context=context)[data_event.product_id.id]
324                 return {'value':{'unit_price' : unit_price , 'invoice_label' : data_event.product_id.name}}
325             data_partner = self.pool.get('res.partner').browse(cr,uid,partner_invoice_id)
326             context.update({'partner_id':data_partner})
327             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]
328             return {'value':{'unit_price' :unit_price , 'invoice_label' : data_event.product_id.name}}
329         return {'value':{'unit_price' : False,'invoice_label' : False}}
330
331
332     def onchange_partner_id(self, cr, uid, ids, part, event_id, email=False):
333         data={}
334         data['badge_partner'] = data['contact_id'] = data['partner_invoice_id'] = data['email_from'] = data['badge_title'] = data['badge_name'] = False
335         if not part:
336             return {'value':data}
337         data['partner_invoice_id']=part
338         # this calls onchange_partner_invoice_id
339         d = self.onchange_partner_invoice_id(cr, uid, ids, event_id,part)
340         # this updates the dictionary
341         data.update(d['value'])
342         addr = self.pool.get('res.partner').address_get(cr, uid, [part])
343         if addr:
344             if addr.has_key('default'):
345                 job_ids = self.pool.get('res.partner.job').search(cr, uid, [('address_id','=',addr['default'])])
346                 if job_ids:
347                     data['contact_id'] = self.pool.get('res.partner.job').browse(cr, uid, job_ids[0]).contact_id.id
348                     d = self.onchange_contact_id(cr, uid, ids, data['contact_id'],part)
349                     data.update(d['value'])
350         partner_data = self.pool.get('res.partner').browse(cr, uid, part)
351         data['badge_partner'] = partner_data.name
352         return {'value':data}
353
354     def onchange_partner_invoice_id(self, cr, uid, ids, event_id, partner_invoice_id):
355         data={}
356         context={}
357         data['unit_price']=False
358         if not event_id:
359             return {'value':data}
360         data_event =  self.pool.get('event.event').browse(cr,uid,event_id)
361
362         if data_event.product_id:
363             if not partner_invoice_id:
364                 data['unit_price']=self.pool.get('product.product').price_get(cr, uid, [data_event.product_id.id],context=context)[data_event.product_id.id]
365                 return {'value':data}
366             data_partner = self.pool.get('res.partner').browse(cr,uid,partner_invoice_id)
367             context.update({'partner_id':data_partner})
368             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]
369             return {'value':data}
370         return {'value':data}
371
372     def onchange_categ_id(self, cr, uid, ids, categ, context={}):
373         if not categ:
374             return {'value':{}}
375         cat = self.pool.get('crm.case.categ').browse(cr, uid, categ, context).probability
376         return {'value':{'probability':cat}}
377
378     def _map_ids(self,method,cr, uid, ids, *args, **argv):
379         case_data = self.browse(cr,uid,ids)
380         new_ids=[]
381         for case in case_data:
382             if case.case_id:
383                 new_ids.append(case.case_id.id)
384         return getattr(self.pool.get('crm.case'),method)(cr, uid, new_ids, *args, **argv)
385
386
387     def case_close(self,cr, uid, ids, *args, **argv):
388         return self._map_ids('case_close',cr,uid,ids,*args,**argv)
389     def case_escalate(self,cr, uid, ids, *args, **argv):
390         return self._map_ids('case_escalate',cr,uid,ids,*args,**argv)
391     def case_open(self,cr, uid, ids, *args, **argv):
392         return self._map_ids('case_open',cr,uid,ids,*args,**argv)
393     def case_cancel(self,cr, uid, ids, *args, **argv):
394         return self._map_ids('case_cancel',cr,uid,ids,*args,**argv)
395     def case_pending(self,cr, uid, ids, *args, **argv):
396         return self._map_ids('case_pending',cr,uid,ids,*args,**argv)
397     def case_reset(self,cr, uid, ids, *args, **argv):
398         return self._map_ids('case_reset',cr,uid,ids,*args,**argv)
399     def case_log(self,cr, uid, ids, *args, **argv):
400         return self._map_ids('case_log',cr,uid,ids,*args,**argv)
401     def case_log_reply(self,cr, uid, ids, *args, **argv):
402         return self._map_ids('case_log_reply',cr,uid,ids,*args,**argv)
403     def add_reply(self,cr, uid, ids, *args, **argv):
404         return self._map_ids('add_reply',cr,uid,ids,*args,**argv)
405     def remind_partner(self,cr, uid, ids, *args, **argv):
406         return self._map_ids('remind_partner',cr,uid,ids,*args,**argv)
407     def remind_user(self,cr, uid, ids, *args, **argv):
408         return self._map_ids('remind_user',cr,uid,ids,*args,**argv)
409
410
411 event_registration()
412
413
414
415 class report_event_registration(osv.osv):
416     _name = "report.event.registration"
417     _description = "Events on registrations"
418     _auto = False
419     _columns = {
420         'name': fields.char('Event',size=20),
421         'date_begin': fields.datetime('Beginning date', required=True),
422         'date_end': fields.datetime('Ending date', required=True),
423         'draft_state': fields.integer('Draft Registration',size=20),
424         'confirm_state': fields.integer('Confirm Registration',size=20),
425         'register_max': fields.integer('Maximum Registrations'),
426     }
427     def init(self, cr):
428         cr.execute("""
429             create or replace view report_event_registration as (
430                 select
431                 e.id as id,
432                 c.name as name,
433                 e.date_begin as date_begin,
434                 e.date_end as date_end,
435                 (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,
436                 (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,
437                 e.register_max as register_max
438                 from
439                 event_event e,crm_case_section c
440                 where
441                 e.section_id=c.id
442                 )""")
443
444 report_event_registration()
445
446 class report_event_type_registration(osv.osv):
447     _name = "report.event.type.registration"
448     _description = "Event type on registration"
449     _auto = False
450     _columns = {
451         'name': fields.char('Event Type',size=20),
452         'nbevent':fields.integer('Number Of Events'),
453         'draft_state': fields.integer('Draft Registrations',size=20),
454         'confirm_state': fields.integer('Confirm Registrations',size=20),
455         }
456     def init(self, cr):
457         cr.execute("""
458             create or replace view report_event_type_registration as (
459                 select
460                 count(t.id) as id,
461                 t.name as name,
462                 (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 ,
463                 (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,
464                 count(t.id) as nbevent
465                 from
466                     event_event e
467                 inner join
468                     crm_case_section c1 on (e.section_id=c1.id)
469                 inner join
470                     event_type t on (e.type=t.id)
471                 group by
472                     t.name,t.id
473
474             )""")
475 report_event_type_registration()
476
477
478 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
479