From 0386c9f843216cbf54285da33e954a3d285d0cf3 Mon Sep 17 00:00:00 2001 From: Invitu Date: Thu, 9 May 2013 22:22:37 -1000 Subject: [PATCH] [IMP] Add Dial button in Lead and Opportunity views [IMP] Add CDR account management for Originating Call --- asterisk_click2dial/asterisk_click2dial.py | 7 +- .../i18n/asterisk_click2dial.pot | 10 ++ asterisk_click2dial/i18n/fr.po | 10 ++ asterisk_click2dial/res_users_view.xml | 1 + asterisk_click2dial_crm/__openerp__.py | 2 + .../asterisk_click2dial_crm.py | 109 ++++++++++++++++ asterisk_click2dial_crm/crm_lead_view.xml | 58 +++++++++ .../i18n/asterisk_click2dial_crm.pot | 108 ++++++++++++---- asterisk_click2dial_crm/i18n/fr.po | 122 +++++++++++++----- 9 files changed, 368 insertions(+), 59 deletions(-) create mode 100644 asterisk_click2dial_crm/crm_lead_view.xml diff --git a/asterisk_click2dial/asterisk_click2dial.py b/asterisk_click2dial/asterisk_click2dial.py index 31696ca..aae4261 100644 --- a/asterisk_click2dial/asterisk_click2dial.py +++ b/asterisk_click2dial/asterisk_click2dial.py @@ -273,7 +273,8 @@ class asterisk_server(osv.osv): priority = str(ast_server.extension_priority), timeout = str(ast_server.wait_time*1000), caller_id = user.callerid, - variable = variable) + account = user.cdraccount, + variable = variable) except Exception, e: _logger.error("Error in the Originate request to Asterisk server %s" % ast_server.ip_address) _logger.error("Here is the detail of the error : '%s'" % unicode(e)) @@ -335,7 +336,9 @@ class res_users(osv.osv): help="Caller ID used for the calls initiated by this user."), # You'd probably think : Asterisk should reuse the callerID of sip.conf ! # But it cannot, cf http://lists.digium.com/pipermail/asterisk-users/2012-January/269787.html - 'asterisk_chan_type': fields.selection([ + 'cdraccount': fields.char('CDR Account', size=50, + help="CDR Account used for billing this user."), + 'asterisk_chan_type': fields.selection([ ('SIP', 'SIP'), ('IAX2', 'IAX2'), ('DAHDI', 'DAHDI'), diff --git a/asterisk_click2dial/i18n/asterisk_click2dial.pot b/asterisk_click2dial/i18n/asterisk_click2dial.pot index bbec3fb..e10a3a2 100644 --- a/asterisk_click2dial/i18n/asterisk_click2dial.pot +++ b/asterisk_click2dial/i18n/asterisk_click2dial.pot @@ -41,6 +41,11 @@ msgstr "Current phone" msgid "Caller ID" msgstr "Identification de l'appelant" +#. module: asterisk_click2dial +#: field:res.users,cdraccount:0 +msgid "CDR Account" +msgstr "" + #. module: asterisk_click2dial #: field:asterisk.server,wait_time:0 msgid "Wait time (sec)" @@ -254,6 +259,11 @@ msgstr "Erreur :" msgid "User's internal phone number." msgstr "Numéro de téléphone interne de l'utilisateur." +#. module: asterisk_click2dial +#: help:res.users,cdraccount:0 +msgid "CDR Account used for billing this user." +msgstr "" + #. module: asterisk_click2dial #: model:ir.actions.act_window,name:asterisk_click2dial.action_open_calling_partner #: model:ir.ui.menu,name:asterisk_click2dial.menu_open_calling_partner_sales diff --git a/asterisk_click2dial/i18n/fr.po b/asterisk_click2dial/i18n/fr.po index c50bfd2..0eecd72 100644 --- a/asterisk_click2dial/i18n/fr.po +++ b/asterisk_click2dial/i18n/fr.po @@ -41,6 +41,11 @@ msgstr "Tél. actuel" msgid "Caller ID" msgstr "Identification de l'appelant" +#. module: asterisk_click2dial +#: field:res.users,cdraccount:0 +msgid "CDR Account" +msgstr "Compte CDR" + #. module: asterisk_click2dial #: field:asterisk.server,wait_time:0 msgid "Wait time (sec)" @@ -103,6 +108,11 @@ msgstr "Mettre à jour un contact existant" msgid "Internal number" msgstr "Numéro interne" +#. module: asterisk_click2dial +#: help:res.users,cdraccount:0 +msgid "CDR Account used for billing this user." +msgstr "Compte CDR utilisé pour facturer cet utilisateur." + #. module: asterisk_click2dial #: field:res.users,asterisk_chan_type:0 msgid "Asterisk channel type" diff --git a/asterisk_click2dial/res_users_view.xml b/asterisk_click2dial/res_users_view.xml index 774e962..d6c6a0f 100644 --- a/asterisk_click2dial/res_users_view.xml +++ b/asterisk_click2dial/res_users_view.xml @@ -22,6 +22,7 @@ + diff --git a/asterisk_click2dial_crm/__openerp__.py b/asterisk_click2dial_crm/__openerp__.py index c0455b7..ec890db 100644 --- a/asterisk_click2dial_crm/__openerp__.py +++ b/asterisk_click2dial_crm/__openerp__.py @@ -4,6 +4,7 @@ # Asterisk click2dial CRM module for OpenERP # Copyright (c) 2011 Zikzakmedia S.L. (http://zikzakmedia.com) All Rights Reserved. # Copyright (c) 2012-2013 Akretion (http://www.akretion.com) +# Copyright (c) 2013 Invitu (http://www.invitu.com) # @author: Jesús Martín # @author: Alexis de Lattre # @@ -59,6 +60,7 @@ 'wizard/open_calling_partner_view.xml', 'wizard/create_crm_phonecall_view.xml', 'res_users_view.xml', + 'crm_lead_view.xml', ], "installable": True, } diff --git a/asterisk_click2dial_crm/asterisk_click2dial_crm.py b/asterisk_click2dial_crm/asterisk_click2dial_crm.py index dbe9237..4280073 100644 --- a/asterisk_click2dial_crm/asterisk_click2dial_crm.py +++ b/asterisk_click2dial_crm/asterisk_click2dial_crm.py @@ -23,8 +23,19 @@ ############################################################################## from openerp.osv import osv, fields +# Lib required to print logs +import logging # Lib to translate error messages from openerp.tools.translate import _ +# Lib for phone number reformating -> pip install phonenumbers +import phonenumbers +# Lib py-asterisk from http://code.google.com/p/py-asterisk/ +# We need a version which has this commit : http://code.google.com/p/py-asterisk/source/detail?r=8d0e1c941cce727c702582f3c9fcd49beb4eeaa4 +# so a version after Nov 20th, 2012 +from Asterisk import Manager + +_logger = logging.getLogger(__name__) + class res_partner(osv.osv): _inherit = "res.partner" @@ -71,3 +82,101 @@ class res_users(osv.osv): 'context_propose_creation_crm_call': True, } +class crm_lead(osv.osv): + _inherit = "crm.lead" + + + def _format_phonenumber_to_e164(self, cr, uid, ids, name, arg, context=None): + result = {} + for lead in self.read(cr, uid, ids, ['phone', 'mobile', 'fax'], context=context): + result[lead['id']] = {} + for fromfield, tofield in [('phone', 'phone_e164'), ('mobile', 'mobile_e164'), ('fax', 'fax_e164')]: + if not lead.get(fromfield): + res = False + else: + try: + res = phonenumbers.format_number(phonenumbers.parse(lead.get(fromfield), None), phonenumbers.PhoneNumberFormat.E164) + except Exception, e: + _logger.error("Cannot reformat the phone number '%s' to E.164 format. Error message: %s" % (lead.get(fromfield), e)) + _logger.error("You should fix this number and run the wizard 'Reformat all phone numbers' from the menu Settings > Configuration > Asterisk") + # If I raise an exception here, it won't be possible to install + # the module on a DB with bad phone numbers + #raise osv.except_osv(_('Error :'), _("Cannot reformat the phone number '%s' to E.164 format. Error message: %s" % (lead.get(fromfield), e))) + res = False + result[lead['id']][tofield] = res + #print "RESULT _format_phonenumber_to_e164", result + return result + + + _columns = { + 'phone_e164': fields.function(_format_phonenumber_to_e164, type='char', size=64, string='Phone in E.164 format', readonly=True, multi="e164", store={ + 'crm.lead': (lambda self, cr, uid, ids, c={}: ids, ['phone'], 10), + }), + 'mobile_e164': fields.function(_format_phonenumber_to_e164, type='char', size=64, string='Mobile in E.164 format', readonly=True, multi="e164", store={ + 'crm.lead': (lambda self, cr, uid, ids, c={}: ids, ['mobile'], 10), + }), + 'fax_e164': fields.function(_format_phonenumber_to_e164, type='char', size=64, string='Fax in E.164 format', readonly=True, multi="e164", store={ + 'crm.lead': (lambda self, cr, uid, ids, c={}: ids, ['fax'], 10), + }), + } + + def _reformat_phonenumbers(self, cr, uid, vals, context=None): + """Reformat phone numbers in international format i.e. +33141981242""" + phonefields = ['phone', 'fax', 'mobile'] + if any([vals.get(field) for field in phonefields]): + user = self.pool['res.users'].browse(cr, uid, uid, context=context) + # country_id on res.company is a fields.function that looks at + # company_id.partner_id.addres(default).country_id + if user.company_id.country_id: + user_countrycode = user.company_id.country_id.code + else: + # We need to raise an exception here because, if we pass None as second arg of phonenumbers.parse(), it will raise an exception when you try to enter a phone number in national format... so it's better to raise the exception here + raise osv.except_osv(_('Error :'), _("You should set a country on the company '%s'" % user.company_id.name)) + #print "user_countrycode=", user_countrycode + for field in phonefields: + if vals.get(field): + try: + res_parse = phonenumbers.parse(vals.get(field), user_countrycode) + except Exception, e: + raise osv.except_osv(_('Error :'), _("Cannot reformat the phone number '%s' to international format. Error message: %s" % (vals.get(field), e))) + #print "res_parse=", res_parse + vals[field] = phonenumbers.format_number(res_parse, phonenumbers.PhoneNumberFormat.INTERNATIONAL) + return vals + + + def create(self, cr, uid, vals, context=None): + vals_reformated = self._reformat_phonenumbers(cr, uid, vals, context=context) + return super(crm_lead, self).create(cr, uid, vals_reformated, context=context) + + + def write(self, cr, uid, ids, vals, context=None): + vals_reformated = self._reformat_phonenumbers(cr, uid, vals, context=context) + return super(crm_lead, self).write(cr, uid, ids, vals_reformated, context=context) + + + def dial(self, cr, uid, ids, phone_field=['phone', 'phone_e164'], context=None): + '''Read the number to dial and call _connect_to_asterisk the right way''' + erp_number_read = self.read(cr, uid, ids[0], phone_field, context=context) + erp_number_e164 = erp_number_read[phone_field[1]] + erp_number_display = erp_number_read[phone_field[0]] + # Check if the number to dial is not empty + if not erp_number_display: + raise osv.except_osv(_('Error :'), _('There is no phone number !')) + elif erp_number_display and not erp_number_e164: + raise osv.except_osv(_('Error :'), _("The phone number isn't stored in the standard E.164 format. Try to run the wizard 'Reformat all phone numbers' from the menu Settings > Configuration > Asterisk.")) + return self.pool['asterisk.server']._dial_with_asterisk(cr, uid, erp_number_e164, context=context) + + + def action_dial_phone(self, cr, uid, ids, context=None): + '''Function called by the button 'Dial' next to the 'phone' field + in the lead view''' + return self.dial(cr, uid, ids, phone_field=['phone', 'phone_e164'], context=context) + + + def action_dial_mobile(self, cr, uid, ids, context=None): + '''Function called by the button 'Dial' next to the 'mobile' field + in the lead view''' + return self.dial(cr, uid, ids, phone_field=['mobile', 'mobile_e164'], context=context) + + + diff --git a/asterisk_click2dial_crm/crm_lead_view.xml b/asterisk_click2dial_crm/crm_lead_view.xml new file mode 100644 index 0000000..e559572 --- /dev/null +++ b/asterisk_click2dial_crm/crm_lead_view.xml @@ -0,0 +1,58 @@ + + + + + + + + asterisk.crm_lead.simplified.form.dial + crm.lead + 15 + + + + + +