From 9e52016e20456b2716efdd1a54abc98744445d9e Mon Sep 17 00:00:00 2001 From: Alexis de Lattre Date: Fri, 12 Apr 2013 21:09:24 +0200 Subject: [PATCH] The number of digits to match from the end of the phone number is now configurable. This code is now fully located in the asterisk_click2dial module (removed from the "get_cid_name.py" script). WARNING : if you upgrade your asterisk_click2dial module to this version, you should also update the script "get_cid_name.py" on your Asterisk server to this version. The imports now use the new openerp paths. Convert self.pool.get('obj') to self.pool['obj'] so that it crashes exactly where it should. --- asterisk_click2dial/asterisk_click2dial.py | 54 ++++++++++++------- asterisk_click2dial/asterisk_server_view.xml | 1 + asterisk_click2dial/scripts/get_cid_name.py | 11 +--- .../wizard/open_calling_partner.py | 32 +++++------ .../wizard/reformat_all_phonenumbers.py | 6 +-- .../asterisk_click2dial_crm.py | 6 +-- .../wizard/create_crm_phonecall.py | 14 ++--- .../wizard/open_calling_partner.py | 2 +- 8 files changed, 62 insertions(+), 64 deletions(-) diff --git a/asterisk_click2dial/asterisk_click2dial.py b/asterisk_click2dial/asterisk_click2dial.py index 9721c2b..11578b5 100644 --- a/asterisk_click2dial/asterisk_click2dial.py +++ b/asterisk_click2dial/asterisk_click2dial.py @@ -19,11 +19,11 @@ # ############################################################################## -from osv import osv, fields +from openerp.osv import osv, fields # Lib required to print logs import logging # Lib to translate error messages -from tools.translate import _ +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/ @@ -52,6 +52,7 @@ class asterisk_server(osv.osv): 'wait_time': fields.integer('Wait time (sec)', required=True, help="Amount of time (in seconds) Asterisk will try to reach the user's phone before hanging up."), 'extension_priority': fields.integer('Extension priority', required=True, help="Priority of the extension in the Asterisk dialplan. Refer to /etc/asterisk/extensions.conf on your Asterisk server."), 'alert_info': fields.char('Alert-Info SIP header', size=255, help="Set Alert-Info header in SIP request to user's IP Phone for the click2dial feature. If empty, the Alert-Info header will not be added. You can use it to have a special ring tone for click2dial (a silent one !) or to activate auto-answer for example."), + 'number_of_digits_to_match_from_end': fields.integer('Number of digits to match from end', help='In several situations, the Asterisk-OpenERP connector will have to find a Partner in OpenERP from a phone number presented by the calling party. As the phone numbers presented by your phone operator may not always be displayed in a standard format, the best method to find the related Partner in OpenERP is to try to match the end of the phone numbers of the Partners in OpenERP with the N last digits of the phone number presented by the calling party. N is the value you should enter in this field.'), 'company_id': fields.many2one('res.company', 'Company', help="Company who uses the Asterisk server."), } @@ -63,6 +64,7 @@ class asterisk_server(osv.osv): 'international_prefix': '00', 'extension_priority': 1, 'wait_time': 15, + 'number_of_digits_to_match_from_end': 9, } def _check_validity(self, cr, uid, ids): @@ -84,7 +86,9 @@ class asterisk_server(osv.osv): if server.extension_priority < 1: raise osv.except_osv(_('Error :'), _("The 'extension priority' must be a positive value for the Asterisk server '%s'" % server.name)) if server.port > 65535 or server.port < 1: - raise osv.except_osv(_('Error :'), _("You should set a TCP port between 1 and 65535 for the Asterik server '%s'" % server.name)) + raise osv.except_osv(_('Error :'), _("You should set a TCP port between 1 and 65535 for the Asterisk server '%s'" % server.name)) + if server.number_of_digits_to_match_from_end > 20 or server.number_of_digits_to_match_from_end < 1: + raise osv.except_osv(_('Error :'), _("You should set a 'Number of digits to match from end' between 1 and 20 for the Asterisk server '%s'" % server.name)) for check_string in [dialplan_context, alert_info, login, password]: if check_string[1]: try: @@ -95,7 +99,7 @@ class asterisk_server(osv.osv): _constraints = [ - (_check_validity, "Error message in raise", ['out_prefix', 'country_prefix', 'national_prefix', 'international_prefix', 'wait_time', 'extension_priority', 'port', 'context', 'alert_info', 'login', 'password']), + (_check_validity, "Error message in raise", ['out_prefix', 'country_prefix', 'national_prefix', 'international_prefix', 'wait_time', 'extension_priority', 'port', 'context', 'alert_info', 'login', 'password', 'number_of_digits_to_match_from_end']), ] @@ -175,9 +179,10 @@ class asterisk_server(osv.osv): return number - def _get_asterisk_server_from_user(self, cr, uid, user, context=None): + def _get_asterisk_server_from_user(self, cr, uid, context=None): '''Returns an asterisk.server browse object''' # We check if the user has an Asterisk server configured + user = self.pool['res.users'].browse(cr, uid, uid, context=context) if user.asterisk_server_id.id: ast_server = user.asterisk_server_id else: @@ -196,12 +201,12 @@ class asterisk_server(osv.osv): Returns an instance of the Asterisk Manager ''' - user = self.pool.get('res.users').browse(cr, uid, uid, context=context) + user = self.pool['res.users'].browse(cr, uid, uid, context=context) # Note : if I write 'Error' without ' :', it won't get translated... # I don't understand why ! - ast_server = self._get_asterisk_server_from_user(cr, uid, user, context=context) + ast_server = self._get_asterisk_server_from_user(cr, uid, context=context) # We check if the current user has a chan type if not user.asterisk_chan_type: raise osv.except_osv(_('Error :'), _('No channel type configured for the current user.')) @@ -219,8 +224,8 @@ class asterisk_server(osv.osv): ast_manager = Manager.Manager((ast_server.ip_address, ast_server.port), ast_server.login, ast_server.password) 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)) - raise osv.except_osv(_('Error :'), _("Problem in the request from OpenERP to Asterisk. Here is the detail of the error: '%s'" % unicode(e))) + _logger.error("Here is the detail of the error : %s" % e.strerror) + raise osv.except_osv(_('Error :'), _("Problem in the request from OpenERP to Asterisk. Here is the detail of the error: %s." % e.strerror)) return False return (user, ast_server, ast_manager) @@ -396,7 +401,7 @@ class res_partner(osv.osv): """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.get('res.users').browse(cr, uid, uid, context=context) + 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: @@ -436,7 +441,7 @@ class res_partner(osv.osv): 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.get('asterisk.server')._dial_with_asterisk(cr, uid, erp_number_e164, context=context) + 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): @@ -466,28 +471,37 @@ class res_partner(osv.osv): return False - def get_partner_from_phone_number(self, cr, uid, number, context=None): + def get_partner_from_phone_number(self, cr, uid, presented_number, context=None): # We check that "number" is really a number - _logger.debug(u"Call get_name_from_phone_number with number = %s" % number) - if not isinstance(number, (str, unicode)): - _logger.warning(u"Number should be a 'str' or 'unicode' but it is a '%s'" % type(number)) + _logger.debug(u"Call get_name_from_phone_number with number = %s" % presented_number) + if not isinstance(presented_number, (str, unicode)): + _logger.warning(u"Number '%s' should be a 'str' or 'unicode' but it is a '%s'" % (presented_number, type(presented_number))) return False - _logger.warning(u"Number should only contain digits.") - if not number.isdigit(): + if not presented_number.isdigit(): + _logger.warning(u"Number '%s' should only contain digits." % presented_number) return False + ast_server = self.pool['asterisk.server']._get_asterisk_server_from_user(cr, uid, context=context) + nr_digits_to_match_from_end = ast_server.number_of_digits_to_match_from_end + if len(presented_number) >= nr_digits_to_match_from_end: + end_number_to_match = presented_number[-nr_digits_to_match_from_end:len(presented_number)] + else: + end_number_to_match = presented_number + + _logger.debug("Will search phone and mobile numbers in res.partner ending with '%s'" % end_number_to_match) + # We try to match a phone or mobile number with the same end - pg_seach_number = str('%' + number) + pg_seach_number = str('%' + end_number_to_match) res_ids = self.search(cr, uid, ['|', ('phone_e164', 'ilike', pg_seach_number), ('mobile_e164', 'ilike', pg_seach_number)], context=context) # TODO : use is_number_match() of the phonenumber lib ? if len(res_ids) > 1: - _logger.warning(u"There are several partners (IDS = %s) with the same phone number %s" % (str(res_ids), number)) + _logger.warning(u"There are several partners (IDS = %s) with a phone number ending with '%s'" % (str(res_ids), end_number_to_match)) if res_ids: entry = self.read(cr, uid, res_ids[0], ['name', 'parent_id'], context=context) _logger.debug(u"Answer get_partner_from_phone_number with name = %s" % entry['name']) return (entry['id'], entry['parent_id'] and entry['parent_id'][0] or False, entry['name']) else: - _logger.debug(u"No match for phone number %s" % number) + _logger.debug(u"No match for end of phone number '%s'" % end_number_to_match) return False diff --git a/asterisk_click2dial/asterisk_server_view.xml b/asterisk_click2dial/asterisk_server_view.xml index e120123..f6c1cbd 100644 --- a/asterisk_click2dial/asterisk_server_view.xml +++ b/asterisk_click2dial/asterisk_server_view.xml @@ -62,6 +62,7 @@ + diff --git a/asterisk_click2dial/scripts/get_cid_name.py b/asterisk_click2dial/scripts/get_cid_name.py index ebfb252..36c07ac 100755 --- a/asterisk_click2dial/scripts/get_cid_name.py +++ b/asterisk_click2dial/scripts/get_cid_name.py @@ -119,13 +119,6 @@ def geolocate_phone_number(number, my_country_code, lang): res = country return res -def reformat_phone_number_before_query_openerp(number): - '''We match only on the end of the phone number''' - if len(number) >= 9: - return number[-9:len(number)] # Take 9 last numbers - else: - return number - def convert_to_ascii(my_unicode): '''Convert to ascii, with clever management of accents (é -> e, è -> e)''' import unicodedata @@ -189,8 +182,6 @@ def main(options, arguments): res = False if options.server: # Yes, this script can be used without "-s openerp_server" ! - query_number = reformat_phone_number_before_query_openerp(input_cid_number) - stderr_write("phone number sent to OpenERP = %s\n" % query_number) if options.ssl: stdout_write('VERBOSE "Starting XML-RPC secure request on OpenERP %s:%s"\n' % (options.server, str(options.port))) protocol = 'https' @@ -201,7 +192,7 @@ def main(options, arguments): sock = xmlrpclib.ServerProxy('%s://%s:%s/xmlrpc/object' % (protocol, options.server, str(options.port))) try: - res = sock.execute(options.database, options.user, options.password, 'res.partner', 'get_name_from_phone_number', query_number) + res = sock.execute(options.database, options.user, options.password, 'res.partner', 'get_name_from_phone_number', input_cid_number) stdout_write('VERBOSE "End of XML-RPC request on OpenERP"\n') if not res: stdout_write('VERBOSE "Phone number not found in OpenERP"\n') diff --git a/asterisk_click2dial/wizard/open_calling_partner.py b/asterisk_click2dial/wizard/open_calling_partner.py index 3810a67..c91376a 100644 --- a/asterisk_click2dial/wizard/open_calling_partner.py +++ b/asterisk_click2dial/wizard/open_calling_partner.py @@ -19,10 +19,10 @@ # ############################################################################## -from osv import osv, fields +from openerp.osv import osv, fields import logging # Lib to translate error messages -from tools.translate import _ +from openerp.tools.translate import _ _logger = logging.getLogger(__name__) @@ -48,18 +48,12 @@ class wizard_open_calling_partner(osv.osv_memory): '''Thanks to the default_get method, we are able to query Asterisk and get the corresponding partner when we launch the wizard''' res = {} - calling_number = self.pool.get('asterisk.server')._get_calling_number(cr, uid, context=context) + calling_number = self.pool['asterisk.server']._get_calling_number(cr, uid, context=context) #To test the code without Asterisk server #calling_number = "0141981242" if calling_number: res['calling_number'] = calling_number - # We match only on the end of the phone number - # TODO : make this parameter configurable - if len(calling_number) >= 9: - number_to_search = calling_number[-9:len(calling_number)] - else: - number_to_search = calling_number - partner = self.pool.get('res.partner').get_partner_from_phone_number(cr, uid, number_to_search, context=context) + partner = self.pool['res.partner'].get_partner_from_phone_number(cr, uid, calling_number, context=context) if partner: res['partner_id'] = partner[0] res['parent_partner_id'] = partner[1] @@ -80,7 +74,7 @@ class wizard_open_calling_partner(osv.osv_memory): # This module only depends on "base" # and I don't want to add a dependancy on "sale" or "account" # So I just check here that the model exists, to avoid a crash - if not self.pool.get('ir.model').search(cr, uid, [('model', '=', oerp_object._name)], context=context): + if not self.pool['ir.model'].search(cr, uid, [('model', '=', oerp_object._name)], context=context): raise osv.except_osv(_('Error :'), _("The object '%s' is not found in your OpenERP database, probably because the related module is not installed." % oerp_object._description)) partner = self.read(cr, uid, ids[0], ['partner_id', 'parent_partner_id'], context=context) @@ -115,7 +109,7 @@ class wizard_open_calling_partner(osv.osv_memory): record_to_open = self.read(cr, uid, ids[0], [field], context=context)[field] if record_to_open: return { - 'name': self.pool.get('res.partner')._description, + 'name': self.pool['res.partner']._description, 'view_type': 'form', 'view_mode': 'form,tree', 'res_model': 'res.partner', @@ -142,10 +136,9 @@ class wizard_open_calling_partner(osv.osv_memory): def create_partner(self, cr, uid, ids, phone_type='phone', context=None): '''Function called by the related button of the wizard''' calling_number = self.read(cr, uid, ids[0], ['calling_number'], context=context)['calling_number'] - user = self.pool.get('res.users').browse(cr, uid, uid, context=context) - ast_server = self.pool.get('asterisk.server')._get_asterisk_server_from_user(cr, uid, user, context=context) + ast_server = self.pool['asterisk.server']._get_asterisk_server_from_user(cr, uid, context=context) # Convert the number to the international format - number_to_write = self.pool.get('asterisk.server')._convert_number_to_international_format(cr, uid, calling_number, ast_server, context=context) + number_to_write = self.pool['asterisk.server']._convert_number_to_international_format(cr, uid, calling_number, ast_server, context=context) context['default_' + phone_type] = number_to_write @@ -174,10 +167,9 @@ class wizard_open_calling_partner(osv.osv_memory): cur_wizard = self.browse(cr, uid, ids[0], context=context) if not cur_wizard.to_update_partner_id: raise osv.except_osv(_('Error :'), _("Select the partner to update.")) - user = self.pool.get('res.users').browse(cr, uid, uid, context=context) - ast_server = self.pool.get('asterisk.server')._get_asterisk_server_from_user(cr, uid, user, context=context) - number_to_write = self.pool.get('asterisk.server')._convert_number_to_international_format(cr, uid, cur_wizard.calling_number, ast_server, context=context) - self.pool.get('res.partner').write(cr, uid, cur_wizard.to_update_partner_id.id, {phone_type: number_to_write}, context=context) + ast_server = self.pool['asterisk.server']._get_asterisk_server_from_user(cr, uid, context=context) + number_to_write = self.pool['asterisk.server']._convert_number_to_international_format(cr, uid, cur_wizard.calling_number, ast_server, context=context) + self.pool['res.partner'].write(cr, uid, cur_wizard.to_update_partner_id.id, {phone_type: number_to_write}, context=context) action = { 'name': 'Partner: ' + cur_wizard.to_update_partner_id.name, 'view_type': 'form', @@ -203,7 +195,7 @@ class wizard_open_calling_partner(osv.osv_memory): res = {} res['value'] = {} if to_update_partner_id: - to_update_partner = self.pool.get('res.partner').browse(cr, uid, to_update_partner_id, context=context) + to_update_partner = self.pool['res.partner'].browse(cr, uid, to_update_partner_id, context=context) res['value'].update({'current_phone': to_update_partner.phone, 'current_mobile': to_update_partner.mobile}) else: diff --git a/asterisk_click2dial/wizard/reformat_all_phonenumbers.py b/asterisk_click2dial/wizard/reformat_all_phonenumbers.py index b07ae62..d26f684 100644 --- a/asterisk_click2dial/wizard/reformat_all_phonenumbers.py +++ b/asterisk_click2dial/wizard/reformat_all_phonenumbers.py @@ -19,9 +19,9 @@ # ############################################################################## -from osv import osv, fields +from openerp.osv import osv, fields import logging -from tools.translate import _ +from openerp.tools.translate import _ _logger = logging.getLogger(__name__) @@ -35,7 +35,7 @@ class reformat_all_phonenumbers(osv.osv_memory): def run_reformat_all_phonenumbers(self, cr, uid, ids, context=None): - partner_obj = self.pool.get('res.partner') + partner_obj = self.pool['res.partner'] phonefields = ['phone', 'fax', 'mobile'] _logger.info('Starting to reformat all the phone numbers') all_partner_ids = partner_obj.search(cr, uid, ['|', ('active', '=', True), ('active', '=', False)], context=context) diff --git a/asterisk_click2dial_crm/asterisk_click2dial_crm.py b/asterisk_click2dial_crm/asterisk_click2dial_crm.py index e3f0e58..23804c3 100644 --- a/asterisk_click2dial_crm/asterisk_click2dial_crm.py +++ b/asterisk_click2dial_crm/asterisk_click2dial_crm.py @@ -22,9 +22,9 @@ # ############################################################################## -from osv import osv, fields +from openerp.osv import osv, fields # Lib to translate error messages -from tools.translate import _ +from openerp.tools.translate import _ class res_partner(osv.osv): _inherit = "res.partner" @@ -38,7 +38,7 @@ class res_partner(osv.osv): if context is None: context = {} super(res_partner, self).dial(cr, uid, ids, phone_field=phone_field, context=context) - user = self.pool.get('res.users').browse(cr, uid, uid, context=context) + user = self.pool['res.users'].browse(cr, uid, uid, context=context) context['partner_id'] = ids[0] action_start_wizard = { 'name': 'Create phone call in CRM', diff --git a/asterisk_click2dial_crm/wizard/create_crm_phonecall.py b/asterisk_click2dial_crm/wizard/create_crm_phonecall.py index 9a991cb..a16da56 100644 --- a/asterisk_click2dial_crm/wizard/create_crm_phonecall.py +++ b/asterisk_click2dial_crm/wizard/create_crm_phonecall.py @@ -22,25 +22,25 @@ # ############################################################################## -from osv import osv, fields +from openerp.osv import osv, fields # Lib to translate error messages -from tools.translate import _ +from openerp.tools.translate import _ class wizard_create_crm_phonecall(osv.osv_memory): _name = "wizard.create.crm.phonecall" def button_create_outgoing_phonecall(self, cr, uid, ids, context=None): - partner = self.pool.get('res.partner').browse(cr, uid, context.get('partner_id'), context=context) + partner = self.pool['res.partner'].browse(cr, uid, context.get('partner_id'), context=context) return self._create_open_crm_phonecall(cr, uid, partner, crm_categ='Outbound', context=context) def _create_open_crm_phonecall(self, cr, uid, partner, crm_categ, context=None): if context is None: context = {} - crm_phonecall_obj = self.pool.get('crm.phonecall') + crm_phonecall_obj = self.pool['crm.phonecall'] - categ_ids = self.pool.get('crm.case.categ').search(cr, uid, [('name','=',crm_categ)], context={'lang': 'en_US'}) - case_section_ids = self.pool.get('crm.case.section').search(cr, uid, [('member_ids', 'in', uid)], context=context) + categ_ids = self.pool['crm.case.categ'].search(cr, uid, [('name','=',crm_categ)], context={'lang': 'en_US'}) + case_section_ids = self.pool['crm.case.section'].search(cr, uid, [('member_ids', 'in', uid)], context=context) context.update({ 'default_partner_id': partner.id or False, 'default_partner_phone': partner.phone, @@ -70,7 +70,7 @@ class wizard_open_calling_partner(osv.osv_memory): def create_incoming_phonecall(self, cr, uid, ids, crm_categ, context=None): '''Started by button on 'open calling partner wizard''' partner = self.browse(cr, uid, ids[0], context=context).partner_id - action = self.pool.get('wizard.create.crm.phonecall')._create_open_crm_phonecall(cr, uid, partner, crm_categ='Inbound', context=context) + action = self.pool['wizard.create.crm.phonecall']._create_open_crm_phonecall(cr, uid, partner, crm_categ='Inbound', context=context) return action wizard_open_calling_partner() diff --git a/asterisk_click2dial_crm_claim/wizard/open_calling_partner.py b/asterisk_click2dial_crm_claim/wizard/open_calling_partner.py index 3c67e80..b606163 100644 --- a/asterisk_click2dial_crm_claim/wizard/open_calling_partner.py +++ b/asterisk_click2dial_crm_claim/wizard/open_calling_partner.py @@ -20,7 +20,7 @@ # ############################################################################## -from osv import osv, fields +from openerp.osv import osv, fields class wizard_open_calling_partner(osv.osv_memory): _inherit = "wizard.open.calling.partner"