1 # -*- coding: utf-8 -*-
2 ##############################################################################
4 # OpenERP, Open Source Management Solution
5 # Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
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.
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.
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/>.
20 ##############################################################################
22 from osv import fields, osv
27 from tools.translate import _
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)
38 'user_id': lambda self,cr,uid,context: uid,
42 class event_type(osv.osv):
44 _description= 'Event type'
46 'name': fields.char('Event type', size=64, required=True),
52 _description = 'Event'
53 _inherits = {'crm.case.section': 'section_id'}
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'})
59 def button_draft(self, cr, uid, ids, context={}):
60 return self.write(cr, uid, ids, {'state':'draft'})
62 def button_cancel(self, cr, uid, ids, context={}):
63 return self.write(cr, uid, ids, {'state':'cancel'})
65 def button_done(self, cr, uid, ids, context={}):
66 return self.write(cr, uid, ids, {'state':'done'})
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'])])
74 self.pool.get('event.registration').mail_user_confirm(cr, uid, reg_ids)
75 return self.write(cr, uid, ids, {'state':'confirm'})
77 def _get_register(self, cr, uid, ids, name, args, context=None):
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,))
84 res[event.id] = res2[0]
89 def _get_prospect(self, cr, uid, ids, name, args, context=None):
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,))
96 res[event.id] = res2[0]
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)])
108 self.pool.get('event.registration').write(cr, uid, reg_ids, {'date_deadline':vals['date_begin']})
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
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)])
122 self.pool.get('event.registration').write(cr, uid, reg_ids, {'description':vals['mail_confirm']})
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),
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,
152 class event_registration(osv.osv):
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]])
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]})
168 'name': _('Confirm Registration'),
171 'view_mode': 'tree,form',
172 'res_model': 'event.confirm.registration',
173 'views': [(resource_id,'form')],
174 'type': 'ir.actions.act_window',
179 def _history(self, cr, uid,ids,keyword, history=False, email=False, context={}):
180 for case in self.browse(cr, uid, ids):
186 'canal_id': case.canal_id.id,
188 'case_id': case.case_id.id
190 obj = self.pool.get('crm.case.log')
191 obj.create(cr, uid, data, context)
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)
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)
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)
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)
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
226 if reg_id.email_from:
227 dest += [reg_id.email_from]
229 dest += [reg_id.email_cc]
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))
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'))
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
241 if reg_id.email_from:
242 dest += [reg_id.email_from]
244 dest += [reg_id.email_cc]
245 if reg_id.event_id.mail_auto_confirm or reg_id.event_id.mail_auto_registr:
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))
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'))
255 def _create_invoice_lines(self, cr, uid, ids, vals):
256 return self.pool.get('account.invoice.line').create(cr, uid,vals )
258 _name= 'event.registration'
259 _description = 'Event Registration'
260 _inherits = {'crm.case': 'case_id'}
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)."),
286 'nb_register': lambda *a: 1,
287 'tobe_invoiced' : lambda *a: True,
288 'name': lambda *a: 'Registration',
289 'state': lambda *b: 'draft'
292 def onchange_badge_name(self, cr, uid, ids, badge_name):
296 data['name'] = 'Registration: ' + badge_name
297 return {'value':data}
299 def onchange_contact_id(self, cr, uid, ids, contact, partner):
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
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)])
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'])
314 return {'value':data}
316 def onchange_event(self, cr, uid, ids, event_id, partner_invoice_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}}
332 def onchange_partner_id(self, cr, uid, ids, part, event_id, email=False):
334 data['badge_partner'] = data['contact_id'] = data['partner_invoice_id'] = data['email_from'] = data['badge_title'] = data['badge_name'] = False
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])
344 if addr.has_key('default'):
345 job_ids = self.pool.get('res.partner.job').search(cr, uid, [('address_id','=',addr['default'])])
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}
354 def onchange_partner_invoice_id(self, cr, uid, ids, event_id, partner_invoice_id):
357 data['unit_price']=False
359 return {'value':data}
360 data_event = self.pool.get('event.event').browse(cr,uid,event_id)
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}
372 def onchange_categ_id(self, cr, uid, ids, categ, context={}):
375 cat = self.pool.get('crm.case.categ').browse(cr, uid, categ, context).probability
376 return {'value':{'probability':cat}}
378 def _map_ids(self,method,cr, uid, ids, *args, **argv):
379 case_data = self.browse(cr,uid,ids)
381 for case in case_data:
383 new_ids.append(case.case_id.id)
384 return getattr(self.pool.get('crm.case'),method)(cr, uid, new_ids, *args, **argv)
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)
415 class report_event_registration(osv.osv):
416 _name = "report.event.registration"
417 _description = "Events on registrations"
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'),
429 create or replace view report_event_registration as (
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
439 event_event e,crm_case_section c
444 report_event_registration()
446 class report_event_type_registration(osv.osv):
447 _name = "report.event.type.registration"
448 _description = "Event type on registration"
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),
458 create or replace view report_event_type_registration as (
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
468 crm_case_section c1 on (e.section_id=c1.id)
470 event_type t on (e.type=t.id)
475 report_event_type_registration()
478 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: