«Здравствуйте, Вы записаны на завтра, 5 июня 2022 года, на прием к стоматологу, в 10:05. Вы придете на прием?».
Пожалуй, каждый из нас, в той или иной форме получал подобный звонок от оператора колл-центра клиники. На фоне другие операторы кликают клавишами, доносится гул их голосов. Усталым голосом оператор отрабатывает скрипт, кладет трубку. Полезный звонок, надо поставить напоминание в телефоне, предупредить коллег, что с 10 до 11 будешь не на связи.
Такие звонки достаточно просто автоматизировать, обрабатывать и отслеживать. Мало того, с точки зрения комфортной беседы, исполнение такого скрипта роботом с простыми вариантами ответа — «Да», «Нет», «Оператор» — создают более привлекательное впечатление о бизнесе, который инициирует звонок. Приятным голосом, за короткое время, вы получаете полезное сообщение, что может быть удобнее?
Бизнес же экономит ресурсы за счет сокращения времени звонков, перенаправления сил операторов на более важные направления, возможности заранее представлять загрузку специалистов, использовать освободившееся время для визита других клиентов (отдельная интересная задача для автоматизации).
Меня зовут Дмитрий Лупонос. Я был админом и программистом 1С в нулевые, потом перешёл в менеджмент. Сейчас работаю ведущим программистом 1С. У меня есть разный опыт: менеджера, разработчика и админа. И как со всем этим не заняться интеграциями.
В этой инструкции постараюсь максимально широко раскрыть вопрос связки базы данных 1С с роботом МТТ
В клинике на Linux-сервере уже развернута отраслевая конфигурация 1С для работы с пациентами, в которой есть все данные для совершения звонков с уведомлениями о визите.
Чтобы исключить проблемы со связью, выбрали сервис МТТ с использованием voicebox.mtt.ru, там есть доступ к настройкам скриптов обзвона, настройкам кампаний обзвона.
Предполагается, что у пациента, скорее всего, доступна входящая голосовая связь. Он может не прочитать СМС, а мессенджеры и вовсе не установлены (или недоступны к установке). Клиент может предоставить как номер городского пула, так и личный номер мобильного, не всегда может сам ответить на звонок, но, скорее всего, информация будет доведена до пациента.
Все изменения требуется производить «в стороне» от конфигурации, не затрагивая существующие объекты тем или иным образом. У клиента сейчас идет обновление на несколько релизов вперед и он опасается, что изменения могут повлиять как прямым образом на ход обновления, так и косвенным, а именно подрядчик может заявить о «вмешательстве» в ход обновления третьего лица.
Идеальный сценарий: за сутки до визита, в произвольное время дня, но допустимое для звонка, сделать звонок с сервера 1С. В этом звонке роботу нужно обратиться к абоненту по имени и отчеству, сообщить специализацию специалиста, дату и время визита.
Во время звонка могут произойти следующие события:
Затем стоит отразить изменения во время общения робота МТТ с пациентом: в статусе документа в базе данных отразится принятый ответ, что позволит определить загрузку специалистов.
Совершать любой звонок можно не более трех раз при статусах 4 и 5, как только возникает событие 1, 2, 3 прекращаем обзвон по этому пациенту.
В интерфейсе сервиса я нашёл инструменты для настройки скриптов прозвона и извлечения отчетов с детализацией звонков, план нумерации.
Чтобы решить задачу, я создаю сценарий, привязываю его к компании, для чего также использую номер из плана нумерации.
Создаю сценарий с названием 1С тест – уведомление о приеме. В интерфейсе сценарий отображается в виде блок-схемы из блоков различного назначения. Приведу некоторые из них на рисунках 5-6.
Рис. 5: Блок формирования JSON-запроса, вид 1
Рис. 6: Блок формирования JSON-запроса, вид 2
Один из самых ключевых блоков скрипта – блок оповещения, обратной связи с передачей статуса. Нам важно провести сериализацию JSON-запроса, чтобы не перегрузить данными прием ответа и сохранить понятную структуру при различных ответах. Иначе алгоритм обработки полученного от МТТ сообщения о результате скрипта будет слишком ветвистым.
Поэтому, согласно возможным статусам, у JSON-Запроса всего шесть блоков формирования, различаются они только передаваемым статусом. Приведу схему работы запроса на рисунке 7.
Рис. 7: Блок-схема реализации скрипта прозвона Voicebox МТТ
Тип сценария: исходящий сценарий. Содержит в себе начальные настройки для произведения звонка (Рис. 8-10).
Рис. 8: Исходящий звонок, вид 1
Выбираю голос и скорость воспроизведения, переход на блок звонок – единственный вариант в этом блоке. При ошибке наш сервер 1С не получит как call_id (ниже подробнее про ответы Voicebox), и необходим обход по незавершенным статусам и перезапуск. Количество попыток, конечно, стоит ограничить.
Рис. 9: Исходящий звонок, вид 2
Затем идёт настройка переменных JSON, которые в результате работы скрипта будут как приходить, так и отправляться. Тут можно добавлять и исправлять произвольные переменные для использования в голосовом скрипте.
Рис. 10: Исходящий звонок, вид 3
Затем настройки для формирования JSON-запроса, привязанного к инициации звонка. В нашем случае сервер 1С отрабатывает любой не-ответ как ошибку, это стандартное действие, поэтому настроек нет.
После перехода на звонок алгоритм скрипта разветвляется (Рис. 7) на ошибку и успех. По каждой следующей ветке вставим информирование о произведении звонка блоком HTTP. Обратите внимание, в моем алгоритме при успешном совершении передается статус ошибки, это индикатор поднятия трубки абонентом. Теперь, если абонент прервет связь до окончания следующего блока, то сервер 1С уже получит статус успешного звонка из этого блока.
При ошибке звонка сервер 1С получит статус из блока 1С-Недозвон, после чего алгоритм завершится.
Ветка успешного звонка после блока ведёт к ошибке, но это ветвление алгоритма для невозможности передать запрос по ссылке из HTTP блока, и обе стрелки перекрывает на статус «Ошибка». Не стоит обращать на это внимание. Советую убедиться в ветвлении в настройках HTTP запроса (рис. 6) – обе ветки переходят на блок «вопрос».
Рис. 11: Блок «Вопрос», вид 1
В блоке содержатся настройки номера, с помощью которого идёт работа скрипта, переходы.
Рис. 12: Блок «Вопрос», вид 2
Теперь ключевой момент блока «Вопрос» — выделенные фигурными скобками переменные из запроса JSON, который описан в настройке «Исходящий звонок» на рисунке 10.
На стороне 1С сформирована строка {{name}}, в моем случае с Именем и Отчеством пациента и {{visit}}, в которой содержится описание визита – дата, время, специальность специалиста. Приведу часть запроса:
В поле visit данные без лишних символов, которые робот МТТ произнести не сможет, сама процедура в полном объеме ниже.
Рис. 13: Блок «Вопрос», вид 3
В этом блоке обратите внимание на тайминг 10 секунд – ожидание ответа на вопрос, возможность ответа голосом или на клавиатуре. На количестве посещений, равное двум подразумевает количество повторения вопроса скрипта.
Рис. 14 Блок «Вопрос», вид 4
Вариантов перехода блока «Вопрос» больше, чем в предыдущих блоках. Удобнее отследить разветвление алгоритма графически, на рисунке 7.
При переходе на вопрос в результате исполнения блока «Вопрос» в ветках:
1. Успешно – передаем на сервер 1С статус успешно, проигрываем блок Придет.
2. В случае ошибки переводим на оператора.
3. В случае определения блоком Вопрос автоответчика или отказа уходим в блоки 1С-Недозвон и Отбой.
4. В случае успеха (ответ «Да») – передача в 1С данных подтверждения, проигрывания блока Придет и завершения звонка.
5. В случае отказа (ответ «Нет») – снова аналогичный блок вопрос, уточняющий, устроит ли пациента другое время.
5.1. В случае успеха (ответ: «Да») – проигрываем блок с записью другое время и переводим на оператора с уведомлением сервера 1С «оператор».
5.2. В случае ошибки также происходит перевод на оператора с уведомлением сервера 1С «оператор».
5.3. В случае отказа (ответ «Нет») – проигрываем блок «Ничего не нужно» и завершаем звонок с уведомлением сервера 1С «Отказ».
Для реализации JSON метода для обращения к серверу voicebox.mtt.ru необходимо создать кампанию, указать метод прозвона, HTTP-запрос, выбрать тип кампании и номер из пула номеров (Рис. 15).
Рис. 15: настройки компании.
При выборе вида запуска «По HTTP запросу», выборе сценария «1С тест – уведомление о приеме», выборе номера – «наш номер» получаем необходимые для управления данные:
Пароль вносится в метод в виде строки Base64, в который конвертируется так строка : с помощью онлайн-механизмов конвертации или ПО, например, Postman. Полученную строку необходимо использовать при передаче (листинг 5, в моем случае) данных в сокет VoiceBox.
Созданные в конфигурации объекты не касаются типовых объектов. Точкой входа назначена процедура «ПриЗаписи» документа, фиксирующего бронирование времени у специалиста со статусом «Бронь». В данной реализации записи о бронировании заносятся в справочник МТТ_Обзвон со структурой как на рисунке 16.
Рис 16. Структура справочника
Кратко о реквизитах:
UPD1: В связи с вопросами коллег в комментариях, отмечу, что во-первых код изложен для максимального понимания, но не в полном объеме. Только то, что касается обмена 1С-МТТ VoiceBox. Во-вторых, методы решения задачи подстановки значений, в частности, данных справочников лучше, корректнее. Данный код не претендует на идеальность, прошу учитывать данный момент при подстановке в свои решения, требуется оптимизация частей кода, не связанных с работой обмена. В-третьих, те или иные решения формируются из собственного опыта и понимания отношения заказчика к отношению данным базы, в частности, существует гарантия, что наименование элемента справочника «СтатусыДокумента» изменено не будет.
Все методы реализованы в модуле менеджера справочника, являются экспортными и вызываются по ссылке Справочники.МТТ_Обмен.<ИмяМетода>().
1. Метод записи данных справочника: Процедура ОбработатьЗаписьПациента(ЗаписьПациента) Экспорт
Листинг 1: ОбработатьЗаписьПациента(ЗаписьПациента)
Далее следует проверка на корректность номера пациента функцией ПолучитьНомерПациента(Пациент):
Листинг 2: ПолучитьНомерПациента(Пациент)
Достаточно простая функция, не учитывающая содержание в номере только цифр. По-умолчанию мы считаем, что все номера в справочнике проверены.
Листинг 3: ОтправитьЗапросВМТТ(ВыбГУИД)
Основные моменты приведенного листинга: формируем JSON Запрос, отправляем его функциями отправки, получаем ответ call_id или статус HTTP сервера, фиксируем полученные данные в справочнике. В дальнейшем начинаем искать уже по статусу call_id, с которым будут приходить следующие запросы.
Листинг 4: СформироватьJSONМногомерный(СтруктураДанных, ФормироватьСПереносами = Ложь)
Привожу тут код в формате «как есть», подходит для вставки в любую часть вашего кода. Отлаживал и настраивал, код рабочий, проверен.
Листинг 5: Функция ОповеститьСервер(ЗапросJSON)
С функцией отправки предлагаю поступить аналогично функции формирования запроса, а именно использовать в формате «как есть». Долго отлаживал заголовки, получился в итоге рабочий вариант, не требующий изменений.
Листинг 6: Процедура ОбработатьВходящийПакет(ДанныеПакета)
Обязательно приведу листинг 7 процедуры нормализации строки, передаваемой для произнесения роботом МТТ. Есть символы, которые не произносятся и могут вызвать отказ и перевод на оператора.
Листинг 7: Функция НормализацияСтроки(СтрокаJSON)
В статье изложил основные методы и принципы настройки обмена на стороне 1С. Настройки Voicebox от компании МТТ привел на своем примере. Функциональность запущена на реальных данных 30 мая 2022 года, отладку механизма завершил 4 июля.
В результате тестовой работы ошибок обмена нет. Но очень долго шел к тому, что нужно фиксировать установку соединения в результате звонка. Иначе оставались «Мертвые души» в справочнике МТТ_Обмен без статусов. В связи с этим механизм набирал условленное количество раз, которое меньше счетчика справочника МТТ_Обмен.КоличествоНеудачныхПопыток без указания статуса, не менял статус документа.
При реализации HTTP-метода отражения инициации звонка стало понятно, отработал запрос звонка или нет. В итоге стандартным стал считаться статус «взял-положил трубку до отработки скрипта», и все стало работать корректно
МТТ оказали поддержку на всех этапах. Разбирались и оптимизировали скрипты совместно, на все вопросы появились ответы. Особенно это было актуально, когда вместе с заказчиком настраивали веб-сервер IIS для публикации базы данных, обеспечивали нестандартный порт для приема ответов от Voicebox.
Всем спасибо за прочтение статьи, прошу все вопросы задавать в комментариях.
Пожалуй, каждый из нас, в той или иной форме получал подобный звонок от оператора колл-центра клиники. На фоне другие операторы кликают клавишами, доносится гул их голосов. Усталым голосом оператор отрабатывает скрипт, кладет трубку. Полезный звонок, надо поставить напоминание в телефоне, предупредить коллег, что с 10 до 11 будешь не на связи.
Такие звонки достаточно просто автоматизировать, обрабатывать и отслеживать. Мало того, с точки зрения комфортной беседы, исполнение такого скрипта роботом с простыми вариантами ответа — «Да», «Нет», «Оператор» — создают более привлекательное впечатление о бизнесе, который инициирует звонок. Приятным голосом, за короткое время, вы получаете полезное сообщение, что может быть удобнее?
Бизнес же экономит ресурсы за счет сокращения времени звонков, перенаправления сил операторов на более важные направления, возможности заранее представлять загрузку специалистов, использовать освободившееся время для визита других клиентов (отдельная интересная задача для автоматизации).
Меня зовут Дмитрий Лупонос. Я был админом и программистом 1С в нулевые, потом перешёл в менеджмент. Сейчас работаю ведущим программистом 1С. У меня есть разный опыт: менеджера, разработчика и админа. И как со всем этим не заняться интеграциями.
В этой инструкции постараюсь максимально широко раскрыть вопрос связки базы данных 1С с роботом МТТ
Постановка задачи
В клинике на Linux-сервере уже развернута отраслевая конфигурация 1С для работы с пациентами, в которой есть все данные для совершения звонков с уведомлениями о визите.
Чтобы исключить проблемы со связью, выбрали сервис МТТ с использованием voicebox.mtt.ru, там есть доступ к настройкам скриптов обзвона, настройкам кампаний обзвона.
Предполагается, что у пациента, скорее всего, доступна входящая голосовая связь. Он может не прочитать СМС, а мессенджеры и вовсе не установлены (или недоступны к установке). Клиент может предоставить как номер городского пула, так и личный номер мобильного, не всегда может сам ответить на звонок, но, скорее всего, информация будет доведена до пациента.
Все изменения требуется производить «в стороне» от конфигурации, не затрагивая существующие объекты тем или иным образом. У клиента сейчас идет обновление на несколько релизов вперед и он опасается, что изменения могут повлиять как прямым образом на ход обновления, так и косвенным, а именно подрядчик может заявить о «вмешательстве» в ход обновления третьего лица.
Идеальный сценарий: за сутки до визита, в произвольное время дня, но допустимое для звонка, сделать звонок с сервера 1С. В этом звонке роботу нужно обратиться к абоненту по имени и отчеству, сообщить специализацию специалиста, дату и время визита.
Во время звонка могут произойти следующие события:
- Прием звонка и подтверждение визита.
- Прием звонка и отмена визита.
- Прием звонка и, в результате прохождения скрипта, соединение с оператором.
- Прием звонка и отбой до завершения отработки скрипта.
- Отказ от приема – нет соединения или не ответ.
Затем стоит отразить изменения во время общения робота МТТ с пациентом: в статусе документа в базе данных отразится принятый ответ, что позволит определить загрузку специалистов.
Совершать любой звонок можно не более трех раз при статусах 4 и 5, как только возникает событие 1, 2, 3 прекращаем обзвон по этому пациенту.
На рисунках 1-4 я привел укрупненную блок-схему постановки задачи в работу и обработку планировщиком на сервере 1С, прием ответа от МТТ:
Рис. 1: Постановка задания в очередь
Рис. 2: Формирование записи о событии.
Рис. 3: Работа планировшика сервера 1С
Рис. 4: Обработка входящего статуса после завершения звонка
Рис. 1: Постановка задания в очередь
Рис. 2: Формирование записи о событии.
Рис. 3: Работа планировшика сервера 1С
Рис. 4: Обработка входящего статуса после завершения звонка
Про настройку скрипта
В интерфейсе сервиса я нашёл инструменты для настройки скриптов прозвона и извлечения отчетов с детализацией звонков, план нумерации.
Чтобы решить задачу, я создаю сценарий, привязываю его к компании, для чего также использую номер из плана нумерации.
Создание сценария
Создаю сценарий с названием 1С тест – уведомление о приеме. В интерфейсе сценарий отображается в виде блок-схемы из блоков различного назначения. Приведу некоторые из них на рисунках 5-6.
Рис. 5: Блок формирования JSON-запроса, вид 1
Рис. 6: Блок формирования JSON-запроса, вид 2
Один из самых ключевых блоков скрипта – блок оповещения, обратной связи с передачей статуса. Нам важно провести сериализацию JSON-запроса, чтобы не перегрузить данными прием ответа и сохранить понятную структуру при различных ответах. Иначе алгоритм обработки полученного от МТТ сообщения о результате скрипта будет слишком ветвистым.
Поэтому, согласно возможным статусам, у JSON-Запроса всего шесть блоков формирования, различаются они только передаваемым статусом. Приведу схему работы запроса на рисунке 7.
Рис. 7: Блок-схема реализации скрипта прозвона Voicebox МТТ
Тип сценария: исходящий сценарий. Содержит в себе начальные настройки для произведения звонка (Рис. 8-10).
Рис. 8: Исходящий звонок, вид 1
Выбираю голос и скорость воспроизведения, переход на блок звонок – единственный вариант в этом блоке. При ошибке наш сервер 1С не получит как call_id (ниже подробнее про ответы Voicebox), и необходим обход по незавершенным статусам и перезапуск. Количество попыток, конечно, стоит ограничить.
Рис. 9: Исходящий звонок, вид 2
Затем идёт настройка переменных JSON, которые в результате работы скрипта будут как приходить, так и отправляться. Тут можно добавлять и исправлять произвольные переменные для использования в голосовом скрипте.
Рис. 10: Исходящий звонок, вид 3
Затем настройки для формирования JSON-запроса, привязанного к инициации звонка. В нашем случае сервер 1С отрабатывает любой не-ответ как ошибку, это стандартное действие, поэтому настроек нет.
После перехода на звонок алгоритм скрипта разветвляется (Рис. 7) на ошибку и успех. По каждой следующей ветке вставим информирование о произведении звонка блоком HTTP. Обратите внимание, в моем алгоритме при успешном совершении передается статус ошибки, это индикатор поднятия трубки абонентом. Теперь, если абонент прервет связь до окончания следующего блока, то сервер 1С уже получит статус успешного звонка из этого блока.
При ошибке звонка сервер 1С получит статус из блока 1С-Недозвон, после чего алгоритм завершится.
Ветка успешного звонка после блока ведёт к ошибке, но это ветвление алгоритма для невозможности передать запрос по ссылке из HTTP блока, и обе стрелки перекрывает на статус «Ошибка». Не стоит обращать на это внимание. Советую убедиться в ветвлении в настройках HTTP запроса (рис. 6) – обе ветки переходят на блок «вопрос».
Рис. 11: Блок «Вопрос», вид 1
В блоке содержатся настройки номера, с помощью которого идёт работа скрипта, переходы.
Рис. 12: Блок «Вопрос», вид 2
Теперь ключевой момент блока «Вопрос» — выделенные фигурными скобками переменные из запроса JSON, который описан в настройке «Исходящий звонок» на рисунке 10.
На стороне 1С сформирована строка {{name}}, в моем случае с Именем и Отчеством пациента и {{visit}}, в которой содержится описание визита – дата, время, специальность специалиста. Приведу часть запроса:
"data": {
"number": "71234567890",
"guid": "b70a03fe-e239-11ec-0c87-fe3375dcbab9",
"name": "Валерия Сергеевна",
"visit": "Эндоскопист 4 июня 2022 г 11 30"
}
В поле visit данные без лишних символов, которые робот МТТ произнести не сможет, сама процедура в полном объеме ниже.
Рис. 13: Блок «Вопрос», вид 3
В этом блоке обратите внимание на тайминг 10 секунд – ожидание ответа на вопрос, возможность ответа голосом или на клавиатуре. На количестве посещений, равное двум подразумевает количество повторения вопроса скрипта.
Рис. 14 Блок «Вопрос», вид 4
Вариантов перехода блока «Вопрос» больше, чем в предыдущих блоках. Удобнее отследить разветвление алгоритма графически, на рисунке 7.
Итог работы скрипта
При переходе на вопрос в результате исполнения блока «Вопрос» в ветках:
1. Успешно – передаем на сервер 1С статус успешно, проигрываем блок Придет.
2. В случае ошибки переводим на оператора.
3. В случае определения блоком Вопрос автоответчика или отказа уходим в блоки 1С-Недозвон и Отбой.
4. В случае успеха (ответ «Да») – передача в 1С данных подтверждения, проигрывания блока Придет и завершения звонка.
5. В случае отказа (ответ «Нет») – снова аналогичный блок вопрос, уточняющий, устроит ли пациента другое время.
5.1. В случае успеха (ответ: «Да») – проигрываем блок с записью другое время и переводим на оператора с уведомлением сервера 1С «оператор».
5.2. В случае ошибки также происходит перевод на оператора с уведомлением сервера 1С «оператор».
5.3. В случае отказа (ответ «Нет») – проигрываем блок «Ничего не нужно» и завершаем звонок с уведомлением сервера 1С «Отказ».
Настройка прозвона клиентов скриптом 1С тест – уведомление о приеме
Для реализации JSON метода для обращения к серверу voicebox.mtt.ru необходимо создать кампанию, указать метод прозвона, HTTP-запрос, выбрать тип кампании и номер из пула номеров (Рис. 15).
Рис. 15: настройки компании.
При выборе вида запуска «По HTTP запросу», выборе сценария «1С тест – уведомление о приеме», выборе номера – «наш номер» получаем необходимые для управления данные:
- URL для обращения к методу.
- Логин для обращения к методу.
- Пароль для обращения к методу.
- Формат JSON-запроса. Приведу пример моего запроса:
{ "method":"78033x2x-21x7-47xx-x292-590x24146043", "data":{ "number": "<number>", "guid": "<guid>", "name":"<name>", "visit":"<visit>" } }
Пароль вносится в метод в виде строки Base64, в который конвертируется так строка : с помощью онлайн-механизмов конвертации или ПО, например, Postman. Полученную строку необходимо использовать при передаче (листинг 5, в моем случае) данных в сокет VoiceBox.
Как реализовать управление в 1С и особенности обмена с Voicebox
Созданные в конфигурации объекты не касаются типовых объектов. Точкой входа назначена процедура «ПриЗаписи» документа, фиксирующего бронирование времени у специалиста со статусом «Бронь». В данной реализации записи о бронировании заносятся в справочник МТТ_Обзвон со структурой как на рисунке 16.
Рис 16. Структура справочника
Кратко о реквизитах:
- Пациент – ссылка на справочник «Пациенты», где есть информация для работы скрипта: имя, отчество, телефон. Вносятся в данные справочника NameStr, VisitStr.
- ЗаписьПациента – ссылка на документ «ЗаписьПациента», которому нужно устанавливать статус на основе полученного ответа по результатам работы скрипта МТТ.
- Дата, Время приема – разделена переменная ДатаВремяПриема для работы запроса, формирования отчета и работы регламентного задания.
- Завершен – буль, признак завершения задания.
- КоличествоНеудачныхПопыток – счетчик попыток звонка для работы алгоритма.
- Прочие данные заполняются из ответов HTTP-методов Voicebox MTT.
UPD1: В связи с вопросами коллег в комментариях, отмечу, что во-первых код изложен для максимального понимания, но не в полном объеме. Только то, что касается обмена 1С-МТТ VoiceBox. Во-вторых, методы решения задачи подстановки значений, в частности, данных справочников лучше, корректнее. Данный код не претендует на идеальность, прошу учитывать данный момент при подстановке в свои решения, требуется оптимизация частей кода, не связанных с работой обмена. В-третьих, те или иные решения формируются из собственного опыта и понимания отношения заказчика к отношению данным базы, в частности, существует гарантия, что наименование элемента справочника «СтатусыДокумента» изменено не будет.
Листинг методов для работы с Voicebox МТТ
Все методы реализованы в модуле менеджера справочника, являются экспортными и вызываются по ссылке Справочники.МТТ_Обмен.<ИмяМетода>().
1. Метод записи данных справочника: Процедура ОбработатьЗаписьПациента(ЗаписьПациента) Экспорт
&НаСервере
Процедура ОбработатьЗаписьПациента(ЗаписьПациента) Экспорт
//Нет ссылки на документ
Если ЗаписьПациента = Неопределено Тогда
Возврат;
КонецЕсли;
//ДатаИВремя записи меньше окончания сегодняшнего дня (согласно условий задачи звонки идут на прием ТекущаяДата() + День
Если ЗаписьПациента.ДатаИВремя < КонецДня(ТекущаяДата()) Тогда
Возврат;
КонецЕсли;
//Если не заполнены данные пациента – возврат
Если не ТипЗнч(ЗаписьПациента.Пациент) = Тип("СправочникСсылка.Пациенты") Тогда
Возврат;
КонецЕсли;
СписокСтатусов = Новый СписокЗначений;
СписокСтатусов.Добавить(Справочники.СтатусДокумента.НайтиПоНаименованию("Не явка"));
СписокСтатусов.Добавить(Справочники.СтатусДокумента.НайтиПоНаименованию("Отменен"));
СписокСтатусов.Добавить(Справочники.СтатусДокумента.НайтиПоНаименованию("Прием окончен"));
ОбрЭлемент = Справочники.МТТ_Обмен.НайтиПоРеквизиту("ЗаписьПациента",ЗаписьПациента.Ссылка).Ссылка;
//обработка данных записи, выставление статуса «Бронь»
КонецПроцедуры
Листинг 1: ОбработатьЗаписьПациента(ЗаписьПациента)
Далее следует проверка на корректность номера пациента функцией ПолучитьНомерПациента(Пациент):
&НаСервере
Функция ПолучитьНомерПациента(Пациент) Экспорт
ВхСтрока = Пациент.Телефон;
ВыхСтрока = Сред(ВхСтрока,2,1) + Сред(ВхСтрока,4,3) + Сред(ВхСтрока,8,3) + Сред(ВхСтрока,12,2) + Сред(ВхСтрока,15,2);
Возврат ВыхСтрока;
КонецФункции
Листинг 2: ПолучитьНомерПациента(Пациент)
Достаточно простая функция, не учитывающая содержание в номере только цифр. По-умолчанию мы считаем, что все номера в справочнике проверены.
&НаСервере
Процедура ОтправитьЗапросВМТТ(ВыбГУИД) Экспорт
ЭлементСправочника = Справочники.МТТ_Обмен.ПолучитьСсылку(ВыбГУИД);
Если (не ЗначениеЗаполнено(ЭлементСправочника.Ссылка.Пациент)) или (не ЗначениеЗаполнено(ЭлементСправочника.Ссылка.ЗаписьПациента)) Тогда
ЭлементСправочника = ЭлементСправочника.Ссылка.ПолучитьОбъект();
ЭлементСправочника.Завершен = Истина;
КонецЕсли;
Если не ЭлементСправочника.ЗаписьПациента = Документы.ЗаписьПациента.ПустаяСсылка() Тогда
ЗаписьПациента = ЭлементСправочника.ЗаписьПациента.Ссылка.ПолучитьОбъект();
ЗаписьПациента.СтатусДокумента = Справочники.СтатусДокумента.НайтиПоНаименованию("Бронь не подтвержденная");
ЗаписьПациента.ПричинаОтмены = Справочники.ПричиныОтменыЗаписи.НайтиПоНаименованию("автообзвон: недозвон");
Попытка
ЗаписьПациента.Записать();
Исключение
КонецПопытки;
ЭлементСправочника.Записать();
Возврат;
КонецЕсли;
//Прочие преобразования данных
…..
//Формируем данные для передачи запроса в МТТ
ДанныеПакета = Новый Структура;
ДанныеПакета.Вставить("method",Константы.МТТ_ИмяМетода.Получить());
ДанныеОбзвона = Новый Структура;
ДанныеОбзвона.Вставить("number",Строка(ЭлементСправочника.number_b));
ДанныеОбзвона.Вставить("guid",Строка(ЭлементСправочника.УникальныйИдентификатор()));
ДанныеОбзвона.Вставить("name",Строка(ЭлементСправочника.NameStr));
ДанныеОбзвона.Вставить("visit",НормализацияСтроки(СокрЛП(ЭлементСправочника.VisitStr)));
ДанныеПакета.Вставить("data",ДанныеОбзвона);
//Отправляем данные в функцию модуля, листинг 4
ЗапросМТТ = СформироватьJSONМногомерный(ДанныеПакета, Истина);
//Получаем ответ выполнения запроса – ключевой момент – call_id
Результат = ОповеститьСервер(ЗапросМТТ);
ЗаписьОбъект = ЭлементСправочника.Ссылка.ПолучитьОбъект();
ЗаписьОбъект.СтатусОтправкиЗапроса = Строка(Результат);
ЗаписьОбъект.Завершен = Ложь;
ЗаписьОбъект.Записать();
ЧтениеОтвета = Новый ЧтениеJSON;
//Тип число – ответ не обработки запроса, а HTTP метода, статус. Значит, от сервера не получено JSON-формы
Если не ТипЗнч(Результат)=Тип("Число") Тогда
ЧтениеОтвета.УстановитьСтроку(Результат);
Попытка
ДанныеОтвета = ПрочитатьJson(ЧтениеОтвета, Истина);
ЗаписьОбъект.call_id = ДанныеОтвета.Получить("id");
ЗаписьОбъект.call_date = ТекущаяДата();
ЗаписьОбъект.call_time = ТекущаяДата();
ЗаписьОбъект.Записать();
Исключение
Возврат;
КонецПопытки;
КонецЕсли;
КонецПроцедуры
Листинг 3: ОтправитьЗапросВМТТ(ВыбГУИД)
Основные моменты приведенного листинга: формируем JSON Запрос, отправляем его функциями отправки, получаем ответ call_id или статус HTTP сервера, фиксируем полученные данные в справочнике. В дальнейшем начинаем искать уже по статусу call_id, с которым будут приходить следующие запросы.
&НаСервере
Функция СформироватьJSONМногомерный(СтруктураДанных, ФормироватьСПереносами = Ложь) Экспорт
ЗаписьJSON = Новый ЗаписьJSON;
Если ФормироватьСПереносами Тогда
ЗаписьJSON.УстановитьСтроку(Новый ПараметрыЗаписиJSON());
Иначе
ЗаписьJSON.УстановитьСтроку(Новый ПараметрыЗаписиJSON(ПереносСтрокJSON.Unix,,Истина));
КонецЕсли;
НастройкиСериализацииJSON = Новый НастройкиСериализацииJSON;
НастройкиСериализацииJSON.ВариантЗаписиДаты = ВариантЗаписиДатыJSON.ЛокальнаяДатаСоСмещением;
НастройкиСериализацииJSON.ФорматСериализацииДаты = ФорматДатыJSON.ISO;
Попытка
ЗаписатьJSON(ЗаписьJSON, СтруктураДанных, НастройкиСериализацииJSON);
Возврат ЗаписьJSON.Закрыть();
Исключение
Возврат Неопределено;
КонецПопытки;
КонецФункции
Листинг 4: СформироватьJSONМногомерный(СтруктураДанных, ФормироватьСПереносами = Ложь)
Привожу тут код в формате «как есть», подходит для вставки в любую часть вашего кода. Отлаживал и настраивал, код рабочий, проверен.
&НаСервере
Функция ОповеститьСервер(ЗапросJSON) Экспорт
ЗаголовокЗапросаHTTP = Новый Соответствие();
// Передаем в заголовках тип данных на отправку. Пароль храню в константе конфигурации
ЗаголовокЗапросаHTTP.Вставить("Authorization", "Basic " + СокрЛП(Константы.МТТ_ЛогинПароль.Получить()));
ЗаголовокЗапросаHTTP.Вставить("Content-Type", "application/json charset=utf-8");
ЗаголовокЗапросаHTTP.Вставить("Accept", "*/*");
ЗаголовокЗапросаHTTP.Вставить("Connection", "keep-alive");
//РазбитьАдресИнтернет – функция модуля, написана специально для данной задачи. Аналогична функции ПолучитьНомерПациента()
ДанныеАдреса = РазбитьАдресИнтернет(Константы.МТТ_HTTPSАдрес.Получить());
Если ДанныеАдреса.Получить("https") Тогда
HTTP = Новый HTTPСоединение(ДанныеАдреса.Получить("Адрес"),Число(ДанныеАдреса.Получить("Порт")),,,,,Новый ЗащищенноеСоединениеOpenSSL());
Иначе
HTTP = Новый HTTPСоединение(ДанныеАдреса.Получить("Адрес"),Число(ДанныеАдреса.Получить("Порт")));
КонецЕсли;
запросPOST = Новый HTTPЗапрос(ДанныеАдреса.Получить("Суффикс"), ЗаголовокЗапросаHTTP);
запросPOST.УстановитьТелоИзСтроки(ЗапросJSON,"UTF-8");
ОтветСервера = "";
Попытка
HTTPОтвет = HTTP.ОтправитьДляОбработки(запросPOST);
ОтветСервера = HTTPОтвет.ПолучитьТелоКакСтроку();
Если ОтветСервера = "" Тогда
ОтветСервера = HTTPОтвет.КодСостояния;
КонецЕсли;
Исключение
//тут дебаг
КонецПопытки;
Возврат ОтветСервера;
КонецФункции
Листинг 5: Функция ОповеститьСервер(ЗапросJSON)
С функцией отправки предлагаю поступить аналогично функции формирования запроса, а именно использовать в формате «как есть». Долго отлаживал заголовки, получился в итоге рабочий вариант, не требующий изменений.
&НаСервере
Процедура ОбработатьВходящийПакет(ДанныеПакета) Экспорт
//Позиционируемся на справочник по статусу ответа
НашЭлемент = Справочники.МТТ_Обмен.НайтиПоРеквизиту("call_id",Строка(ДанныеПакета.Получить("call_id")));
Если НашЭлемент = Справочники.МТТ_Обмен.ПустаяСсылка() Или НашЭлемент = Неопределено Тогда
//обработка на случай отсуствия call_id
Иначе
НашЭлемент = НашЭлемент.Ссылка.ПолучитьОбъект();
НашЭлемент.СтатусПриемаОтвета = "ОК";
КонецЕсли;
НашЭлемент.call_id= Строка(ДанныеПакета.Получить("call_id"));
НашЭлемент.call_time = ТекущаяДата();
НашЭлемент.call_date = ТекущаяДата();
НашЭлемент.number_b = Строка(ДанныеПакета.Получить("number_b"));
НашЭлемент.ResponseCode = Строка(ДанныеПакета.Получить("response"));
НашЭлемент.Записать();
//Далее идет проверка и установка необходимых статусов, исходя из полученных значений, завершение бронирования.
КонецПроцедуры
Листинг 6: Процедура ОбработатьВходящийПакет(ДанныеПакета)
Обязательно приведу листинг 7 процедуры нормализации строки, передаваемой для произнесения роботом МТТ. Есть символы, которые не произносятся и могут вызвать отказ и перевод на оператора.
Функция НормализацияСтроки(СтрокаJSON) Экспорт
НовСтрока = "";
ПравильныеСимволы = " :1234567890QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnmЙЦУКЕНГШЩЗХЪФЫВАПРОЛДЖЭЯЧСМИТЬБЮйцукенгшщзхъфывапролджэячсмитьбю";
Для Сч = 1 по СтрДлина(СтрокаJSON) Цикл
ТекСимв = Сред(СтрокаJSON, Сч, 1);
Если Найти(ПравильныеСимволы, ТекСимв) > 0 Тогда
НовСтрока = НовСтрока + ТекСимв;
Иначе
НовСтрока = НовСтрока + " ";
КонецЕсли;
КонецЦикла;
Возврат НовСтрока;
КонецФункции
Листинг 7: Функция НормализацияСтроки(СтрокаJSON)
Заключение
В статье изложил основные методы и принципы настройки обмена на стороне 1С. Настройки Voicebox от компании МТТ привел на своем примере. Функциональность запущена на реальных данных 30 мая 2022 года, отладку механизма завершил 4 июля.
В результате тестовой работы ошибок обмена нет. Но очень долго шел к тому, что нужно фиксировать установку соединения в результате звонка. Иначе оставались «Мертвые души» в справочнике МТТ_Обмен без статусов. В связи с этим механизм набирал условленное количество раз, которое меньше счетчика справочника МТТ_Обмен.КоличествоНеудачныхПопыток без указания статуса, не менял статус документа.
При реализации HTTP-метода отражения инициации звонка стало понятно, отработал запрос звонка или нет. В итоге стандартным стал считаться статус «взял-положил трубку до отработки скрипта», и все стало работать корректно
МТТ оказали поддержку на всех этапах. Разбирались и оптимизировали скрипты совместно, на все вопросы появились ответы. Особенно это было актуально, когда вместе с заказчиком настраивали веб-сервер IIS для публикации базы данных, обеспечивали нестандартный порт для приема ответов от Voicebox.
Всем спасибо за прочтение статьи, прошу все вопросы задавать в комментариях.
avbolh
1.
Попытка
ЗаписьПациента.Записать();
Исключение
КонецПопытки;
Вы не пишите в журнал регистрации ничего при ошибке записи? в ветке Исключение. Почему?
Вы не слышали про КоннекторHttp? Опенсорсный проект, просто добавляете общий модуль и работа с http запросами становится лаконичнее и проще
Справочники.СтатусДокумента.НайтиПоНаименованию("Бронь не подтвержденная");
НайтиПоНаименованию? Это ваш же справочник, может предопределенные элементы создать
Bessome Автор
Спасибо за комментарий.
Вся обработка отказов удалена ради легкости чтения логики алгоритма. В обработчике исключений строк больше, чем в основном алгоритме
Используем функционал 1С без дополнительных модулей. В данной задаче наличие внешней компоненты для передачи-приема пары строк запроса не является необходимостью.
Справочник не мой, а находится в не редактируемой в данном случае части конфигурации. Предопределенные значения в нем имеются, но не все необходимые. На вопрос: "Есть ли требование создавать новые предопределенные значения?" заказчик задачи просил не менять ничего в конфигурации, так как ведется "сложный" процесс ее обновления на несколько релизов и у заказчика нет желания возвращаться к доработке приведенного кода в дальнейшем.
vis_inet
Ну, хотя бы "НайтиПоКоду()", и то несколько надёжнее будет.
Bessome Автор
Вопрос привычки, надежность привязки к коду может быть сомнительна. Разработчик меняет тип кода с Числа на Строку и приплыли.
vis_inet
Более вероятно, что какой-нибудь пользователь изменит наименование.
Bessome Автор
Только админ
Будет наказан
Я помечу сейчас в статье рекомендации этой ветки, спасибо за комментарий