Browse Source

Long-awaited feature : automatic pop-up on incoming calls in the OpenERP Web interface. Special thank to Jean-Sébastien Suzanne for his collaboration on this new feature.

pull/7/head
Alexis de Lattre 11 years ago
parent
commit
f34cf339cf
  1. 1
      asterisk_click2dial/__openerp__.py
  2. 14
      asterisk_click2dial/res_users_view.xml
  3. 47
      asterisk_click2dial/scripts/get_cid_name.py
  4. 12
      asterisk_click2dial/wizard/open_calling_partner.py
  5. 13
      asterisk_click2dial_crm/res_users_view.xml
  6. 22
      asterisk_popup/__init__.py
  7. 57
      asterisk_popup/__openerp__.py
  8. 37
      asterisk_popup/i18n/asterisk_popup.pot
  9. 36
      asterisk_popup/i18n/fr.po
  10. 91
      asterisk_popup/popup.py
  11. 36
      asterisk_popup/res_users_view.xml

1
asterisk_click2dial/__openerp__.py

@ -46,6 +46,7 @@ phone number is present in the partners of OpenERP. Here is how it works :
. When the user clicks on the "Open calling partner" button, OpenERP sends a query to the Asterisk Manager Interface to get a list of the current phone calls . When the user clicks on the "Open calling partner" button, OpenERP sends a query to the Asterisk Manager Interface to get a list of the current phone calls
. If it finds a phone call involving the user's phone, it gets the phone number of the calling party . If it finds a phone call involving the user's phone, it gets the phone number of the calling party
. It searches the phone number of the calling party in the Partners of OpenERP. If a record matches, it shows the name of the related Partner and proposes to open it, or open its related sale orders or invoices. If no record matches, it proposes to create a new Contact with the presented phone number as 'Phone' or 'Mobile' number or update an existing Contact. . It searches the phone number of the calling party in the Partners of OpenERP. If a record matches, it shows the name of the related Partner and proposes to open it, or open its related sale orders or invoices. If no record matches, it proposes to create a new Contact with the presented phone number as 'Phone' or 'Mobile' number or update an existing Contact.
It is possible to get a pop-up of the partner corresponding to the calling party without any action from the user via the module *asterisk_popup*.
A detailed documentation for this module is available on the Akretion Web site : http://www.akretion.com/en/products-and-services/openerp-asterisk-voip-connector """, A detailed documentation for this module is available on the Akretion Web site : http://www.akretion.com/en/products-and-services/openerp-asterisk-voip-connector """,
'author': 'Akretion', 'author': 'Akretion',

14
asterisk_click2dial/res_users_view.xml

@ -35,5 +35,19 @@
</field> </field>
</record> </record>
<record id="view_users_form_simple_modif" model="ir.ui.view">
<field name="name">asterisk.preferences.view</field>
<field name="model">res.users</field>
<field name="inherit_id" ref="base.view_users_form_simple_modif" />
<field name="arch" type="xml">
<group string="Email Preferences" position="after">
<group name="telephony">
<!-- Empty group, that is used by other Asterisk modules -->
</group>
</group>
</field>
</record>
</data> </data>
</openerp> </openerp>

47
asterisk_click2dial/scripts/get_cid_name.py

@ -69,18 +69,19 @@ from optparse import OptionParser
default_cid_name = "Not in OpenERP" default_cid_name = "Not in OpenERP"
# Define command line options # Define command line options
option_server = {'names': ('-s', '--server'), 'dest': 'server', 'type': 'string', 'help': 'DNS or IP address of the OpenERP server. Default = none (will not try to connect to OpenERP)', 'action': 'store', 'default': False}
option_port = {'names': ('-p', '--port'), 'dest': 'port', 'type': 'int', 'help': "Port of OpenERP's XML-RPC interface. Default = 8069", 'action': 'store', 'default': 8069}
option_ssl = {'names': ('-e', '--ssl'), 'dest': 'ssl', 'help': "Use XML-RPC secure i.e. with SSL instead of clear XML-RPC. Default = no, use clear XML-RPC", 'action': 'store_true', 'default': False}
option_database = {'names': ('-d', '--database'), 'dest': 'database', 'type': 'string', 'help': "OpenERP database name. Default = 'openerp'", 'action': 'store', 'default': 'openerp'}
option_user = {'names': ('-u', '--user-id'), 'dest': 'user', 'type': 'int', 'help': "OpenERP user ID to use when connecting to OpenERP. Default = 2", 'action': 'store', 'default': 2}
option_password = {'names': ('-w', '--password'), 'dest': 'password', 'type': 'string', 'help': "Password of the OpenERP user. Default = 'demo'", 'action': 'store', 'default': 'demo'}
option_ascii = {'names': ('-a', '--ascii'), 'dest': 'ascii', 'help': "Convert name from UTF-8 to ASCII. Default = no, keep UTF-8", 'action': 'store_true', 'default': False}
option_geoloc = {'names': ('-g', '--geoloc'), 'dest': 'geoloc', 'help': "Try to geolocate phone numbers unknown to OpenERP. This features requires the 'phonenumbers' Python lib. To install it, run 'sudo pip install phonenumbers' Default = no", 'action': 'store_true', 'default': False}
option_geoloc_lang = {'names': ('-l', '--geoloc-lang'), 'dest': 'lang', 'help': "Language in which the name of the country and city name will be displayed by the geolocalisation database. Use the 2 letters ISO code of the language. Default = 'en'", 'action': 'store', 'default': "en"}
option_geoloc_country = {'names': ('-c', '--geoloc-country'), 'dest': 'country', 'help': "2 letters ISO code for your country e.g. 'FR' for France. This will be used by the geolocalisation system to parse the phone number of the calling party. Default = 'FR'", 'action': 'store', 'default': "FR"}
options = [option_server, option_port, option_ssl, option_database, option_user, option_password, option_ascii, option_geoloc, option_geoloc_lang, option_geoloc_country]
options = [
{'names': ('-s', '--server'), 'dest': 'server', 'type': 'string', 'help': 'DNS or IP address of the OpenERP server. Default = none (will not try to connect to OpenERP)', 'action': 'store', 'default': False},
{'names': ('-p', '--port'), 'dest': 'port', 'type': 'int', 'help': "Port of OpenERP's XML-RPC interface. Default = 8069", 'action': 'store', 'default': 8069},
{'names': ('-e', '--ssl'), 'dest': 'ssl', 'help': "Use XML-RPC secure i.e. with SSL instead of clear XML-RPC. Default = no, use clear XML-RPC", 'action': 'store_true', 'default': False},
{'names': ('-d', '--database'), 'dest': 'database', 'type': 'string', 'help': "OpenERP database name. Default = 'openerp'", 'action': 'store', 'default': 'openerp'},
{'names': ('-u', '--user-id'), 'dest': 'user', 'type': 'int', 'help': "OpenERP user ID to use when connecting to OpenERP. Default = 2", 'action': 'store', 'default': 2},
{'names': ('-w', '--password'), 'dest': 'password', 'type': 'string', 'help': "Password of the OpenERP user. Default = 'demo'", 'action': 'store', 'default': 'demo'},
{'names': ('-a', '--ascii'), 'dest': 'ascii', 'help': "Convert name from UTF-8 to ASCII. Default = no, keep UTF-8", 'action': 'store_true', 'default': False},
{'names': ('-n', '--notify'), 'dest': 'notify', 'help': "Notify OpenERP users via a pop-up (requires the OpenERP module 'asterisk_popup'). If you use this option, you must pass the logins of the OpenERP users to notify as argument to the script. Default = no", 'action': 'store_true', 'default': False},
{'names': ('-g', '--geoloc'), 'dest': 'geoloc', 'help': "Try to geolocate phone numbers unknown to OpenERP. This features requires the 'phonenumbers' Python lib. To install it, run 'sudo pip install phonenumbers' Default = no", 'action': 'store_true', 'default': False},
{'names': ('-l', '--geoloc-lang'), 'dest': 'lang', 'help': "Language in which the name of the country and city name will be displayed by the geolocalisation database. Use the 2 letters ISO code of the language. Default = 'en'", 'action': 'store', 'default': "en"},
{'names': ('-c', '--geoloc-country'), 'dest': 'country', 'help': "2 letters ISO code for your country e.g. 'FR' for France. This will be used by the geolocalisation system to parse the phone number of the calling party. Default = 'FR'", 'action': 'store', 'default': "FR"},
]
def stdout_write(string): def stdout_write(string):
'''Wrapper on sys.stdout.write''' '''Wrapper on sys.stdout.write'''
@ -189,10 +190,23 @@ def main(options, arguments):
stdout_write('VERBOSE "Starting clear XML-RPC request on OpenERP %s:%s"\n' % (options.server, str(options.port))) stdout_write('VERBOSE "Starting clear XML-RPC request on OpenERP %s:%s"\n' % (options.server, str(options.port)))
protocol = 'http' protocol = 'http'
sock = xmlrpclib.ServerProxy('%s://%s:%s/xmlrpc/object' % (protocol, options.server, str(options.port)))
sock = xmlrpclib.ServerProxy(
'%s://%s:%s/xmlrpc/object'
% (protocol, options.server, str(options.port)))
try: try:
res = sock.execute(options.database, options.user, options.password, 'res.partner', 'get_name_from_phone_number', input_cid_number)
if options.notify and arguments:
res = sock.execute(
options.database, options.user, options.password,
'res.partner', 'incall_notify_by_login',
input_cid_number, arguments)
stdout_write('VERBOSE "Calling incall_notify_by_login"\n')
else:
res = sock.execute(
options.database, options.user, options.password,
'res.partner', 'get_name_from_phone_number',
input_cid_number)
stdout_write('VERBOSE "Calling get_name_from_phone_number"\n')
stdout_write('VERBOSE "End of XML-RPC request on OpenERP"\n') stdout_write('VERBOSE "End of XML-RPC request on OpenERP"\n')
if not res: if not res:
stdout_write('VERBOSE "Phone number not found in OpenERP"\n') stdout_write('VERBOSE "Phone number not found in OpenERP"\n')
@ -225,7 +239,10 @@ def main(options, arguments):
return True return True
if __name__ == '__main__': if __name__ == '__main__':
parser = OptionParser()
usage = "Usage: get_cid_name.py [options] login1 login2 login3 ..."
epilog = "Script written by Alexis de Lattre. Published under the GNU AGPL licence."
description = "This is an AGI script that sends a query to OpenERP. It can also be used without OpenERP as to geolocate phone numbers of incoming calls."
parser = OptionParser(usage=usage, epilog=epilog, description=description)
for option in options: for option in options:
param = option['names'] param = option['names']
del option['names'] del option['names']

12
asterisk_click2dial/wizard/open_calling_partner.py

@ -47,9 +47,19 @@ class wizard_open_calling_partner(orm.TransientModel):
'''Thanks to the default_get method, we are able to query Asterisk and '''Thanks to the default_get method, we are able to query Asterisk and
get the corresponding partner when we launch the wizard''' get the corresponding partner when we launch the wizard'''
res = {} res = {}
if context is None:
context = {}
if 'incall_number_popup' in context:
# That's when we come from incall_notify_by_user_ids()
# of the module asterisk_popup()
res['partner_id'] = False
res['parent_partner_id'] = False
res['to_update_partner_id'] = False
res['calling_number'] = context.get('incall_number_popup')
else:
calling_number = self.pool['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 #To test the code without Asterisk server
#calling_number = "0141981242"
#calling_number = "0141981246"
if calling_number: if calling_number:
res['calling_number'] = calling_number res['calling_number'] = calling_number
partner = self.pool['res.partner'].get_partner_from_phone_number(cr, uid, calling_number, context=context) partner = self.pool['res.partner'].get_partner_from_phone_number(cr, uid, calling_number, context=context)

13
asterisk_click2dial_crm/res_users_view.xml

@ -23,17 +23,14 @@
<record id="asterisk_crm_preferences_option_view" model="ir.ui.view"> <record id="asterisk_crm_preferences_option_view" model="ir.ui.view">
<field name="name">asterisk.crm.preferences.option.view</field> <field name="name">asterisk.crm.preferences.option.view</field>
<field name="model">res.users</field> <field name="model">res.users</field>
<field name="inherit_id" ref="base.view_users_form_simple_modif" />
<field name="inherit_id" ref="asterisk_click2dial.view_users_form_simple_modif" />
<field name="arch" type="xml"> <field name="arch" type="xml">
<field name="signature" position="after">
<group colspan="4" col="2" >
<!-- I create a group to avoid that the long "string" of the
field context_propose_creation_crm_call pushes all other fields
to the right -->
<separator string="Telephony preferences" colspan="2"/>
<group name="telephony" position="inside">
<field name="context_propose_creation_crm_call" readonly="0"/> <field name="context_propose_creation_crm_call" readonly="0"/>
</group> </group>
</field>
<group name="telephony" position="attributes">
<attribute name="string">Telephony Preferences</attribute>
</group>
</field> </field>
</record> </record>

22
asterisk_popup/__init__.py

@ -0,0 +1,22 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# Asterisk Pop-up module for OpenERP
# Copyright (C) 2014 Alexis de Lattre <alexis@via.ecp.fr>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
from . import popup

57
asterisk_popup/__openerp__.py

@ -0,0 +1,57 @@
# -*- encoding: utf-8 -*-
##############################################################################
#
# Asterisk Pop-up module for OpenERP
# Copyright (C) 2014 Alexis de Lattre <alexis@via.ecp.fr>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
{
'name': 'Asterisk Pop-up',
'version': '0.4',
'category': 'Extra Tools',
'license': 'AGPL-3',
'summary': 'Pop-up the Partner to the User on Incoming Calls',
'description': """
Asterisk-OpenERP Connector: Display Pop-up to User on Incoming Calls
====================================================================
When the user receives a phone call, OpenERP can automatically open the corresponding partner in a pop-up without any action from the user.
The module *web_action_request* can be downloaded with Mercurial:
hg clone http://bitbucket.org/anybox/web_action_request
It depends on 2 other modules, *web_longpolling* and *web_socketio*, that can be downloaded with this command:
hg clone http://bitbucket.org/anybox/web_socketio
You will find some hints in this documentation : https://bitbucket.org/anybox/web_action_request
Warning : proxying WebSockets is only supported since Nginx 1.3.13 ; the feature provided by this module won't work with older versions of Nginx.
TODO : document this new feature on the Akretion Web site : http://www.akretion.com/en/products-and-services/openerp-asterisk-voip-connector """,
'author': 'Akretion',
'website': 'http://www.akretion.com/',
'depends': ['asterisk_click2dial', 'web_action_request'],
'data': [
'res_users_view.xml',
],
'demo': [],
'images': [],
'active': False,
}

37
asterisk_popup/i18n/asterisk_popup.pot

@ -0,0 +1,37 @@
# Translation of OpenERP Server.
# This file contains the translation of the following modules:
# * asterisk_popup
#
msgid ""
msgstr ""
"Project-Id-Version: OpenERP Server 7.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2014-01-31 23:34+0000\n"
"PO-Revision-Date: 2014-01-31 23:34+0000\n"
"Last-Translator: <>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: \n"
#. module: asterisk_popup
#: model:ir.model,name:asterisk_popup.model_res_partner
msgid "Partner"
msgstr ""
#. module: asterisk_popup
#: field:res.users,context_incall_popup:0
msgid "Pop-up on Incoming Calls"
msgstr ""
#. module: asterisk_popup
#: model:ir.model,name:asterisk_popup.model_res_users
msgid "Users"
msgstr ""
#. module: asterisk_popup
#: view:res.users:0
msgid "Telephony Preferences"
msgstr ""

36
asterisk_popup/i18n/fr.po

@ -0,0 +1,36 @@
# Translation of OpenERP Server.
# This file contains the translation of the following modules:
# * asterisk_popup
#
msgid ""
msgstr ""
"Project-Id-Version: OpenERP Server 7.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2014-01-31 23:35+0000\n"
"PO-Revision-Date: 2014-01-31 23:35+0000\n"
"Last-Translator: <>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: \n"
#. module: asterisk_popup
#: model:ir.model,name:asterisk_popup.model_res_partner
msgid "Partner"
msgstr "Partenaire"
#. module: asterisk_popup
#: field:res.users,context_incall_popup:0
msgid "Pop-up on Incoming Calls"
msgstr "Pop-up sur Appel Entrant"
#. module: asterisk_popup
#: model:ir.model,name:asterisk_popup.model_res_users
msgid "Users"
msgstr "Utilisateurs"
#. module: asterisk_popup
#: view:res.users:0
msgid "Telephony Preferences"
msgstr "Préférences téléphoniques"

91
asterisk_popup/popup.py

@ -0,0 +1,91 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# Asterisk Pop-up module for OpenERP
# Copyright (C) 2014 Alexis de Lattre <alexis@via.ecp.fr>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
from openerp.osv import orm, fields
import logging
logger = logging.getLogger(__name__)
class res_partner(orm.Model):
_inherit = 'res.partner'
def _prepare_incall_pop_action(
self, cr, uid, partner_res, number, context=None):
if partner_res:
action = {
'name': 'Partner',
'type': 'ir.actions.act_window',
'res_model': 'res.partner',
'view_type': 'form',
'view_mode': 'form,tree,kanban',
'views': [[False, 'form']], # Beurk, but needed
'target': 'new',
'res_id': partner_res[0],
}
else:
action = {
'name': 'No Partner Found',
'type': 'ir.actions.act_window',
'res_model': 'wizard.open.calling.partner',
'view_type': 'form',
'view_mode': 'form',
'views': [[False, 'form']], # Beurk, but needed
'target': 'new',
'context': {'incall_number_popup': number}
}
return action
def incall_notify_by_login(
self, cr, uid, number, login_list, context=None):
assert isinstance(login_list, list), 'login_list must be a list'
res = self.get_partner_from_phone_number(
cr, uid, number, context=context)
user_ids = self.pool['res.users'].search(
cr, uid, [('login', 'in', login_list)], context=context)
logger.debug(
'Notify incoming call from number %s to users %s'
% (number, user_ids))
action = self._prepare_incall_pop_action(
cr, uid, res, number, context=context)
if action:
users = self.pool['res.users'].read(
cr, uid, user_ids, ['context_incall_popup'], context=context)
for user in users:
if user['context_incall_popup']:
self.pool['action.request'].notify(
cr, uid, to_id=user['id'], **action)
logger.debug(
'This action has been sent to user ID %d: %s'
% (user['id'], action))
return res
class res_users(orm.Model):
_inherit = 'res.users'
_columns = {
'context_incall_popup': fields.boolean('Pop-up on Incoming Calls'),
}
_defaults = {
'context_incall_popup': True,
}

36
asterisk_popup/res_users_view.xml

@ -0,0 +1,36 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2014 Alexis de Lattre <alexis@via.ecp.fr>
The licence is in the file __openerp__.py
-->
<openerp>
<data>
<record id="asterisk_res_users" model="ir.ui.view">
<field name="name">asterisk.popup.res.users.form</field>
<field name="model">res.users</field>
<field name="inherit_id" ref="asterisk_click2dial.asterisk_res_users_internal_number"/>
<field name="arch" type="xml">
<field name="asterisk_server_id" position="after">
<field name="context_incall_popup"/>
</field>
</field>
</record>
<record id="view_users_form_simple_modif" model="ir.ui.view">
<field name="name">asterisk.popup.preferences.view</field>
<field name="model">res.users</field>
<field name="inherit_id" ref="asterisk_click2dial.view_users_form_simple_modif" />
<field name="arch" type="xml">
<group name="telephony" position="inside">
<field name="context_incall_popup" readonly="0"/>
</group>
<group name="telephony" position="attributes">
<attribute name="string">Telephony Preferences</attribute>
</group>
</field>
</record>
</data>
</openerp>
Loading…
Cancel
Save