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 crm import crm_base
23 from osv import fields, osv
24 from tools.translate import _
27 from datetime import datetime
29 class crm_phonecall(crm_base, osv.osv):
30 """ Phonecall Cases """
32 _name = "crm.phonecall"
33 _description = "Phonecall"
35 _inherit = ['mail.thread']
38 'id': fields.integer('ID', readonly=True),
39 'name': fields.char('Call Summary', size=64, required=True),
40 'active': fields.boolean('Active', required=False),
41 'date_action_last': fields.datetime('Last Action', readonly=1),
42 'date_action_next': fields.datetime('Next Action', readonly=1),
43 'create_date': fields.datetime('Creation Date' , readonly=True),
44 'section_id': fields.many2one('crm.case.section', 'Sales Team', \
45 select=True, help='Sales team to which Case belongs to.'),
46 'user_id': fields.many2one('res.users', 'Responsible'),
47 'partner_id': fields.many2one('res.partner', 'Partner'),
48 'partner_address_id': fields.many2one('res.partner.address', 'Partner Contact', \
49 domain="[('partner_id','=',partner_id)]"),
50 'company_id': fields.many2one('res.company', 'Company'),
51 'description': fields.text('Description'),
52 'state': fields.selection([
55 ('cancel', 'Cancelled'),
57 ('pending', 'Not Held'),
58 ], 'State', size=16, readonly=True,
59 help='The state is set to \'Todo\', when a case is created.\
60 \nIf the case is in progress the state is set to \'Open\'.\
61 \nWhen the call is over, the state is set to \'Held\'.\
62 \nIf the call needs to be done then the state is set to \'Not Held\'.'),
63 'email_from': fields.char('Email', size=128, help="These people will receive email."),
64 'date_open': fields.datetime('Opened', readonly=True),
66 'duration': fields.float('Duration', help="Duration in Minutes"),
67 'categ_id': fields.many2one('crm.case.categ', 'Category', \
68 domain="['|',('section_id','=',section_id),('section_id','=',False),\
69 ('object_id.model', '=', 'crm.phonecall')]"),
70 'partner_phone': fields.char('Phone', size=32),
71 'partner_contact': fields.related('partner_address_id', 'name', \
72 type="char", string="Contact", size=128),
73 'partner_mobile': fields.char('Mobile', size=32),
74 'priority': fields.selection(crm.AVAILABLE_PRIORITIES, 'Priority'),
75 'date_closed': fields.datetime('Closed', readonly=True),
76 'date': fields.datetime('Date'),
77 'opportunity_id': fields.many2one ('crm.lead', 'Lead/Opportunity'),
78 'message_ids': fields.one2many('mail.message', 'res_id', 'Messages', domain=[('model','=',_name)]),
81 def _get_default_state(self, cr, uid, context=None):
82 if context and context.get('default_state', False):
83 return context.get('default_state')
87 'date': lambda *a: time.strftime('%Y-%m-%d %H:%M:%S'),
88 'priority': crm.AVAILABLE_PRIORITIES[2][0],
89 'state': _get_default_state,
90 'user_id': lambda self,cr,uid,ctx: uid,
94 def case_get_note_msg_prefix(self, cr, uid, id, context=None):
97 def create(self, cr, uid, vals, context=None):
98 obj_id = super(crm_phonecall, self).create(cr, uid, vals, context)
99 for phonecall in self.browse(cr, uid, [obj_id], context=context):
100 if not phonecall.opportunity_id:
101 self.case_open_send_note(cr, uid, [obj_id], context=context)
104 def get_needaction_user_id(self, cr, uid, ids, name, arg, context=None):
106 for obj in self.browse(cr, uid, ids, context=context):
107 result[obj.id] = False
108 if (obj.state == 'draft' and obj.user_id):
109 result[obj.id] = obj.user_id.id
112 def case_cancel_send_note(self, cr, uid, ids, context=None):
113 for phonecall in self.browse(cr, uid, ids, context=context):
114 message = _("Phonecall has been <b>cancelled</b>.")
115 phonecall.message_append_note( _('System notification'),
116 message, type='notification', context=context)
119 def case_pending_send_note(self, cr, uid, ids, context=None):
120 for phonecall in self.browse(cr, uid, ids, context=context):
121 message = _("Phonecall is <b>pending</b>.")
122 phonecall.message_append_note('' ,message)
125 def case_done_send_note(self, cr, uid, ids, context=None):
126 for phonecall in self.browse(cr, uid, ids, context=context):
127 message = _("Phonecall has been <b>done</b>.")
128 phonecall.message_append_note('', message)
131 def case_open_send_note(self, cr, uid, ids, context=None):
132 lead_obj = self.pool.get('crm.lead')
133 for phonecall in self.browse(cr, uid, ids, context=context):
134 phonecall.message_subscribe([phonecall.user_id.id], context=context)
135 if phonecall.opportunity_id :
136 for lead in lead_obj.browse(cr, uid, [phonecall.opportunity_id.id], context=context):
137 message = _("Phonecall linked to the opportunity <em>%s</em> has been <b>created and opened </b>on <em>%s</em>.") % (lead.name, phonecall.date)
139 message = _("Phonecall has been <b>created and opened</b>.")
140 phonecall.message_append_note('' ,message)
143 def set_partner_send_note(self, cr, uid, ids, context=None):
144 for phonecall in self.browse(cr, uid, ids, context=context):
145 message = _("Partner has been <b>created</b>")
146 phonecall.message_append_note('' ,message)
150 def onchange_partner_address_id(self, cr, uid, ids, add, email=False):
151 res = super(crm_phonecall, self).onchange_partner_address_id(cr, uid, ids, add, email)
152 res.setdefault('value', {})
154 address = self.pool.get('res.partner.address').browse(cr, uid, add)
155 res['value']['partner_phone'] = address.phone
156 res['value']['partner_mobile'] = address.mobile
159 def case_close(self, cr, uid, ids, context=None):
160 """Overrides close for crm_case for setting close date
163 for phone in self.browse(cr, uid, ids):
165 data = {'date_closed': time.strftime('%Y-%m-%d %H:%M:%S')}
166 if phone.duration <=0:
167 duration = datetime.now() - datetime.strptime(phone.date, '%Y-%m-%d %H:%M:%S')
168 data.update({'duration': duration.seconds/float(60)})
169 res = super(crm_phonecall, self).case_close(cr, uid, [phone_id], context)
170 self.write(cr, uid, [phone_id], data)
171 self.case_done_send_note(cr, uid, [phone_id], context);
174 def case_reset(self, cr, uid, ids, context=None):
175 """Resets case as Todo
177 res = super(crm_phonecall, self).case_reset(cr, uid, ids, context)
178 self.write(cr, uid, ids, {'duration': 0.0, 'state':'open'})
179 self.case_open_send_note(cr, uid, ids, context=context)
183 def case_open(self, cr, uid, ids, context=None):
184 """Overrides cancel for crm_case for setting Open Date
186 res = super(crm_phonecall, self).case_open(cr, uid, ids, context)
187 self.write(cr, uid, ids, {'date_open': time.strftime('%Y-%m-%d %H:%M:%S')})
190 def schedule_another_phonecall(self, cr, uid, ids, schedule_time, call_summary, \
191 user_id=False, section_id=False, categ_id=False, action='schedule', context=None):
193 action :('schedule','Schedule a call'), ('log','Log a call')
195 model_data = self.pool.get('ir.model.data')
198 res_id = model_data._get_id(cr, uid, 'crm', 'categ_phone2')
200 categ_id = model_data.browse(cr, uid, res_id, context=context).res_id
201 for call in self.browse(cr, uid, ids, context=context):
203 section_id = call.section_id and call.section_id.id or False
205 user_id = call.user_id and call.user_id.id or False
207 'name' : call_summary,
208 'user_id' : user_id or False,
209 'categ_id' : categ_id or False,
210 'description' : call.description or False,
211 'date' : schedule_time,
212 'section_id' : section_id or False,
213 'partner_id': call.partner_id and call.partner_id.id or False,
214 'partner_address_id': call.partner_address_id and call.partner_address_id.id or False,
215 'partner_phone' : call.partner_phone,
216 'partner_mobile' : call.partner_mobile,
217 'priority': call.priority,
219 new_id = self.create(cr, uid, vals, context=context)
221 self.case_close(cr, uid, [new_id])
222 phonecall_dict[call.id] = new_id
223 return phonecall_dict
225 def _call_create_partner(self, cr, uid, phonecall, context=None):
226 partner = self.pool.get('res.partner')
227 partner_id = partner.create(cr, uid, {
228 'name': phonecall.name,
229 'user_id': phonecall.user_id.id,
230 'comment': phonecall.description,
235 def _call_set_partner(self, cr, uid, ids, partner_id, context=None):
236 self.write(cr, uid, ids, {'partner_id' : partner_id}, context=context)
237 self.set_partner_send_note(cr, uid, ids, context)
239 def _call_create_partner_address(self, cr, uid, phonecall, partner_id, context=None):
240 address = self.pool.get('res.partner.address')
241 return address.create(cr, uid, {
242 'partner_id': partner_id,
243 'name': phonecall.name,
244 'phone': phonecall.partner_phone,
247 def convert_partner(self, cr, uid, ids, action='create', partner_id=False, context=None):
249 This function convert partner based on action.
250 if action is 'create', create new partner with contact and assign lead to new partner_id.
251 otherwise assign lead to specified partner_id
256 for call in self.browse(cr, uid, ids, context=context):
257 if action == 'create':
259 partner_id = self._call_create_partner(cr, uid, call, context=context)
260 self._call_create_partner_address(cr, uid, call, partner_id, context=context)
261 self._call_set_partner(cr, uid, [call.id], partner_id, context=context)
262 partner_ids[call.id] = partner_id
266 def redirect_phonecall_view(self, cr, uid, phonecall_id, context=None):
267 model_data = self.pool.get('ir.model.data')
269 tree_view = model_data.get_object_reference(cr, uid, 'crm', 'crm_case_phone_tree_view')
270 form_view = model_data.get_object_reference(cr, uid, 'crm', 'crm_case_phone_form_view')
271 search_view = model_data.get_object_reference(cr, uid, 'crm', 'view_crm_case_phonecalls_filter')
273 'name': _('Phone Call'),
275 'view_mode': 'tree,form',
276 'res_model': 'crm.phonecall',
277 'res_id' : int(phonecall_id),
278 'views': [(form_view and form_view[1] or False, 'form'), (tree_view and tree_view[1] or False, 'tree'), (False, 'calendar')],
279 'type': 'ir.actions.act_window',
280 'search_view_id': search_view and search_view[1] or False,
285 def convert_opportunity(self, cr, uid, ids, opportunity_summary=False, partner_id=False, planned_revenue=0.0, probability=0.0, context=None):
286 partner = self.pool.get('res.partner')
287 address = self.pool.get('res.partner.address')
288 opportunity = self.pool.get('crm.lead')
289 opportunity_dict = {}
290 default_contact = False
291 for call in self.browse(cr, uid, ids, context=context):
293 partner_id = call.partner_id and call.partner_id.id or False
295 address_id = partner.address_get(cr, uid, [partner_id])['default']
297 default_contact = address.browse(cr, uid, address_id, context=context)
298 opportunity_id = opportunity.create(cr, uid, {
299 'name': opportunity_summary or call.name,
300 'planned_revenue': planned_revenue,
301 'probability': probability,
302 'partner_id': partner_id or False,
303 'partner_address_id': default_contact and default_contact.id,
304 'phone': default_contact and default_contact.phone,
305 'mobile': default_contact and default_contact.mobile,
306 'section_id': call.section_id and call.section_id.id or False,
307 'description': call.description or False,
308 'priority': call.priority,
309 'type': 'opportunity',
310 'phone': call.partner_phone or False,
311 'email_from': default_contact and default_contact.email,
314 'partner_id': partner_id,
315 'opportunity_id' : opportunity_id,
317 self.write(cr, uid, [call.id], vals)
318 self.case_close(cr, uid, [call.id])
319 opportunity.case_open(cr, uid, [opportunity_id])
320 opportunity_dict[call.id] = opportunity_id
321 return opportunity_dict
323 def action_make_meeting(self, cr, uid, ids, context=None):
325 This opens Meeting's calendar view to schedule meeting on current Phonecall
326 @return : Dictionary value for created Meeting view
329 for phonecall in self.browse(cr, uid, ids, context=context):
330 data_obj = self.pool.get('ir.model.data')
333 result = data_obj._get_id(cr, uid, 'crm', 'view_crm_case_meetings_filter')
334 res = data_obj.read(cr, uid, result, ['res_id'])
335 id1 = data_obj._get_id(cr, uid, 'crm', 'crm_case_calendar_view_meet')
336 id2 = data_obj._get_id(cr, uid, 'crm', 'crm_case_form_view_meet')
337 id3 = data_obj._get_id(cr, uid, 'crm', 'crm_case_tree_view_meet')
339 id1 = data_obj.browse(cr, uid, id1, context=context).res_id
341 id2 = data_obj.browse(cr, uid, id2, context=context).res_id
343 id3 = data_obj.browse(cr, uid, id3, context=context).res_id
346 'default_phonecall_id': phonecall.id,
347 'default_partner_id': phonecall.partner_id and phonecall.partner_id.id or False,
348 'default_email': phonecall.email_from ,
349 'default_name': phonecall.name
353 'name': _('Meetings'),
354 'domain' : "[('user_id','=',%s)]" % (uid),
357 'view_mode': 'calendar,form,tree',
358 'res_model': 'crm.meeting',
360 'views': [(id1, 'calendar'), (id2, 'form'), (id3, 'tree')],
361 'type': 'ir.actions.act_window',
362 'search_view_id': res['res_id'],
371 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: