Каталог решений - HTTP сервис на 1С:Шина за 1 день

HTTP сервис на 1С:Шина за 1 день

HTTP сервис на 1С:Шина за 1 день

В наличии

Инструкция как сделать на 1С:Шина http сервис, который будет принимать json и перенаправлять в 1с-ную систему, в которой есть БСП
Позволит программисту создать свой http сервис за 1 день!
Технические детали:
1С:Шина версия 4.1.6 (В основе 1С:Шины лежит технология 1С:Предприятие.Элемент. )
Платформа 8.3.25.1394 (все зависит какие у вас требования у типовой конфигурации 1С с которой выполняется обмен)

Категория:

Описание

Статья написана по хроникам внедрения 1С:Шина версии 4.1 в Первом Бите на Спортивной.

Меня зовут Галац Михаил, хочу поделиться  реализацией отдельного http м ет ода на при внедрении шины у клиента, у которого 1С-ные и не 1С-ные информационные системы. Статья актуальная версия на декабрь 2024 г. 

 

Сокращения:

  • ИС 1С –информация система на базе 1С конфигурация с БСП.
  • Шина – 1С:Шина версии 4.1.
  • Json – текстовый файл в формате json.
  • Транслятор – объект 1С:Шина в котором выполняется преобразование сообщения.
  • Канал – объект 1С:Шина, который осуществляется доставку сообщения.
  • id – уникальный код в формате uuid.
  • РС — регистр сведений.
  • Проект — термин 1с:Шина.
  • Сообщение — сообщение интеграции.

 

Допуски:

  • У вас имеется развернутая 1С:Шина не ниже версии 4.1

 

Источники:

  • Официальная документация по продукту 1С:Шина. Ссылка
  • Неофициальная группа в tg @esb_1C

 

Благодарности:

Отдельная благодарность, это наличие  Алексея Борисевича, моего технического архитектора по внедрению проектов 1С:Шина, за консультации и помощь в реализации, когда я был в тупике.

Моему руководителю Гейдару Габриэлянцу за корректировки в статье. 

 

Описание задачи

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

 

Краткое описание реализации:

Шина получает json и направляет его в канал внутри шины. 

На стороне шины нужно сделать ряд проверок (проверки на заполнение, операции с датами) и  в случае обнаружения дать ответ в виде json Формат 1.

В случае отсутствия ошибок, присвоить в шине данному пакету id и сделать запись в РС «Сообщения для внешних систем», чтобы зафиксировать заявку в виде json Формате 5. При формировании сообщения добавить ему параметры id и тип сообщения.

ИС 1С забирает из канала с ообщение и записывает его во внутренний регистр сведений «Полученные сообщения» и уже на основе сформированной записи из РС «Полученные сообщения» создается документ. При изменении статус документа, выполняется формируется json и кладем в регистр сведений «Отправленные сообщения» в виде отдельной записи, а json записываем в реквизите РС «Тело сообщения».

Далее из РС «Отправленные сообщение» с использованием сервис интеграции отправляется в шину сообщение. Данное сообщение внутри шины преобразуется через транслятор и сохраняется запись в шине в регистр сведений «Сообщения для внешних систем». На рисунке 1, представлено схематичное описание решения, которое рассматривается в данной статье:

 

Рисунок 1. Пример для Шины-Создание заявки

 

А теперь более подробно с примерами кода и скринами из приложений, чтобы стало более понятно и вы смогли бы воспроизвести у себя и получить профит от данной статьи.

Предполагается, что у вас уже есть проект, приложение можно создать из архива, который можно скачать в конце статьи. Или более тернистый путь и создать самостоятельно в 1С: Шина в виде отдельного  приложения на основе данной статьи. 

Процесс интеграции – http сервис – шаблон, ну и в модулях добавить код из статьи. Кстати, в дефолтовой инструкции процесс создания Процесс интеграции – http сервис – шаблон описан подробно.

Обычно для несложных проектов используется одно приложение, такой вариант предлагается, потому что сопровождать проще, выгружать / загружать данные было более удобно. Разработку с использованием git не рассматриваем (но, возможно, кто осветит данный аспект для 1С:Шина), напомню, моя задача показать практический пример, который вы сразу сможете использовать у себя на проекте. 

Вся разработка выполняется во встроенной ide шины.

А теперь создадим свой http сервис.

В навигаторе проекта, в контекстном меню создаем новый элемент проекта, см. Рисунок 2, а на рисунке 3 выбираем Элемент проекта. 

 

Рисунок 2 Создание нового элемента проекта

 

Рисунок 3 Создание Процесса Интеграции

 

  1. Права доступа пока ставим "РазрешеноВсем", если требуется ограничивать, то следующий уровень понимания.
  2. Корневой Url ставим "v1" это наша первая версия сервиса.

Примечание.

url нашего сервиса будет примерно такой http://localhost:9090/applications/<ИмяПроекта>

Внутри сервиса интеграции рисуем схему, по которой будут идти сообщения. У меня получилось так.

 

Рисунок 4 Схема Процесса Интеграции

 

 

Краткое описание по рисунку 4.

json, который присылают на http сервис мы проверим и отправим в Программный Источник и далее Сообщение Интеграции  отправляем в канал "ИзВнешнихСистем", далее сервис интеграции в ИС 1С заберет сообщения, которые там будут находиться. Взаимодействия из ИС 1С в шину в данном бизнес процессе не рассматривается.

Запустим приложение, жмем F5 и посмотрим, что получилось для нашего случая 

http://localhost:9090/applications/test

Перейдя по ссылке в браузере должно отобразиться так, см. рисунок 5.

 

Рисунок 5 Пример запущенного тестового приложения

 

Далее создаем новый шаблон у http сервиса для рассматриваемой задачи, нужен с типом POST.

В свойствах шаблона указываем следующие действия:

Переходим в раздел Шаблоны -> Новый -> Шаблон URL, см рисунок 6.

 

Рисунок 6 Создание нового шаблона

 

И заполняем свойства шаблона:

  • Имя «Заявка»
  • КонтрольДоступа — Вызов — РазрешеноВсем
  • Шаблон /orders

 

Рисунок 7 Свойства шаблона созданного http сервиса

 

Теперь добавляем, какие запросы этот шаблон должен обрабатывать, у меня это POST:

  • имя POST
  • Метод: POST
  • Обработчик: жмем на лупу или вводим свое имя метода и жмем лупу.

 

Рисунок 8.Свойства запроса

 

В дереве объектов получится так

 

Рисунок 9 Дерево объектов созданного http сервиса

 

Теперь, когда у нас созданы все объекты, то переходим в метод определенном на рисунке 8 «ОбработкаЗапроса», если в обработчике будет пусто, жмем на лупу, и название присваивается по умолчанию, как моем примере. 

Ниже приведен текст метода с комментариями

// Тут описываем структуры, которые есть внутри json

 

структура КонтактыКлиента
    обз пер cargos: Массив<product>
;

метод ОбработкаЗапросаЗаявка(Запрос: HttpСервисЗапрос)
    // Область переменных, корые нужно объявить заранее
    пер ПустойМассив = новый Массив<Число>()
    пер ТелоОтвета: Строка
    пер ГуидВызова = новый Ууид()
    
    /* 
    Так как поток после прочтения закрывается ,поэтому готовим его заранее, 
    чтобы передавать его в канал    
    Тело запрос сериализуем в json, далее в строку и создаем поток из строки.
    */    
    
    знч ТелоЗапросаИзПотока = Запрос.Тело.ПрочитатьКакСтроку()    
    пер ТелоЗапросаПоток = ПотокЧтения.ИзСтроки(ТелоЗапросаИзПотока)
    пер ТелоЗапроса = СериализацияJson.ПрочитатьОбъект(ТелоЗапросаПоток)
    пер ТелоЗапросаСтрокаПоток = ПотокЧтения.ИзСтроки(ТелоЗапросаИзПотока)
    
    // В канал отправляем тело запроса, коорые получилии и добавляем параметры апроса, 
    // чтобы идентифицировать и маршрутизировать данное сообщение в ИСНазначение
    пер Сообщение = новый СообщениеИнтеграции(
        {
            "id": ГуидВызова.ВСтроку(), "type" : "orders"
        }, ТелоЗапросаСтрокаПоток)

    пер Грузы = ТелоЗапроса["cargos"] // как Массив<Объект?>
    если Грузы == ПустойМассив //ORD107  
        пер КодОшибки = "ORD107"
        пер РасшифровкаТекстОшибки = "Отсутствуют грузы"
        пер ТекстОшибки =
            {
                "errorCode": КодОшибки,
                "errorMessage": РасшифровкаТекстОшибки
            }
        ТелоОтвета = СериализацияJson.ЗаписатьОбъект(ТекстОшибки)
    иначе если Грузы.ВСтроку() != ""
        для Груз из Грузы
            если Груз["places"] == ПустойМассив
                пер КодОшибки = "ORD108"
                пер РасшифровкаТекстОшибки = "Отсутствуют грузоместа"
                пер ТекстОшибки =
                    {
                        "errorCode": КодОшибки,
                        "errorMessage": РасшифровкаТекстОшибки
                    }
                ТелоОтвета = СериализацияJson.ЗаписатьОбъект(ТекстОшибки)
                прервать
            иначе
                пер грузоместа = Груз["places"] // Массив грузомест
                для грузоместо из грузоместа
                    если грузоместо["weight"]["value"] < 0
                        пер КодОшибки = "ORD113"
                        пер РасшифровкаТекстОшибки = "Некорректный вес грузового места"
                        пер ТекстОшибки =
                            {
                                "errorCode": КодОшибки,
                                "errorMessage": РасшифровкаТекстОшибки
                            }
                        ТелоОтвета = СериализацияJson.ЗаписатьОбъект(ТекстОшибки)
                        прервать
                    ;
                ;
            ;
            если Груз["items"] == ПустойМассив
                пер КодОшибки = "ORD109"
                пер РасшифровкаТекстОшибки = "Отсутствует номенклатура"
                пер ТекстОшибки =
                    {
                        "errorCode": КодОшибки,
                        "errorMessage": РасшифровкаТекстОшибки
                    }
                ТелоОтвета = СериализацияJson.ЗаписатьОбъект(ТекстОшибки)
                прервать
            ;
            если (Груз["origin"]["dueDate"]["from"] == "") или (Груз["destination"]["dueDate"]["from"] == "")
                пер КодОшибки = "ORD104"
                пер РасшифровкаТекстОшибки = "Не указано время 'От' в точке погрузке/выгрузки"
                пер ТекстОшибки =
                    {
                        "errorCode": КодОшибки,
                        "errorMessage": РасшифровкаТекстОшибки
                    }
                ТелоОтвета = СериализацияJson.ЗаписатьОбъект(ТекстОшибки)
                прервать
            иначе
                пер ДатаПогрузкиДо = новый Момент(Груз["origin"]["dueDate"]["to"])
                пер ДатаПогрузкиОт = новый Момент(Груз["origin"]["dueDate"]["from"])
                пер ДатаВыгрузкиДо = новый Момент(Груз["destination"]["dueDate"]["to"])
                пер ДатаВыгрузкиОт = новый Момент(Груз["destination"]["dueDate"]["from"])

                пер ДопустимоеВремяПогрузки = новый Длительность(4, 0, 0)
                знч ОтметкаВремениСейчас = Момент.Сейчас()

                если (ДатаПогрузкиОт >= ДатаПогрузкиДо) или (ДатаВыгрузкиОт >= ДатаВыгрузкиДо)
                    пер КодОшибки = "ORD279"
                    пер РасшифровкаТекстОшибки = "Дата 'до' ('to') раньше или равна дате 'от' ('from') той же операции"
                    пер ТекстОшибки =
                        {
                            "errorCode": КодОшибки,
                            "errorMessage": РасшифровкаТекстОшибки
                        }
                    ТелоОтвета = СериализацияJson.ЗаписатьОбъект(ТекстОшибки)
                    прервать
                иначе если ДатаВыгрузкиОт <= ДатаПогрузкиОт или ДатаВыгрузкиОт <= ДатаПогрузкиДо
                    пер КодОшибки = "ORD277"
                    пер РасшифровкаТекстОшибки = "Дата-время выгрузки 'от' ('from') раньше или равна дате погрузки"
                    пер ТекстОшибки =
                        {
                            "errorCode": КодОшибки,
                            "errorMessage": РасшифровкаТекстОшибки
                        }
                    ТелоОтвета = СериализацияJson.ЗаписатьОбъект(ТекстОшибки)
                    прервать
                иначе если ДатаПогрузкиОт < (ОтметкаВремениСейчас + ДопустимоеВремяПогрузки)
                    пер КодОшибки = "ORD270"
                    пер РасшифровкаТекстОшибки = "Недостаточно времени до погрузки"
                    пер ТекстОшибки =
                        {
                            "errorCode": КодОшибки,
                            "errorMessage": РасшифровкаТекстОшибки
                        }
                    ТелоОтвета = СериализацияJson.ЗаписатьОбъект(ТекстОшибки)
                    прервать
                
                ;
            ;
        ;                
    ;

    // Если нет ошибок в сообщении, то отдаем guid в виде простого json
    если ТелоОтвета == ""
        пер ЗаявкаСоздана =
                {
                    "id": ГуидВызова
                } 
            ТелоОтвета = СериализацияJson.ЗаписатьОбъект(ЗаявкаСоздана)
    ;
    //Запись в РС Сообщения из внешних систем.
    //ГуидВызова - уид для сообщения, ДатаЗаписи - дата и время когда была сделана запись, ИсходноеСообщение - тело которое нам пришло
    //ВнешнийКлиент - от какого завода пришло сообщение, пока служебно пишем Внешний клиент  
    
    пер Запись =
        новый СообщенияДляВнешнихСистем.Запись(Период = Момент.Сейчас() , ГуидВызова = ГуидВызова, ДатаЗаписи = ДатаВремя.Сейчас(
        ЧасовойПояс {UTC+3}), ИсходноеСообщение = ТелоЗапросаИзПотока, ВнешнийКлиент = "Внешний клиент", Обработано = Истина)
    СообщенияДляВнешнихСистем.Записать(Запись)

    
    // Отправляем сообщение в Узел "ПрограммныйИсточник" из него Шина отправляет в канал 
    Обмен_ВнешниеСистемы.ОтправитьСообщениеВУзлы(Сообщение, Обмен_ВнешниеСистемы.Схема.Узлы.ПрограммныйИсточник)
    // тут мы даем ответ на обращение в http сервис или ошибку или присвоенный guid
    
    Запрос.Ответ.УстановитьТело(ТелоОтвета, "UTF-8")
;

   

Рекомендую через Postman или аналогичное ПО сформировать post запрос и отправить на вновь созданный http service и в отладке посмотреть какие значения присваиваются и как работает логика.

Сразу предупреждаю оптимальности кода не преследовалась, это пример который вы можете доработать и улучшить

Кстати, намеренно не описал создание РС Сообщения для внешних систем, создайте самостоятельно, документация по 1С:Шина позволяет это сделать без мук и испытаний, единственно отмечу, что делайте его периодическим с периодом МоментВремени.

Запускаем приложение, через Postman отправляете json в формате 1 и получаете ответ в виде ошибки или с id заявки примерно такое:

 

Рисунок 10 Заявка создана и id присвоен. Скриншот из Postman

Рисунок 11.Сообщение в канале для ИС1С

 

Создаем но вый Сервис Интеграции.  

Изменения теперь выполняем в ИС 1C, чтобы забрать сообщение из канала шины

Процедура Основной_Обмен_ВнешниеСистемы_ИзВнешнихСистемОбработкаПолученияСообщения(Сообщение, Отказ)
	//РазмерСообщения = Сообщение.Параметры.Получить("РазмерСообщения");  
	РазмерСообщения = Сообщение.РазмерТела;
	ТипВходящегоСообщения = Сообщение.Параметры.Получить("type");  
	ID = Сообщение.Параметры.Получить("id");
	ПОпытка
		//////////////////////////////////////////
		Если РазмерСообщения <> Неопределено Тогда
			РазмерБуфера = Число(РазмерСообщения);
		Иначе
			РазмерБуфера = 1024;
		КонецЕсли;
		Тело = Новый БуферДвоичныхДанных(0);
		Буфер = Новый БуферДвоичныхДанных(РазмерБуфера);
		Поток = Сообщение.ПолучитьТелоКакПоток();
		Пока Истина Цикл
			Прочитано = Поток.Прочитать(Буфер, 0, РазмерБуфера);
			Если Прочитано > 0 Тогда
				Тело = Тело.Соединить(Буфер);
			КонецЕсли;
			Если Прочитано < РазмерБуфера Тогда
				Прервать;
			КонецЕсли;
		КонецЦикла;  
		//////////////////////////////////////    
		ТелоСтрока = ПолучитьСтрокуИзБуфераДвоичныхДанных(Тело);     
	Исключение      
		Возврат;
	КонецПопытки; 
	Если ЗначениеЗаполнено(ТипВходящегоСообщения) Тогда
		
		СтруктураРегистра = Новый Структура;
		СтруктураРегистра.Вставить("ИдентификаторСообщения", Новый УникальныйИдентификатор);
		СтруктураРегистра.Вставить("Получатель", Перечисления.битПолучателиИнформационныеСистемы.ВнешниеСистемы);
		СтруктураРегистра.Вставить("ТелоСообщения", СокрП(ТелоСтрока));
		СтруктураРегистра.Вставить("ID", ID);
		СтруктураРегистра.Вставить("ДатаПолученияОтвета", ТекущаяДатаСеанса());
		СтруктураРегистра.Вставить("ДатаОтправки", ТекущаяДатаСеанса());
		СтруктураРегистра.Вставить("ТипЗапроса", ТипВходящегоСообщения);
		РегистрыСведений.БитПолученныеСообщения.ЗаписатьВРегистрПолученныеСообщения(СтруктураРегистра);
		
	Иначе 
		СтруктураРегистра = Новый Структура;
		СтруктураРегистра.Вставить("ИдентификаторСообщения", Новый УникальныйИдентификатор);
		СтруктураРегистра.Вставить("Получатель", Перечисления.битПолучателиИнформационныеСистемы.ВнешниеСистемы);
		СтруктураРегистра.Вставить("ОписаниеОшибки", СокрП(ТелоСтрока));
		СтруктураРегистра.Вставить("ID", ID);
		СтруктураРегистра.Вставить("ОшибкаОбработки", Истина);
		СтруктураРегистра.Вставить("ДатаПолученияОтвета", ТекущаяДатаСеанса());
		СтруктураРегистра.Вставить("ДатаОтправки", ТекущаяДатаСеанса());
		СтруктураРегистра.Вставить("ТипЗапроса", "error");
		РегистрыСведений.БитПолученныеСообщения.ЗаписатьВРегистрПолученныеСообщения(СтруктураРегистра);
		
	КонецЕсли;
КонецПроцедуры

 

 

В данной процедуре смотрим на значение параметра сообщения “type”, если они заполнено, то забираем с канала сообщение интеграции и сохраняем его в РС «Полученные сообщения»

В отладке все вопросы должны уйти, если все же останутся вопросы, пишите в комментариях, дополню статью.

Впечатления от использования шины:

Общее впечатление по продукт у 1С:Шина положительное, а теперь подробней.

Удобным назову способ программирования — это встроенная ide, хотя она периодически подглючивает, жмешь F5, чтобы обновить страницу в браузере, а у тебя запускается приложение в отладке.

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

Вообще складывается впечатление, что синтаксис 1С Элемента позаимствован из современных web скриптовых языков.

Существуют 2 документации:

  • Документация по шине. 
  • Синтакс помощник.

 

 

Документация  — это про установку, про описание объектов и примеры кода.

Синтакс-Помощник — это описание методов, которые есть в шине.

Из недостатков: 

Документация очень скудная и часто  приходится в отладке подбирать синтаксис.  А если есть примеры, то они прям очень простые или из идеальной жизни без вариаций.

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

При условии, что я не имел опыта программирования на 1С:Элемент и сам продукт 1С: Шина не щупал руками, на реализацию функционала ушла неделя.

has been added to your cart:
Оформление заказа