updates
This commit is contained in:
7
voip_ringcentral/models/__init__.py
Normal file
7
voip_ringcentral/models/__init__.py
Normal file
@@ -0,0 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright 2026 Nexa Systems Inc.
|
||||
# License OPL-1 (Odoo Proprietary License v1.0)
|
||||
|
||||
from . import voip_provider
|
||||
from . import res_users_settings
|
||||
from . import res_users
|
||||
27
voip_ringcentral/models/res_users.py
Normal file
27
voip_ringcentral/models/res_users.py
Normal file
@@ -0,0 +1,27 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright 2026 Nexa Systems Inc.
|
||||
# License OPL-1 (Odoo Proprietary License v1.0)
|
||||
|
||||
from odoo import api, fields, models
|
||||
|
||||
|
||||
class ResUsers(models.Model):
|
||||
_inherit = 'res.users'
|
||||
|
||||
rc_authorization_id = fields.Char(
|
||||
string='RingCentral Authorization ID',
|
||||
compute='_compute_rc_authorization_id',
|
||||
inverse='_reflect_change_in_res_users_settings',
|
||||
groups='base.group_user',
|
||||
)
|
||||
|
||||
@api.depends('res_users_settings_id.rc_authorization_id')
|
||||
def _compute_rc_authorization_id(self):
|
||||
for user in self:
|
||||
user.rc_authorization_id = user.res_users_settings_id.rc_authorization_id
|
||||
|
||||
@api.model
|
||||
def _get_voip_user_configuration_fields(self):
|
||||
return super()._get_voip_user_configuration_fields() + [
|
||||
'rc_authorization_id',
|
||||
]
|
||||
11
voip_ringcentral/models/res_users_settings.py
Normal file
11
voip_ringcentral/models/res_users_settings.py
Normal file
@@ -0,0 +1,11 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright 2026 Nexa Systems Inc.
|
||||
# License OPL-1 (Odoo Proprietary License v1.0)
|
||||
|
||||
from odoo import fields, models
|
||||
|
||||
|
||||
class ResUsersSettings(models.Model):
|
||||
_inherit = 'res.users.settings'
|
||||
|
||||
rc_authorization_id = fields.Char('RingCentral Authorization ID')
|
||||
138
voip_ringcentral/models/voip_provider.py
Normal file
138
voip_ringcentral/models/voip_provider.py
Normal file
@@ -0,0 +1,138 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright 2026 Nexa Systems Inc.
|
||||
# License OPL-1 (Odoo Proprietary License v1.0)
|
||||
|
||||
import logging
|
||||
|
||||
from odoo import api, fields, models, _
|
||||
from odoo.exceptions import UserError
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class VoipProvider(models.Model):
|
||||
_inherit = 'voip.provider'
|
||||
|
||||
rc_client_id = fields.Char(
|
||||
string='RingCentral Client ID',
|
||||
groups='base.group_system',
|
||||
)
|
||||
rc_client_secret = fields.Char(
|
||||
string='RingCentral Client Secret',
|
||||
groups='base.group_system',
|
||||
)
|
||||
rc_jwt_token = fields.Char(
|
||||
string='RingCentral JWT Token',
|
||||
groups='base.group_system',
|
||||
)
|
||||
rc_server_url = fields.Char(
|
||||
string='RingCentral Server URL',
|
||||
default='https://platform.ringcentral.com',
|
||||
groups='base.group_system',
|
||||
)
|
||||
rc_device_id = fields.Char(
|
||||
string='RingCentral Device ID',
|
||||
readonly=True,
|
||||
groups='base.group_system',
|
||||
help='Device ID assigned by RingCentral during SIP provisioning. '
|
||||
'Use this to find the device in RingCentral Admin > Phones & Devices and configure its Caller ID.',
|
||||
)
|
||||
|
||||
def action_provision_sip(self):
|
||||
"""Call RingCentral SIP Provision API and auto-configure provider + user credentials."""
|
||||
self.ensure_one()
|
||||
|
||||
if not all([self.rc_client_id, self.rc_client_secret, self.rc_jwt_token]):
|
||||
raise UserError(_(
|
||||
'Please fill in the RingCentral Client ID, Client Secret, and JWT Token before provisioning.'
|
||||
))
|
||||
|
||||
try:
|
||||
from ringcentral import SDK
|
||||
except ImportError:
|
||||
raise UserError(_(
|
||||
'The ringcentral Python package is not installed. Run: pip install ringcentral'
|
||||
))
|
||||
|
||||
try:
|
||||
server_url = self.rc_server_url or 'https://platform.ringcentral.com'
|
||||
sdk = SDK(self.rc_client_id, self.rc_client_secret, server_url)
|
||||
platform = sdk.platform()
|
||||
platform.login(jwt=self.rc_jwt_token)
|
||||
|
||||
response = platform.post(
|
||||
'/restapi/v1.0/client-info/sip-provision',
|
||||
body={'sipInfo': [{'transport': 'WSS'}]},
|
||||
)
|
||||
data = response.json()
|
||||
|
||||
sip_info_list = getattr(data, 'sipInfo', None) or (data.get('sipInfo') if isinstance(data, dict) else None)
|
||||
if not sip_info_list:
|
||||
raise UserError(_('No SIP info returned from RingCentral.'))
|
||||
|
||||
sip_info = sip_info_list[0]
|
||||
|
||||
device_obj = getattr(data, 'device', None) or (data.get('device') if isinstance(data, dict) else None)
|
||||
device_id = ''
|
||||
if device_obj:
|
||||
device_id = str(getattr(device_obj, 'id', '') or
|
||||
(device_obj.get('id', '') if isinstance(device_obj, dict) else ''))
|
||||
|
||||
outbound_proxy = getattr(sip_info, 'outboundProxy', '') or ''
|
||||
domain = getattr(sip_info, 'domain', '') or ''
|
||||
username = getattr(sip_info, 'username', '') or ''
|
||||
password = getattr(sip_info, 'password', '') or ''
|
||||
auth_id = str(getattr(sip_info, 'authorizationId', '') or '')
|
||||
|
||||
if not all([outbound_proxy, domain, username, password]):
|
||||
raise UserError(_('Incomplete SIP credentials returned from RingCentral.'))
|
||||
|
||||
provider_vals = {
|
||||
'ws_server': f'wss://{outbound_proxy}',
|
||||
'pbx_ip': domain,
|
||||
'mode': 'prod',
|
||||
}
|
||||
if device_id:
|
||||
provider_vals['rc_device_id'] = device_id
|
||||
self.write(provider_vals)
|
||||
|
||||
# Auto-configure the current user's SIP credentials
|
||||
user_settings = self.env['res.users.settings']._find_or_create_for_user(self.env.user)
|
||||
user_settings.write({
|
||||
'voip_provider_id': self.id,
|
||||
'voip_username': username,
|
||||
'voip_secret': password,
|
||||
'rc_authorization_id': auth_id,
|
||||
})
|
||||
|
||||
_logger.info(
|
||||
"RingCentral SIP provisioned: WSS=%s, domain=%s, user=%s, authId=%s, deviceId=%s",
|
||||
outbound_proxy, domain, username, auth_id, device_id,
|
||||
)
|
||||
|
||||
device_msg = ''
|
||||
if device_id:
|
||||
device_msg = f'\nDevice ID: {device_id} (visible in RingCentral Admin > Phones & Devices)'
|
||||
|
||||
return {
|
||||
'type': 'ir.actions.client',
|
||||
'tag': 'display_notification',
|
||||
'params': {
|
||||
'title': _('SIP Provisioned Successfully'),
|
||||
'message': _(
|
||||
'RingCentral SIP credentials configured.\n'
|
||||
'WebSocket: wss://%(proxy)s\n'
|
||||
'Domain: %(domain)s\n'
|
||||
'SIP User: %(user)s%(device_msg)s',
|
||||
proxy=outbound_proxy, domain=domain, user=username, device_msg=device_msg,
|
||||
),
|
||||
'type': 'success',
|
||||
'sticky': True,
|
||||
},
|
||||
}
|
||||
|
||||
except UserError:
|
||||
raise
|
||||
except Exception as e:
|
||||
_logger.exception("RingCentral SIP provisioning failed")
|
||||
raise UserError(_('RingCentral SIP provisioning failed: %s') % str(e))
|
||||
Reference in New Issue
Block a user