Привет всем. Ко мне обратился заказчик из стоматологии с просьбой сделать интеграцию с системой ЛоялМед. Это система лояльности для медицинских клиник у них есть чат-бот и система начисления бонусов за оказанные услуги.
После детального изучения выяснилось: необходим односторонний обмен - выгрузка данных пациентов, их записей на прием, приемов, платежей на сайт ЛоялМеда. Со стороны ЛоялМед настроено Django REST framework(далее DRF) для приема данных в JSON.
Конфигурация заказчика БИТ.Стоматология 2.0
Решение было следующее:
В отдельном расширении создан регистр сведений для регистрации очереди на выгрузку в DRF.
Подписки на события при записи объектов: справочник Клиенты, документ Заявка, документ ОказаниеУслуг
Регламентное задание на выгрузку DRF, если выгрузка объекта удачна - запись удаляется из регистра, если нет в логах DRF - пишется описание ошибки.
Авторизация идет по токену, хост и токен положил в константы.
Выгрузка сперва идет методом POST, если объект уже создан, то выгрузка идет методом PUT.
Ниже пример выгрузки клиента на сайт:
Процедура ВыгрузитьКлиента(Клиент, ТокенЛМ, ХостЛМ)
Попытка
Соединение = Новый HTTPСоединение(ХостЛМ,,"","",,,Новый ЗащищенноеСоединениеOpenSSL()
);
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Клиенты.Код КАК Код,
| Клиенты.Фамилия КАК Фамилия,
| Клиенты.Имя КАК Имя,
| Клиенты.Отчество КАК Отчество,
| Клиенты.ДатаРождения КАК ДатаРождения,
| Клиенты.ДатаСоздания КАК ДатаСоздания,
| Клиенты.Пол КАК Пол,
| Клиенты.КлиентЛМ КАК КлиентЛМ,
| Клиенты.ДатаЛМ КАК ДатаЛМ,
| Клиенты.ЗаконныйПредставитель КАК ЗаконныйПредставитель,
| ЕСТЬNULL(КонтактнаяИнформация.Представление, """") КАК Телефон,
| Клиенты.ЗаконныйПредставитель.Код КАК ЗаконныйПредставительКод
|ИЗ
| Справочник.Клиенты КАК Клиенты
| ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.КонтактнаяИнформация КАК КонтактнаяИнформация
| ПО Клиенты.Ссылка = КонтактнаяИнформация.Объект
| И (КонтактнаяИнформация.Вид = &Вид)
|ГДЕ
| Клиенты.Ссылка = &Ссылка";
Запрос.УстановитьПараметр("Ссылка", Клиент);
Запрос.УстановитьПараметр("Вид", Справочники.ВидыКонтактнойИнформации.ТелефонСотовый);
Результат = Запрос.Выполнить();
Контрагент = Результат.Выбрать();
Пока Контрагент.Следующий() Цикл
//Формируем структуру с данными
СтруктураЗапроса = Новый Структура;
КК = ПолучитьЧислоИзСтроки(Контрагент.Код);
СтруктураЗапроса.Вставить("id", КК);
СтруктураЗапроса.Вставить("lastname", Контрагент.Фамилия);
СтруктураЗапроса.Вставить("firstname", Контрагент.Имя);
СтруктураЗапроса.Вставить("midname", Контрагент.Отчество);
Если ЗначениеЗаполнено(Контрагент.ДатаРождения) Тогда
СтруктураЗапроса.Вставить("birthdate", Формат(Контрагент.ДатаРождения,"ДФ=гггг-ММ-дд"));
КонецЕсли;
СтруктураЗапроса.Вставить("created_in_mis", ?(ЗначениеЗаполнено(Контрагент.ДатаСоздания),Формат(Контрагент.ДатаСоздания,"ДФ=гггг-ММ-ддTЧЧ:мм:сс"), Формат(ТекущаяДата(),"ДФ=гггг-ММ-ддTЧЧ:мм:сс")));
СтруктураЗапроса.Вставить("gender", ПолучитьПол(Контрагент.Пол));
СтруктураЗапроса.Вставить("loyalmed_type", ?(Контрагент.КлиентЛМ = Истина,1,0));
Тел = Контрагент.Телефон;
Тел = ПолучитьЧислоИзСтроки(Тел);
Если Лев(Тел,1) = "8" Тогда
Тел = Сред(Тел,2);
Тел = "7"+Тел;
КонецЕсли;
СтруктураЗапроса.Вставить("phone1", Тел);
Если ЗначениеЗаполнено(Контрагент.ДатаЛМ) Тогда
СтруктураЗапроса.Вставить("loyalmed_enabled_timestamp", Формат(Контрагент.ДатаЛМ,"ДФ=гггг-ММ-ддTЧЧ:мм:сс"));
КонецЕсли;
СтруктураЗапроса.Вставить("updated_in_mis", Формат(ТекущаяДата(),"ДФ=гггг-ММ-ддTЧЧ:мм:сс"));
Если ЗначениеЗаполнено(Контрагент.ЗаконныйПредставитель) И ТипЗнч(Контрагент.ЗаконныйПредставитель) = Тип("СправочникСсылка.Клиенты") Тогда
СтруктураЗапроса.Вставить("representative_id", ПолучитьЧислоИзСтроки(Контрагент.ЗаконныйПредставительКод));
КонецЕсли;
//Преобразуем полученную структура в JSON
ЗаписьJSON = Новый ЗаписьJSON;
ЗаписьJSON.УстановитьСтроку();
ЗаписатьJSON(ЗаписьJSON, СтруктураЗапроса);
СтрокаЗапроса = ЗаписьJSON.Закрыть();
HTTPОтвет = ОтправитьPOSTЗапрос(Соединение, СтрокаЗапроса, ТокенЛМ, "clients");
//если объект успешно создан DRF возвращает код 201, иначе отправляем PUT
Если HTTPОтвет.КодСостояния = 201 Тогда
//удаляем объект из регистра очереди
УдалитьОбъектИзОчереди(Клиент);
Иначе
HTTPОтвет = ОтправитьPUTЗапрос(Соединение, СтрокаЗапроса, ТокенЛМ, "clients", КК);
//если обновление объекта прошло - возращается код 200, иначе сохраняем ответ в спец регистр
Если HTTPОтвет.КодСостояния = 200 Тогда
УдалитьОбъектИзОчереди(Клиент);
Иначе
ТелоОтвета = HTTPОтвет.ПолучитьТелоКакСтроку();
ЗаписатьОтвет(Контрагент, ТелоОтвета);
КонецЕсли;
КонецЕсли;
КонецЦикла;
Исключение
ЗаписатьОшибку(Контрагент, ОписаниеОшибки());
//ЖурналРегистрации.
КонецПопытки;
КонецПроцедуры
Процедура УдалитьОбъектИзОчереди(Объект)
ЗаписьCOM = РегистрыСведений.ОбъектыДляВыгрузкиВЛМ.СоздатьМенеджерЗаписи();
ЗаписьCOM.ОбъектДляВыгрузки = Объект;
ЗаписьCOM.Удалить();
КонецПроцедуры
Функция ОтправитьPOSTЗапрос(Соединение, СтрокаЗапроса, ТокенЛМ, ТипОбъекта)
HTTPЗапрос = Новый HTTPЗапрос("/"+ТипОбъекта+"/");
HTTPЗапрос.Заголовки.Вставить("Content-type", "application/json");
//Авторизация идет по токену, токен выдали на стороне DRF
HTTPЗапрос.Заголовки.Вставить("Authorization", "token "+ТокенЛМ+"");
HTTPЗапрос.УстановитьТелоИзСтроки(СтрокаЗапроса, КодировкаТекста.UTF8, ИспользованиеByteOrderMark.НеИспользовать);
HTTPОтвет = Соединение.ОтправитьДляОбработки(HTTPЗапрос);
Возврат HTTPОтвет;
КонецФункции
Функция ОтправитьPUTЗапрос(Соединение, СтрокаЗапроса, ТокенЛМ, ТипОбъекта, ИдОбъекта)
HTTPЗапрос = Новый HTTPЗапрос("/"+ТипОбъекта+"/"+ИдОбъекта+"/");
HTTPЗапрос.Заголовки.Вставить("Content-type", "application/json");
HTTPЗапрос.Заголовки.Вставить("Authorization", "token "+ТокенЛМ+"");
HTTPЗапрос.УстановитьТелоИзСтроки(СтрокаЗапроса, КодировкаТекста.UTF8, ИспользованиеByteOrderMark.НеИспользовать);
HTTPОтвет = Соединение.ВызватьHTTPМетод("PUT",HTTPЗапрос);
Возврат HTTPОтвет;
КонецФункции