6ac404b9e63b13ff1350c411421ca1b09fcd38b3
[odoo/odoo.git] / addons / crm / crm_phonecall.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 crm import crm_base
23 from osv import fields, osv
24 from tools.translate import _
25 import crm
26 import time
27 from datetime import datetime
28
29 class crm_phonecall(crm_base, osv.osv):
30     """ Phonecall Cases """
31
32     _name = "crm.phonecall"
33     _description = "Phonecall"
34     _order = "id desc"
35     _inherit = ['mail.thread']
36     _columns = {
37         # From crm.case
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([
53                                     ('draft', 'Draft'),
54                                     ('open', 'Todo'),
55                                     ('cancel', 'Cancelled'),
56                                     ('done', 'Held'),
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),
65         # phonecall fields
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)]),
79     }
80
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')
84         return 'open'
85
86     _defaults = {
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,
91         'active': 1,
92     }
93
94     def case_get_note_msg_prefix(self, cr, uid, id, context=None):
95         return ''
96
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)
102         return obj_id
103
104     def get_needaction_user_id(self, cr, uid, ids, name, arg, context=None):
105         result = {}
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
110         return result
111
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)
117         return True
118
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)
123         return True
124
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)
129         return True
130
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)
138             else:
139                 message = _("Phonecall has been <b>created and opened</b>.")
140             phonecall.message_append_note('' ,message)
141         return True
142
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)
147         return True
148
149     # From crm.case
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', {})
153         if add:
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
157         return res
158
159     def case_close(self, cr, uid, ids, context=None):
160         """Overrides close for crm_case for setting close date
161         """
162         res = True
163         for phone in self.browse(cr, uid, ids):
164             phone_id = phone.id
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);
172         return res
173
174     def case_reset(self, cr, uid, ids, context=None):
175         """Resets case as Todo
176         """
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)
180         return res
181
182
183     def case_open(self, cr, uid, ids, context=None):
184         """Overrides cancel for crm_case for setting Open Date
185         """
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')})
188         return res
189
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):
192         """
193         action :('schedule','Schedule a call'), ('log','Log a call')
194         """
195         model_data = self.pool.get('ir.model.data')
196         phonecall_dict = {}
197         if not categ_id:
198             res_id = model_data._get_id(cr, uid, 'crm', 'categ_phone2')
199             if res_id:
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):
202             if not section_id:
203                 section_id = call.section_id and call.section_id.id or False
204             if not user_id:
205                 user_id = call.user_id and call.user_id.id or False
206             vals = {
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,
218             }
219             new_id = self.create(cr, uid, vals, context=context)
220             if action == 'log':
221                 self.case_close(cr, uid, [new_id])
222             phonecall_dict[call.id] = new_id
223         return phonecall_dict
224
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,
231                     'address': []
232         })
233         return partner_id
234
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)
238
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,
245         })
246
247     def convert_partner(self, cr, uid, ids, action='create', partner_id=False, context=None):
248         """
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
252         """
253         if context is None:
254             context = {}
255         partner_ids = {}
256         for call in self.browse(cr, uid, ids, context=context):
257             if action == 'create':
258                if not partner_id:
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
263         return partner_ids
264
265
266     def redirect_phonecall_view(self, cr, uid, phonecall_id, context=None):
267         model_data = self.pool.get('ir.model.data')
268         # Select the view
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')
272         value = {
273                 'name': _('Phone Call'),
274                 'view_type': 'form',
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,
281         }
282         return value
283
284
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):
292             if not partner_id:
293                 partner_id = call.partner_id and call.partner_id.id or False
294             if partner_id:
295                 address_id = partner.address_get(cr, uid, [partner_id])['default']
296                 if address_id:
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,
312                         })
313             vals = {
314                     'partner_id': partner_id,
315                     'opportunity_id' : opportunity_id,
316             }
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
322
323     def action_make_meeting(self, cr, uid, ids, context=None):
324         """
325         This opens Meeting's calendar view to schedule meeting on current Phonecall
326         @return : Dictionary value for created Meeting view
327         """
328         value = {}
329         for phonecall in self.browse(cr, uid, ids, context=context):
330             data_obj = self.pool.get('ir.model.data')
331
332             # Get meeting views
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')
338             if id1:
339                 id1 = data_obj.browse(cr, uid, id1, context=context).res_id
340             if id2:
341                 id2 = data_obj.browse(cr, uid, id2, context=context).res_id
342             if id3:
343                 id3 = data_obj.browse(cr, uid, id3, context=context).res_id
344
345             context = {
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
350                     }
351
352             value = {
353                 'name': _('Meetings'),
354                 'domain' : "[('user_id','=',%s)]" % (uid),
355                 'context': context,
356                 'view_type': 'form',
357                 'view_mode': 'calendar,form,tree',
358                 'res_model': 'crm.meeting',
359                 'view_id': False,
360                 'views': [(id1, 'calendar'), (id2, 'form'), (id3, 'tree')],
361                 'type': 'ir.actions.act_window',
362                 'search_view_id': res['res_id'],
363                 'nodestroy': True
364                 }
365
366         return value
367
368 crm_phonecall()
369
370
371 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: