Browse Source

Merge pull request #109 from akretion/10-mig-generic-modules

[10.0] Port most modules and fix bug 117
pull/132/head
Alexis de Lattre 8 years ago
committed by GitHub
parent
commit
73d8d7cb03
  1. 3
      .travis.yml
  2. 2
      asterisk_click2dial/__init__.py
  3. 10
      asterisk_click2dial/__manifest__.py
  4. 2
      asterisk_click2dial/controller.py
  5. 4
      asterisk_click2dial/demo/asterisk_click2dial_demo.xml
  6. 5
      asterisk_click2dial/models/__init__.py
  7. 177
      asterisk_click2dial/models/asterisk_server.py
  8. 73
      asterisk_click2dial/models/phone_common.py
  9. 108
      asterisk_click2dial/models/res_users.py
  10. 4
      asterisk_click2dial/scripts/odoo_popup_timeout.sh
  11. 62
      asterisk_click2dial/scripts/set_name_agi.py
  12. 2
      asterisk_click2dial/scripts/set_name_incoming_timeout.sh
  13. 2
      asterisk_click2dial/scripts/set_name_outgoing_timeout.sh
  14. 25
      asterisk_click2dial/static/src/js/asterisk_click2dial.js
  15. 4
      asterisk_click2dial/static/src/xml/asterisk_click2dial.xml
  16. 3
      asterisk_click2dial/views/asterisk_server.xml
  17. 3
      asterisk_click2dial/views/res_users.xml
  18. 2
      asterisk_click2dial/web_asterisk_click2dial.xml
  19. 8
      base_phone/common.py
  20. 16
      base_phone/controllers/main.py
  21. 1
      base_phone/models/__init__.py
  22. 17
      base_phone/models/ir_fields_converter.py
  23. 4
      base_phone/static/src/js/phone_widget.js
  24. 18
      base_phone/static/src/xml/phone.xml
  25. 16
      base_phone/tests/test_phone.py
  26. 2
      base_phone/wizard/number_not_found.py
  27. 3
      crm_claim_phone/__init__.py
  28. 50
      crm_claim_phone/__manifest__.py
  29. 12
      crm_claim_phone/crm_claim_phone.py
  30. 22
      crm_claim_phone/crm_claim_view.xml
  31. 2
      crm_phone/__init__.py
  32. 5
      crm_phone/__manifest__.py
  33. 4
      crm_phone/demo/crm_phonecall.xml
  34. 7
      crm_phone/models/__init__.py
  35. 49
      crm_phone/models/crm_lead.py
  36. 96
      crm_phone/models/crm_phonecall.py
  37. 22
      crm_phone/models/phone_common.py
  38. 26
      crm_phone/models/res_partner.py
  39. 16
      crm_phone/models/res_users.py
  40. 4
      crm_phone/security/ir.model.access.csv
  41. 8
      crm_phone/security/phonecall_security.xml
  42. 4
      crm_phone/tests/test_crm_phone.py
  43. 25
      crm_phone/view/crm_lead.xml
  44. 8
      crm_phone/view/crm_phonecall.xml
  45. 4
      crm_phone/view/res_partner.xml
  46. 2
      crm_phone/view/res_users.xml
  47. 10
      crm_phone/wizard/create_crm_phonecall.py
  48. 11
      crm_phone/wizard/create_crm_phonecall_view.xml
  49. 9
      crm_phone/wizard/number_not_found.py
  50. 7
      crm_phone/wizard/number_not_found_view.xml
  51. 2
      event_phone/__init__.py
  52. 9
      event_phone/__manifest__.py
  53. 24
      event_phone/event_view.xml
  54. 3
      event_phone/models/__init__.py
  55. 4
      event_phone/models/event_registration.py
  56. 2
      hr_phone/__init__.py
  57. 9
      hr_phone/__manifest__.py
  58. 49
      hr_phone/hr_view.xml
  59. 3
      hr_phone/models/__init__.py
  60. 4
      hr_phone/models/hr_employee.py
  61. 2
      hr_recruitment_phone/__init__.py
  62. 9
      hr_recruitment_phone/__manifest__.py
  63. 38
      hr_recruitment_phone/hr_recruitment_view.xml
  64. 3
      hr_recruitment_phone/models/__init__.py
  65. 4
      hr_recruitment_phone/models/hr_applicant.py
  66. 3
      requirements.txt

3
.travis.yml

@ -31,7 +31,8 @@ install:
- git clone https://github.com/OCA/maintainer-quality-tools.git ${HOME}/maintainer-quality-tools - git clone https://github.com/OCA/maintainer-quality-tools.git ${HOME}/maintainer-quality-tools
- export PATH=${HOME}/maintainer-quality-tools/travis:${PATH} - export PATH=${HOME}/maintainer-quality-tools/travis:${PATH}
- travis_install_nightly - travis_install_nightly
- pip install phonenumbers py-Asterisk SOAPpy
- printf '[options]\n\nrunning_env = dev\n' > ${HOME}/.openerp_serverrc
- ln -s ${TRAVIS_BUILD_DIR}/server_environment_files_sample ${TRAVIS_BUILD_DIR}/server_environment_files
script: script:
- travis_run_tests - travis_run_tests

2
asterisk_click2dial/__init__.py

@ -1,4 +1,4 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from . import asterisk_click2dial
from . import models
from . import controller from . import controller

10
asterisk_click2dial/__manifest__.py

@ -4,7 +4,7 @@
{ {
'name': 'Asterisk Click2dial', 'name': 'Asterisk Click2dial',
'version': '9.0.1.0.0',
'version': '10.0.1.0.0',
'category': 'Phone', 'category': 'Phone',
'license': 'AGPL-3', 'license': 'AGPL-3',
'summary': 'Asterisk-Odoo connector', 'summary': 'Asterisk-Odoo connector',
@ -80,14 +80,14 @@ http://www.akretion.com/products-and-services/openerp-asterisk-voip-connector
'depends': ['base_phone'], 'depends': ['base_phone'],
'external_dependencies': {'python': ['Asterisk']}, 'external_dependencies': {'python': ['Asterisk']},
'data': [ 'data': [
'asterisk_server_view.xml',
'res_users_view.xml',
'views/asterisk_server.xml',
'views/res_users.xml',
'security/ir.model.access.csv', 'security/ir.model.access.csv',
'web_asterisk_click2dial.xml', 'web_asterisk_click2dial.xml',
], ],
'demo': ['asterisk_click2dial_demo.xml'],
'demo': ['demo/asterisk_click2dial_demo.xml'],
'qweb': ['static/src/xml/*.xml'], 'qweb': ['static/src/xml/*.xml'],
'css': ['static/src/css/*.css'], 'css': ['static/src/css/*.css'],
'application': True, 'application': True,
'installable': False,
'installable': True,
} }

2
asterisk_click2dial/controller.py

@ -3,7 +3,7 @@
# © 2015-2016 Juris Malinens (port to v9) # © 2015-2016 Juris Malinens (port to v9)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from openerp import http
from odoo import http
class AsteriskClick2dialController(http.Controller): class AsteriskClick2dialController(http.Controller):

4
asterisk_click2dial/asterisk_click2dial_demo.xml → asterisk_click2dial/demo/asterisk_click2dial_demo.xml

@ -4,8 +4,7 @@
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
--> -->
<odoo>
<data noupdate="1">
<odoo noupdate="1">
<record id="demo_ast_server" model="asterisk.server"> <record id="demo_ast_server" model="asterisk.server">
@ -37,5 +36,4 @@
</record> </record>
</data>
</odoo> </odoo>

5
asterisk_click2dial/models/__init__.py

@ -0,0 +1,5 @@
# -*- coding: utf-8 -*-
from . import asterisk_server
from . import res_users
from . import phone_common

177
asterisk_click2dial/asterisk_click2dial.py → asterisk_click2dial/models/asterisk_server.py

@ -2,19 +2,19 @@
# © 2010-2016 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>) # © 2010-2016 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). # 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
from odoo import models, fields, api, _
from odoo.exceptions import UserError, ValidationError
from pprint import pformat from pprint import pformat
import logging
_logger = logging.getLogger(__name__)
try: try:
# pip install py-Asterisk # pip install py-Asterisk
from Asterisk import Manager from Asterisk import Manager
except ImportError: except ImportError:
_logger.debug('Cannot import Asterisk')
Manager = None Manager = None
_logger = logging.getLogger(__name__)
class AsteriskServer(models.Model): class AsteriskServer(models.Model):
'''Asterisk server object, stores the parameters of the Asterisk IPBXs''' '''Asterisk server object, stores the parameters of the Asterisk IPBXs'''
@ -236,170 +236,3 @@ class AsteriskServer(models.Model):
return calling_number return calling_number
else: else:
return False return False
class ResUsers(models.Model):
_inherit = "res.users"
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),
(_('Caller ID'), user.callerid),
]
for check_string in strings_to_check:
if check_string[1]:
try:
check_string[1].encode('ascii')
except UnicodeEncodeError:
raise ValidationError(_(
"The '%s' for the user '%s' should only have "
"ASCII caracters")
% (check_string[0], user.name))
@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(models.AbstractModel):
_inherit = 'phone.common'
@api.model
def click2dial(self, erp_number):
res = super(PhoneCommon, self).click2dial(erp_number)
if not erp_number:
raise UserError(_('Missing phone number'))
user, ast_server, ast_manager = \
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)
ast_number = '%s%s' % (ast_server.out_prefix, ast_number)
_logger.debug('Number to be sent to Asterisk = %s', ast_number)
# The user should have a CallerID
if not user.callerid:
raise UserError(_('No callerID configured for the current user'))
variable = []
if user.asterisk_chan_type == 'SIP':
# We can only have one alert-info header in a SIP request
if user.alert_info:
variable.append(
'SIPAddHeader=Alert-Info: %s' % user.alert_info)
elif ast_server.alert_info:
variable.append(
'SIPAddHeader=Alert-Info: %s' % ast_server.alert_info)
if user.variable:
for user_variable in user.variable.split('|'):
variable.append(user_variable.strip())
channel = '%s/%s' % (user.asterisk_chan_type, user.resource)
if user.dial_suffix:
channel += '/%s' % user.dial_suffix
try:
ast_manager.Originate(
channel,
context=ast_server.context,
extension=ast_number,
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)
_logger.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))
finally:
ast_manager.Logoff()
res['dialed_number'] = ast_number
return res

73
asterisk_click2dial/models/phone_common.py

@ -0,0 +1,73 @@
# -*- 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 odoo import models, api, _
from odoo.exceptions import UserError
import logging
_logger = logging.getLogger(__name__)
class PhoneCommon(models.AbstractModel):
_inherit = 'phone.common'
@api.model
def click2dial(self, erp_number):
res = super(PhoneCommon, self).click2dial(erp_number)
if not erp_number:
raise UserError(_('Missing phone number'))
user, ast_server, ast_manager = \
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)
ast_number = '%s%s' % (ast_server.out_prefix, ast_number)
_logger.debug('Number to be sent to Asterisk = %s', ast_number)
# The user should have a CallerID
if not user.callerid:
raise UserError(_('No callerID configured for the current user'))
variable = []
if user.asterisk_chan_type == 'SIP':
# We can only have one alert-info header in a SIP request
if user.alert_info:
variable.append(
'SIPAddHeader=Alert-Info: %s' % user.alert_info)
elif ast_server.alert_info:
variable.append(
'SIPAddHeader=Alert-Info: %s' % ast_server.alert_info)
if user.variable:
for user_variable in user.variable.split('|'):
variable.append(user_variable.strip())
channel = '%s/%s' % (user.asterisk_chan_type, user.resource)
if user.dial_suffix:
channel += '/%s' % user.dial_suffix
try:
ast_manager.Originate(
channel,
context=ast_server.context,
extension=ast_number,
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)
_logger.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))
finally:
ast_manager.Logoff()
res['dialed_number'] = ast_number
return res

108
asterisk_click2dial/models/res_users.py

@ -0,0 +1,108 @@
# -*- 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 odoo import models, fields, api, _
from odoo.exceptions import UserError, ValidationError
class ResUsers(models.Model):
_inherit = "res.users"
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),
(_('Caller ID'), user.callerid),
]
for check_string in strings_to_check:
if check_string[1]:
try:
check_string[1].encode('ascii')
except UnicodeEncodeError:
raise ValidationError(_(
"The '%s' for the user '%s' should only have "
"ASCII caracters")
% (check_string[0], user.name))
@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

4
asterisk_click2dial/scripts/openerp_popup_timeout.sh → asterisk_click2dial/scripts/odoo_popup_timeout.sh

@ -19,9 +19,9 @@
# In this example, we chose 2 seconds. # In this example, we chose 2 seconds.
# To test this script manually (i.e. outside of Asterisk), run : # To test this script manually (i.e. outside of Asterisk), run :
# echo "agi_callerid:0141401242"|openerp_popup_timeout.sh
# echo "agi_callerid:0141401242"|odoo_popup_timeout.sh
# where 0141401242 is a phone number that could be presented by the calling party # where 0141401242 is a phone number that could be presented by the calling party
PATH=/usr/local/sbin:/usr/local/bin:/var/lib/asterisk/agi-bin:/sbin:/bin:/usr/sbin:/usr/bin:/usr/share/asterisk/agi-bin PATH=/usr/local/sbin:/usr/local/bin:/var/lib/asterisk/agi-bin:/sbin:/bin:/usr/sbin:/usr/bin:/usr/share/asterisk/agi-bin
timeout 2s set_name_agi.py --server openerp.mycompany.com --database erp_prod --user-id 12 --password "thepasswd" --notify admin demo
timeout 2s set_name_agi.py --server odoo.mycompany.com --database erp_prod --user-id 12 --password "thepasswd" --notify admin demo

62
asterisk_click2dial/scripts/set_name_agi.py

@ -16,7 +16,7 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
""" """
Name lookup in OpenERP for incoming and outgoing calls with an
Name lookup in Odoo for incoming and outgoing calls with an
Asterisk IPBX Asterisk IPBX
This script is designed to be used as an AGI on an Asterisk IPBX... This script is designed to be used as an AGI on an Asterisk IPBX...
@ -32,12 +32,12 @@
See my 2 sample wrappers "set_name_incoming_timeout.sh" and See my 2 sample wrappers "set_name_incoming_timeout.sh" and
"set_name_outgoing_timeout.sh" "set_name_outgoing_timeout.sh"
It's probably a good idea to create a user in OpenERP dedicated to this task.
It's probably a good idea to create a user in Odoo dedicated to this task.
This user only needs to be part of the group "Phone CallerID", which has This user only needs to be part of the group "Phone CallerID", which has
read access on the 'res.partner' and other objects with phone numbers and read access on the 'res.partner' and other objects with phone numbers and
names. names.
Note that this script can be used without OpenERP, with just the
Note that this script can be used without Odoo, with just the
geolocalisation feature : for that, don't use option --server ; geolocalisation feature : for that, don't use option --server ;
only use --geoloc only use --geoloc
@ -45,14 +45,13 @@
1) INCOMING CALLS 1) INCOMING CALLS
When executed from the dialplan on an incoming phone call, it will When executed from the dialplan on an incoming phone call, it will
lookup in OpenERP's partners and other objects with phone numbers
lookup in Odoo's partners and other objects with phone numbers
(leads, employees, etc...), and, if it finds the phone number, it will (leads, employees, etc...), and, if it finds the phone number, it will
get the corresponding name of the person and use this name as CallerID get the corresponding name of the person and use this name as CallerID
name for the incoming call. name for the incoming call.
Requires the "base_phone" module Requires the "base_phone" module
available from https://code.launchpad.net/openerp-asterisk-connector
for OpenERP version >= 7.0
available from https://github.com/OCA/connector-telephony
Asterisk dialplan example : Asterisk dialplan example :
@ -65,7 +64,7 @@
2) OUTGOING CALLS 2) OUTGOING CALLS
When executed from the dialplan on an outgoing call, it will When executed from the dialplan on an outgoing call, it will
lookup in OpenERP the name corresponding to the phone number
lookup in Odoo the name corresponding to the phone number
that is called by the user and it will update the name of the that is called by the user and it will update the name of the
callee on the screen of the phone of the caller. callee on the screen of the phone of the caller.
@ -79,9 +78,9 @@
as parameter to the CONNECTEDLINE function. as parameter to the CONNECTEDLINE function.
Here is the code that I used on the pre-process subroutine Here is the code that I used on the pre-process subroutine
"openerp-out-call" of the Outgoing Call of my Xivo server :
"odoo-out-call" of the Outgoing Call of my Xivo server :
[openerp-out-call]
[odoo-out-call]
exten = s,1,AGI(/var/lib/asterisk/agi-bin/set_name_outgoing_timeout.sh) exten = s,1,AGI(/var/lib/asterisk/agi-bin/set_name_outgoing_timeout.sh)
same = n,Set(CONNECTEDLINE(name,i)=${connectedlinename}) same = n,Set(CONNECTEDLINE(name,i)=${connectedlinename})
same = n,Set(CONNECTEDLINE(name-pres,i)=allowed) same = n,Set(CONNECTEDLINE(name-pres,i)=allowed)
@ -110,11 +109,11 @@ not_found_name = False
options = [ options = [
{'names': ('-s', '--server'), 'dest': 'server', 'type': 'string', {'names': ('-s', '--server'), 'dest': 'server', 'type': 'string',
'action': 'store', 'default': False, 'action': 'store', 'default': False,
'help': 'DNS or IP address of the OpenERP server. Default = none '
'(will not try to connect to OpenERP)'},
'help': 'DNS or IP address of the Odoo server. Default = none '
'(will not try to connect to Odoo)'},
{'names': ('-p', '--port'), 'dest': 'port', 'type': 'int', {'names': ('-p', '--port'), 'dest': 'port', 'type': 'int',
'action': 'store', 'default': 8069, 'action': 'store', 'default': 8069,
'help': "Port of OpenERP's XML-RPC interface. Default = 8069"},
'help': "Port of Odoo's XML-RPC interface. Default = 8069"},
{'names': ('-e', '--ssl'), 'dest': 'ssl', {'names': ('-e', '--ssl'), 'dest': 'ssl',
'help': "Use SSL connections instead of clear connections. " 'help': "Use SSL connections instead of clear connections. "
"Default = no, use clear XML-RPC or JSON-RPC", "Default = no, use clear XML-RPC or JSON-RPC",
@ -124,31 +123,31 @@ options = [
"Default = no, use XML-RPC", "Default = no, use XML-RPC",
'action': 'store_true', 'default': False}, 'action': 'store_true', 'default': False},
{'names': ('-d', '--database'), 'dest': 'database', 'type': 'string', {'names': ('-d', '--database'), 'dest': 'database', 'type': 'string',
'action': 'store', 'default': 'openerp',
'help': "OpenERP database name. Default = 'openerp'"},
'action': 'store', 'default': 'odoo',
'help': "Odoo database name. Default = 'odoo'"},
{'names': ('-u', '--user-id'), 'dest': 'userid', 'type': 'int', {'names': ('-u', '--user-id'), 'dest': 'userid', 'type': 'int',
'action': 'store', 'default': 2, 'action': 'store', 'default': 2,
'help': "OpenERP user ID to use when connecting to OpenERP in "
'help': "Odoo user ID to use when connecting to Odoo in "
"XML-RPC. Default = 2"}, "XML-RPC. Default = 2"},
{'names': ('-t', '--username'), 'dest': 'username', 'type': 'string', {'names': ('-t', '--username'), 'dest': 'username', 'type': 'string',
'action': 'store', 'default': 'demo', 'action': 'store', 'default': 'demo',
'help': "OpenERP username to use when connecting to OpenERP in "
'help': "Odoo username to use when connecting to Odoo in "
"JSON-RPC. Default = demo"}, "JSON-RPC. Default = demo"},
{'names': ('-w', '--password'), 'dest': 'password', 'type': 'string', {'names': ('-w', '--password'), 'dest': 'password', 'type': 'string',
'action': 'store', 'default': 'demo', 'action': 'store', 'default': 'demo',
'help': "Password of the OpenERP user. Default = 'demo'"},
'help': "Password of the Odoo user. Default = 'demo'"},
{'names': ('-a', '--ascii'), 'dest': 'ascii', {'names': ('-a', '--ascii'), 'dest': 'ascii',
'action': 'store_true', 'default': False, 'action': 'store_true', 'default': False,
'help': "Convert name from UTF-8 to ASCII. Default = no, keep UTF-8"}, 'help': "Convert name from UTF-8 to ASCII. Default = no, keep UTF-8"},
{'names': ('-n', '--notify'), 'dest': 'notify', {'names': ('-n', '--notify'), 'dest': 'notify',
'action': 'store_true', 'default': False, 'action': 'store_true', 'default': False,
'help': "Notify OpenERP users via a pop-up (requires the OpenERP "
'help': "Notify Odoo users via a pop-up (requires the Odoo "
"module 'base_phone_popup'). If you use this option, you must pass " "module 'base_phone_popup'). If you use this option, you must pass "
"the logins of the OpenERP users to notify as argument to the "
"the logins of the Odoo users to notify as argument to the "
"script. Default = no"}, "script. Default = no"},
{'names': ('-g', '--geoloc'), 'dest': 'geoloc', {'names': ('-g', '--geoloc'), 'dest': 'geoloc',
'action': 'store_true', 'default': False, 'action': 'store_true', 'default': False,
'help': "Try to geolocate phone numbers unknown to OpenERP. This "
'help': "Try to geolocate phone numbers unknown to Odoo. This "
"features requires the 'phonenumbers' Python lib. To install it, " "features requires the 'phonenumbers' Python lib. To install it, "
"run 'sudo pip install phonenumbers' Default = no"}, "run 'sudo pip install phonenumbers' Default = no"},
{'names': ('-l', '--geoloc-lang'), 'dest': 'lang', 'type': 'string', {'names': ('-l', '--geoloc-lang'), 'dest': 'lang', 'type': 'string',
@ -267,7 +266,7 @@ def main(options, arguments):
else: else:
# If we already have a "True" caller ID name # If we already have a "True" caller ID name
# i.e. not just digits, but a real name, then we don't try to # i.e. not just digits, but a real name, then we don't try to
# connect to OpenERP or geoloc, we just keep it
# connect to Odoo or geoloc, we just keep it
if ( if (
stdinput.get('agi_calleridname') and stdinput.get('agi_calleridname') and
not stdinput.get('agi_calleridname').isdigit() and not stdinput.get('agi_calleridname').isdigit() and
@ -309,12 +308,12 @@ def main(options, arguments):
method = 'get_name_from_phone_number' method = 'get_name_from_phone_number'
res = False res = False
# Yes, this script can be used without "-s openerp_server" !
# Yes, this script can be used without "-s odoo_server" !
if options.server and options.jsonrpc: if options.server and options.jsonrpc:
import odoorpc import odoorpc
proto = options.ssl and 'jsonrpc+ssl' or 'jsonrpc' proto = options.ssl and 'jsonrpc+ssl' or 'jsonrpc'
stdout_write( stdout_write(
'VERBOSE "Starting %s request on OpenERP %s:%d database '
'VERBOSE "Starting %s request on Odoo %s:%d database '
'%s username %s"\n' % ( '%s username %s"\n' % (
proto.upper(), options.server, options.port, options.database, proto.upper(), options.server, options.port, options.database,
options.username)) options.username))
@ -329,11 +328,11 @@ def main(options, arguments):
stdout_write('VERBOSE "Called method %s"\n' % method) stdout_write('VERBOSE "Called method %s"\n' % method)
except: except:
stdout_write( stdout_write(
'VERBOSE "Could not connect to OpenERP in JSON-RPC"\n')
'VERBOSE "Could not connect to Odoo in JSON-RPC"\n')
elif options.server: elif options.server:
proto = options.ssl and 'https' or 'http' proto = options.ssl and 'https' or 'http'
stdout_write( stdout_write(
'VERBOSE "Starting %s XML-RPC request on OpenERP %s:%d '
'VERBOSE "Starting %s XML-RPC request on Odoo %s:%d '
'database %s user ID %d"\n' % ( 'database %s user ID %d"\n' % (
proto, options.server, options.port, options.database, proto, options.server, options.port, options.database,
options.userid)) options.userid))
@ -351,7 +350,7 @@ def main(options, arguments):
'phone.common', method, phone_number) 'phone.common', method, phone_number)
stdout_write('VERBOSE "Called method %s"\n' % method) stdout_write('VERBOSE "Called method %s"\n' % method)
except: except:
stdout_write('VERBOSE "Could not connect to OpenERP in XML-RPC"\n')
stdout_write('VERBOSE "Could not connect to Odoo in XML-RPC"\n')
# To simulate a long execution of the XML-RPC request # To simulate a long execution of the XML-RPC request
# import time # import time
# time.sleep(5) # time.sleep(5)
@ -361,16 +360,16 @@ def main(options, arguments):
if len(res) > options.max_size: if len(res) > options.max_size:
res = res[0:options.max_size] res = res[0:options.max_size]
elif options.geoloc: elif options.geoloc:
# if the number is not found in OpenERP, we try to geolocate
# if the number is not found in Odoo, we try to geolocate
stdout_write( stdout_write(
'VERBOSE "Trying to geolocate with country %s and lang %s"\n' 'VERBOSE "Trying to geolocate with country %s and lang %s"\n'
% (options.country, options.lang)) % (options.country, options.lang))
res = geolocate_phone_number( res = geolocate_phone_number(
phone_number, options.country, options.lang) phone_number, options.country, options.lang)
else: else:
# if the number is not found in OpenERP and geoloc is off,
# if the number is not found in Odoo and geoloc is off,
# we put 'not_found_name' as Name # we put 'not_found_name' as Name
stdout_write('VERBOSE "Phone number not found in OpenERP"\n')
stdout_write('VERBOSE "Phone number not found in Odoo"\n')
res = not_found_name res = not_found_name
# All SIP phones should support UTF-8... # All SIP phones should support UTF-8...
@ -387,12 +386,13 @@ def main(options, arguments):
stdout_write('SET CALLERID "%s"<%s>\n' % (res, phone_number)) stdout_write('SET CALLERID "%s"<%s>\n' % (res, phone_number))
return True return True
if __name__ == '__main__': if __name__ == '__main__':
usage = "Usage: get_name_agi.py [options] login1 login2 login3 ..." usage = "Usage: get_name_agi.py [options] login1 login2 login3 ..."
epilog = "Script written by Alexis de Lattre. " epilog = "Script written by Alexis de Lattre. "
"Published under the GNU AGPL licence." "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 "
description = "This is an AGI script that sends a query to Odoo. "
"It can also be used without Odoo to geolocate phone numbers "
"of incoming calls." "of incoming calls."
parser = OptionParser(usage=usage, epilog=epilog, description=description) parser = OptionParser(usage=usage, epilog=epilog, description=description)
for option in options: for option in options:

2
asterisk_click2dial/scripts/set_name_incoming_timeout.sh

@ -29,4 +29,4 @@
PATH=/usr/local/sbin:/usr/local/bin:/var/lib/asterisk/agi-bin:/sbin:/bin:/usr/sbin:/usr/bin:/usr/share/asterisk/agi-bin:. PATH=/usr/local/sbin:/usr/local/bin:/var/lib/asterisk/agi-bin:/sbin:/bin:/usr/sbin:/usr/bin:/usr/share/asterisk/agi-bin:.
timeout 2s set_name_agi.py --server openerp.mycompany.com --database erp_prod --user-id 12 --password "thepasswd" --geoloc --geoloc-country "FR" --geoloc-lang "fr"
timeout 2s set_name_agi.py --server odoo.mycompany.com --database erp_prod --user-id 12 --password "thepasswd" --geoloc --geoloc-country "FR" --geoloc-lang "fr"

2
asterisk_click2dial/scripts/set_name_outgoing_timeout.sh

@ -29,4 +29,4 @@
PATH=/usr/local/sbin:/usr/local/bin:/var/lib/asterisk/agi-bin:/sbin:/bin:/usr/sbin:/usr/bin:/usr/share/asterisk/agi-bin:. PATH=/usr/local/sbin:/usr/local/bin:/var/lib/asterisk/agi-bin:/sbin:/bin:/usr/sbin:/usr/bin:/usr/share/asterisk/agi-bin:.
timeout 2s set_name_agi.py --server openerp.mycompany.com --database erp_prod --user-id 12 --password "thepasswd" --outgoing --outgoing-agi-variable extension
timeout 2s set_name_agi.py --server odoo.mycompany.com --database erp_prod --user-id 12 --password "thepasswd" --outgoing --outgoing-agi-variable extension

25
asterisk_click2dial/static/src/js/asterisk_click2dial.js

@ -5,8 +5,7 @@
odoo.define('asterisk_click2dial.click2dial', function (require) { odoo.define('asterisk_click2dial.click2dial', function (require) {
"use strict"; "use strict";
var UserMenu = require('web.UserMenu');
var WebClient = require('web.WebClient');
var SystrayMenu = require('web.SystrayMenu');
var web_client = require('web.web_client'); var web_client = require('web.web_client');
var Widget = require('web.Widget'); var Widget = require('web.Widget');
var core = require('web.core'); var core = require('web.core');
@ -14,12 +13,13 @@ var _t = core._t;
var click2dial = {}; var click2dial = {};
click2dial.OpenCaller = Widget.extend({
var click2dialOpenCaller = Widget.extend({
template: 'asterisk_click2dial.OpenCaller', template: 'asterisk_click2dial.OpenCaller',
events: {
'click': 'on_open_caller',
},
start: function () { start: function () {
this.$('#asterisk-open-caller').on(
'click', this.on_open_caller);
this._super(); this._super();
}, },
@ -56,9 +56,9 @@ click2dial.OpenCaller = Widget.extend({
} }
else if (typeof r == 'object' && r.length == 3) { else if (typeof r == 'object' && r.length == 3) {
self.do_notify( // Not working
self.do_notify(
_t('Success'), _t('Success'),
_t('Moving to %s ID %d', r[0], r[1]),
_.str.sprintf(_t('Moving to %s ID %d'), r[0], r[1]),
false); false);
var action = { var action = {
type: 'ir.actions.act_window', type: 'ir.actions.act_window',
@ -82,15 +82,6 @@ click2dial.OpenCaller = Widget.extend({
}, },
}); });
UserMenu.include({
do_update: function(){
this._super.apply(this, arguments);
this.update_promise.then(function() {
var asterisk_button = new click2dial.OpenCaller();
// attach the phone logo/button to the systray
asterisk_button.appendTo($('.oe_systray'));
});
},
});
SystrayMenu.Items.push(click2dialOpenCaller);
}); });

4
asterisk_click2dial/static/src/xml/asterisk_click2dial.xml

@ -16,8 +16,8 @@
<!-- Add Dial button in phone widget for click2dial feature --> <!-- Add Dial button in phone widget for click2dial feature -->
<t t-extend="FieldPhone"> <t t-extend="FieldPhone">
<t t-jquery="a.oe_form_uri" t-operation="after">
<a id="click2dial" href="#" class="oe_bold"/>
<t t-jquery="a.o_form_uri" t-operation="after">
<a t-if="widget.clickable" id="click2dial" href="#" class="oe_bold"/>
</t> </t>
</t> </t>

3
asterisk_click2dial/asterisk_server_view.xml → asterisk_click2dial/views/asterisk_server.xml

@ -5,7 +5,7 @@
--> -->
<odoo> <odoo>
<data>
<record id="view_asterisk_server_search" model="ir.ui.view"> <record id="view_asterisk_server_search" model="ir.ui.view">
<field name="name">asterisk.server.search</field> <field name="name">asterisk.server.search</field>
@ -83,5 +83,4 @@
<menuitem action="action_asterisk_server" id="act_menu_ast_server" parent="base_phone.menu_config_phone" sequence="50"/> <menuitem action="action_asterisk_server" id="act_menu_ast_server" parent="base_phone.menu_config_phone" sequence="50"/>
</data>
</odoo> </odoo>

3
asterisk_click2dial/res_users_view.xml → asterisk_click2dial/views/res_users.xml

@ -7,7 +7,7 @@
--> -->
<odoo> <odoo>
<data>
<record id="view_users_form" model="ir.ui.view"> <record id="view_users_form" model="ir.ui.view">
<field name="name">asterisk_click2dial.res.users.form</field> <field name="name">asterisk_click2dial.res.users.form</field>
@ -47,5 +47,4 @@
</record> </record>
</data>
</odoo> </odoo>

2
asterisk_click2dial/web_asterisk_click2dial.xml

@ -5,7 +5,6 @@
--> -->
<odoo> <odoo>
<data>
<template id="assets_backend" name="asterisk_click2dial assets" <template id="assets_backend" name="asterisk_click2dial assets"
inherit_id="web.assets_backend"> inherit_id="web.assets_backend">
@ -15,5 +14,4 @@
</xpath> </xpath>
</template> </template>
</data>
</odoo> </odoo>

8
base_phone/common.py

@ -42,12 +42,16 @@ def convert_all_phone_fields(self, vals, fields_to_convert):
country = False country = False
if country_key: if country_key:
if country_key in loc_vals: if country_key in loc_vals:
country = self.env['res.country'].browse(vals[country_key])
# Warning: when we edit or create a partner from the
# POS frontend vals[country_key] is a string !
country = self.env['res.country'].browse(
int(vals[country_key]))
else: else:
country = self[country_key] country = self[country_key]
if partner_key and not country: if partner_key and not country:
if partner_key in loc_vals: if partner_key in loc_vals:
partner = self.env['res.partner'].browse(vals[partner_key])
partner = self.env['res.partner'].browse(
int(vals[partner_key]))
else: else:
partner = self[partner_key] partner = self[partner_key]
if partner: if partner:

16
base_phone/controllers/main.py

@ -19,15 +19,13 @@
# #
############################################################################## ##############################################################################
import odoo
from odoo import http
class BasePhoneController(odoo.http.Controller):
@odoo.http.route('/base_phone', type='json', auth='none')
def click2dial(self, req, phone_number, click2dial_model, click2dial_id):
res = req.session.model('phone.common').click2dial(
phone_number, {
'click2dial_model': click2dial_model,
'click2dial_id': click2dial_id,
})
class BasePhoneController(http.Controller):
@http.route('/base_phone/click2dial', type='json', auth='user')
def click2dial(self, phone_number, click2dial_model, click2dial_id):
res = http.request.env['phone.common'].with_context(
click2dial_model=click2dial_model,
click2dial_id=click2dial_id).click2dial(phone_number)
return res return res

1
base_phone/models/__init__.py

@ -4,3 +4,4 @@ from . import base
from . import res_company from . import res_company
from . import res_partner from . import res_partner
from . import phone_common from . import phone_common
from . import ir_fields_converter

17
base_phone/models/ir_fields_converter.py

@ -0,0 +1,17 @@
# -*- coding: utf-8 -*-
# © 2016 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import models, api
class IrFieldsConverter(models.AbstractModel):
_inherit = 'ir.fields.converter'
@api.model
def _str_to_phone(self, model, field, value):
return super(IrFieldsConverter, self)._str_to_char(model, field, value)
@api.model
def _str_to_fax(self, model, field, value):
return super(IrFieldsConverter, self)._str_to_char(model, field, value)

4
base_phone/static/src/js/phone_widget.js

@ -49,9 +49,9 @@ odoo.define('base_phone.phone_widget', function (require) {
if (phone_num && !this.options.dial_button_invisible) { if (phone_num && !this.options.dial_button_invisible) {
click2dial_text = _t('Dial'); click2dial_text = _t('Dial');
} }
this.$el.find('#click2dial').off('click');
this.$el.find('#click2dial')
this.$el.filter('#click2dial')
.text(click2dial_text) .text(click2dial_text)
.attr('href', '#')
.on('click', function(ev) { .on('click', function(ev) {
self.do_notify( self.do_notify(
_t('Click2dial started'), _t('Click2dial started'),

18
base_phone/static/src/xml/phone.xml

@ -7,12 +7,22 @@
<templates id="template" xml:space="preserve"> <templates id="template" xml:space="preserve">
<t t-name="FieldFax">
<t t-call="FieldEmail"/>
<t t-name="FieldFax" t-extend="FieldEmail">
<t t-jquery="span" t-operation="replace">
<t t-if="widget.get('effective_readonly')">
<a t-if="widget.clickable" class="o_form_uri o_text_overflow" href="#" target="_blank"/>
<span t-if="!widget.clickable" class="o_text_overflow"/>
</t>
</t>
</t> </t>
<t t-name="FieldPhone">
<t t-call="FieldFax"/>
<t t-name="FieldPhone" t-extend="FieldFax">
<t t-jquery="span" t-operation="replace">
<t t-if="widget.get('effective_readonly')">
<a t-if="widget.clickable" class="o_form_uri o_text_overflow" href="#" target="_blank"/>
<span t-if="!widget.clickable" class="o_text_overflow"/>
</t>
</t>
</t> </t>
</templates> </templates>

16
base_phone/tests/test_phone.py

@ -8,7 +8,8 @@ class TestPhone(TransactionCase):
def test_phone(self): def test_phone(self):
company = self.env.ref('base.main_company') company = self.env.ref('base.main_company')
company.country_id = self.env.ref('base.fr').id
fr_country_id = self.env.ref('base.fr').id
company.country_id = fr_country_id
rpo = self.env['res.partner'] rpo = self.env['res.partner']
# Create an existing partner without country # Create an existing partner without country
partner1 = rpo.create({ partner1 = rpo.create({
@ -40,7 +41,7 @@ class TestPhone(TransactionCase):
# Write on an existing partner with country at the same time # Write on an existing partner with country at the same time
agrolait.write({ agrolait.write({
'fax': '04 72 89 32 43', 'fax': '04 72 89 32 43',
'country_id': self.env.ref('base.fr').id,
'country_id': fr_country_id,
}) })
self.assertEquals(agrolait.fax, u'+33 4 72 89 32 43') self.assertEquals(agrolait.fax, u'+33 4 72 89 32 43')
# Write an invalid phone number # Write an invalid phone number
@ -52,3 +53,14 @@ class TestPhone(TransactionCase):
self.assertEquals(name, 'Pierre Paillet') self.assertEquals(name, 'Pierre Paillet')
name2 = pco.get_name_from_phone_number('0041216191010') name2 = pco.get_name_from_phone_number('0041216191010')
self.assertEquals(name2, u'Joël Grand-Guillaume (Camptocamp)') self.assertEquals(name2, u'Joël Grand-Guillaume (Camptocamp)')
# Test against the POS bug
# https://github.com/OCA/connector-telephony/issues/113
# When we edit/create a partner from the POS,
# the country_id key in create(vals) is given as a string !
partnerpos = rpo.create({
'name': u'POS customer',
'phone': '04-72-08-87-42',
'country_id': str(fr_country_id),
})
self.assertEquals(partnerpos.phone, u'+33 4 72 08 87 42')
self.assertEquals(partnerpos.country_id.id, fr_country_id)

2
base_phone/wizard/number_not_found.py

@ -29,7 +29,7 @@ class NumberNotFound(models.TransientModel):
number_type = fields.Selection(selection=[ number_type = fields.Selection(selection=[
('phone', 'Fixed'), ('phone', 'Fixed'),
('mobile', 'Mobile') ('mobile', 'Mobile')
], string='Fixed/Mobile', required=True)
], string='Fixed/Mobile', required=True)
to_update_partner_id = fields.Many2one( to_update_partner_id = fields.Many2one(
comodel_name='res.partner', string='Partner to Update', comodel_name='res.partner', string='Partner to Update',
help="Partner on which the phone number will be written") help="Partner on which the phone number will be written")

3
crm_claim_phone/__init__.py

@ -1,3 +0,0 @@
# -*- coding: utf-8 -*-
from . import crm_claim_phone

50
crm_claim_phone/__manifest__.py

@ -1,50 +0,0 @@
# -*- encoding: utf-8 -*-
##############################################################################
#
# CRM Claim Phone module for Odoo/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': 'CRM Claim Phone',
'version': '8.0.0.1.0',
'category': 'Phone',
'license': 'AGPL-3',
'summary': 'Validate phone numbers in CRM Claims',
'description': """
CRM Claims Phone
================
This module validate phone numbers in the CRM Claim module, just like the
*base_phone* module valide phone numbers in the Partner form. Please refer to
the description of the *base_phone* module for more information.
This module is independant from the Asterisk connector.
Please contact Alexis de Lattre from Akretion <alexis.delattre@akretion.com>
for any help or question about this module.
""",
'author': "Akretion,Odoo Community Association (OCA)",
'website': 'http://www.akretion.com/',
'depends': ['base_phone', 'crm_claim'],
'data': ['crm_claim_view.xml'],
'images': [],
'installable': False,
'auto_install': True,
'active': False,
}

12
crm_claim_phone/crm_claim_phone.py

@ -1,12 +0,0 @@
# -*- coding: utf-8 -*-
# © 2012-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
from openerp.addons.base_phone.fields import Phone
class CrmClaim(models.Model):
_inherit = 'crm.claim'
partner_phone = Phone(partner_field='partner_id')

22
crm_claim_phone/crm_claim_view.xml

@ -1,22 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
© 2014-2016 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>)
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
-->
<odoo>
<data>
<record id="crm_case_claims_form_view" model="ir.ui.view">
<field name="name">crm_claim_phone.crm_claim.form</field>
<field name="model">crm.claim</field>
<field name="inherit_id" ref="crm_claim.crm_case_claims_form_view"/>
<field name="arch" type="xml">
<field name="partner_phone" position="attributes">
<attribute name="widget">phone</attribute>
</field>
</field>
</record>
</data>
</odoo>

2
crm_phone/__init__.py

@ -1,4 +1,4 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from . import crm_phone
from . import models
from . import wizard from . import wizard

5
crm_phone/__manifest__.py

@ -4,7 +4,7 @@
{ {
'name': 'CRM Phone', 'name': 'CRM Phone',
'version': '9.0.1.0.0',
'version': '10.0.1.0.0',
'category': 'Phone', 'category': 'Phone',
'license': 'AGPL-3', 'license': 'AGPL-3',
'summary': 'Validate phone numbers in CRM', 'summary': 'Validate phone numbers in CRM',
@ -24,6 +24,7 @@ for any help or question about this module.
'author': "Akretion,Odoo Community Association (OCA)", 'author': "Akretion,Odoo Community Association (OCA)",
'website': 'http://www.akretion.com/', 'website': 'http://www.akretion.com/',
'depends': ['base_phone', 'crm'], 'depends': ['base_phone', 'crm'],
'external_dependencies': {'python': ['phonenumbers']},
'conflicts': ['crm_voip'], 'conflicts': ['crm_voip'],
'data': [ 'data': [
'security/phonecall_security.xml', 'security/phonecall_security.xml',
@ -36,6 +37,6 @@ for any help or question about this module.
'wizard/create_crm_phonecall_view.xml', 'wizard/create_crm_phonecall_view.xml',
], ],
'demo': ['demo/crm_phonecall.xml'], 'demo': ['demo/crm_phonecall.xml'],
'installable': False,
'installable': True,
'auto_install': True, 'auto_install': True,
} }

4
crm_phone/demo/crm_phonecall.xml

@ -1,6 +1,5 @@
<?xml version="1.0"?> <?xml version="1.0"?>
<odoo>
<data noupdate="1">
<odoo noupdate="1">
<record id="crm_phonecall1" model="crm.phonecall"> <record id="crm_phonecall1" model="crm.phonecall">
@ -55,5 +54,4 @@
</data>
</odoo> </odoo>

7
crm_phone/models/__init__.py

@ -0,0 +1,7 @@
# -*- coding: utf-8 -*-
from . import crm_phonecall
from . import crm_lead
from . import res_partner
from . import res_users
from . import phone_common

49
crm_phone/models/crm_lead.py

@ -0,0 +1,49 @@
# -*- coding: utf-8 -*-
# © 2012-2016 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import models, fields, api
from odoo.addons.base_phone.fields import Phone, Fax
class CrmLead(models.Model):
_inherit = 'crm.lead'
_phone_name_sequence = 20
phone = Phone(country_field='country_id', partner_field='partner_id')
mobile = Phone(country_field='country_id', partner_field='partner_id')
fax = Fax(country_field='country_id', partner_field='partner_id')
phonecall_ids = fields.One2many(
'crm.phonecall', 'opportunity_id', string='Phone Calls')
phonecall_count = fields.Integer(
compute='_count_phonecalls', string='Number of Phonecalls',
readonly=True)
@api.multi
def name_get(self):
if self._context.get('callerid'):
res = []
for lead in self:
if lead.partner_name and lead.contact_name:
name = u'%s (%s)' % (lead.contact_name, lead.partner_name)
elif lead.partner_name:
name = lead.partner_name
elif lead.contact_name:
name = lead.contact_name
else:
name = lead.name
res.append((lead.id, name))
return res
else:
return super(CrmLead, self).name_get()
@api.multi
@api.depends('phonecall_ids')
def _count_phonecalls(self):
cpo = self.env['crm.phonecall']
for lead in self:
try:
lead.phonecall_count = cpo.search_count(
[('opportunity_id', '=', lead.id)])
except:
lead.phonecall_count = 0

96
crm_phone/crm_phone.py → crm_phone/models/crm_phonecall.py

@ -2,51 +2,8 @@
# © 2012-2016 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>) # © 2012-2016 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from openerp import models, fields, api, _
from openerp.addons.base_phone.fields import Phone
class CrmLead(models.Model):
_inherit = 'crm.lead'
_phone_name_sequence = 20
phone = Phone(country_field='country_id', partner_field='partner_id')
mobile = Phone(country_field='country_id', partner_field='partner_id')
fax = Phone(country_field='country_id', partner_field='partner_id')
phonecall_ids = fields.One2many(
'crm.phonecall', 'opportunity_id', string='Phone Calls')
phonecall_count = fields.Integer(
compute='_count_phonecalls', string='Number of Phonecalls',
readonly=True)
@api.multi
def name_get(self):
if self._context.get('callerid'):
res = []
for lead in self:
if lead.partner_name and lead.contact_name:
name = u'%s (%s)' % (lead.contact_name, lead.partner_name)
elif lead.partner_name:
name = lead.partner_name
elif lead.contact_name:
name = lead.contact_name
else:
name = lead.name
res.append((lead.id, name))
return res
else:
return super(CrmLead, self).name_get()
@api.multi
@api.depends('phonecall_ids')
def _count_phonecalls(self):
cpo = self.env['crm.phonecall']
for lead in self:
try:
lead.phonecall_count = cpo.search_count(
[('opportunity_id', '=', lead.id)])
except:
lead.phonecall_count = 0
from odoo import models, fields, api, _
from odoo.addons.base_phone.fields import Phone
class CrmPhonecall(models.Model): class CrmPhonecall(models.Model):
@ -134,52 +91,3 @@ class CrmPhonecall(models.Model):
'context': ctx, 'context': ctx,
} }
return action return action
class ResPartner(models.Model):
_inherit = 'res.partner'
phonecall_ids = fields.One2many(
'crm.phonecall', 'partner_id', string='Phone Calls')
phonecall_count = fields.Integer(
compute='_count_phonecalls', string='Number of Phonecalls',
readonly=True)
@api.multi
@api.depends('phonecall_ids')
def _count_phonecalls(self):
cpo = self.env['crm.phonecall']
for partner in self:
try:
partner.phonecall_count = cpo.search_count(
[('partner_id', 'child_of', partner.id)])
except:
partner.phonecall_count = 0
class ResUsers(models.Model):
_inherit = "res.users"
# Field name starts with 'context_' to allow modification by the user
# in his preferences, cf server/openerp/addons/base/res/res_users.py
# in "def write()" of "class res_users(osv.osv)"
context_propose_creation_crm_call = fields.Boolean(
string='Propose to create a call in CRM after a click2dial',
default=True)
class PhoneCommon(models.AbstractModel):
_inherit = 'phone.common'
@api.model
def click2dial(self, erp_number):
res = super(PhoneCommon, self).click2dial(erp_number)
if (
self.env.user.context_propose_creation_crm_call and
self.env.context.get('click2dial_model')
in ('res.partner', 'crm.lead')):
res.update({
'action_name': _('Create Call in CRM'),
'action_model': 'wizard.create.crm.phonecall',
})
return res

22
crm_phone/models/phone_common.py

@ -0,0 +1,22 @@
# -*- coding: utf-8 -*-
# © 2012-2016 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import models, api, _
class PhoneCommon(models.AbstractModel):
_inherit = 'phone.common'
@api.model
def click2dial(self, erp_number):
res = super(PhoneCommon, self).click2dial(erp_number)
if (
self.env.user.context_propose_creation_crm_call and
self.env.context.get('click2dial_model')
in ('res.partner', 'crm.lead')):
res.update({
'action_name': _('Create Call in CRM'),
'action_model': 'wizard.create.crm.phonecall',
})
return res

26
crm_phone/models/res_partner.py

@ -0,0 +1,26 @@
# -*- coding: utf-8 -*-
# © 2012-2016 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import models, fields, api
class ResPartner(models.Model):
_inherit = 'res.partner'
phonecall_ids = fields.One2many(
'crm.phonecall', 'partner_id', string='Phone Calls')
phonecall_count = fields.Integer(
compute='_count_phonecalls', string='Number of Phonecalls',
readonly=True)
@api.multi
@api.depends('phonecall_ids')
def _count_phonecalls(self):
cpo = self.env['crm.phonecall']
for partner in self:
try:
partner.phonecall_count = cpo.search_count(
[('partner_id', 'child_of', partner.id)])
except:
partner.phonecall_count = 0

16
crm_phone/models/res_users.py

@ -0,0 +1,16 @@
# -*- coding: utf-8 -*-
# © 2012-2016 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import models, fields
class ResUsers(models.Model):
_inherit = "res.users"
# Field name starts with 'context_' to allow modification by the user
# in his preferences, cf odoo/odoo/addons/base/res/res_users.py
# in "def write()" of "class res_users(osv.osv)"
context_propose_creation_crm_call = fields.Boolean(
string='Propose to create a call in CRM after a click2dial',
default=True)

4
crm_phone/security/ir.model.access.csv

@ -1,5 +1,5 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
callerid_crm_lead_read,Read access on crm.lead,crm.model_crm_lead,base_phone.group_callerid,1,0,0,0 callerid_crm_lead_read,Read access on crm.lead,crm.model_crm_lead,base_phone.group_callerid,1,0,0,0
access_crm_phonecall_partner_manager,Full access on crm.phonecall to Contact mgr,model_crm_phonecall,base.group_partner_manager,1,1,1,1 access_crm_phonecall_partner_manager,Full access on crm.phonecall to Contact mgr,model_crm_phonecall,base.group_partner_manager,1,1,1,1
access_crm_phonecall_sale_manager,Full access on crm.phonecall to Sale mgr,model_crm_phonecall,base.group_sale_manager,1,1,1,1
access_crm_phonecall_sale_user,Read/Write/Create access on crm.phonecall to Sale users,model_crm_phonecall,base.group_sale_salesman,1,1,1,0
access_crm_phonecall_sale_manager,Full access on crm.phonecall to Sale mgr,model_crm_phonecall,sales_team.group_sale_manager,1,1,1,1
access_crm_phonecall_sale_user,Read/Write/Create access on crm.phonecall to Sale users,model_crm_phonecall,sales_team.group_sale_salesman,1,1,1,0

8
crm_phone/security/phonecall_security.xml

@ -1,19 +1,18 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<odoo>
<data noupdate="1">
<odoo noupdate="1">
<record id="my_crm_phonecall_rule" model="ir.rule"> <record id="my_crm_phonecall_rule" model="ir.rule">
<field name="name">Personal Phone Calls</field> <field name="name">Personal Phone Calls</field>
<field name="model_id" ref="model_crm_phonecall"/> <field name="model_id" ref="model_crm_phonecall"/>
<field name="groups" eval="[(4, ref('base.group_sale_salesman'))]"/>
<field name="groups" eval="[(4, ref('sales_team.group_sale_salesman'))]"/>
<field name="domain_force">['|', ('user_id', '=', False), ('user_id', '=', user.id)]</field> <field name="domain_force">['|', ('user_id', '=', False), ('user_id', '=', user.id)]</field>
</record> </record>
<record id="all_crm_phonecall_rule" model="ir.rule"> <record id="all_crm_phonecall_rule" model="ir.rule">
<field name="name">All Phone Calls</field> <field name="name">All Phone Calls</field>
<field name="model_id" ref="model_crm_phonecall"/> <field name="model_id" ref="model_crm_phonecall"/>
<field name="groups" eval="[(4, ref('base.group_sale_salesman_all_leads'))]"/>
<field name="groups" eval="[(4, ref('sales_team.group_sale_salesman_all_leads'))]"/>
<field name="domain_force">[(1, '=', 1)]</field> <field name="domain_force">[(1, '=', 1)]</field>
</record> </record>
@ -24,5 +23,4 @@
</record> </record>
</data>
</odoo> </odoo>

4
crm_phone/tests/test_crm_phone.py

@ -1,8 +1,8 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# © 2016 Akretion France (Alexis de Lattre <alexis.delattre@akretion.com>) # © 2016 Akretion France (Alexis de Lattre <alexis.delattre@akretion.com>)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from openerp.tests.common import TransactionCase
from odoo.tests.common import TransactionCase
class TestCRMPhone(TransactionCase): class TestCRMPhone(TransactionCase):

25
crm_phone/view/crm_lead.xml

@ -5,7 +5,6 @@
--> -->
<odoo> <odoo>
<data>
<record id="crm_case_form_view_leads" model="ir.ui.view"> <record id="crm_case_form_view_leads" model="ir.ui.view">
@ -13,12 +12,6 @@
<field name="model">crm.lead</field> <field name="model">crm.lead</field>
<field name="inherit_id" ref="crm.crm_case_form_view_leads"/> <field name="inherit_id" ref="crm.crm_case_form_view_leads"/>
<field name="arch" type="xml"> <field name="arch" type="xml">
<field name="mobile" position="attributes">
<attribute name="widget">phone</attribute>
</field>
<field name="fax" position="attributes">
<attribute name="widget">fax</attribute>
</field>
<div name="button_box" position="inside"> <div name="button_box" position="inside">
<button class="oe_inline oe_stat_button" type="action" <button class="oe_inline oe_stat_button" type="action"
name="%(crm_phone.crm_phonecall_action)d" name="%(crm_phone.crm_phonecall_action)d"
@ -30,28 +23,11 @@
</field> </field>
</record> </record>
<record id="crm_case_tree_view_leads" model="ir.ui.view">
<field name="name">crm_phone.crm_lead.tree</field>
<field name="model">crm.lead</field>
<field name="inherit_id" ref="crm.crm_case_tree_view_leads"/>
<field name="arch" type="xml">
<field name="phone" position="attributes">
<attribute name="widget">phone</attribute>
</field>
</field>
</record>
<record id="crm_case_form_view_oppor" model="ir.ui.view"> <record id="crm_case_form_view_oppor" model="ir.ui.view">
<field name="name">crm_phone.case.view_opportuniy.form</field> <field name="name">crm_phone.case.view_opportuniy.form</field>
<field name="model">crm.lead</field> <field name="model">crm.lead</field>
<field name="inherit_id" ref="crm.crm_case_form_view_oppor"/> <field name="inherit_id" ref="crm.crm_case_form_view_oppor"/>
<field name="arch" type="xml"> <field name="arch" type="xml">
<field name="mobile" position="attributes">
<attribute name="widget">phone</attribute>
</field>
<field name="fax" position="attributes">
<attribute name="widget">fax</attribute>
</field>
<div name="button_box" position="inside"> <div name="button_box" position="inside">
<button class="oe_inline oe_stat_button" type="action" <button class="oe_inline oe_stat_button" type="action"
name="%(crm_phone.crm_phonecall_action)d" name="%(crm_phone.crm_phonecall_action)d"
@ -64,5 +40,4 @@
</record> </record>
</data>
</odoo> </odoo>

8
crm_phone/view/crm_phonecall.xml

@ -5,7 +5,6 @@
--> -->
<odoo> <odoo>
<data>
<record id="crm_phonecall_form" model="ir.ui.view"> <record id="crm_phonecall_form" model="ir.ui.view">
@ -33,8 +32,8 @@
<field name="date"/> <field name="date"/>
<field name="user_id"/> <field name="user_id"/>
<field name="partner_id"/> <field name="partner_id"/>
<field name="partner_phone" widget="phone"/>
<field name="partner_mobile" widget="phone"/>
<field name="partner_phone"/>
<field name="partner_mobile"/>
<field name="opportunity_id"/> <field name="opportunity_id"/>
</group> </group>
<group name="right"> <group name="right">
@ -127,7 +126,7 @@
</record> </record>
<menuitem id="crm_phonecall_menu" name="Phone Calls" <menuitem id="crm_phonecall_menu" name="Phone Calls"
parent="base.menu_base_partner" sequence="7" groups="base.group_sale_salesman"/>
parent="sales_team.menu_base_partner" sequence="7" groups="sales_team.group_sale_salesman"/>
<record id="crm_phonecall_action" model="ir.actions.act_window"> <record id="crm_phonecall_action" model="ir.actions.act_window">
<field name="name">Phone Calls</field> <field name="name">Phone Calls</field>
@ -156,5 +155,4 @@
parent="crm_phonecall_menu" sequence="20"/> parent="crm_phonecall_menu" sequence="20"/>
</data>
</odoo> </odoo>

4
crm_phone/view/res_partner.xml

@ -5,14 +5,13 @@
--> -->
<odoo> <odoo>
<data>
<record id="view_partner_form" model="ir.ui.view"> <record id="view_partner_form" model="ir.ui.view">
<field name="name">phonecall.res.partner.form</field> <field name="name">phonecall.res.partner.form</field>
<field name="model">res.partner</field> <field name="model">res.partner</field>
<field name="inherit_id" ref="base.view_partner_form"/> <field name="inherit_id" ref="base.view_partner_form"/>
<field name="groups_id" eval="[(4, ref('base.group_sale_salesman')), (4, ref('base.group_partner_manager'))]"/>
<field name="groups_id" eval="[(4, ref('sales_team.group_sale_salesman')), (4, ref('base.group_partner_manager'))]"/>
<field name="arch" type="xml"> <field name="arch" type="xml">
<div name="button_box" position="inside"> <div name="button_box" position="inside">
<button class="oe_inline oe_stat_button" type="action" <button class="oe_inline oe_stat_button" type="action"
@ -26,5 +25,4 @@
</record> </record>
</data>
</odoo> </odoo>

2
crm_phone/view/res_users.xml

@ -5,7 +5,6 @@
--> -->
<odoo> <odoo>
<data>
<!-- Add option on user form view --> <!-- Add option on user form view -->
<record id="view_users_form" model="ir.ui.view"> <record id="view_users_form" model="ir.ui.view">
@ -32,5 +31,4 @@
</field> </field>
</record> </record>
</data>
</odoo> </odoo>

10
crm_phone/wizard/create_crm_phonecall.py

@ -2,8 +2,14 @@
# © 2012-2016 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>) # © 2012-2016 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from openerp import models, api, _
import phonenumbers
from odoo import models, api, _
import logging
logger = logging.getLogger(__name__)
try:
import phonenumbers
except ImportError:
logger.debug('Cannot import phonenumbers lib.')
class WizardCreateCrmPhonecall(models.TransientModel): class WizardCreateCrmPhonecall(models.TransientModel):

11
crm_phone/wizard/create_crm_phonecall_view.xml

@ -1,12 +1,10 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<!-- <!--
Copyright (C) 2012-2013 Akretion (http://www.akretion.com)
@author: Alexis de Lattre <alexis.delattre@akretion.com>
The licence is in the file __openerp__.py
© 2012-2016 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>)
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
--> -->
<openerp>
<data>
<odoo>
<!-- Add button on the "Get partner from incoming phone call view" --> <!-- Add button on the "Get partner from incoming phone call view" -->
<record id="create_crm_phonecall_view" model="ir.ui.view"> <record id="create_crm_phonecall_view" model="ir.ui.view">
@ -32,5 +30,4 @@
</record> </record>
</data>
</openerp>
</odoo>

9
crm_phone/wizard/number_not_found.py

@ -2,8 +2,9 @@
# © 2010-2016 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>) # © 2010-2016 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from openerp import models, fields, api, _
from openerp.exceptions import UserError
from odoo import models, fields, api, _
from odoo.addons.base_phone.fields import Phone
from odoo.exceptions import UserError
class NumberNotFound(models.TransientModel): class NumberNotFound(models.TransientModel):
@ -13,10 +14,10 @@ class NumberNotFound(models.TransientModel):
'crm.lead', string='Lead to Update', 'crm.lead', string='Lead to Update',
domain=[('type', '=', 'lead')], domain=[('type', '=', 'lead')],
help="Lead on which the phone number will be written") help="Lead on which the phone number will be written")
current_lead_phone = fields.Char(
current_lead_phone = Phone(
related='to_update_lead_id.phone', string='Current Phone', related='to_update_lead_id.phone', string='Current Phone',
readonly=True) readonly=True)
current_lead_mobile = fields.Char(
current_lead_mobile = Phone(
related='to_update_lead_id.mobile', string='Current Mobile', related='to_update_lead_id.mobile', string='Current Mobile',
readonly=True) readonly=True)

7
crm_phone/wizard/number_not_found_view.xml

@ -5,7 +5,7 @@
--> -->
<odoo> <odoo>
<data>
<record id="number_not_found_form" model="ir.ui.view"> <record id="number_not_found_form" model="ir.ui.view">
<field name="name">crm_phone.number.not.found.form</field> <field name="name">crm_phone.number.not.found.form</field>
@ -19,9 +19,9 @@
string="Create Lead with this Number" type="object" string="Create Lead with this Number" type="object"
class="oe_highlight"/> class="oe_highlight"/>
<field name="to_update_lead_id"/> <field name="to_update_lead_id"/>
<field name="current_lead_phone" widget="phone"
<field name="current_lead_phone"
options="{'dial_button_invisible': True}"/> options="{'dial_button_invisible': True}"/>
<field name="current_lead_mobile" widget="phone"
<field name="current_lead_mobile"
options="{'dial_button_invisible': True}"/> options="{'dial_button_invisible': True}"/>
<button name="update_lead" colspan="2" <button name="update_lead" colspan="2"
string="Update Lead with this Number" type="object" string="Update Lead with this Number" type="object"
@ -32,5 +32,4 @@
</record> </record>
</data>
</odoo> </odoo>

2
event_phone/__init__.py

@ -1,3 +1,3 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from . import event_phone
from . import models

9
event_phone/__manifest__.py

@ -5,7 +5,7 @@
{ {
'name': 'Event Phone', 'name': 'Event Phone',
'version': '9.0.1.0.0',
'version': '10.0.1.0.0',
'category': 'Phone', 'category': 'Phone',
'license': 'AGPL-3', 'license': 'AGPL-3',
'summary': 'Validate phone numbers in Events', 'summary': 'Validate phone numbers in Events',
@ -25,10 +25,7 @@ for any help or question about this module.
'author': "Akretion,Odoo Community Association (OCA)", 'author': "Akretion,Odoo Community Association (OCA)",
'website': 'http://www.akretion.com/', 'website': 'http://www.akretion.com/',
'depends': ['base_phone', 'event'], 'depends': ['base_phone', 'event'],
'data': [
'security/ir.model.access.csv',
'event_view.xml',
],
'installable': False,
'data': ['security/ir.model.access.csv'],
'installable': True,
'auto_install': True, 'auto_install': True,
} }

24
event_phone/event_view.xml

@ -1,24 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
© 2014-2016 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>)
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl)
-->
<odoo>
<data>
<record id="view_event_registration_form" model="ir.ui.view">
<field name="name">event_phone.event_registration.form</field>
<field name="model">event.registration</field>
<field name="inherit_id" ref="event.view_event_registration_form"/>
<field name="arch" type="xml">
<field name="phone" position="attributes">
<attribute name="widget">phone</attribute>
</field>
</field>
</record>
</data>
</odoo>

3
event_phone/models/__init__.py

@ -0,0 +1,3 @@
# -*- coding: utf-8 -*-
from . import event_registration

4
event_phone/event_phone.py → event_phone/models/event_registration.py

@ -2,8 +2,8 @@
# © 2012-2016 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>) # © 2012-2016 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from openerp import models
from openerp.addons.base_phone.fields import Phone
from odoo import models
from odoo.addons.base_phone.fields import Phone
class EventRegistration(models.Model): class EventRegistration(models.Model):

2
hr_phone/__init__.py

@ -1,3 +1,3 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from . import hr_phone
from . import models

9
hr_phone/__manifest__.py

@ -4,7 +4,7 @@
{ {
'name': 'HR Phone', 'name': 'HR Phone',
'version': '9.0.1.0.0',
'version': '10.0.1.0.0',
'category': 'Phone', 'category': 'Phone',
'license': 'AGPL-3', 'license': 'AGPL-3',
'summary': 'Validate phone numbers in HR', 'summary': 'Validate phone numbers in HR',
@ -24,10 +24,7 @@ for any help or question about this module.
'author': "Akretion,Odoo Community Association (OCA)", 'author': "Akretion,Odoo Community Association (OCA)",
'website': 'http://www.akretion.com/', 'website': 'http://www.akretion.com/',
'depends': ['base_phone', 'hr'], 'depends': ['base_phone', 'hr'],
'data': [
'security/ir.model.access.csv',
'hr_view.xml',
],
'installable': False,
'data': ['security/ir.model.access.csv'],
'installable': True,
'auto_install': True, 'auto_install': True,
} }

49
hr_phone/hr_view.xml

@ -1,49 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
© 2014-2016 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>)
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
-->
<odoo>
<data>
<record id="view_employee_form" model="ir.ui.view">
<field name="name">hr_phone.hr_employee.form</field>
<field name="model">hr.employee</field>
<field name="inherit_id" ref="hr.view_employee_form"/>
<field name="arch" type="xml">
<field name="work_phone" position="attributes">
<attribute name="widget">phone</attribute>
</field>
<field name="mobile_phone" position="attributes">
<attribute name="widget">phone</attribute>
</field>
</field>
</record>
<record id="view_employee_tree" model="ir.ui.view">
<field name="name">hr_phone.hr_employee.tree</field>
<field name="model">hr.employee</field>
<field name="inherit_id" ref="hr.view_employee_tree"/>
<field name="arch" type="xml">
<field name="work_phone" position="attributes">
<attribute name="widget">phone</attribute>
</field>
</field>
</record>
<record id="view_partner_tree2" model="ir.ui.view">
<field name="name">hr_phone.hr.employee.tree2</field>
<field name="model">hr.employee</field>
<field name="inherit_id" ref="hr.view_partner_tree2"/>
<field name="arch" type="xml">
<field name="work_phone" position="attributes">
<attribute name="widget">phone</attribute>
</field>
</field>
</record>
</data>
</odoo>

3
hr_phone/models/__init__.py

@ -0,0 +1,3 @@
# -*- coding: utf-8 -*-
from . import hr_employee

4
hr_phone/hr_phone.py → hr_phone/models/hr_employee.py

@ -2,8 +2,8 @@
# © 2012-2016 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>) # © 2012-2016 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from openerp import models
from openerp.addons.base_phone.fields import Phone
from odoo import models
from odoo.addons.base_phone.fields import Phone
class HrEmployee(models.Model): class HrEmployee(models.Model):

2
hr_recruitment_phone/__init__.py

@ -1,3 +1,3 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from . import hr_recruitment_phone
from . import models

9
hr_recruitment_phone/__manifest__.py

@ -4,7 +4,7 @@
{ {
'name': 'HR Recruitment Phone', 'name': 'HR Recruitment Phone',
'version': '9.0.1.0.0',
'version': '10.0.1.0.0',
'category': 'Phone', 'category': 'Phone',
'license': 'AGPL-3', 'license': 'AGPL-3',
'summary': 'Validate phone numbers in HR Recruitment', 'summary': 'Validate phone numbers in HR Recruitment',
@ -24,10 +24,7 @@ for any help or question about this module.
'author': "Akretion,Odoo Community Association (OCA)", 'author': "Akretion,Odoo Community Association (OCA)",
'website': 'http://www.akretion.com/', 'website': 'http://www.akretion.com/',
'depends': ['base_phone', 'hr_recruitment'], 'depends': ['base_phone', 'hr_recruitment'],
'data': [
'security/ir.model.access.csv',
'hr_recruitment_view.xml',
],
'installable': False,
'data': ['security/ir.model.access.csv'],
'installable': True,
'auto_install': True, 'auto_install': True,
} }

38
hr_recruitment_phone/hr_recruitment_view.xml

@ -1,38 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
© 2014-2016 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>)
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl)
-->
<odoo>
<data>
<record id="crm_case_form_view_job" model="ir.ui.view">
<field name="name">hr_recruitment_phone.hr_applicant.form</field>
<field name="model">hr.applicant</field>
<field name="inherit_id" ref="hr_recruitment.crm_case_form_view_job"/>
<field name="arch" type="xml">
<field name="partner_phone" position="attributes">
<attribute name="widget">phone</attribute>
</field>
<field name="partner_mobile" position="attributes">
<attribute name="widget">phone</attribute>
</field>
</field>
</record>
<record id="crm_case_tree_view_job" model="ir.ui.view">
<field name="name">hr_recruitment_phone.hr_applicant.tree</field>
<field name="model">hr.applicant</field>
<field name="inherit_id" ref="hr_recruitment.crm_case_tree_view_job"/>
<field name="arch" type="xml">
<field name="partner_phone" position="attributes">
<attribute name="widget">phone</attribute>
</field>
</field>
</record>
</data>
</odoo>

3
hr_recruitment_phone/models/__init__.py

@ -0,0 +1,3 @@
# -*- coding: utf-8 -*-
from . import hr_applicant

4
hr_recruitment_phone/hr_recruitment_phone.py → hr_recruitment_phone/models/hr_applicant.py

@ -2,8 +2,8 @@
# © 2012-2016 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>) # © 2012-2016 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from openerp import models, api
from openerp.addons.base_phone.fields import Phone
from odoo import models, api
from odoo.addons.base_phone.fields import Phone
class HrApplicant(models.Model): class HrApplicant(models.Model):

3
requirements.txt

@ -0,0 +1,3 @@
phonenumbers
py-Asterisk
SOAPpy
Loading…
Cancel
Save