diff --git a/asterisk_click2dial/__openerp__.py b/asterisk_click2dial/__openerp__.py index 73bbd1f..427aae4 100644 --- a/asterisk_click2dial/__openerp__.py +++ b/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 . 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 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 """, 'author': 'Akretion', diff --git a/asterisk_click2dial/res_users_view.xml b/asterisk_click2dial/res_users_view.xml index 48f2065..fce25c1 100644 --- a/asterisk_click2dial/res_users_view.xml +++ b/asterisk_click2dial/res_users_view.xml @@ -35,5 +35,19 @@ + + asterisk.preferences.view + res.users + + + + + + + + + + + diff --git a/asterisk_click2dial/scripts/get_cid_name.py b/asterisk_click2dial/scripts/get_cid_name.py index 290e5e1..b3616cb 100755 --- a/asterisk_click2dial/scripts/get_cid_name.py +++ b/asterisk_click2dial/scripts/get_cid_name.py @@ -69,18 +69,19 @@ from optparse import OptionParser default_cid_name = "Not in OpenERP" # 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): '''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))) 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: - 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') if not res: stdout_write('VERBOSE "Phone number not found in OpenERP"\n') @@ -225,7 +239,10 @@ def main(options, arguments): return True 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: param = option['names'] del option['names'] diff --git a/asterisk_click2dial/wizard/open_calling_partner.py b/asterisk_click2dial/wizard/open_calling_partner.py index 2426b71..61bf5d7 100644 --- a/asterisk_click2dial/wizard/open_calling_partner.py +++ b/asterisk_click2dial/wizard/open_calling_partner.py @@ -47,22 +47,32 @@ class wizard_open_calling_partner(orm.TransientModel): '''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['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 - 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] - else: - res['partner_id'] = False - res['parent_partner_id'] = False + 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: - _logger.debug("Could not get the calling number from Asterisk.") - raise orm.except_orm(_('Error :'), _("Could not get the calling number from Asterisk. Is your phone ringing or are you currently on the phone ? If yes, check your setup and look at the OpenERP debug logs.")) + calling_number = self.pool['asterisk.server']._get_calling_number(cr, uid, context=context) + #To test the code without Asterisk server + #calling_number = "0141981246" + if calling_number: + res['calling_number'] = calling_number + 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] + else: + res['partner_id'] = False + res['parent_partner_id'] = False + res['to_update_partner_id'] = False + else: + _logger.debug("Could not get the calling number from Asterisk.") + raise orm.except_orm(_('Error :'), _("Could not get the calling number from Asterisk. Is your phone ringing or are you currently on the phone ? If yes, check your setup and look at the OpenERP debug logs.")) return res diff --git a/asterisk_click2dial_crm/res_users_view.xml b/asterisk_click2dial_crm/res_users_view.xml index 9572c5d..a227405 100644 --- a/asterisk_click2dial_crm/res_users_view.xml +++ b/asterisk_click2dial_crm/res_users_view.xml @@ -23,17 +23,14 @@ asterisk.crm.preferences.option.view res.users - + - - - - - - - + + + + + Telephony Preferences + diff --git a/asterisk_popup/__init__.py b/asterisk_popup/__init__.py new file mode 100644 index 0000000..09972ec --- /dev/null +++ b/asterisk_popup/__init__.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Asterisk Pop-up module for OpenERP +# Copyright (C) 2014 Alexis de Lattre +# +# 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 . +# +############################################################################## + +from . import popup diff --git a/asterisk_popup/__openerp__.py b/asterisk_popup/__openerp__.py new file mode 100644 index 0000000..5d7d7a3 --- /dev/null +++ b/asterisk_popup/__openerp__.py @@ -0,0 +1,57 @@ +# -*- encoding: utf-8 -*- +############################################################################## +# +# Asterisk Pop-up module for OpenERP +# Copyright (C) 2014 Alexis de Lattre +# +# 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 . +# +############################################################################## + + +{ + '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, +} diff --git a/asterisk_popup/i18n/asterisk_popup.pot b/asterisk_popup/i18n/asterisk_popup.pot new file mode 100644 index 0000000..3ecb1a8 --- /dev/null +++ b/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 "" + diff --git a/asterisk_popup/i18n/fr.po b/asterisk_popup/i18n/fr.po new file mode 100644 index 0000000..94095dc --- /dev/null +++ b/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" diff --git a/asterisk_popup/popup.py b/asterisk_popup/popup.py new file mode 100644 index 0000000..b3899cc --- /dev/null +++ b/asterisk_popup/popup.py @@ -0,0 +1,91 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Asterisk Pop-up module for OpenERP +# Copyright (C) 2014 Alexis de Lattre +# +# 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 . +# +############################################################################## + +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, + } diff --git a/asterisk_popup/res_users_view.xml b/asterisk_popup/res_users_view.xml new file mode 100644 index 0000000..0b9eb8f --- /dev/null +++ b/asterisk_popup/res_users_view.xml @@ -0,0 +1,36 @@ + + + + + + + + asterisk.popup.res.users.form + res.users + + + + + + + + + + asterisk.popup.preferences.view + res.users + + + + + + + Telephony Preferences + + + + + +