Выгрузка данных на сайт из 1С через Django REST framework

10.06.24

Интеграция - Сайты и интернет-магазины

Пример одностороннего обмена с сайтом Django через Django REST framework.

Привет всем. Ко мне обратился заказчик из стоматологии с просьбой сделать интеграцию с системой ЛоялМед. Это система лояльности для медицинских клиник у них есть чат-бот и система начисления бонусов за оказанные услуги.

После детального изучения выяснилось: необходим односторонний обмен - выгрузка данных пациентов, их записей на прием, приемов, платежей на сайт ЛоялМеда. Со стороны ЛоялМед настроено 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Ответ;
	
КонецФункции

 

обмен DRF HTTP-Запрос

См. также

Сайты и интернет-магазины Платформа 1С v8.3 1С:Розница 3.0 Розничная и сетевая торговля (FMCG) Россия Платные (руб)

Готовое интеграционное решение для оплаты покупок Долями в 1C:Розница 3.0. Реализовано в виде расширения. Интеграция сервиса dolyame.ru для приема платежей в рассрочку. Поддерживает работу от разных юридических лиц. Работа: в составе РИБ, отдельно от РИБ, тонкий, толстый клиент, web-клиент (через интернет-браузер). Интегрировано в Чек ККМ, Рабочее место кассира (РМК)

24000 руб.

02.11.2024    1283    10    0    

8

Сайты и интернет-магазины Платформа 1С v8.3 1С:Розница 2 Розничная и сетевая торговля (FMCG) Россия Платные (руб)

Интеграция сервиса dolyame.ru с 1С:Розница 2.3 для приема платежей в рассрочку. Готовое интеграционное решение для оплаты покупок Долями в 1C:Розница 2.3. Реализовано в виде расширения. Интеграция сервиса dolyame.ru для приема платежей в рассрочку. Поддерживает работу от разных юридических лиц.Работа: в составе РИБ, отдельно от РИБ, тонкий, толстый клиент, web-клиент (через интернет-браузер).

22440 руб.

19.12.2023    7313    45    12    

41

Сайты и интернет-магазины WEB-интеграция Системный администратор Программист Пользователь Платформа 1С v8.3 1C:Бухгалтерия 1С:Управление торговлей 11 Автомобили, автосервисы Россия Управленческий учет Платные (руб)

Интеграционный модуль обмена между конфигурацией Альфа Авто 5 и Альфа Авто 6 и порталом AUTOCRM. Данный модуль универсален. Позволяет работать с несколькими обменами AUTOCRM разных брендов в одной информационной базе в ручном и автоматическом режиме.

36000 руб.

03.08.2020    19340    24    22    

20

Прайсы Оптовая торговля Сайты и интернет-магазины Программист Пользователь Платформа 1С v8.3 Оперативный учет Управляемые формы 1С:Управление торговлей 11 Транспорт, автопарки, такси Управленческий учет Платные (руб)

Внешняя обработка адаптирована для 1C: УТ 11, предназначена для наполнения вашей базы данных товарами и сопутствующей информацией, предоставляемой b2b.4tochki.ru, обновления остатков и цен.

8160 руб.

31.01.2020    32457    17    7    

16

Сайты и интернет-магазины Программист Пользователь Платформа 1С v8.3 Бухгалтерский учет 1С:Бухгалтерия 3.0 Россия Платные (руб)

Данный модуль предоставляет возможность выгружать заказы из 1С: Управление торговлей 11 версии в "MEASOFT" (ранее "Курьерская служба 2008").

9600 руб.

27.04.2022    11873    21    3    

12

Сайты и интернет-магазины Программист Пользователь Платформа 1С v8.3 План видов характеристик 1С:Управление торговлей 11 1С:Комплексная автоматизация 2.х Розничная и сетевая торговля (FMCG) Оптовая торговля, дистрибуция, логистика Россия Управленческий учет Платные (руб)

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

3600 руб.

25.05.2020    21182    16    16    

20
Комментарии
Подписаться на ответы Инфостарт бот Сортировка: Древо развёрнутое
Свернуть все
1. Nikola23 707 10.06.24 17:25 Сейчас в теме
Прошу уточнить, при чем тут Jango, если пример демонстрирует формирование HTTP запроса?
Не сомневаюсь, что на той стороне джанго существует, но разве это имеет какое-то значение?
В примере это не раскрыто

А из своего опыта, я понимаю, что никакой особой разницы, какой там фреймворк - нет
2. gea29021988 6 10.06.24 17:37 Сейчас в теме
(1) Насколько я знаю именно строка адреса запроса формируется у всех по-разному, здесь именно Django REST Framework, это не джанго чистый это API к Django и здесь я показываю запрос именно к этому API вида
"/"+ТипОбъекта+"/"+ИдОбъекта+"/"
Знаю точно что в других API есть где ИдОбъекта пихается в тело запроса, а не в адрес.
3. Nikola23 707 10.06.24 22:52 Сейчас в теме
(2) Я абсолютно не против статей, где раз за разом показывают одно и тоже
Но вот без указания, что фишка статьи вот в этой строке
"/"+ТипОбъекта+"/"+ИдОбъекта+"/"
- как-то я совсем не догадался.
Может как-то выделить это?)
8. RocKeR_13 1411 11.06.24 16:30 Сейчас в теме
(3)
что фишка статьи вот в этой строке

Это не фишка, это обычная строка адреса запроса, правило формирования которой должно быть изложено в документации. Фишкой в свое время было описание формирования тела запроса multipart/form-data. А это именно то, что вы и написали сначала:

пример демонстрирует формирование HTTP запроса
4. gybson 11.06.24 00:02 Сейчас в теме
Такие огромные попытки зло и здесь очень хорошо видно почему. Если исключение произойдет при установке соединения, то при попытке сформировать сообщение об ошибке произойдет исключение. И даже если исключение обработается, то из него не очень будет понятно где и что произошло.

Если получен код 4** или 500, то смысл продолжать?

Конкатенация строк вместо шаблона.

Транзакции нет.

ОбъектыДляВыгрузкиВЛМ не используется в запросе

Как-то вообще все не так.
5. gea29021988 6 11.06.24 07:21 Сейчас в теме
(4) Если получен код 4** или 500, то смысл продолжать?
Если метод POST возвращает 400, то запускается PUT редактирование объекта
6. RocKeR_13 1411 11.06.24 16:24 Сейчас в теме
(4)
Транзакции нет.

Про транзакцию не понял: зачем она тут? В остальном согласен: много воды, вопросов и ничего нового.
7. gybson 11.06.24 16:28 Сейчас в теме
(6) чтобы не снимать с регистрации без положительного ответа сервиса
10. RocKeR_13 1411 11.06.24 16:35 Сейчас в теме
(7)
чтобы не снимать с регистрации без положительного ответа сервиса

А транзакция-то тут при чем?) Отправили запрос - пришел ответ: если ок, то сняли, если ошибка - продолжили. Единственный смысл - это открыть транзакцию перед началом цикла, но она, наоборот, в этом случае будет только вредить: транзакция в случае ошибки будет откатываться исключительно в 1С, а на стороне http-сервиса успешные запросы не откатятся; в итоге если на 5 запросе придет ошибка, то в 1С регистрация не снимется, но первые 4 запроса так и останутся успешно обработанными на стороне сервиса - в итоге 4 запроса при следующей выгрузке лишний раз будут продублированы
13. gybson 11.06.24 18:44 Сейчас в теме
(10) несомненно именно так и будет, если так сделать


Имеется в виду объединение в транзакцию удаление записи из регистра и запрос на сервис. Если запрос вызвал исключение, то записи не будет. А исключение он может дать запросто. Например сервис закроет соединение за спам или по таймауту.
14. RocKeR_13 1411 11.06.24 21:10 Сейчас в теме
(13) Ну отвалится по таймауту и ладно, транзакция зачем?) Транзакция нужна, чтобы данные в базе изменялись согласованно и при возникновении ошибки отменялись все изменения, произведённые в рамках транзакции. А тут по сути 2 действия: запрос к стороннему сервису и удаление записи регистра; первое действие не производит никаких действий в базе и отмена транзакции никак на него не может повлиять. Тут простая проверка условия: запрос выполнен успешно - удаляем запись; иначе делаем другие манипуляции или пишем ошибку в журнал. Транзакция не нужна для этого
9. Nikola23 707 11.06.24 16:33 Сейчас в теме
(8)
(6)
много воды, вопросов и ничего нового


Вот и я в первом сообщении завуалировал эту мысль.
Но не хотелось быть токсиком, поэтому не стал хэйтить, пошел вокруг)
11. RocKeR_13 1411 11.06.24 16:40 Сейчас в теме
(9) Ну можно же не минусовать) Ну познакомился человек с http-запросами - отлично и полезно. А мы тут подскажем, что не так и, может быть, подскажем, что сделать, чтобы было другим полезно и интересно))
12. Nikola23 707 11.06.24 16:59 Сейчас в теме
(11) а при чем тут минуса? Это не ко мне
15. RocKeR_13 1411 11.06.24 21:11 Сейчас в теме
Оставьте свое сообщение