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 = ['ir.needaction_mixin', '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 'company_id': fields.many2one('res.company', 'Company'),
49 'description': fields.text('Description'),
50 'state': fields.selection([
53 ('cancel', 'Cancelled'),
55 ('pending', 'Not Held'),
56 ], 'State', size=16, readonly=True,
57 help='The state is set to \'Todo\', when a case is created.\
58 \nIf the case is in progress the state is set to \'Open\'.\
59 \nWhen the call is over, the state is set to \'Held\'.\
60 \nIf the call needs to be done then the state is set to \'Not Held\'.'),
61 'email_from': fields.char('Email', size=128, help="These people will receive email."),
62 'date_open': fields.datetime('Opened', readonly=True),
64 'duration': fields.float('Duration', help="Duration in Minutes"),
65 'categ_id': fields.many2one('crm.case.categ', 'Category', \
66 domain="['|',('section_id','=',section_id),('section_id','=',False),\
67 ('object_id.model', '=', 'crm.phonecall')]"),
68 'partner_phone': fields.char('Phone', size=32),
69 'partner_mobile': fields.char('Mobile', size=32),
70 'priority': fields.selection(crm.AVAILABLE_PRIORITIES, 'Priority'),
71 'date_closed': fields.datetime('Closed', readonly=True),
72 'date': fields.datetime('Date'),
73 'opportunity_id': fields.many2one ('crm.lead', 'Lead/Opportunity'),
74 'message_ids': fields.one2many('mail.message', 'res_id', 'Messages', domain=[('model','=',_name)]),
77 def _get_default_state(self, cr, uid, context=None):
78 if context and context.get('default_state', False):
79 return context.get('default_state')
83 'date': lambda *a: time.strftime('%Y-%m-%d %H:%M:%S'),
84 'priority': crm.AVAILABLE_PRIORITIES[2][0],
85 'state': _get_default_state,
86 'user_id': lambda self,cr,uid,ctx: uid,
90 def create(self, cr, uid, vals, context=None):
91 obj_id = super(crm_phonecall, self).create(cr, uid, vals, context)
92 for phonecall in self.browse(cr, uid, [obj_id], context=context):
93 if not phonecall.opportunity_id:
94 self.case_open_send_note(cr, uid, [obj_id], context=context)
97 def case_close(self, cr, uid, ids, context=None):
98 """Overrides close for crm_case for setting close date
101 for phone in self.browse(cr, uid, ids):
103 data = {'date_closed': time.strftime('%Y-%m-%d %H:%M:%S')}
104 if phone.duration <=0:
105 duration = datetime.now() - datetime.strptime(phone.date, '%Y-%m-%d %H:%M:%S')
106 data.update({'duration': duration.seconds/float(60)})
107 res = super(crm_phonecall, self).case_close(cr, uid, [phone_id], context)
108 self.write(cr, uid, [phone_id], data)
111 def case_reset(self, cr, uid, ids, context=None):
112 """Resets case as Todo
114 res = super(crm_phonecall, self).case_reset(cr, uid, ids, context)
115 self.write(cr, uid, ids, {'duration': 0.0, 'state':'open'})
119 def case_open(self, cr, uid, ids, context=None):
120 """Overrides cancel for crm_case for setting Open Date
122 res = super(crm_phonecall, self).case_open(cr, uid, ids, context)
123 self.write(cr, uid, ids, {'date_open': time.strftime('%Y-%m-%d %H:%M:%S')})
126 def schedule_another_phonecall(self, cr, uid, ids, schedule_time, call_summary, \
127 user_id=False, section_id=False, categ_id=False, action='schedule', context=None):
129 action :('schedule','Schedule a call'), ('log','Log a call')
131 model_data = self.pool.get('ir.model.data')
134 res_id = model_data._get_id(cr, uid, 'crm', 'categ_phone2')
136 categ_id = model_data.browse(cr, uid, res_id, context=context).res_id
137 for call in self.browse(cr, uid, ids, context=context):
139 section_id = call.section_id and call.section_id.id or False
141 user_id = call.user_id and call.user_id.id or False
143 'name' : call_summary,
144 'user_id' : user_id or False,
145 'categ_id' : categ_id or False,
146 'description' : call.description or False,
147 'date' : schedule_time,
148 'section_id' : section_id or False,
149 'partner_id': call.partner_id and call.partner_id.id or False,
150 'partner_phone' : call.partner_phone,
151 'partner_mobile' : call.partner_mobile,
152 'priority': call.priority,
154 new_id = self.create(cr, uid, vals, context=context)
156 self.case_close(cr, uid, [new_id])
157 phonecall_dict[call.id] = new_id
158 return phonecall_dict
160 def _call_create_partner(self, cr, uid, phonecall, context=None):
161 partner = self.pool.get('res.partner')
162 partner_id = partner.create(cr, uid, {
163 'name': phonecall.name,
164 'user_id': phonecall.user_id.id,
165 'comment': phonecall.description,
170 def _call_set_partner(self, cr, uid, ids, partner_id, context=None):
171 write_res = self.write(cr, uid, ids, {'partner_id' : partner_id}, context=context)
172 self._call_set_partner_send_note(cr, uid, ids, context)
175 def _call_create_partner_address(self, cr, uid, phonecall, partner_id, context=None):
176 address = self.pool.get('res.partner')
177 return address.create(cr, uid, {
178 'parent_id': partner_id,
179 'name': phonecall.name,
180 'phone': phonecall.partner_phone,
183 def convert_partner(self, cr, uid, ids, action='create', partner_id=False, context=None):
185 This function convert partner based on action.
186 if action is 'create', create new partner with contact and assign lead to new partner_id.
187 otherwise assign lead to specified partner_id
192 for call in self.browse(cr, uid, ids, context=context):
193 if action == 'create':
195 partner_id = self._call_create_partner(cr, uid, call, context=context)
196 self._call_create_partner_address(cr, uid, call, partner_id, context=context)
197 self._call_set_partner(cr, uid, [call.id], partner_id, context=context)
198 partner_ids[call.id] = partner_id
202 def redirect_phonecall_view(self, cr, uid, phonecall_id, context=None):
203 model_data = self.pool.get('ir.model.data')
205 tree_view = model_data.get_object_reference(cr, uid, 'crm', 'crm_case_phone_tree_view')
206 form_view = model_data.get_object_reference(cr, uid, 'crm', 'crm_case_phone_form_view')
207 search_view = model_data.get_object_reference(cr, uid, 'crm', 'view_crm_case_phonecalls_filter')
209 'name': _('Phone Call'),
211 'view_mode': 'tree,form',
212 'res_model': 'crm.phonecall',
213 'res_id' : int(phonecall_id),
214 'views': [(form_view and form_view[1] or False, 'form'), (tree_view and tree_view[1] or False, 'tree'), (False, 'calendar')],
215 'type': 'ir.actions.act_window',
216 'search_view_id': search_view and search_view[1] or False,
221 def convert_opportunity(self, cr, uid, ids, opportunity_summary=False, partner_id=False, planned_revenue=0.0, probability=0.0, context=None):
222 partner = self.pool.get('res.partner')
223 opportunity = self.pool.get('crm.lead')
224 opportunity_dict = {}
225 default_contact = False
226 for call in self.browse(cr, uid, ids, context=context):
228 partner_id = call.partner_id and call.partner_id.id or False
230 address_id = partner.address_get(cr, uid, [partner_id])['default']
232 default_contact = partner.browse(cr, uid, address_id, context=context)
233 opportunity_id = opportunity.create(cr, uid, {
234 'name': opportunity_summary or call.name,
235 'planned_revenue': planned_revenue,
236 'probability': probability,
237 'partner_id': partner_id or False,
238 'mobile': default_contact and default_contact.mobile,
239 'section_id': call.section_id and call.section_id.id or False,
240 'description': call.description or False,
241 'priority': call.priority,
242 'type': 'opportunity',
243 'phone': call.partner_phone or False,
244 'email_from': default_contact and default_contact.email,
247 'partner_id': partner_id,
248 'opportunity_id' : opportunity_id,
250 self.write(cr, uid, [call.id], vals)
251 self.case_close(cr, uid, [call.id])
252 opportunity.case_open(cr, uid, [opportunity_id])
253 opportunity_dict[call.id] = opportunity_id
254 return opportunity_dict
256 def action_make_meeting(self, cr, uid, ids, context=None):
258 This opens Meeting's calendar view to schedule meeting on current Phonecall
259 @return : Dictionary value for created Meeting view
262 for phonecall in self.browse(cr, uid, ids, context=context):
263 data_obj = self.pool.get('ir.model.data')
266 result = data_obj._get_id(cr, uid, 'crm', 'view_crm_case_meetings_filter')
267 res = data_obj.read(cr, uid, result, ['res_id'])
268 id1 = data_obj._get_id(cr, uid, 'crm', 'crm_case_calendar_view_meet')
269 id2 = data_obj._get_id(cr, uid, 'crm', 'crm_case_form_view_meet')
270 id3 = data_obj._get_id(cr, uid, 'crm', 'crm_case_tree_view_meet')
272 id1 = data_obj.browse(cr, uid, id1, context=context).res_id
274 id2 = data_obj.browse(cr, uid, id2, context=context).res_id
276 id3 = data_obj.browse(cr, uid, id3, context=context).res_id
279 'default_phonecall_id': phonecall.id,
280 'default_partner_id': phonecall.partner_id and phonecall.partner_id.id or False,
281 'default_email': phonecall.email_from ,
282 'default_name': phonecall.name
286 'name': _('Meetings'),
287 'domain' : "[('user_id','=',%s)]" % (uid),
290 'view_mode': 'calendar,form,tree',
291 'res_model': 'crm.meeting',
293 'views': [(id1, 'calendar'), (id2, 'form'), (id3, 'tree')],
294 'type': 'ir.actions.act_window',
295 'search_view_id': res['res_id'],
301 # ----------------------------------------
302 # OpenChatter methods and notifications
303 # ----------------------------------------
305 def get_needaction_user_ids(self, cr, uid, ids, context=None):
306 result = dict.fromkeys(ids)
307 for obj in self.browse(cr, uid, ids, context=context):
309 if (obj.state == 'draft' and obj.user_id):
310 result[obj.id] = [obj.user_id.id]
313 def case_get_note_msg_prefix(self, cr, uid, id, context=None):
316 def case_reset_send_note(self, cr, uid, ids, context=None):
317 message = _('Phonecall has been <b>reset and set as open</b>.')
318 return self.message_append_note(cr, uid, ids, body=message, context=context)
320 def case_open_send_note(self, cr, uid, ids, context=None):
321 lead_obj = self.pool.get('crm.lead')
322 for phonecall in self.browse(cr, uid, ids, context=context):
323 phonecall.message_subscribe([phonecall.user_id.id], context=context)
324 if phonecall.opportunity_id:
325 lead = phonecall.opportunity_id
326 # convert datetime field to a datetime, using server format, then
327 # convert it to the user TZ and re-render it with %Z to add the timezone
328 phonecall_datetime = fields.DT.datetime.strptime(phonecall.date, tools.DEFAULT_SERVER_DATETIME_FORMAT)
329 phonecall_date_str = fields.datetime.context_timestamp(cr, uid, phonecall_datetime, context=context).strftime(tools.DATETIME_FORMATS_MAP['%+'] + " (%Z)")
330 message = _("Phonecall linked to the opportunity <em>%s</em> has been <b>created</b> and <b>scheduled</b> on <em>%s</em>.") % (lead.name, phonecall_date_str)
332 message = _("Phonecall has been <b>created and opened</b>.")
333 phonecall.message_append_note(body=message)
336 def _call_set_partner_send_note(self, cr, uid, ids, context=None):
337 return self.message_append_note(cr, uid, ids, body=_("Partner has been <b>created</b>"), context=context)
343 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: