44894fc881d580adf9d8f44df4d5975f749b5f99
[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 base_status.base_state import base_state
23 import crm
24 from datetime import datetime
25 from osv import fields, osv
26 import time
27 from tools import DEFAULT_SERVER_DATE_FORMAT, DEFAULT_SERVER_DATETIME_FORMAT, DATETIME_FORMATS_MAP
28 from tools.translate import _
29
30 class crm_phonecall(base_state, osv.osv):
31     """ Model for CRM phonecalls """
32     _name = "crm.phonecall"
33     _description = "Phonecall"
34     _order = "id desc"
35     _inherit = ['mail.thread']
36     _columns = {
37         # base_state required fields
38         'date_action_last': fields.datetime('Last Action', readonly=1),
39         'date_action_next': fields.datetime('Next Action', readonly=1),
40         'create_date': fields.datetime('Creation Date' , readonly=True),
41         'section_id': fields.many2one('crm.case.section', 'Sales Team', \
42                         select=True, help='Sales team to which Case belongs to.'),
43         'user_id': fields.many2one('res.users', 'Responsible'),
44         'partner_id': fields.many2one('res.partner', 'Contact'),
45         'company_id': fields.many2one('res.company', 'Company'),
46         'description': fields.text('Description'),
47         'state': fields.selection([ ('draft', 'Draft'),
48                                     ('open', 'Confirmed'),
49                                     ('pending', 'Not Held'),
50                                     ('cancel', 'Cancelled'),
51                                     ('done', 'Held'),],
52                         string='Status', size=16, readonly=True,
53                         help='The state is set to \'Todo\', when a case is created.\
54                                 If the case is in progress the state is set to \'Open\'.\
55                                 When the call is over, the state is set to \'Held\'.\
56                                 If the call needs to be done then the state is set to \'Not Held\'.'),
57         'email_from': fields.char('Email', size=128, help="These people will receive email."),
58         'date_open': fields.datetime('Opened', readonly=True),
59         # phonecall fields
60         'name': fields.char('Call Summary', size=64, required=True),
61         'active': fields.boolean('Active', required=False),
62         'duration': fields.float('Duration', help="Duration in Minutes"),
63         'categ_id': fields.many2one('crm.case.categ', 'Category', \
64                         domain="['|',('section_id','=',section_id),('section_id','=',False),\
65                         ('object_id.model', '=', 'crm.phonecall')]"),
66         'partner_phone': fields.char('Phone', size=32),
67         'partner_mobile': fields.char('Mobile', size=32),
68         'priority': fields.selection(crm.AVAILABLE_PRIORITIES, 'Priority'),
69         'date_closed': fields.datetime('Closed', readonly=True),
70         'date': fields.datetime('Date'),
71         'opportunity_id': fields.many2one ('crm.lead', 'Lead/Opportunity'),
72     }
73
74     def _get_default_state(self, cr, uid, context=None):
75         if context and context.get('default_state', False):
76             return context.get('default_state')
77         return 'open'
78
79     _defaults = {
80         'date': fields.datetime.now,
81         'priority': crm.AVAILABLE_PRIORITIES[2][0],
82         'state':  _get_default_state,
83         'user_id': lambda self,cr,uid,ctx: uid,
84         'active': 1
85     }
86
87     def create(self, cr, uid, vals, context=None):
88         obj_id = super(crm_phonecall, self).create(cr, uid, vals, context)
89         for phonecall in self.browse(cr, uid, [obj_id], context=context):
90             if not phonecall.opportunity_id:
91                 self.case_open_send_note(cr, uid, [obj_id], context=context)
92         return obj_id
93
94     def case_close(self, cr, uid, ids, context=None):
95         """ Overrides close for crm_case for setting duration """
96         res = True
97         for phone in self.browse(cr, uid, ids, context=context):
98             phone_id = phone.id
99             data = {}
100             if phone.duration <=0:
101                 duration = datetime.now() - datetime.strptime(phone.date, DEFAULT_SERVER_DATETIME_FORMAT)
102                 data['duration'] = duration.seconds/float(60)
103             res = super(crm_phonecall, self).case_close(cr, uid, [phone_id], context=context)
104             self.write(cr, uid, [phone_id], data, context=context)
105         return res
106
107     def case_reset(self, cr, uid, ids, context=None):
108         """Resets case as Todo
109         """
110         res = super(crm_phonecall, self).case_reset(cr, uid, ids, context)
111         self.write(cr, uid, ids, {'duration': 0.0, 'state':'open'}, context=context)
112         return res
113
114     def schedule_another_phonecall(self, cr, uid, ids, schedule_time, call_summary, \
115                     user_id=False, section_id=False, categ_id=False, action='schedule', context=None):
116         """
117         action :('schedule','Schedule a call'), ('log','Log a call')
118         """
119         model_data = self.pool.get('ir.model.data')
120         phonecall_dict = {}
121         if not categ_id:
122             res_id = model_data._get_id(cr, uid, 'crm', 'categ_phone2')
123             if res_id:
124                 categ_id = model_data.browse(cr, uid, res_id, context=context).res_id
125         for call in self.browse(cr, uid, ids, context=context):
126             if not section_id:
127                 section_id = call.section_id and call.section_id.id or False
128             if not user_id:
129                 user_id = call.user_id and call.user_id.id or False
130             vals = {
131                     'name' : call_summary,
132                     'user_id' : user_id or False,
133                     'categ_id' : categ_id or False,
134                     'description' : call.description or False,
135                     'date' : schedule_time,
136                     'section_id' : section_id or False,
137                     'partner_id': call.partner_id and call.partner_id.id or False,
138                     'partner_phone' : call.partner_phone,
139                     'partner_mobile' : call.partner_mobile,
140                     'priority': call.priority,
141             }
142             new_id = self.create(cr, uid, vals, context=context)
143             if action == 'log':
144                 self.case_close(cr, uid, [new_id])
145             phonecall_dict[call.id] = new_id
146         return phonecall_dict
147
148     def _call_create_partner(self, cr, uid, phonecall, context=None):
149         partner = self.pool.get('res.partner')
150         partner_id = partner.create(cr, uid, {
151                     'name': phonecall.name,
152                     'user_id': phonecall.user_id.id,
153                     'comment': phonecall.description,
154                     'address': []
155         })
156         return partner_id
157
158     def _call_set_partner(self, cr, uid, ids, partner_id, context=None):
159         write_res = self.write(cr, uid, ids, {'partner_id' : partner_id}, context=context)
160         self._call_set_partner_send_note(cr, uid, ids, context)
161         return write_res
162
163     def _call_create_partner_address(self, cr, uid, phonecall, partner_id, context=None):
164         address = self.pool.get('res.partner')
165         return address.create(cr, uid, {
166                     'parent_id': partner_id,
167                     'name': phonecall.name,
168                     'phone': phonecall.partner_phone,
169         })
170
171     def convert_partner(self, cr, uid, ids, action='create', partner_id=False, context=None):
172         """
173         This function convert partner based on action.
174         if action is 'create', create new partner with contact and assign lead to new partner_id.
175         otherwise assign lead to specified partner_id
176         """
177         if context is None:
178             context = {}
179         partner_ids = {}
180         force_partner_id = partner_id
181         for call in self.browse(cr, uid, ids, context=context):
182             if action == 'create':
183                 partner_id = force_partner_id or self._call_create_partner(cr, uid, call, context=context)
184                 self._call_create_partner_address(cr, uid, call, partner_id, context=context)
185             self._call_set_partner(cr, uid, [call.id], partner_id, context=context)
186             partner_ids[call.id] = partner_id
187         return partner_ids
188
189
190     def redirect_phonecall_view(self, cr, uid, phonecall_id, context=None):
191         model_data = self.pool.get('ir.model.data')
192         # Select the view
193         tree_view = model_data.get_object_reference(cr, uid, 'crm', 'crm_case_phone_tree_view')
194         form_view = model_data.get_object_reference(cr, uid, 'crm', 'crm_case_phone_form_view')
195         search_view = model_data.get_object_reference(cr, uid, 'crm', 'view_crm_case_phonecalls_filter')
196         value = {
197                 'name': _('Phone Call'),
198                 'view_type': 'form',
199                 'view_mode': 'tree,form',
200                 'res_model': 'crm.phonecall',
201                 'res_id' : int(phonecall_id),
202                 'views': [(form_view and form_view[1] or False, 'form'), (tree_view and tree_view[1] or False, 'tree'), (False, 'calendar')],
203                 'type': 'ir.actions.act_window',
204                 'search_view_id': search_view and search_view[1] or False,
205         }
206         return value
207
208
209     def convert_opportunity(self, cr, uid, ids, opportunity_summary=False, partner_id=False, planned_revenue=0.0, probability=0.0, context=None):
210         partner = self.pool.get('res.partner')
211         opportunity = self.pool.get('crm.lead')
212         opportunity_dict = {}
213         default_contact = False
214         for call in self.browse(cr, uid, ids, context=context):
215             if not partner_id:
216                 partner_id = call.partner_id and call.partner_id.id or False
217             if partner_id:
218                 address_id = partner.address_get(cr, uid, [partner_id])['default']
219                 if address_id:
220                     default_contact = partner.browse(cr, uid, address_id, context=context)
221             opportunity_id = opportunity.create(cr, uid, {
222                             'name': opportunity_summary or call.name,
223                             'planned_revenue': planned_revenue,
224                             'probability': probability,
225                             'partner_id': partner_id or False,
226                             'mobile': default_contact and default_contact.mobile,
227                             'section_id': call.section_id and call.section_id.id or False,
228                             'description': call.description or False,
229                             'priority': call.priority,
230                             'type': 'opportunity',
231                             'phone': call.partner_phone or False,
232                             'email_from': default_contact and default_contact.email,
233                         })
234             vals = {
235                     'partner_id': partner_id,
236                     'opportunity_id' : opportunity_id,
237             }
238             self.write(cr, uid, [call.id], vals)
239             self.case_close(cr, uid, [call.id])
240             opportunity.case_open(cr, uid, [opportunity_id])
241             opportunity_dict[call.id] = opportunity_id
242         return opportunity_dict
243
244     def action_make_meeting(self, cr, uid, ids, context=None):
245         """ This opens Meeting's calendar view to schedule meeting on current Phonecall
246             @return : Dictionary value for created Meeting view
247         """
248         phonecall = self.browse(cr, uid, ids[0], context)
249         res = self.pool.get('ir.actions.act_window').for_xml_id(cr, uid, 'base_calendar', 'action_crm_meeting', context)
250         res['context'] = {
251             'default_phonecall_id': phonecall.id,
252             'default_partner_id': phonecall.partner_id and phonecall.partner_id.id or False,
253             'default_user_id': uid,
254             'default_email_from': phonecall.email_from,
255             'default_state': 'open',
256             'default_name': phonecall.name,
257         }
258         return res
259     
260     # ----------------------------------------
261     # OpenChatter
262     # ----------------------------------------
263
264     def case_get_note_msg_prefix(self, cr, uid, id, context=None):
265         return 'Phonecall'
266     
267     def case_reset_send_note(self, cr, uid, ids, context=None):
268         message = _('Phonecall has been <b>reset and set as open</b>.')
269         return self.message_post(cr, uid, ids, body=message, context=context)
270
271     def case_open_send_note(self, cr, uid, ids, context=None):
272         lead_obj = self.pool.get('crm.lead')
273         for phonecall in self.browse(cr, uid, ids, context=context):
274             if phonecall.opportunity_id:
275                 lead = phonecall.opportunity_id
276                 # convert datetime field to a datetime, using server format, then
277                 # convert it to the user TZ and re-render it with %Z to add the timezone
278                 phonecall_datetime = fields.DT.datetime.strptime(phonecall.date, DEFAULT_SERVER_DATETIME_FORMAT)
279                 phonecall_date_str = fields.datetime.context_timestamp(cr, uid, phonecall_datetime, context=context).strftime(DATETIME_FORMATS_MAP['%+'] + " (%Z)")
280                 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)
281             else:
282                 message = _("Phonecall has been <b>created and opened</b>.")
283             phonecall.message_post(body=message)
284         return True
285
286     def _call_set_partner_send_note(self, cr, uid, ids, context=None):
287         return self.message_post(cr, uid, ids, body=_("Partner has been <b>created</b>."), context=context)
288
289
290 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: