Browse Source

Port asterisk_click2dial to new API

pull/88/head
Alexis de Lattre 8 years ago
parent
commit
b381adf93c
  1. 19
      asterisk_click2dial/__init__.py
  2. 47
      asterisk_click2dial/__openerp__.py
  3. 491
      asterisk_click2dial/asterisk_click2dial.py
  4. 69
      asterisk_click2dial/asterisk_click2dial_demo.xml
  5. 20
      asterisk_click2dial/asterisk_server_view.xml
  6. 23
      asterisk_click2dial/controller.py
  7. 1
      asterisk_click2dial/requirements.txt
  8. 7
      asterisk_click2dial/res_users_view.xml
  9. 5
      asterisk_click2dial/static/src/css/asterisk_click2dial.css
  10. 106
      asterisk_click2dial/static/src/js/asterisk_click2dial.js
  11. 8
      asterisk_click2dial/static/src/xml/asterisk_click2dial.xml
  12. 9
      asterisk_click2dial/web_asterisk_click2dial.xml
  13. 19
      ovh_telephony_connector/__init__.py
  14. 4
      ovh_telephony_connector/__openerp__.py
  15. 24
      ovh_telephony_connector/ovh_connector.py

19
asterisk_click2dial/__init__.py

@ -1,23 +1,4 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# Asterisk Click2Dial module for OpenERP
# Copyright (C) 2010-2013 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 asterisk_click2dial
from . import controller

47
asterisk_click2dial/__openerp__.py

@ -1,33 +1,15 @@
# -*- encoding: utf-8 -*-
##############################################################################
#
# Asterisk Click2dial module for OpenERP
# Copyright (C) 2010-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/>.
#
##############################################################################
# -*- coding: utf-8 -*-
# © 2010-2016 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
{
'name': 'Asterisk Click2dial',
'version': '8.0.0.4.0',
'version': '9.0.1.0.0',
'category': 'Phone',
'license': 'AGPL-3',
'summary': 'Asterisk-OpenERP connector',
'summary': 'Asterisk-Odoo connector',
'description': """
Asterisk-OpenERP connector
Asterisk-Odoo connector
==========================
The technical name of this module is *asterisk_click2dial*, but this module
@ -38,21 +20,21 @@ functionalities:
dial a phone number through Asterisk. This feature is usually known as
*click2dial*. Here is how it works :
* In OpenERP, the user clicks on the *Dial* button next to a phone number
* In Odoo, the user clicks on the *Dial* button next to a phone number
field in the partner view.
* OpenERP connects to the Asterisk Manager Interface and Asterisk makes the
* Odoo connects to the Asterisk Manager Interface and Asterisk makes the
user's phone ring.
* The user answers his own phone (if he doesn't, the process stops here).
* Asterisk dials the phone number found in OpenERP in place of the user.
* Asterisk dials the phone number found in Odoo in place of the user.
* If the remote party answers, the user can talk to his correspondent.
2) It adds the ability to show the name of the calling party on the screen of
your IP phone on incoming phone calls if the presented phone number is
present in the partner/leads/employees/... of OpenERP. Here is how it works:
present in the partner/leads/employees/... of Odoo. Here is how it works:
* On incoming phone calls, the Asterisk dialplan executes an AGI script
"set_name_incoming_timeout.sh".
@ -60,7 +42,7 @@ functionalities:
* The "set_name_incoming_timeout.sh" script calls the "set_name_agi.py"
script with a short timeout.
* The "set_name_agi.py" script will make an XML-RPC request on the OpenERP
* The "set_name_agi.py" script will make an XML-RPC request on the Odoo
server to try to find the name of the person corresponding to the phone
number presented by the calling party.
@ -75,14 +57,14 @@ functionalities:
(next to the Preferences) to get the partner/lead/candidate/registrations
corresponding to the calling party in one click. Here is how it works :
* When the user clicks on the phone icon, OpenERP sends a query to the
* When the user clicks on the phone icon, Odoo 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/Leads/Candidates/Registrations of OpenERP. If a record matches,
Partners/Leads/Candidates/Registrations of Odoo. If a record matches,
it takes you to the form view of this record. If no record matchs, it
opens a wizard which proposes to create a new Partner with the presented
phone number as *Phone* or *Mobile* number or update an existing Partner.
@ -107,6 +89,5 @@ http://www.akretion.com/products-and-services/openerp-asterisk-voip-connector
'qweb': ['static/src/xml/*.xml'],
'css': ['static/src/css/*.css'],
'application': True,
'installable': False,
'active': False,
'installable': True,
}

491
asterisk_click2dial/asterisk_click2dial.py

@ -1,31 +1,13 @@
# -*- encoding: utf-8 -*-
##############################################################################
#
# Asterisk Click2dial module for OpenERP
# Copyright (C) 2010-2013 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 fields, orm
from openerp.tools.translate import _
# -*- coding: utf-8 -*-
# © 2010-2016 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from openerp import models, fields, api, _
from openerp.exceptions import UserError, ValidationError
import logging
try:
# Lib py-asterisk from http://code.google.com/p/py-asterisk/
# -> pip install py-Asterisk
# pip install py-Asterisk
from Asterisk import Manager
except ImportError:
Manager = None
@ -33,73 +15,66 @@ except ImportError:
_logger = logging.getLogger(__name__)
class asterisk_server(orm.Model):
class AsteriskServer(models.Model):
'''Asterisk server object, stores the parameters of the Asterisk IPBXs'''
_name = "asterisk.server"
_description = "Asterisk Servers"
_columns = {
'name': fields.char('Asterisk Server Name', size=50, required=True),
'active': fields.boolean(
'Active', help="The active field allows you to hide the Asterisk "
"server without deleting it."),
'ip_address': fields.char(
'Asterisk IP address or DNS', size=50, required=True,
help="IP address or DNS name of the Asterisk server."),
'port': fields.integer(
'Port', required=True,
help="TCP port on which the Asterisk Manager Interface listens. "
"Defined in /etc/asterisk/manager.conf on Asterisk."),
'out_prefix': fields.char(
'Out Prefix', size=4, help="Prefix to dial to make outgoing "
"calls. If you don't use a prefix to make outgoing calls, "
"leave empty."),
'login': fields.char(
'AMI Login', size=30, required=True,
help="Login that OpenERP will use to communicate with the "
"Asterisk Manager Interface. Refer to /etc/asterisk/manager.conf "
"on your Asterisk server."),
'password': fields.char(
'AMI Password', size=30, required=True,
help="Password that OpenERP will use to communicate with the "
"Asterisk Manager Interface. Refer to /etc/asterisk/manager.conf "
"on your Asterisk server."),
'context': fields.char(
'Dialplan Context', size=50, required=True,
help="Asterisk dialplan context from which the calls will be "
"made. Refer to /etc/asterisk/extensions.conf on your Asterisk "
"server."),
'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."),
'company_id': fields.many2one(
'res.company', 'Company',
help="Company who uses the Asterisk server."),
}
_defaults = {
'active': True,
'port': 5038, # Default AMI port
'extension_priority': 1,
'wait_time': 15,
'company_id': lambda self, cr, uid, context:
self.pool['res.company']._company_default_get(
cr, uid, 'asterisk.server', context=context),
}
def _check_validity(self, cr, uid, ids):
for server in self.browse(cr, uid, ids):
name = fields.Char(string='Asterisk Server Name', required=True)
active = fields.Boolean(
string='Active', default=True)
ip_address = fields.Char(
string='Asterisk IP address or DNS', required=True)
port = fields.Integer(
string='Port', required=True, default=5038,
help="TCP port on which the Asterisk Manager Interface listens. "
"Defined in /etc/asterisk/manager.conf on Asterisk.")
out_prefix = fields.Char(
string='Out Prefix', size=4, help="Prefix to dial to make outgoing "
"calls. If you don't use a prefix to make outgoing calls, "
"leave empty.")
login = fields.Char(
string='AMI Login', required=True,
help="Login that Odoo will use to communicate with the "
"Asterisk Manager Interface. Refer to /etc/asterisk/manager.conf "
"on your Asterisk server.")
password = fields.Char(
string='AMI Password', required=True,
help="Password that Odoo will use to communicate with the "
"Asterisk Manager Interface. Refer to /etc/asterisk/manager.conf "
"on your Asterisk server.")
context = fields.Char(
string='Dialplan Context', required=True,
help="Asterisk dialplan context from which the calls will be "
"made. Refer to /etc/asterisk/extensions.conf on your Asterisk "
"server.")
wait_time = fields.Integer(
string='Wait Time', required=True, default=15,
help="Amount of time (in seconds) Asterisk will try to reach "
"the user's phone before hanging up.")
extension_priority = fields.Integer(
string='Extension Priority', required=True, default=1,
help="Priority of the extension in the Asterisk dialplan. Refer "
"to /etc/asterisk/extensions.conf on your Asterisk server.")
alert_info = fields.Char(
string='Alert-Info SIP Header',
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.")
company_id = fields.Many2one(
'res.company', string='Company',
default=lambda self: self.env['res.company']._company_default_get(
'asterisk.server'),
help="Company who uses the Asterisk server.")
@api.multi
@api.constrains(
'out_prefix', 'wait_time', 'extension_priority', 'port',
'context', 'alert_info', 'login', 'password')
def _check_validity(self):
for server in self:
out_prefix = ('Out prefix', server.out_prefix)
dialplan_context = ('Dialplan context', server.context)
alert_info = ('Alert-Info SIP header', server.alert_info)
@ -107,23 +82,19 @@ class asterisk_server(orm.Model):
password = ('AMI password', server.password)
if out_prefix[1] and not out_prefix[1].isdigit():
raise orm.except_orm(
_('Error:'),
raise ValidationError(
_("Only use digits for the '%s' on the Asterisk server "
"'%s'" % (out_prefix[0], server.name)))
if server.wait_time < 1 or server.wait_time > 120:
raise orm.except_orm(
_('Error:'),
raise ValidationError(
_("You should set a 'Wait time' value between 1 and 120 "
"seconds for the Asterisk server '%s'" % server.name))
if server.extension_priority < 1:
raise orm.except_orm(
_('Error:'),
raise ValidationError(
_("The 'extension priority' must be a positive value for "
"the Asterisk server '%s'" % server.name))
if server.port > 65535 or server.port < 1:
raise orm.except_orm(
_('Error:'),
raise ValidationError(
_("You should set a TCP port between 1 and 65535 for the "
"Asterisk server '%s'" % server.name))
for check_str in [dialplan_context, alert_info, login, password]:
@ -131,70 +102,34 @@ class asterisk_server(orm.Model):
try:
check_str[1].encode('ascii')
except UnicodeEncodeError:
raise orm.except_orm(
_('Error:'),
raise ValidationError(
_("The '%s' should only have ASCII caracters for "
"the Asterisk server '%s'"
% (check_str[0], server.name)))
return True
_constraints = [(
_check_validity,
"Error message in raise",
[
'out_prefix', 'wait_time', 'extension_priority', 'port',
'context', 'alert_info', 'login', 'password']
)]
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:
asterisk_server_ids = self.search(
cr, uid, [('company_id', '=', user.company_id.id)],
context=context)
# If the user doesn't have an asterisk server,
# we take the first one of the user's company
if not asterisk_server_ids:
raise orm.except_orm(
_('Error:'),
_("No Asterisk server configured for the company '%s'.")
% user.company_id.name)
else:
ast_server = self.browse(
cr, uid, asterisk_server_ids[0], context=context)
return ast_server
def _connect_to_asterisk(self, cr, uid, context=None):
@api.model
def _connect_to_asterisk(self):
'''
Open the connection to the Asterisk Manager
Returns an instance of the Asterisk Manager
'''
user = self.pool['res.users'].browse(cr, uid, uid, context=context)
ast_server = self._get_asterisk_server_from_user(
cr, uid, context=context)
user = self.env.user
ast_server = user.get_asterisk_server_from_user()
# We check if the current user has a chan type
if not user.asterisk_chan_type:
raise orm.except_orm(
_('Error:'),
raise UserError(
_('No channel type configured for the current user.'))
# We check if the current user has an internal number
if not user.resource:
raise orm.except_orm(
_('Error:'),
raise UserError(
_('No resource name configured for the current user'))
_logger.debug(
"User's phone: %s/%s" % (user.asterisk_chan_type, user.resource))
"User's phone: %s/%s", user.asterisk_chan_type, user.resource)
_logger.debug(
"Asterisk server: %s:%d"
% (ast_server.ip_address, ast_server.port))
"Asterisk server: %s:%d", ast_server.ip_address, ast_server.port)
# Connect to the Asterisk Manager Interface
try:
@ -203,41 +138,38 @@ class asterisk_server(orm.Model):
ast_server.login, ast_server.password)
except Exception, e:
_logger.error(
"Error in the request to the Asterisk Manager Interface %s"
% ast_server.ip_address)
_logger.error("Here is the error message: %s" % e)
raise orm.except_orm(
_('Error:'),
_("Problem in the request from OpenERP to Asterisk. "
"Error in the request to the Asterisk Manager Interface %s",
ast_server.ip_address)
_logger.error("Here is the error message: %s", e)
raise UserError(
_("Problem in the request from Odoo to Asterisk. "
"Here is the error message: %s" % e))
return (user, ast_server, ast_manager)
def test_ami_connection(self, cr, uid, ids, context=None):
assert len(ids) == 1, 'Only 1 ID'
ast_server = self.browse(cr, uid, ids[0], context=context)
@api.multi
def test_ami_connection(self):
self.ensure_one()
ast_manager = False
try:
ast_manager = Manager.Manager(
(ast_server.ip_address, ast_server.port),
ast_server.login,
ast_server.password)
(self.ip_address, self.port),
self.login,
self.password)
except Exception, e:
raise orm.except_orm(
_("Connection Test Failed!"),
_("Here is the error message: %s" % e))
raise UserError(
_("Connection Test Failed! The error message is: %s" % e))
finally:
if ast_manager:
ast_manager.Logoff()
raise orm.except_orm(
_("Connection Test Successfull!"),
_("Odoo can successfully login to the Asterisk Manager "
"Interface."))
raise UserError(_(
"Connection Test Successfull! Odoo can successfully login to "
"the Asterisk Manager Interface."))
def _get_calling_number(self, cr, uid, context=None):
@api.model
def _get_calling_number(self):
user, ast_server, ast_manager = self._connect_to_asterisk(
cr, uid, context=context)
user, ast_server, ast_manager = self._connect_to_asterisk()
calling_party_number = False
try:
list_chan = ast_manager.Status()
@ -255,42 +187,41 @@ class asterisk_server(orm.Model):
break
# 6 = Up
if (
chan.get('ChannelState') == '6'
and sip_account in chan.get('BridgedChannel', '')):
chan.get('ChannelState') == '6' and
sip_account in chan.get('BridgedChannel', '')):
_logger.debug("Found a matching Event in 'Up' state")
calling_party_number = chan.get('CallerIDNum')
break
# Compatibility with Asterisk 1.4
if (
chan.get('State') == 'Up'
and sip_account in chan.get('Link', '')):
chan.get('State') == 'Up' and
sip_account in chan.get('Link', '')):
_logger.debug("Found a matching Event in 'Up' state")
calling_party_number = chan.get('CallerIDNum')
break
except Exception, e:
_logger.error(
"Error in the Status request to Asterisk server %s"
% ast_server.ip_address)
"Error in the Status request to Asterisk server %s",
ast_server.ip_address)
_logger.error(
"Here are the details of the error: '%s'" % unicode(e))
raise orm.except_orm(
_('Error:'),
"Here are the details of the error: '%s'", unicode(e))
raise UserError(
_("Can't get calling number from Asterisk.\nHere is the "
"error: '%s'" % unicode(e)))
finally:
ast_manager.Logoff()
_logger.debug("Calling party number: '%s'" % calling_party_number)
_logger.debug("Calling party number: '%s'", calling_party_number)
return calling_party_number
def get_record_from_my_channel(self, cr, uid, context=None):
calling_number = self.pool['asterisk.server']._get_calling_number(
cr, uid, context=context)
@api.model
def get_record_from_my_channel(self):
calling_number = self.env['asterisk.server']._get_calling_number()
# calling_number = "0641981246"
if calling_number:
record = self.pool['phone.common'].get_record_from_phone_number(
cr, uid, calling_number, context=context)
record = self.env['phone.common'].get_record_from_phone_number(
calling_number)
if record:
return record
else:
@ -299,75 +230,72 @@ class asterisk_server(orm.Model):
return False
class res_users(orm.Model):
class ResUsers(models.Model):
_inherit = "res.users"
_columns = {
'internal_number': fields.char(
'Internal Number', size=15,
help="User's internal phone number."),
'dial_suffix': fields.char(
'User-specific Dial Suffix', size=15,
help="User-specific dial suffix such as aa=2wb for SCCP "
"auto answer."),
'callerid': fields.char(
'Caller ID', size=50,
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
'cdraccount': fields.char(
'CDR Account', size=50,
help="Call Detail Record (CDR) account used for billing this "
"user."),
'asterisk_chan_type': fields.selection([
('SIP', 'SIP'),
('IAX2', 'IAX2'),
('DAHDI', 'DAHDI'),
('Zap', 'Zap'),
('Skinny', 'Skinny'),
('MGCP', 'MGCP'),
('mISDN', 'mISDN'),
('H323', 'H323'),
('SCCP', 'SCCP'),
('Local', 'Local'),
], 'Asterisk Channel Type',
help="Asterisk channel type, as used in the Asterisk dialplan. "
"If the user has a regular IP phone, the channel type is 'SIP'."),
'resource': fields.char(
'Resource Name', size=64,
help="Resource name for the channel type selected. For example, "
"if you use 'Dial(SIP/phone1)' in your Asterisk dialplan to ring "
"the SIP phone of this user, then the resource name for this user "
"is 'phone1'. For a SIP phone, the phone number is often used as "
"resource name, but not always."),
'alert_info': fields.char(
'User-specific Alert-Info SIP Header', size=255,
help="Set a user-specific 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."),
'variable': fields.char(
'User-specific Variable', size=255,
help="Set a user-specific 'Variable' field in the Asterisk "
"Manager Interface 'originate' request for the click2dial "
"feature. If you want to have several variable headers, separate "
"them with '|'."),
'asterisk_server_id': fields.many2one(
'asterisk.server', 'Asterisk Server',
help="Asterisk server on which the user's phone is connected. "
"If you leave this field empty, it will use the first Asterisk "
"server of the user's company."),
}
_defaults = {
'asterisk_chan_type': 'SIP',
}
def _check_validity(self, cr, uid, ids):
for user in self.browse(cr, uid, ids):
internal_number = fields.Char(
string='Internal Number', copy=False,
help="User's internal phone number.")
dial_suffix = fields.Char(
string='User-specific Dial Suffix',
help="User-specific dial suffix such as aa=2wb for SCCP auto answer.")
callerid = fields.Char(
string='Caller ID', copy=False,
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
cdraccount = fields.Char(
string='CDR Account',
help="Call Detail Record (CDR) account used for billing this user.")
asterisk_chan_type = fields.Selection([
('SIP', 'SIP'),
('IAX2', 'IAX2'),
('DAHDI', 'DAHDI'),
('Zap', 'Zap'),
('Skinny', 'Skinny'),
('MGCP', 'MGCP'),
('mISDN', 'mISDN'),
('H323', 'H323'),
('SCCP', 'SCCP'),
# Local works for click2dial, but it won't work in
# _get_calling_number() when trying to identify the
# channel of the user, so it's better not to propose it
# ('Local', 'Local'),
], string='Asterisk Channel Type', default='SIP',
help="Asterisk channel type, as used in the Asterisk dialplan. "
"If the user has a regular IP phone, the channel type is 'SIP'.")
resource = fields.Char(
string='Resource Name', copy=False,
help="Resource name for the channel type selected. For example, "
"if you use 'Dial(SIP/phone1)' in your Asterisk dialplan to ring "
"the SIP phone of this user, then the resource name for this user "
"is 'phone1'. For a SIP phone, the phone number is often used as "
"resource name, but not always.")
alert_info = fields.Char(
string='User-specific Alert-Info SIP Header',
help="Set a user-specific 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.")
variable = fields.Char(
string='User-specific Variable',
help="Set a user-specific 'Variable' field in the Asterisk "
"Manager Interface 'originate' request for the click2dial "
"feature. If you want to have several variable headers, separate "
"them with '|'.")
asterisk_server_id = fields.Many2one(
'asterisk.server', string='Asterisk Server',
help="Asterisk server on which the user's phone is connected. "
"If you leave this field empty, it will use the first Asterisk "
"server of the user's company.")
@api.multi
@api.constrains('resource', 'internal_number', 'callerid')
def _check_validity(self):
for user in self:
strings_to_check = [
(_('Resource Name'), user.resource),
(_('Internal Number'), user.internal_number),
@ -378,47 +306,53 @@ class res_users(orm.Model):
try:
check_string[1].encode('ascii')
except UnicodeEncodeError:
raise orm.except_orm(
_('Error:'),
_("The '%s' for the user '%s' should only have "
"ASCII caracters")
raise ValidationError(_(
"The '%s' for the user '%s' should only have "
"ASCII caracters")
% (check_string[0], user.name))
return True
_constraints = [(
_check_validity,
"Error message in raise",
['resource', 'internal_number', 'callerid']
)]
@api.multi
def get_asterisk_server_from_user(self):
'''Returns an asterisk.server recordset'''
self.ensure_one()
# We check if the user has an Asterisk server configured
if self.asterisk_server_id:
ast_server = self.asterisk_server_id
else:
asterisk_servers = self.env['asterisk.server'].search(
[('company_id', '=', self.company_id.id)])
# If the user doesn't have an asterisk server,
# we take the first one of the user's company
if not asterisk_servers:
raise UserError(
_("No Asterisk server configured for the company '%s'.")
% self.company_id.name)
else:
ast_server = asterisk_servers[0]
return ast_server
class PhoneCommon(orm.AbstractModel):
class PhoneCommon(models.AbstractModel):
_inherit = 'phone.common'
def click2dial(self, cr, uid, erp_number, context=None):
res = super(PhoneCommon, self).click2dial(
cr, uid, erp_number, context=context)
@api.model
def click2dial(self, erp_number):
res = super(PhoneCommon, self).click2dial(erp_number)
if not erp_number:
raise orm.except_orm(
_('Error:'),
_('Missing phone number'))
raise UserError(_('Missing phone number'))
user, ast_server, ast_manager = \
self.pool['asterisk.server']._connect_to_asterisk(
cr, uid, context=context)
ast_number = self.convert_to_dial_number(
cr, uid, erp_number, context=context)
self.env['asterisk.server']._connect_to_asterisk()
ast_number = self.convert_to_dial_number(erp_number)
# Add 'out prefix'
if ast_server.out_prefix:
_logger.debug('Out prefix = %s' % ast_server.out_prefix)
_logger.debug('Out prefix = %s', ast_server.out_prefix)
ast_number = '%s%s' % (ast_server.out_prefix, ast_number)
_logger.debug('Number to be sent to Asterisk = %s' % ast_number)
_logger.debug('Number to be sent to Asterisk = %s', ast_number)
# The user should have a CallerID
if not user.callerid:
raise orm.except_orm(
_('Error:'),
_('No callerID configured for the current user'))
raise UserError(_('No callerID configured for the current user'))
variable = []
if user.asterisk_chan_type == 'SIP':
@ -441,19 +375,18 @@ class PhoneCommon(orm.AbstractModel):
channel,
context=ast_server.context,
extension=ast_number,
priority=str(ast_server.extension_priority),
timeout=str(ast_server.wait_time * 1000),
priority=unicode(ast_server.extension_priority),
timeout=unicode(ast_server.wait_time * 1000),
caller_id=user.callerid,
account=user.cdraccount,
variable=variable)
except Exception, e:
_logger.error(
"Error in the Originate request to Asterisk server %s"
% ast_server.ip_address)
"Error in the Originate request to Asterisk server %s",
ast_server.ip_address)
_logger.error(
"Here are the details of the error: '%s'" % unicode(e))
raise orm.except_orm(
_('Error:'),
"Here are the details of the error: '%s'", unicode(e))
raise UserError(
_("Click to dial with Asterisk failed.\nHere is the error: "
"'%s'")
% unicode(e))

69
asterisk_click2dial/asterisk_click2dial_demo.xml

@ -1,38 +1,41 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Asterisk Click2dial module for OpenERP
Copyright (C) 2010-2012 Alexis de Lattre <alexis@via.ecp.fr>
The licence is in the file __openerp__.py
Demo data for the click2dial module
© 2010-2016 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>)
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
-->
<openerp>
<data noupdate="1">
<record id="demo_ast_server" model="asterisk.server">
<field name="name">Akretion Asterisk IPBX</field>
<field name="ip_address">asterisk.akretion.com</field>
<field name="login">click2dial</field>
<field name="password">mypassword</field>
<field name="context">from-internal</field>
<field name="alert_info">info=&lt;Bellcore-dr5&gt;</field>
<field name="company_id" ref="base.main_company" />
</record>
<record id="base.user_root" model="res.users">
<field name="internal_number">11</field>
<field name="resource">11</field>
<field name="callerid">Administrator &lt;0141981242&gt;</field>
<field name="asterisk_server_id" ref="demo_ast_server"/>
</record>
<record id="base.user_demo" model="res.users">
<field name="internal_number">12</field>
<field name="resource">12</field>
<field name="callerid">Demo user &lt;0141984212&gt;</field>
<field name="asterisk_server_id" ref="demo_ast_server"/>
</record>
<record id="base.main_partner" model="res.partner">
<field name="country_id" ref="base.fr"/>
</record>
</data>
</openerp>
<odoo>
<data noupdate="1">
<record id="demo_ast_server" model="asterisk.server">
<field name="name">Akretion Asterisk IPBX</field>
<field name="ip_address">asterisk.akretion.com</field>
<field name="login">odoo</field>
<field name="password">mypassword</field>
<field name="context">from-internal</field>
<field name="alert_info">info=&lt;Bellcore-dr5&gt;</field>
<field name="company_id" ref="base.main_company" />
</record>
<record id="base.user_root" model="res.users">
<field name="internal_number">11</field>
<field name="resource">11</field>
<field name="callerid">Administrator &lt;0141981242&gt;</field>
<field name="asterisk_server_id" ref="demo_ast_server"/>
</record>
<record id="base.user_demo" model="res.users">
<field name="internal_number">12</field>
<field name="resource">12</field>
<field name="callerid">Demo user &lt;0141984212&gt;</field>
<field name="asterisk_server_id" ref="demo_ast_server"/>
</record>
<record id="base.main_partner" model="res.partner">
<field name="country_id" ref="base.fr"/>
</record>
</data>
</odoo>

20
asterisk_click2dial/asterisk_server_view.xml

@ -1,14 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Asterisk Click2dial module for OpenERP
Copyright (C) 2010-2014 Alexis de Lattre <alexis@via.ecp.fr>
Asterisk Click2dial module for Odoo
Copyright (C) 2010-2016 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>)
The licence is in the file __openerp__.py
-->
<openerp>
<odoo>
<data>
<!-- Search view for asterisk.server -->
<record id="view_asterisk_server_search" model="ir.ui.view">
<field name="name">asterisk.server.search</field>
<field name="model">asterisk.server</field>
@ -20,12 +19,11 @@
</field>
</record>
<!-- Form view for asterisk.server -->
<record id="view_asterisk_server_form" model="ir.ui.view">
<field name="name">asterisk.server.form</field>
<field name="model">asterisk.server</field>
<field name="arch" type="xml">
<form string="Asterisk Servers" version="7.0">
<form string="Asterisk Servers">
<sheet>
<div class="oe_title">
<label for="name" string="Server Name" class="oe_edit_only"/>
@ -52,14 +50,17 @@
<field name="extension_priority" />
<field name="out_prefix" />
<field name="alert_info" />
<field name="wait_time" />
<label for="wait_time"/>
<div>
<field name="wait_time" class="oe_inline"/>
<label string=" seconds" class="oe_inline"/>
</div>
</group>
</sheet>
</form>
</field>
</record>
<!-- Tree view for asterisk.server -->
<record id="view_asterisk_server_tree" model="ir.ui.view">
<field name="name">asterisk.server.tree</field>
<field name="model">asterisk.server</field>
@ -73,7 +74,6 @@
</field>
</record>
<!-- Action for asterisk.server -->
<record id="action_asterisk_server" model="ir.actions.act_window">
<field name="name">Asterisk Servers</field>
<field name="res_model">asterisk.server</field>
@ -85,4 +85,4 @@
</data>
</openerp>
</odoo>

23
asterisk_click2dial/controller.py

@ -1,23 +1,6 @@
# -*- encoding: utf-8 -*-
##############################################################################
#
# Asterisk click2dial 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/>.
#
##############################################################################
# -*- coding: utf-8 -*-
# © 2014-2016 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
import openerp

1
asterisk_click2dial/requirements.txt

@ -1,2 +1 @@
phonenumbers
py-Asterisk

7
asterisk_click2dial/res_users_view.xml

@ -1,13 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Asterisk Click2dial module for OpenERP
Copyright (C) 2010-2013 Alexis de Lattre <alexis@via.ecp.fr>
Copyright (C) 2010-2016 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>)
The licence is in the file __openerp__.py
Inherit res_users view to add the click2dial-related fields
-->
<openerp>
<odoo>
<data>
<record id="view_users_form" model="ir.ui.view">
@ -37,4 +36,4 @@
</record>
</data>
</openerp>
</odoo>

5
asterisk_click2dial/static/src/css/asterisk_click2dial.css

@ -1,7 +1,6 @@
/*
Asterisk Click2dial module for OpenERP
Copyright (C) 2014 Alexis de Lattre <alexis@via.ecp.fr>
The licence is in the file __openerp__.py
© 2016 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>)
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
*/
.openerp .oe_topbar_item.oe_topbar_open_caller{

106
asterisk_click2dial/static/src/js/asterisk_click2dial.js

@ -1,62 +1,62 @@
/* Asterisk_click2dial module for OpenERP
Copyright (C) 2014 Alexis de Lattre <alexis@via.ecp.fr>
The licence is in the file __openerp__.py */
/* © 2016 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>)
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). */
openerp.asterisk_click2dial = function (instance) {
odoo.define('asterisk_click2dial.OpenCaller', function (require) {
"use strict";
var _t = instance.web._t;
var _t = core._t;
var Widget = require('web.Widget');
var OpenCaller = Widget.extend({
template: 'asterisk_click2dial.OpenCaller',
instance.web.OpenCaller = instance.web.Widget.extend({
template:'asterisk_click2dial.OpenCaller',
start: function () {
this.$('#asterisk-open-caller').on(
'click', this.on_open_caller);
this._super();
},
start: function () {
this.$('#asterisk-open-caller').on(
'click', this.on_open_caller);
this._super();
},
on_open_caller: function (event) {
event.stopPropagation();
var self = this;
self.rpc('/asterisk_click2dial/get_record_from_my_channel', {}).done(function(r) {
// console.log('RESULT RPC r='+r);
// console.log('RESULT RPC type r='+typeof r);
if (r === false) {
self.do_notify(
_t('Failure'),
_t('Problem in the connection to Asterisk'));
}
else if (typeof r == 'string') {
var action = {
name: _t('Number Not Found'),
type: 'ir.actions.act_window',
res_model: 'number.not.found',
view_mode: 'form',
views: [[false, 'form']],
target: 'new',
context: {'default_calling_number': r},
};
instance.client.action_manager.do_action(action);
on_open_caller: function (event) {
event.stopPropagation();
var self = this;
self.rpc('/asterisk_click2dial/get_record_from_my_channel', {}).done(function(r) {
// console.log('RESULT RPC r='+r);
// console.log('RESULT RPC type r='+typeof r);
if (r === false) {
self.do_notify(
_t('Failure'),
_t('Problem in the connection to Asterisk'));
}
else if (typeof r == 'string') {
var action = {
name: _t('Number Not Found'),
type: 'ir.actions.act_window',
res_model: 'number.not.found',
view_mode: 'form',
views: [[false, 'form']],
target: 'new',
context: {'default_calling_number': r},
};
instance.client.action_manager.do_action(action);
}
else if (typeof r == 'object' && r.length == 3) {
self.do_notify( // Not working
_t('Success'),
_t('Moving to %s ID %d', r[0], r[1]));
var action = {
type: 'ir.actions.act_window',
res_model: r[0],
res_id: r[1],
view_mode: 'form,tree',
views: [[false, 'form']],
target: 'current',
context: {},
};
instance.client.action_manager.do_action(action);
}
});
},
else if (typeof r == 'object' && r.length == 3) {
self.do_notify( // Not working
_t('Success'),
_t('Moving to %s ID %d', r[0], r[1]));
var action = {
type: 'ir.actions.act_window',
res_model: r[0],
res_id: r[1],
view_mode: 'form,tree',
views: [[false, 'form']],
target: 'current',
context: {},
};
instance.client.action_manager.do_action(action);
}
});
},
});
instance.web.UserMenu.include({
do_update: function(){
@ -68,6 +68,6 @@ openerp.asterisk_click2dial = function (instance) {
},
});
};
});

8
asterisk_click2dial/static/src/xml/asterisk_click2dial.xml

@ -1,19 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Asterisk Click2dial module for OpenERP
Copyright (C) 2014 Alexis de Lattre <alexis@via.ecp.fr>
The licence is in the file __openerp__.py
© 2014-2016 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>)
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
-->
<template>
<!-- Add phone button in top right menu for "Open Caller" -->
<!--
<t t-name="asterisk_click2dial.OpenCaller">
<li class="oe_topbar_item oe_topbar_open_caller"
title="Open Caller">
<a id="asterisk-open-caller" href="#" class="fa fa-phone"/>
</li>
</t>
</t>-->
<!-- Add Dial button in phone widget for click2dial feature -->
<t t-extend="FieldPhone">

9
asterisk_click2dial/web_asterisk_click2dial.xml

@ -1,14 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Asterisk Click2dial module for OpenERP/Odoo
Copyright (C) 2014 Alexis de Lattre <alexis@via.ecp.fr>
The licence is in the file __openerp__.py
© 2014-2016 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>)
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
-->
<openerp>
<data>
<!--
<template id="assets_backend" name="asterisk_click2dial assets"
inherit_id="web.assets_backend">
<xpath expr="." position="inside">
@ -16,7 +15,7 @@
src="/asterisk_click2dial/static/src/js/asterisk_click2dial.js"></script>
</xpath>
</template>
-->
</data>
</openerp>

19
ovh_telephony_connector/__init__.py

@ -1,22 +1,3 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# OVH Connector module for Odoo
# Copyright (C) 2015 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 ovh_connector

4
ovh_telephony_connector/__openerp__.py

@ -1,4 +1,4 @@
# -*- encoding: utf-8 -*-
# -*- coding: utf-8 -*-
##############################################################################
#
# OVH Connector module for Odoo
@ -21,7 +21,7 @@
{
'name': 'OVH Telephony Connector',
'version': '8.0.0.1.0',
'version': '9.0.0.1.0',
'category': 'Phone',
'license': 'AGPL-3',
'summary': 'OVH-Odoo telephony connector (click2call)',

24
ovh_telephony_connector/ovh_connector.py

@ -1,4 +1,4 @@
# -*- encoding: utf-8 -*-
# -*- coding: utf-8 -*-
##############################################################################
#
# OVH connector module for Odoo
@ -20,7 +20,7 @@
##############################################################################
from openerp import models, fields, api, _
from openerp.exceptions import Warning
from openerp.exceptions import UserError
import logging
try:
@ -51,24 +51,24 @@ class PhoneCommon(models.AbstractModel):
def click2dial(self, erp_number):
res = super(PhoneCommon, self).click2dial(erp_number)
if not erp_number:
raise Warning(
raise UserError(
_('Missing phone number'))
user = self.env.user
if not user.ovh_billing_number:
raise Warning(
raise UserError(
_('Missing OVH Billing Number on user %s') % user.name)
if not user.ovh_calling_number:
raise Warning(
raise UserError(
_('Missing OVH Calling Number on user %s') % user.name)
if not user.ovh_click2call_login:
raise Warning(
raise UserError(
_('Missing OVH Click2call Login on user %s') % user.name)
if not user.ovh_click2call_password:
raise Warning(
raise UserError(
_('Missing OVH Click2dial Password on user %s') % user.name)
soap = WSDL.Proxy('https://www.ovh.com/soapi/soapi-re-1.63.wsdl')
@ -77,9 +77,9 @@ class PhoneCommon(models.AbstractModel):
_logger.debug(
'Starting OVH telephonyClick2CallDo request with '
'login = %s billing number = %s calling number = %s '
'and called_number = %s'
% (user.ovh_click2call_login, user.ovh_billing_number,
user.ovh_calling_number, called_number))
'and called_number = %s',
user.ovh_click2call_login, user.ovh_billing_number,
user.ovh_calling_number, called_number)
try:
soap.telephonyClick2CallDo(
@ -94,8 +94,8 @@ class PhoneCommon(models.AbstractModel):
_logger.error(
"Error in the OVH telephonyClick2CallDo request")
_logger.error(
"Here are the details of the error: '%s'" % unicode(e))
raise Warning(
"Here are the details of the error: '%s'", unicode(e))
raise UserError(
_("Click to call to OVH failed.\nHere is the error: "
"'%s'")
% unicode(e))

Loading…
Cancel
Save