- API
- Интеграция с IP-телефонией
- Введение [object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object]
- Работа с типами
- Глобальный контекст и изоляция
- Работа с приложениями
- Массовые действия с элементами приложения
- Работа с внешними сервисами
- Скрипты в виджетах
- Веб компоненты
- Права доступа
- Начало работы с процессами
- Начало работы с подписями
- Начало работы с предпросмотром файлов
- Начало работы с организационной структурой
- Начало работы с пользователями и группами
- Начало работы с типом данных Таблица
- Начало работы с типом данных Категория
- Динамическое вычисление типа события
- Решение типовых задач
- API
- API
- Интеграция с IP-телефонией
Сообщите об опечатке
Текст, в котором допущена ошибка:
Ваш отзыв успешно отправлен!
Спасибо за обратную связь.
Интеграция с IP-телефонией
Система из коробки включает в себя интеграции с различными провайдерами IP-телефонии. Если нужной именно вам интеграции не нашлось, вы можете воспользоваться данным API для создания собственной интеграции. Для этого вам нужно создать пользовательский модуль и реализовать несколько функций в скриптах модуля на языке TypeScript.
Встроенные и пользовательские модули интеграции с IP-телефонией по функционалу принципиально ничем не отличаются. Вашему модулю будут доступны следующие возможности:
Ограничения
Прежде чем реализовывать модуль интеграции, обратите внимание на следующие ограничения API:
Реализация
Для создания модуля интеграции вам необходимо в скриптах пользовательского модуля реализовать следующие функции:
// Проверить соединение с телефонией. Вызывается при нажатии кнопки Проверить соединение на странице модуля // Возвращает статус проверки соединения, который отобразится для пользователя на странице модуля async function VoipTestConnection(): Promise<VoipTestConnectionResult> { } // Обработать запрос от провайдера IP-телефонии. Вызывается, когда происходит запрос на вебхук модуля // В параметре `request` содержится информация об HTTP-запросе, в том числе HTTP-заголовки и содержимое тела запроса // Функция возвращает результат обработки запроса, на основании которого система будет показывать уведомления // о входящем звонке, сохранять запись звонка и т. д. async function VoipParseWebhookRequest(request: FetchRequest): Promise<VoipWebhookParseResult> { } // Получить список пользователей со стороны провайдера IP-телефонии // Вызывается при сопоставлении пользователей телефонии с пользователями системы после нажатия кнопки Настроить на странице модуля // Возвращает список пользователей провайдера IP-телефонии async function VoipGetMembers(): Promise<VoipMember[]> { } // Сгенерировать исходящий звонок. Функция вызывается, когда пользователь системы нажимает кнопку звонка // в контекстном меню поля типа Телефон или кнопку Перезвонить в карточке звонка. В параметре // `srcPhone` указывается номер звонящего пользователя, в `dstPhone` — номер, на который нужно позвонить, // `ext` — добавочный номер. Рекомендуется настроить АТС или SIP-софтфон таким образом, чтобы добавочный номер // автоматически набирался тональным набором после ответа на вызов другой стороной. async function VoipGenerateCall(srcPhone: string, dstPhone: string, ext?: string): Promise<void> { } // Получить ссылку на запись звонка. Функция вызывается, когда пользователь системы проигрывает запись звонка из // ленты элемента приложения или при сохранении ссылки на запись звонка в контекст элемента приложения Звонок // раздела Телефония. В параметре `callData` содержатся данные, которые были указаны при сохранении // информации о записи звонка из функции `VoipParseWebhookRequest`. Функция должна возвращать ссылку на файл async function VoipGetCallLink(callData: any): Promise<string> { } // Вызывается автоматически при изменении ссылки на вебхук (например, при обновлении токена) // В параметре `webhookUrl` указывается абсолютная ссылка на вебхук модуля интеграции. Функция не обязательна к реализации async function VoipOnWebhookUpdated(webhookUrl: string): Promise<void> { }После реализации этих функций и сохранения скрипта на странице модуля вы найдете новый раздел под названием Настройки телефонии. В этом разделе будет указана ссылка на вебхук — при отправке данных на эту ссылку будет вызываться функция
VoipParseWebhookRequestиз скрипта. В этой функции вы должны обработать запрос и вернуть из неё экземплярVoipWebhookParseResult, на основании которого система отобразит уведомления о входящем звонке или сохранит информацию о записи звонка. Саму ссылку на вебхук вам необходимо указать в настройках вашего провайдера телефонии. Ссылка обрабатывает HTTP-запросы типаGETиPOST. Также в ссылке должен присутствовать обязательный параметрtoken.Рекомендуем вам ознакомиться со статьей справки «Интеграция с IP-телефонией через пользовательский модуль». Внутри статьи вы найдете заготовку модуля и пример реального использования API на основе интеграции с IP-телефонией Гравител.
Реализация поддержки кнопок в карточке звонка
При получении входящего звонка или совершении исходящего звонка у пользователя системы в правом нижнем углу появляется карточка с информацией о текущем звонке. В зависимости от состояния звонка, в этой карточке могут отображаться различные кнопки: Принять звонок, Завершить звонок, Переназначить и так далее. Чтобы эти кнопки отображались, реализуйте следующие функции в пользовательском модуле телефонии:
// Принять звонок. Функция вызывается, когда в карточке звонка пользователь системы нажимает кнопку Принять звонок // После этого начинают передаваться голосовые данные между оператором и клиентом // В параметре `srcPhone` указывается номер телефона звонящего, в `dstPhone` — номер, на который производится звонок async function VoipAcceptCall(srcPhone: string, dstPhone: string): Promise<void> { } // Завершить звонок. Функция вызывается, когда в карточке звонка пользователь системы нажимает кнопку Завершить звонок // Звонок между оператором и клиентом завершается // В параметре `srcPhone` указывается номер телефона звонящего, в `dstPhone` — номер, на который производится звонок async function VoipHangupCall(srcPhone: string, dstPhone: string): Promise<void> { } // Переназначить звонок. Функция вызывается, когда в карточке звонка пользователь системы нажимает кнопку Переназначить // Звонок текущего оператора завершается, и клиент соединяется с другим оператором // В параметре `srcPhone` указывается номер телефона звонящего, в `dstPhone` — номер, на который производится звонок, // `redirectTo` — внутренний номер оператора, на которого переназначается звонок async function VoipRedirectCall(srcPhone: string, dstPhone: string, redirectTo: string): Promise<void> { } // Поставить звонок на ожидание. Функция вызывается, когда в карточке звонка пользователь системы // нажимает кнопку Поставить на ожидание. Передача голосовых данных между оператором и клиентом прекращается без завершения звонка // В параметре `srcPhone` указывается номер телефона звонящего, в `dstPhone` — номер, на который производится звонок, // `hold` — значение `true`. Оно указывает, что нужно поставить звонок на ожидание, иначе — снять с ожидания async function VoipHoldCall(srcPhone: string, dstPhone: string, hold: boolean): Promise<void> { }Если в пользовательском модуле телефонии функция не реализована, соответствующая кнопка не будет отображаться в карточке звонка.
Реализация поддержки CTI-панели для звонков через браузер
Если провайдер телефонии поддерживает технологию WebRTC, то можно совершать звонки напрямую из браузера с помощью встроенной в систему CTI-панели. Она позволяет работать со звонками из единого интерфейса. Установка SIP-софтфона в таком случае не нужна.
Функционал CTI-панели доступен только при наличии у пользователя лицензии ELMA365 Omni отдельно или в составе другой лицензии.
Взаимодействие CTI-панели и телефонии
Интеграция телефонии в CTI-панели системы реализуется через виджет пользовательского модуля. Когда сотрудник выбирает провайдера телефонии в CTI-панели, автоматически создаётся экземпляр виджета. В его клиентских скриптах вызывается функция
connectдля инициализации подключения к провайдеру телефонии. Виджет позволяет:BrowserVoipClient.call. В результате, в виджете должен инициироваться исходящий звонок по протоколу телефонии, а в систему возвращаться объект с информацией о звонке. Подробнее о типах данных читайте в примере ниже;BrowserVoipEventSink.callReceived, чтобы в CTI-панели отобразилась информация о входящем звонке;Настройка пользовательского виджета для работы с CTI-панелью
Для реализации виджета взаимодействия с CTI-панелью выполните следующие шаги:
В пользовательском модуле телефонии создайте виджет со следующими параметрами:
browser_voip_client. По этому коду в системе определяется, какой конкретно виджет из модуля нужно использовать для интеграции с CTI-панелью;В открывшемся дизайнере интерфейсов на вкладке Скрипты добавьте клиентские скрипты с описанием интерфейсов для работы с CTI-панелью:
данные для подключения к телефонии:
interface BrowserVoipClientCredentials { // Внутренний номер пользователя телефонии extension: string; // Логин пользователя телефонии username: string; // Пароль пользователя телефонии password: string; }управление звонками через CTI-панель. Все методы интерфейса
BrowserVoipClient, кромеgetCallId, обязательны для реализации:// Установленное подключение к телефонии // @template TIncomingCall Входящий звонок // @template TOutgoingCall Исходящий звонок interface BrowserVoipClient<TIncomingCall = unknown, TOutgoingCall = unknown> { // Отключиться от телефонии. Вызывается системой, когда пользователь выключает CTI-панель disconnect(): Promise<void>; // Совершить исходящий звонок. Вызывается системой, когда пользователь вводит номер // в номеронабирателе и нажимает кнопку Совершить исходящий звонок. Также может // вызываться при звонке через контекстное меню поля Номер телефона // @param phoneNumber Номер телефона, на который нужно позвонить // @param ext Добавочный номер, который нужно автоматически набрать в тональном режиме // после установки соединения // @returns Объект, представляющий собой звонок. В этом объекте виджет может хранить // любые данные звонка // Объект будет передан в другие методы интерфейса `BrowserVoipClient`, когда в CTI-панели нужно // изменить состояние звонка call(phoneNumber: string, ext?: string): Promise<TOutgoingCall>; // Принять входящий звонок. Вызывается системой, когда пользователь нажал кнопку // принятия входящего звонка. Она появляется после того, как пришло событие телефонии о // новом входящем звонке. Подробнее читайте в описании `BrowserVoipEventSink.callReceived` // @param invite Входящий звонок, который был указан в аргументе // метода `BrowserVoipEventSink.callReceived` accept(invite: TIncomingCall): void; // Завершить звонок, т. е. повесить трубку. Также вызывается, если нужно отклонить входящий звонок // @param call Звонок hangup(call: TIncomingCall | TOutgoingCall): void; // Поставить звонок на удержание // @param call Звонок hold(call: TIncomingCall | TOutgoingCall): void; // Снять звонок с удержания // @param call Звонок unhold(call: TIncomingCall | TOutgoingCall): void; // Произвести слепой перевод (blind transfer) на указанный номер телефона. В результате вызова метода // ожидается, что переданный звонок будет завершён // @param call Звонок // @param redirectPhoneNumber Номер телефона, на который нужно произвести слепой перевод blindTransfer(call: TIncomingCall | TOutgoingCall, redirectPhoneNumber: string): void; // Завершить перевод с сопровождением (attended transfer). В результате вызова метода ожидается, что // два указанных абонента будут соединены друг с другом, а звонок `transferor` перейдёт в // состояние Звонок завершён // @param transferor Звонок текущего пользователя с клиентом, которого нужно перевести // на сотрудника `caller` // @param caller Звонок текущего пользователя с сотрудником, на которого будет переведён звонок attendedTransfer(transferor: TIncomingCall | TOutgoingCall, caller: TIncomingCall | TOutgoingCall): void; // Отправить DTMF-сигнал. Вызывается системой при вводе пользователем DTMF-кода в интерфейсе CTI-панели // @param call Звонок // @param key Сигнал для отправки. Например: '1', '5', '*', '#' // @returns Promise, который разрешается после отправки сигнала sendDtmf(call: TIncomingCall | TOutgoingCall, key: string): Promise<void>; // Получить уникальный идентификатор звонка на стороне телефонии. Данный идентификатор должен быть // одинаковым на стороне клиента в браузере и в событии, которое генерируется функцией // `VoipParseWebhookRequest` при обработке события через вебхук. ID звонка используется системой для // обновления информации о звонке дополнительными данными с сервера. Например, к звонку в CTI-панели // может быть привязан элемент приложения Звонок раздела Телефония // @param call Звонок // @returns Идентификатор звонка или null, если идентификатор недоступен getCallId?(call: TIncomingCall | TOutgoingCall): string | null; }отправка уведомлений в CTI-панель:
// Объект, через который соединение с телефонией `BrowserVoipClient` может отправлять уведомления // об изменении состояния звонков в CTI-панель // @template TIncomingCall Входящий звонок // @template TOutgoingCall Исходящий звонок interface BrowserVoipEventSink<TIncomingCall = unknown, TOutgoingCall = unknown> { // Уведомить о новом входящем звонке. В CTI-панели пользователю отобразится предложение // принять или отклонить входящий звонок // @param invite Объект с информацией о входящем звонке. Это значение будет передано как есть в // `BrowserVoipClient.accept` или `BrowserVoipClient.hangup` // @param phoneNumber Номер телефона, с которого нам звонят callReceived(invite: TIncomingCall, phoneNumber: string): void; // Уведомить о завершении звонка. В CTI-панели звонок перейдёт в состояние Звонок завершён // @param call Звонок callFinished(call: TIncomingCall | TOutgoingCall): void; // Уведомить об успешной установке соединения между двумя абонентами для указанного звонка. // Ожидается, что оба абонента могут слышать друг друга. В CTI-панели звонок перейдёт в состояние // Идёт разговор // @param call Звонок callEstablished(call: TIncomingCall | TOutgoingCall): void; // Отправить событие потери соединения с телефонией. Этот метод следует вызывать, когда // произошла критическая ошибка, из-за которой автоматически восстановить соединение // с телефонией невозможно // @param reason Причина ошибки, которую увидит пользователь disconnected(reason: string): void; }Также на вкладке Скрипты в клиентских скриптах реализуйте функцию
connect. Она вызывается автоматически после того, как пользователь системы включит CTI-панель. При успешном подключении к телефонии с помощью этой функции возвращается реализация интерфейсаBrowserVoipClient. В дальнейшем в системе будут вызываться методы этого объекта в зависимости от действий пользователя в CTI-панели. Метод также принимает параметр типаBrowserVoipClientCredentials, в котором находится внутренний номер, логин и пароль для подключения к телефонии. Администратор системы заполняет эту информацию на странице настроек модуля телефонии. ОбъектBrowserVoipEventSinkиспользуется для отправки событий в CTI-панель, например, получение нового входящего звонка или изменение состояния звонка.async function connect(credentials: BrowserVoipClientCredentials, eventSink: BrowserVoipEventSink): Promise<BrowserVoipClient> { const client: BrowserVoipClient = { // Реализуйте интерфейс BrowserVoipClient }; try { // Подключитесь к каналу сигнализации телефонии, используя данные из аргумента `credentials` ... // На момент возврата данных из метода экземпляр `BrowserVoipClient` должен быть подключён к телефонии return client; } catch { // В случае ошибки соединения закройте все подключения к телефонии ... // Пробросьте исключение, чтобы в CTI-панели пользователь увидел // сообщение об ошибке подключения телефонии throw; } }Сохраните и опубликуйте виджет. После этого при включённом модуле пользователи смогут выбрать провайдера телефонии в CTI-панели.
Автоматическая аутентификация в телефонии (SSO)
Чтобы сотрудники могли подключаться к телефонии через CTI-панель, администратор системы должен заполнить в настройках пользовательского модуля логин и пароль для каждого пользователя телефонии. При большом количестве сотрудников это может быть трудоёмко. Чтобы повысить безопасность и снизить нагрузку на администратора системы, рекомендуется автоматически получать учётные данные из телефонии или стороннего сервиса. Схема работы может выглядеть следующим образом:
voip_supports_single_sign_onс типом данных Выбор «да/нет». Укажите значение по умолчанию для этого поля — Да или вынесите его на форму настроек модуля. Когда в этом поле указано значение Да, в системе не отображаются поля для ввода логина и пароля пользователя телефонии при настройке CTI-панели;api_keyс типом данных Строка. В этом поле хранится API-ключ для аутентификации в телефонии.extensionс типом данных Строка. Используется, чтобы передать внутренний номер пользователя, для которого нужно получить токен;auth_tokenс типом данных Строка. Используется, чтобы получить токен для подключения к телефонии.connectклиентских скриптов добавьте вызов серверной функции. С её помощью отправляется запрос на получение учётных данных для подключения к телефонии. Текущего пользователя можно получить вызовом методаSystem.users.getCurrentUser(). Полученные учётные данные сохраните в контекстной переменной виджетаauth_token.// Клиентские скрипты async function connect(credentials: BrowserVoipClientCredentials, eventSink: BrowserVoipEventSink): Promise<BrowserVoipClient> { // Сохраняем внутренний номер пользователя в переменную, чтобы серверный скрипт имел к нему доступ Context.data.extension = credentials.extension; await Server.rpc.getAuthToken(); // Вызов getAuthToken() сохранит токен в контекстной переменной const token = Context.data.auth_token; if (!token) { throw new Error('Не удалось получить токен авторизации'); } // Используйте `token` для подключения к телефонии ... } // Серверные скрипты async function getAuthToken(): Promise<void> { const currentUser = await System.users.getCurrentUser(); const extension = Context.data.extension; // API-ключ для стороннего сервиса, обычно заполняется на странице настроек модуля const apiKey = (await Namespace.getParams()).data.api_key; const response = await fetch('https://example.com/auth', { method: 'POST', body: JSON.stringify({ userId: currentUser.id, extension: extension, apiKey: apiKey, }), }); if (response.ok) { const token = await response.text(); Context.data.auth_token = token; } }