Browse Source

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.
pull/7/head
Alexis de Lattre 11 years ago
parent
commit
9e52016e20
  1. 54
      asterisk_click2dial/asterisk_click2dial.py
  2. 1
      asterisk_click2dial/asterisk_server_view.xml
  3. 11
      asterisk_click2dial/scripts/get_cid_name.py
  4. 32
      asterisk_click2dial/wizard/open_calling_partner.py
  5. 6
      asterisk_click2dial/wizard/reformat_all_phonenumbers.py
  6. 6
      asterisk_click2dial_crm/asterisk_click2dial_crm.py
  7. 14
      asterisk_click2dial_crm/wizard/create_crm_phonecall.py
  8. 2
      asterisk_click2dial_crm_claim/wizard/open_calling_partner.py

54
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

1
asterisk_click2dial/asterisk_server_view.xml

@ -62,6 +62,7 @@
<field name="country_prefix" />
<field name="alert_info" />
<field name="wait_time" />
<field name="number_of_digits_to_match_from_end" />
</group>
</sheet>
</form>

11
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')

32
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:

6
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)

6
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',

14
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()

2
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"

Loading…
Cancel
Save