0d7004e005b85478012d116beac4e486b8c26fed
[odoo/odoo.git] / addons / crm / crm_phonecall.py
1 # -*- coding: utf-8 -*-
2 ##############################################################################
3 #
4 #    OpenERP, Open Source Management Solution
5 #    Copyright (C) 2004-today OpenERP SA (<http://www.openerp.com>)
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 openerp.addons.base_status.base_state import base_state
23 import crm
24 from datetime import datetime
25 from openerp.osv import fields, osv
26 from openerp.tools import DEFAULT_SERVER_DATETIME_FORMAT
27 from openerp.tools.translate import _
28
29 class crm_phonecall(base_state, osv.osv):
30     """ Model for CRM phonecalls """
31     _name = "crm.phonecall"
32     _description = "Phonecall"
33     _order = "id desc"
34     _inherit = ['mail.thread']
35     _columns = {
36         # base_state required fields
37         'date_action_last': fields.datetime('Last Action', readonly=1),
38         'date_action_next': fields.datetime('Next Action', readonly=1),
39         'create_date': fields.datetime('Creation Date' , readonly=True),
40         'section_id': fields.many2one('crm.case.section', 'Sales Team', \
41                         select=True, help='Sales team to which Case belongs to.'),
42         'user_id': fields.many2one('res.users', 'Responsible'),
43         'partner_id': fields.many2one('res.partner', 'Contact'),
44         'company_id': fields.many2one('res.company', 'Company'),
45         'description': fields.text('Description'),
46         'state': fields.selection([ ('draft', 'Draft'),
47                                     ('open', 'Confirmed'),
48                                     ('pending', 'Not Held'),
49                                     ('cancel', 'Cancelled'),
50                                     ('done', 'Held'),],
51                         string='Status', size=16, readonly=True, track_visibility='onchange',
52                         help='The status is set to \'Todo\', when a case is created.\
53                                 If the case is in progress the status is set to \'Open\'.\
54                                 When the call is over, the status is set to \'Held\'.\
55                                 If the call needs to be done then the status is set to \'Not Held\'.'),
56         'email_from': fields.char('Email', size=128, help="These people will receive email."),
57         'date_open': fields.datetime('Opened', readonly=True),
58         # phonecall fields
59         'name': fields.char('Call Summary', size=64, required=True),
60         'active': fields.boolean('Active', required=False),
61         'duration': fields.float('Duration', help="Duration in Minutes"),
62         'categ_id': fields.many2one('crm.case.categ', 'Category', \
63                         domain="['|',('section_id','=',section_id),('section_id','=',False),\
64                         ('object_id.model', '=', 'crm.phonecall')]"),
65         'partner_phone': fields.char('Phone', size=32),
66         'partner_mobile': fields.char('Mobile', size=32),
67         'priority': fields.selection(crm.AVAILABLE_PRIORITIES, 'Priority'),
68         'date_closed': fields.datetime('Closed', readonly=True),
69         'date': fields.datetime('Date'),
70         'opportunity_id': fields.many2one ('crm.lead', 'Lead/Opportunity'),
71     }
72
73     def _get_default_state(self, cr, uid, context=None):
74         if context and context.get('default_state', False):
75             return context.get('default_state')
76         return 'open'
77
78     _defaults = {
79         'date': fields.datetime.now,
80         'priority': crm.AVAILABLE_PRIORITIES[2][0],
81         'state':  _get_default_state,
82         'user_id': lambda self,cr,uid,ctx: uid,
83         'active': 1
84     }
85
86     def case_close(self, cr, uid, ids, context=None):
87         """ Overrides close for crm_case for setting duration """
88         res = True
89         for phone in self.browse(cr, uid, ids, context=context):
90             phone_id = phone.id
91             data = {}
92             if phone.duration <=0:
93                 duration = datetime.now() - datetime.strptime(phone.date, DEFAULT_SERVER_DATETIME_FORMAT)
94                 data['duration'] = duration.seconds/float(60)
95             res = super(crm_phonecall, self).case_close(cr, uid, [phone_id], context=context)
96             self.write(cr, uid, [phone_id], data, context=context)
97         return res
98
99     def case_reset(self, cr, uid, ids, context=None):
100         """Resets case as Todo
101         """
102         res = super(crm_phonecall, self).case_reset(cr, uid, ids, context)
103         self.write(cr, uid, ids, {'duration': 0.0, 'state':'open'}, context=context)
104         return res
105
106     def schedule_another_phonecall(self, cr, uid, ids, schedule_time, call_summary, \
107                     user_id=False, section_id=False, categ_id=False, action='schedule', context=None):
108         """
109         action :('schedule','Schedule a call'), ('log','Log a call')
110         """
111         model_data = self.pool.get('ir.model.data')
112         phonecall_dict = {}
113         if not categ_id:
114             res_id = model_data._get_id(cr, uid, 'crm', 'categ_phone2')
115             if res_id:
116                 categ_id = model_data.browse(cr, uid, res_id, context=context).res_id
117         for call in self.browse(cr, uid, ids, context=context):
118             if not section_id:
119                 section_id = call.section_id and call.section_id.id or False
120             if not user_id:
121                 user_id = call.user_id and call.user_id.id or False
122             if not schedule_time:
123                 schedule_time = call.date
124             vals = {
125                     'name' : call_summary,
126                     'user_id' : user_id or False,
127                     'categ_id' : categ_id or False,
128                     'description' : call.description or False,
129                     'date' : schedule_time,
130                     'section_id' : section_id or False,
131                     'partner_id': call.partner_id and call.partner_id.id or False,
132                     'partner_phone' : call.partner_phone,
133                     'partner_mobile' : call.partner_mobile,
134                     'priority': call.priority,
135             }
136             new_id = self.create(cr, uid, vals, context=context)
137             if action == 'log':
138                 self.case_close(cr, uid, [new_id])
139             phonecall_dict[call.id] = new_id
140         return phonecall_dict
141
142     def _call_create_partner(self, cr, uid, phonecall, context=None):
143         partner = self.pool.get('res.partner')
144         partner_id = partner.create(cr, uid, {
145                     'name': phonecall.name,
146                     'user_id': phonecall.user_id.id,
147                     'comment': phonecall.description,
148                     'address': []
149         })
150         return partner_id
151
152     def on_change_opportunity(self, cr, uid, ids, opportunity_id, context=None):
153         values = {}
154         if opportunity_id:
155             opportunity = self.pool.get('crm.lead').browse(cr, uid, opportunity_id, context=context)
156             values = {
157                 'section_id' : opportunity.section_id and opportunity.section_id.id or False,
158                 'partner_phone' : opportunity.phone,
159                 'partner_mobile' : opportunity.mobile,
160                 'partner_id' : opportunity.partner_id and opportunity.partner_id.id or False,
161             }
162         return {'value' : values}
163
164     def _call_set_partner(self, cr, uid, ids, partner_id, context=None):
165         write_res = self.write(cr, uid, ids, {'partner_id' : partner_id}, context=context)
166         self._call_set_partner_send_note(cr, uid, ids, context)
167         return write_res
168
169     def _call_create_partner_address(self, cr, uid, phonecall, partner_id, context=None):
170         address = self.pool.get('res.partner')
171         return address.create(cr, uid, {
172                     'parent_id': partner_id,
173                     'name': phonecall.name,
174                     'phone': phonecall.partner_phone,
175         })
176
177     def handle_partner_assignation(self, cr, uid, ids, action='create', partner_id=False, context=None):
178         """
179         Handle partner assignation during a lead conversion.
180         if action is 'create', create new partner with contact and assign lead to new partner_id.
181         otherwise assign lead to specified partner_id
182
183         :param list ids: phonecalls ids to process
184         :param string action: what has to be done regarding partners (create it, assign an existing one, or nothing)
185         :param int partner_id: partner to assign if any
186         :return dict: dictionary organized as followed: {lead_id: partner_assigned_id}
187         """
188         #TODO this is a duplication of the handle_partner_assignation method of crm_lead
189         partner_ids = {}
190         # If a partner_id is given, force this partner for all elements
191         force_partner_id = partner_id
192         for call in self.browse(cr, uid, ids, context=context):
193             # If the action is set to 'create' and no partner_id is set, create a new one
194             if action == 'create':
195                 partner_id = force_partner_id or 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
199         return partner_ids
200
201
202     def redirect_phonecall_view(self, cr, uid, phonecall_id, context=None):
203         model_data = self.pool.get('ir.model.data')
204         # Select the view
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')
208         value = {
209                 'name': _('Phone Call'),
210                 'view_type': 'form',
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,
217         }
218         return value
219
220     def convert_opportunity(self, cr, uid, ids, opportunity_summary=False, partner_id=False, planned_revenue=0.0, probability=0.0, context=None):
221         partner = self.pool.get('res.partner')
222         opportunity = self.pool.get('crm.lead')
223         opportunity_dict = {}
224         default_contact = False
225         for call in self.browse(cr, uid, ids, context=context):
226             if not partner_id:
227                 partner_id = call.partner_id and call.partner_id.id or False
228             if partner_id:
229                 address_id = partner.address_get(cr, uid, [partner_id])['default']
230                 if address_id:
231                     default_contact = partner.browse(cr, uid, address_id, context=context)
232             opportunity_id = opportunity.create(cr, uid, {
233                             'name': opportunity_summary or call.name,
234                             'planned_revenue': planned_revenue,
235                             'probability': probability,
236                             'partner_id': partner_id or False,
237                             'mobile': default_contact and default_contact.mobile,
238                             'section_id': call.section_id and call.section_id.id or False,
239                             'description': call.description or False,
240                             'priority': call.priority,
241                             'type': 'opportunity',
242                             'phone': call.partner_phone or False,
243                             'email_from': default_contact and default_contact.email,
244                         })
245             vals = {
246                     'partner_id': partner_id,
247                     'opportunity_id' : opportunity_id,
248             }
249             self.write(cr, uid, [call.id], vals)
250             self.case_close(cr, uid, [call.id])
251             opportunity.case_open(cr, uid, [opportunity_id])
252             opportunity_dict[call.id] = opportunity_id
253         return opportunity_dict
254
255     def action_make_meeting(self, cr, uid, ids, context=None):
256         """
257         Open meeting's calendar view to schedule a meeting on current phonecall.
258         :return dict: dictionary value for created meeting view
259         """
260         phonecall = self.browse(cr, uid, ids[0], context)
261         res = self.pool.get('ir.actions.act_window').for_xml_id(cr, uid, 'base_calendar', 'action_crm_meeting', context)
262         res['context'] = {
263             'default_phonecall_id': phonecall.id,
264             'default_partner_id': phonecall.partner_id and phonecall.partner_id.id or False,
265             'default_user_id': uid,
266             'default_email_from': phonecall.email_from,
267             'default_state': 'open',
268             'default_name': phonecall.name,
269         }
270         return res
271
272     def action_button_convert2opportunity(self, cr, uid, ids, context=None):
273         """
274         Convert a phonecall into an opp and then redirect to the opp view.
275
276         :param list ids: list of calls ids to convert (typically contains a single id)
277         :return dict: containing view information
278         """
279         if len(ids) != 1:
280             raise osv.except_osv(_('Warning!'),_('It\'s only possible to convert one phonecall at a time.'))
281
282         opportunity_dict = self.convert_opportunity(cr, uid, ids, context=context)
283         return self.pool.get('crm.lead').redirect_opportunity_view(cr, uid, opportunity_dict[ids[0]], context)
284
285     # ----------------------------------------
286     # OpenChatter
287     # ----------------------------------------
288
289     def _call_set_partner_send_note(self, cr, uid, ids, context=None):
290         return self.message_post(cr, uid, ids, body=_("Partner has been <b>created</b>."), context=context)
291
292 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: