Как бесплатно и без зависаний интегрировать Asterisk с 1С 8.3 для открытия карточки клиента при звонке

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

Связка корпоративной телефонии Asterisk и учетной системы 1С:Предприятие — это классический инструмент повышения эффективности отдела продаж. При входящем звонке менеджер должен мгновенно видеть, кто ему звонит, чтобы обращаться к клиенту по имени и сразу иметь перед глазами историю сделок. Однако разработчики часто сталкиваются с проблемой: старая и некогда популярная бесплатная библиотека ROM-Asterisk.dll, работающая по технологии COM/ActiveX, безнадежно устарела. На современных платформах 1С 8.3.13, 8.3.14, 8.3.15 и новее она вызывает регулярные зависания сеансов, утечки памяти и аварийные завершения работы закрытого клиента.

Использовать постоянный опрос сервера Asterisk через HTTP-запросы (механизм AJAM) — тоже плохая идея, поскольку это создает колоссальную паразитную нагрузку на сеть и базы данных. В этой статье мы подробно разберем три современных, надежных и полностью бесплатных архитектурных пути интеграции Asterisk с 1С, которые не требуют платных лицензий и работают в режиме реального времени.

Проанализируем ситуацию и пошагово разберем каждое решение, чтобы вы могли выбрать наиболее подходящий вариант для вашей инфраструктуры.

---

Решение 1: Переход на современные Native API компоненты (AMI)

Если вы хотите сохранить привычную логику работы через внешнюю компоненту, но избавиться от зависаний COM-технологий, лучшим выбором будет использование Native API. Сообщество разработчиков переписало старые библиотеки на современный стандарт 1С. В открытом доступе на GitHub вы можете найти бесплатные проекты, такие как BROM-Asterisk-Native или InnovaIT-Asterisk-Native.

Эти компоненты используют технологию Native API, благодаря чему они стабильно работают как в 32-битных, так и в 64-битных клиентах 1С, а также не требуют регистрации в реестре Windows. Компонента напрямую подключается к порту AMI Asterisk (обычно 5038), слушает TCP-сокет в фоновом потоке и при возникновении события генерирует стандартное внешнее событие в 1С.

Разберем по шагам, как настроить такую интеграцию в коде 1С:

  1. Поместите файл компоненты (обычно это ZIP-архив с библиотеками под разные ОС) в общий макет конфигурации с типом Двоичные данные.
  2. В модуле управляемого приложения выполните подключение компоненты при запуске системы.
  3. Настройте перехват события звонка в обработчике внешнего события.

Рассмотрим подробнее пример кода для инициализации компоненты в модуле управляемого приложения:


Процедура ПриНачалеРаботыСистемы()
    // Подключаем компоненту из макета конфигурации
    РезультатПодключения = ПодключитьВнешнююКомпоненту("ОбщийМакет.КомпонентаAsteriskNative", "AsteriskAddIn", ТипВнешнейКомпоненты.Native);
    
    Если РезультатПодключения Тогда
        Попытка
            // Создаем объект компоненты
            ОбъектAsterisk = Новый("AddIn.AsteriskAddIn.AMI");
            
            // Задаем параметры подключения к Asterisk Manager Interface
            ОбъектAsterisk.Хост = "192.168.1.100";
            ОбъектAsterisk.Порт = 5038;
            ОбъектAsterisk.ИмяПользователя = "manager1c";
            ОбъектAsterisk.Пароль = "super_secret_password";
            
            // Устанавливаем соединение в асинхронном режиме
            ОбъектAsterisk.Подключиться();
        Исключение
            ЗаписатьЛогОшибок("Ошибка инициализации AMI Asterisk: " + ОписаниеОшибки());
        КонецПопытки;
    Иначе
        ЗаписатьЛогОшибок("Не удалось загрузить внешнюю компоненту Asterisk Native API.");
    КонецЕсли;
КонецПроцедуры

После успешного подключения компонента начинает слушать поток событий Asterisk. При поступлении входящего вызова на телефон сотрудника сработает предопределенная процедура ОбработкаВнешнегоСобытия в модуле управляемого приложения или в форме. Нам остается лишь перехватить ее и открыть форму нужного контрагента.

Посмотрим на пример обработки события:


Процедура ОбработкаВнешнегоСобытия(Источник, Событие, Данные)
    // Проверяем, что событие пришло именно от нашей компоненты телефонии
    Если Источник = "AsteriskAddIn" И Событие = "NewState" Тогда
        // Переменная Данные обычно содержит строку с параметрами (например, в формате JSON или CSV)
        // Предположим, компонента передает строку: "CallerID:79991112233;Extension:101;State:Ringing"
        
        ПараметрыСобытия = РаспарситьДанныеСобытия(Данные);
        
        Если ПараметрыСобытия.Получить("State") = "Ringing" Тогда
            НомерТелефона = ПараметрыСобытия.Получить("CallerID");
            ВнутреннийНомер = ПараметрыСобытия.Получить("Extension");
            
            // Проверяем, назначен ли этот звонок текущему пользователю 1С
            ТекущийПользователь = Пользователи.ТекущийПользователь();
            Если ПолучитьВнутреннийНомерПользователя(ТекущийПользователь) = ВнутреннийНомер Тогда
                // Находим контрагента в базе по номеру телефона
                СсылкаНаКлиента = НайтиКонтрагентаПоТелефону(НомерТелефона);
                
                Если ЗначениеЗаполнено(СсылкаНаКлиента) Тогда
                    // Открываем карточку найденного контрагента
                    ПараметрыФормы = Новый Структура("Ключ", СсылкаНаКлиента);
                    ОткрытьФорму("Справочник.Контрагенты.ФормаОбъекта", ПараметрыФормы);
                Иначе
                    // Если клиент не найден, открываем форму создания нового контрагента с заполненным телефоном
                    ПараметрыЗаполнения = Новый Структура;
                    ПараметрыЗаполнения.Вставить("ТелефонКонтрагента", НомерТелефона);
                    
                    ПараметрыОткрытия = Новый Структура("ЗначенияЗаполнения", ПараметрыЗаполнения);
                    ОткрытьФорму("Справочник.Контрагенты.ФормаОбъекта", ПараметрыОткрытия);
                КонецЕсли;
            КонецЕсли;
        КонецЕсли;
    КонецЕсли;
КонецПроцедуры

---

Решение 2: Интеграция через «Систему взаимодействия» 1С (Без DLL и внешних компонент)

Если в вашей компании используется современная клиент-серверная архитектура, вы можете полностью отказаться от использования DLL-файлов на компьютерах пользователей. Это особенно актуально, если сотрудники работают на разных операционных системах (Windows, macOS, Linux) или используют веб-клиент в браузере. Данное решение базируется на штатных механизмах платформы 1С — HTTP-сервисах и встроенной Системе взаимодействия (доступна начиная с версии платформы 8.3.10).

Давайте разберем по шагам, как работает эта элегантная и отказоустойчивая архитектурная схема:

  1. При поступлении входящего вызова Asterisk обрабатывает его в своем плане набора (Dialplan). Прямо из диалплана выполняется быстрый асинхронный HTTP-запрос (вебхук) к опубликованному HTTP-сервису базы 1С. Для этого используется стандартная утилита curl или встроенная функция Asterisk curl.
  2. Сервер 1С моментально принимает этот запрос, выполняет поиск контрагента по номеру телефона в базе данных и определяет, какому пользователю адресован звонок.
  3. Поскольку сервер не может напрямую дать команду открытому окну пользователя 1С на клиенте, он задействует механизм Системы взаимодействия. Сервер программно отправляет системное сообщение в специальный невидимый канал для этого пользователя.
  4. На клиентском компьютере платформа 1С мгновенно ловит это сообщение и выполняет код по открытию карточки клиента.

Рассмотрим, как настроить отправку запроса из плана набора Asterisk (файл extensions.conf):


; Настройка диалплана Asterisk при входящем звонке
[incoming-calls]
exten => _X.,1,NoOp(Входящий звонок от ${CALLERID(num)} на внутренний ${EXTEN})
; Вызываем HTTP-сервис 1С в фоновом режиме, передавая номер звонящего и получателя
exten => _X.,n,System(curl -s -X POST "http://1c-server/trade/hs/telephony/incoming" -d "caller=${CALLERID(num)}&called=${EXTEN}" &)
exten => _X.,n,Dial(SIP/${EXTEN},30)
exten => _X.,n,Hangup()

Теперь проанализируем реализацию HTTP-сервиса на стороне 1С. Создадим HTTP-сервис с именем telephony и шаблоном URL /incoming. Напишем обработчик метода POST:


Функция ШаблонЗапросаIncomingPOST(Запрос)
    // Извлекаем тело POST-запроса
    ТелоЗапроса = Запрос.ПолучитьТелоКакСтроку();
    ПараметрыЗвонка = РаспарситьПараметрыЗапроса(ТелоЗапроса);
    
    НомерЗвонящего = ПараметрыЗвонка.Получить("caller");
    ВнутреннийНомер = ПараметрыЗвонка.Получить("called");
    
    // Выполняем поиск пользователя 1С по его внутреннему номеру телефона
    ЦелевойПользователь = НайтиПользователяПоНомерам(ВнутреннийНомер);
    
    Если ЦелевойПользователь <> Неопределено Тогда
        // Находим интеграционное обсуждение Системы взаимодействия для передачи события
        ПараметрыСобытия = Новый Структура;
        ПараметрыСобытия.Вставить("Событие", "ВходящийЗвонок");
        ПараметрыСобытия.Вставить("НомерТелефона", НомерЗвонящего);
        
        // Отправляем системное push-сообщение пользователю в 1С
        СистемаВзаимодействия.ОтправитьСистемноеСообщениеПользователю(ЦелевойПользователь, ПараметрыСобытия);
    КонецЕсли;
    
    // Быстро возвращаем АТС ответ 200 OK, чтобы не задерживать диалплан
    Ответ = Новый HTTPСервисОтвет(200);
    Ответ.УстановитьТелоИзСтроки("OK");
    Возврат Ответ;
КонецФункции

На стороне клиента в модуле управляемого приложения нам остается только подписаться на получение этих сообщений через Систему взаимодействия и открыть форму справочника. Этот метод абсолютно надежен, не нагружает рабочие станции и работает со скоростью света.

---

Решение 3: Прямая работа через встроенный WebSocket-клиент 1С (ARI)

Начиная с версии платформы 8.3.8, в 1С появился мощный встроенный объект КлиентWebSocket. Благодаря этому нововведению отпала необходимость писать или искать сложные внешние компоненты, работающие сокетами. Мы можем подключить 1С напрямую к интерфейсу Asterisk REST Interface (ARI) по протоколу WebSockets.

При таком подходе клиентское приложение 1С при запуске открывает постоянное сетевое WebSocket-соединение с Asterisk. Сервер телефонии асинхронно отправляет JSON-пакеты событий прямо в сеанс 1С. Платформа парсит эти данные встроенными средствами и реагирует на звонки.

Рассмотрим по шагам, как запустить и использовать встроенный WebSocket-клиент в коде 1С:


Перем WSСоединение Экспорт;

Процедура ИнициализироватьТелефониюWebSocket() Экспорт
    // Формируем адрес подключения к ARI Asterisk
    // Замените хост, порт, имя приложения (app) и авторизационные данные на свои
    АдресПодключения = "ws://192.168.1.100:8088/ari/events?api_key=ari_user:ari_password&app=1c_telephony";
    
    WSСоединение = Новый КлиентWebSocket(АдресПодключения);
    
    // Назначаем обработчики событий для асинхронной работы сокета
    ДобавлениеОбработчика WSСоединение.ПриПолученииТекстовогоСообщения, ОбработкаСообщенияWS;
    ДобавлениеОбработчика WSСоединение.ПриЗакрытии, ОбработкаЗакрытияWS;
    ДобавлениеОбработчика WSСоединение.ПриОшибке, ОбработкаОшибкиWS;
    
    Попытка
        WSСоединение.ПодключитьАсинхронно();
    Исключение
        ЗаписатьЛогОшибок("Ошибка асинхронного подключения к WebSocket: " + ОписаниеОшибки());
    КонецПопытки;
КонецПроцедуры

При поступлении нового события от Asterisk сработает назначенный нами обработчик текстового сообщения. Платформа 1С получит структурированный JSON-пакет. Нам необходимо распарсить его с помощью объекта ЧтениеJSON и вытащить данные о входящем вызове:


Процедура ОбработкаСообщенияWS(Соединение, ТекстСообщения)
    // Читаем входящий JSON-пакет от ARI
    Чтение = Новый ЧтениеJSON;
    Чтение.УстановитьСтроку(ТекстСообщения);
    ДанныеСобытия = ПрочитатьJSON(Чтение);
    Чтение.Закрыть();
    
    // Анализируем тип события ARI (например, начало отслеживания звонка в приложении Stasis)
    Если ДанныеСобытия.Свойство("type") И ДанныеСобытия.type = "StasisStart" Тогда
        // Извлекаем детальную информацию о канале звонка
        ДанныеКанала = ДанныеСобытия.channel;
        НомерЗвонящего = ДанныеКанала.caller.number;
        
        // Выполняем открытие карточки
        СсылкаНаКонтрагента = НайтиКонтрагентаПоТелефону(НомерЗвонящего);
        Если ЗначениеЗаполнено(СсылкаНаКонтрагента) Тогда
            ПараметрыФормы = Новый Структура("Ключ", СсылкаНаКонтрагента);
            ОткрытьФорму("Справочник.Контрагенты.ФормаОбъекта", ПараметрыФормы);
        КонецЕсли;
    КонецЕсли;
КонецПроцедуры

Использование встроенного КлиентWebSocket позволяет разработчику полностью контролировать логику взаимодействия с телефонией на уровне платформенного кода 1С, обеспечивая максимальную гибкость и кроссплатформенность.

---

Резюме: какой путь выбрать?

Мы подробно проанализировали три отличных архитектурных подхода. Чтобы сделать правильный выбор, ориентируйтесь на следующие критерии:

← На главную