Статья написана по хроникам внедрения 1С:Шина версии 4.1 в Первом Бите на Спортивной.
Меня зовут Галац Михаил, хочу поделиться реализацией отдельного http метода на при внедрении шины у клиента, у которого 1С-ные и не 1С-ные информационные системы.
Статья актуальная, версия на январь 2025.
Сокращения:
- ИС 1С –информация система на базе 1С конфигурация с БСП.
- Шина – 1С:Шина версии 4.1.
- Json – текстовый файл в формате json.
- Транслятор – объект 1С:Шина в котором выполняется преобразование сообщения.
- Канал – объект 1С:Шина, который осуществляется доставку сообщения.
- id – уникальный код в формате uuid.
- РС - регистр сведений.
- Проект - термин 1с:Шина.
- Сообщение - сообщение интеграции.
Допуски:
- У вас имеется развернутая 1С:Шина не ниже версии 4.1
или
- второй файл для 1С:Шина версии 6.1.6
Источники:
- Официальная документация по продукту 1С:Шина. Ссылка.
- Неофициальная группа в tg @esb_1C
Благодарности:
Отдельная благодарность, это наличие Алексея Борисевича, моего технического архитектора по внедрению проектов 1С:Шина, за консультации и помощь в реализации, когда я был в тупике.
Моему руководителю Гейдару Габриэлянцу за корректировки в статье, моему коллеге Сергею Губареву, который участвовал редактировании кода при переходе на 6 версию 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 Создание Процесса Интеграции
- Права доступа пока ставим "РазрешеноВсем", если требуется ограничивать, то следующий уровень понимания.
- Корневой Url ставим "v1" это наша первая версия сервиса.
Примечание.
url нашего сервиса будет примерно такой http://localhost:9090/applications/<ИмяПроекта>
Внутри сервиса интеграции рисуем схему, по которой будут идти сообщения. У меня получилось так.
Рисунок 4 Схема Процесса Интеграции
Краткое описание по рисунку 4.
json, который присылают на http сервис мы проверим и отправим в Программный Источник и далее Сообщение Интеграции отправляем в канал "ИзСтороннихСистем", далее сервис интеграции в ИС 1С заберет сообщения, которые там будут находиться. Взаимодействия из ИС 1С в шину в данном бизнес процессе не рассматривается.
Запустим приложение, жмем F5 и посмотрим, что получилось для нашего случая
http://localhost:9090/applications/test
Перейдя по ссылке в браузере должно отобразиться так, см. рисунок 5.
Рисунок 5 Пример запущенного тестового приложения
Перечисление "ТипыЗапросов" создается вообще без каких либо сложностей. Значения: order, status, cancel
РС "СообщенияДляСтороннихСистем", создать с периодом Момент, также имеет следующую структуру:
Измерения:
- ГуидВызова. ТипУуид
- Пользователь. ТипНеопределено, ПользовательСсылка
Ресурсы:
- ИсходноеСообщение. Тип Строка неограниченная
- Обрабатано. Тип Булево
- ТипЗапроса. Тип Перечисление.ТипыЗапросов
Далее создаем новый шаблон у http сервиса для рассматриваемой задачи, нужен с типом POST.
В свойствах шаблона указываем следующие действия:
Переходим в раздел Шаблоны -> Новый -> Шаблон URL, см рисунок 6.
Рисунок 6 Создание нового шаблона
И заполняем свойства шаблона:
- Имя «Заявка»
- КонтрольДоступа - Вызов - РазрешеноВсем
- Шаблон /orders
Внимание. С такими настройками разрешен анонимный доступ
Рисунок 7 Свойства шаблона созданного http сервиса
Теперь добавляем, какие запросы этот шаблон должен обрабатывать, у меня это POST:
- имя POST
- Метод: POST
- Обработчик: жмем на лупу или вводим свое имя метода и жмем лупу.
Рисунок 8.Свойства запроса
В дереве объектов получится так
Рисунок 9 Дерево объектов созданного http сервиса
Теперь, когда у нас созданы все объекты, то переходим в метод определенном на рисунке 8 «ОбработкаЗапроса», если в обработчике будет пусто, жмем на лупу, и название присваивается по умолчанию, как моем примере.
Ниже приведен текст метода с комментариями
// Тут описываем структуры, которые есть внутри json
1C:Шина версия 4.1
структура КонтактыКлиента
обз пер 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")
;
Описываете все возможные значения, которые могут быть, пусть они не будут в json который вы получаете это приведет к ошибке.
1C:Шина версия 6.1.6
//====================НАЧАЛО ОБЪЯВЛЕНИЯ СТРУКТУР=====================
структура BankDetails
пер bankName: Строка?
пер bankCode: Строка?
пер bankAddress: Строка?
пер accountNumber: Строка?
пер correspondentAccountNumber: Строка?
;
структура Phone
пер number: Строка?
пер extension: Строка?
;
структура Product
пер guid: Строка?
пер name: Строка?
пер nsiCode: Строка?
пер skmtrCode: Строка?
пер nomenclatureGroup: Строка?
пер isValuable: Булево?
;
структура Quantity
пер value: Число?
пер unitId: Число?
;
структура Contact
пер name: Строка?
пер phone: Phone?
пер email: Строка?
;
структура Contract
пер name: Строка?
пер date: Строка?
пер number: Строка?
;
структура Customer
пер name: Строка?
пер inn: Строка?
пер kpp: Строка?
пер email: Строка?
пер phone: Строка?
пер factAddress: Строка?
пер legalAddress: Строка?
пер actualAddress: Строка?
пер taxSystem: Строка?
пер contract: Contract?
пер bankDetails: BankDetails?
;
структура CustomerHeadCompany
пер name: Строка?
пер inn: Строка?
пер kpp: Строка?
пер phone: Строка?
пер factAddress: Строка? //w нет
пер legalAddress: Строка?
пер contract: Contract?
пер bankDetails: BankDetails?
;
структура DangerClassDetails
пер dangerClass: Строка?
пер comment: Строка?
;
структура EstimatedCost
пер currency: Строка?
пер amount: Число?
;
структура ExternalInitiator
пер name: Строка?
пер phone: Строка?
пер email: Строка?
;
структура Initiator
пер firstName: Строка?
пер middleName: Строка?
пер lastName: Строка?
пер email: Строка?
пер phone: Строка?
;
структура Location
пер address: Строка?
пер name: Строка?
пер regionId: Строка?
пер region: Region?
пер coords: Coords?
пер comment: Строка?
пер mapFileId: Строка?
;
структура Coords
пер lat: Число?
пер lot: Число?
;
структура Length
пер value: Число?
пер unit: Строка?
;
структура Width
пер value: Число?
пер unit: Строка?
;
структура Height
пер value: Число?
пер unit: Строка?
;
структура Weight
пер value: Число?
пер unit: Строка?
;
структура Region
пер name: Строка?
пер code: Строка?
;
структура MaxDimensions
пер length: Число?
пер width: Число?
пер height: Число?
пер unit: Строка?
;
структура Tariff
//возможно будет баг, зарезервированное слово
пер types: Строка? //должно быть пер type: Строка?
пер minTime: Число?
;
структура TemperatureRange
пер min: Число?
пер max: Число?
;
структура Vehicle
пер trailerTypeId: Число?
пер loadingMethods: Массив<Строка>?
;
структура Volume
пер value: Число?
пер unit: Строка?
;
структура Origin
пер companyId: Строка?
пер contacts: Массив<Contact>?
пер location: Location?
пер dueDate: DueDate?
пер company: Company?
пер vehicleRestrictions: VehicleRestrictions?
;
структура Owner
пер companyId: Строка?
пер company: Company?
пер legalAddress: Строка?
;
структура Item
пер product: Product?
пер quantity: Quantity?
пер estimatedCost: EstimatedCost?
пер externalCargoNumber: Строка? // нет в w
;
структура Place
пер packagingTypeId: Число?
пер weight: Weight?
пер volume: Volume?
пер dimensions: Dimensions?
пер quantity: Число?
;
структура Seller
пер companyId: Строка?
пер legalAddress: Строка?
пер company: Company?
;
структура Shipper
пер company: Company?
пер companyId: Строка?
пер seller: Seller?
пер externalAssignmentNumber: Строка?
пер contacts: Массив<Contact>?
пер documentNumber: Строка?
;
структура СonfirmationDocuments
пер documents: Строка?
пер submitDeadlineDays: Число?
;
структура Cargo
пер items: Массив<Item>?
пер places: Массив<Place>?
пер isValuable: Булево?
пер maxDimensions: MaxDimensions?
пер origin: Origin?
пер destination: Destination?
пер dangerClassDetails: DangerClassDetails?
пер shippingInstructions: Строка?
пер loadingSchemeFileId: Строка?
пер owner: Owner?
пер shipper: Shipper?
пер seller: Seller?
пер externalAssignmentNumber: Строка?
пер externalCargoNumber: Строка?
;
структура Company
пер name: Строка?
пер inn: Строка?
пер kpp: Строка?
пер legalAddress: Строка?
пер actualAddress: Строка?
пер phone: Строка?
пер bankDetails: BankDetails?
;
структура Destination
пер company: Company?
пер contacts: Массив<Contact>?
пер location: Location?
пер dueDate: DueDate?
пер companyId: Строка?
пер vehicleRestrictions: VehicleRestrictions?
;
структура Dimensions
пер length: Число?
пер width: Число?
пер height: Число?
пер unit: Строка?
;
структура DueDate
пер from: Строка? //ДатаВремя
пер to: Строка? //ДатаВремя
;
структура VehicleRestrictions
пер length: Length?
пер width: Width?
пер height: Height?
пер weight: Weight?
;
структура Payer
пер name: Строка?
пер inn: Строка?
пер kpp: Строка?
пер legalAddress: Строка?
пер actualAddress: Строка?
пер factAddress: Строка?
пер phone: Строка?
пер contract: Contract?
пер bankDetails: BankDetails?
;
структура Shipping
пер dueDate: Строка? //ДатаВремя
пер temperatureRange: TemperatureRange?
;
структура Requirements
пер vehicle: Vehicle?
пер specialRequirementIds: Массив<Строка>?
пер confirmationDocuments: СonfirmationDocuments?
пер shipping: Shipping?
пер comment: Строка?
;
структура ЗаявкаНаТранспорт
пер cargos: Массив<Cargo>?
пер requirements: Requirements?
пер externalInitiator: ExternalInitiator?
пер comment: Строка?
пер customerPrice: Число?
пер isBaggage: Булево?
пер tariff: Tariff?
пер deliveryType: Строка?
пер customer: Customer?
пер payer: Payer?
пер initiator: Initiator?
пер isAdvancedPaymentEnabled: Булево?
пер customerHeadCompany: CustomerHeadCompany?
пер customerType: Строка?
;
//====================КОНЕЦ ОБЪЯВЛЕНИЯ СТРУКТУР========================
конст order = ТипыЗапросов.order
конст cancel = ТипыЗапросов.cancel
конст status = ТипыЗапросов.status
метод ОбработкаЗапросаЗаявкаНаТранспорт(Запрос: HttpСервисЗапрос)
// Область переменных, корые нужно объявить заранее
пер ТелоОтвета: Строка
пер ГуидВызова = новый Ууид()
знч Пользователь = Пользователи.ТекущийПользователь
/*
* Так как поток после прочтения закрывается ,поэтому готовим его заранее,
* чтобы передавать его в канал
* Тело запрос сериализуем в json, далее в строку и создаем поток из строки.
*/
знч ТелоЗапросаИзПотока = Запрос.Тело.ПрочитатьКакСтроку()
/* в структуре json есть узел type, но данное слово зарезервировано,
поэтому заменяем types*/
знч ТелоЗапросИзмененное = ТелоЗапросаИзПотока.Заменить("type", "types")
пер ИзначальноеСообщение = ПотокЧтения.ИзСтроки(ТелоЗапросаИзПотока)
пер ТелоЗапросаПоток = ПотокЧтения.ИзСтроки(ТелоЗапросИзмененное)
пер ТелоЗапроса = СериализацияJson.ПрочитатьОбъект(ТелоЗапросаПоток, Тип<ЗаявкаНаТранспорт>)
пер Сообщение = новый СообщениеИнтеграции(
{
"id": ГуидВызова.ВСтроку(),
"type": "order"
}, ИзначальноеСообщение)
пер грузы = ТелоЗапроса.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)
пер ДопустимоеВремяПогрузки = Обмен_СторонниеСистемы.Параметры.ДопустимоеВремяПогрузки
знч ОтметкаВремениСейчас = Момент.Сейчас()
если (ДатаПогрузкиОт >= ДатаПогрузкиДо) или (ДатаВыгрузкиОт >= ДатаВыгрузкиДо)
пер КодОшибки = "ORD279"
пер РасшифровкаТекстОшибки =
"Дата 'до' ('to') раньше или равна дате 'от' ('from') той же операции"
пер ТекстОшибки = {
"errorCode": КодОшибки,
"errorMessage": РасшифровкаТекстОшибки
}
ТелоОтвета = СериализацияJson.ЗаписатьОбъект(ТекстОшибки)
прервать
иначе если ДатаВыгрузкиОт <= ДатаПогрузкиОт или ДатаВыгрузкиОт <= ДатаПогрузкиДо
пер КодОшибки = "ORD277"
пер РасшифровкаТекстОшибки = "Дата-время выгрузки 'от' ('from') раньше или равна дате погрузки"
пер ТекстОшибки = {
"errorCode": КодОшибки,
"errorMessage": РасшифровкаТекстОшибки
}
ТелоОтвета = СериализацияJson.ЗаписатьОбъект(ТекстОшибки)
прервать
иначе если ДатаПогрузкиОт < (ОтметкаВремениСейчас + ДопустимоеВремяПогрузки)
пер КодОшибки = "ORD270"
пер РасшифровкаТекстОшибки = "Недостаточно времени до погрузки"
пер ТекстОшибки = {
"errorCode": КодОшибки,
"errorMessage": РасшифровкаТекстОшибки
}
ТелоОтвета = СериализацияJson.ЗаписатьОбъект(ТекстОшибки)
прервать
;
;
;
//Запрос.Ответ.УстановитьТело(ТелоОтвета, "UTF-8")
;
// Если нет ошибок в сообщении, то отдаем guid в виде простого json
если ТелоОтвета == ""
пер ЗаявкаСоздана = {
"id": ГуидВызова
}
ТелоОтвета = СериализацияJson.ЗаписатьОбъект(ЗаявкаСоздана)
;
//Запись в РС Сообщения из сторонних систем.
//ГуидВызова - уид для сообщения, ДатаЗаписи - дата и время когда была сделана запись, ИсходноеСообщение - тело которое нам пришло
//Пользователь - элемент справочника Пользователи, под которым подключились к шине и было отправлено сообщение
пер Запись = новый СообщенияДляСтороннихСистем.Запись(Период = Момент.Сейчас(), ГуидВызова = ГуидВызова,
ДатаЗаписи = ДатаВремя.Сейчас(
ЧасовойПояс {UTC+3}), ИсходноеСообщение = ТелоЗапросаИзПотока, Пользователь = Пользователь, ТипЗапроса = order,
Обработано = Истина)
СообщенияДляСтороннихСистем.Записать(Запись)
// Отправляем сообщение в Узел "ПрограммныйИсточник" из него Шина отправляет в канал
Обмен_СторонниеСистемы.ОтправитьСообщениеВУзлы(Сообщение, Обмен_сторонниеСистемы.Схема.Узлы.ПрограммныйИсточник)
;
// отправляем сообщение об ошибке или гуид о новой заявке, смотря что мы выше записали в переменную ТелоОтвета
Запрос.Ответ.УстановитьТело(ТелоОтвета, "UTF-8")
;
Рекомендую через Postman или аналогичное ПО сформировать post запрос и отправить на вновь созданный http service и в отладке посмотреть какие значения присваиваются и как работает логика.
Сразу предупреждаю оптимальности кода не преследовалась, это пример который вы можете доработать и улучшить
Кстати, намеренно не описал создание РС Сообщения для Сторонних систем, создайте самостоятельно, документация по 1С:Шина позволяет это сделать без мук и испытаний, единственно отмечу, что делайте его периодическим с периодом МоментВремени.
Запускаем приложение, через Postman отправляете json в формате 1 и получаете ответ в виде ошибки или с id заявки примерно такое:
Рисунок 10 Заявка создана и id присвоен. Скриншот из Postman
Рисунок 11.Сообщение в канале для ИС1С
Создаем но вый Сервис Интеграции.
Изменения теперь выполняем в ИС 1C, чтобы забрать сообщение из канала шины
- Адрес Стороннего сервиса интеграции: http://localhost:9090/applications/test
- Имя: Любое.
- В модуле добавляем Процедуру:
версия 4.1.
Процедура Основной_Обмен_СторонниеСистемы_ИзСтороннихСистемОбработкаПолученияСообщения(Сообщение, Отказ)
//РазмерСообщения = Сообщение.Параметры.Получить("РазмерСообщения");
РазмерСообщения = Сообщение.РазмерТела;
ТипВходящегоСообщения = Сообщение.Параметры.Получить("type");
ID = Сообщение.Параметры.Получить("id");
ПОпытка
//////////////////////////////////////////
Если РазмерСообщения <> Неопределено Тогда
РазмерБуфера = Число(РазмерСообщения);
Иначе
РазмерБуфера = 1024;
КонецЕсли;
Тело = Новый БуферДвоичныхДанных(0);
Буфер = Новый БуферДвоичныхДанных(РазмерБуфера);
Поток = Сообщение.ПолучитьТелоКакПоток();
Пока Истина Цикл
Прочитано = Поток.Прочитать(Буфер, 0, РазмерБуфера);
Если Прочитано > 0 Тогда
Тело = Тело.Соединить(Буфер);
КонецЕсли;
Если Прочитано < РазмерБуфера Тогда
Прервать;
КонецЕсли;
КонецЦикла;
//////////////////////////////////////
ТелоСтрока = ПолучитьСтрокуИзБуфераДвоичныхДанных(Тело);
Исключение
Возврат;
КонецПопытки;
Если ЗначениеЗаполнено(ТипВходящегоСообщения) Тогда
СтруктураРегистра = Новый Структура;
СтруктураРегистра.Вставить("ИдентификаторСообщения", Новый УникальныйИдентификатор);
СтруктураРегистра.Вставить("Получатель", Перечисления.битПолучателиИнформационныеСистемы.СторонниеСистемы);
СтруктураРегистра.Вставить("ТелоСообщения", СокрП(ТелоСтрока));
СтруктураРегистра.Вставить("ID", ID);
СтруктураРегистра.Вставить("ДатаПолученияОтвета", ТекущаяДатаСеанса());
СтруктураРегистра.Вставить("ДатаОтправки", ТекущаяДатаСеанса());
СтруктураРегистра.Вставить("ТипЗапроса", ТипВходящегоСообщения);
РегистрыСведений.БитПолученныеСообщения.ЗаписатьВРегистрПолученныеСообщения(СтруктураРегистра);
Иначе
СтруктураРегистра = Новый Структура;
СтруктураРегистра.Вставить("ИдентификаторСообщения", Новый УникальныйИдентификатор);
СтруктураРегистра.Вставить("Получатель", Перечисления.битПолучателиИнформационныеСистемы.СторонниеСистемы);
СтруктураРегистра.Вставить("ОписаниеОшибки", СокрП(ТелоСтрока));
СтруктураРегистра.Вставить("ID", ID);
СтруктураРегистра.Вставить("ОшибкаОбработки", Истина);
СтруктураРегистра.Вставить("ДатаПолученияОтвета", ТекущаяДатаСеанса());
СтруктураРегистра.Вставить("ДатаОтправки", ТекущаяДатаСеанса());
СтруктураРегистра.Вставить("ТипЗапроса", "error");
РегистрыСведений.БитПолученныеСообщения.ЗаписатьВРегистрПолученныеСообщения(СтруктураРегистра);
КонецЕсли;
КонецПроцедуры
В данной процедуре смотрим на значение параметра сообщения “type”, если они заполнено, то забираем с канала сообщение интеграции и сохраняем его в РС «Полученные сообщения»
В отладке все вопросы должны уйти, если все же останутся вопросы, пишите в комментариях, дополню статью.
Впечатления от использования шины:
Общее впечатление по продукт у 1С:Шина положительное, а теперь подробней.
Удобным назову способ программирования - это встроенная ide, хотя она периодически подглючивает, жмешь F5, чтобы обновить страницу в браузере, а у тебя запускается приложение в отладке.
Сам код хоть и похож на 1С, то таковым не является, синтаксис циклов вообще удивляет (непривычен), все ключевые слова пишутся с маленькой буквы, хотя 1С нас учит другому, но привыкаешь быстро и в итоге для меня оказалось проще писать с маленькой буквы.
Вообще складывается впечатление, что синтаксис 1С Элемента позаимствован из современных web скриптовых языков.
Существуют 2 документации:
- Документация по шине.
- Синтакс помощник.
Рисунок 12. Виды документаций 1С:Шина
Документация - это про установку, про описание объектов и примеры кода.
Синтакс-Помощник - это описание методов, которые есть в шине.
Из недостатков:
Документация очень скудная и часто приходится в отладке подбирать синтаксис. А если есть примеры, то они прям очень простые или из идеальной жизни без вариаций.
Честно скажу, это самое неприятное при работе с шиной - отсутствие вменяемой документации и развитого сообщество, у меня была возможность сходить к опытному товарищу, который помогал с вопросами, это прям ускоряло процесс.
При условии, что я не имел опыта программирования на 1С:Элемент и сам продукт 1С: Шина не щупал руками, на реализацию функционала ушла неделя.
Имея подобную статью до начала реализации, это значительно ускорило процесс разработки, чего и вам желаю.
14.01.2025 внес изменения и исправления ошибок
- добавлено перечисление для хранения статусов
- в Параметр выведено ранее захардкоженное значение.
- исправлена ошибка с выводом ответного json
- добавлен ресурс в РС для хранения статуса
- исправлен запрос с учетом добавленного статуса
28.01.2025
Добавил отдельный архив для версии шины 6, в статье дополнил, ссылка на изменения.
- Обновлена 1С:Шина до версии 6.1.6
- Выполнен рефакторинг под 6 версию шины (основное изменение)
- исправлены ошибки по сортировки сообщений в массиве по статусам
- для авторизации теперь используются токены, поэтому есть изменения в правах. Если у вас будет 403 ошибка в постмане, то после изменения прав доступа к сервису выполните "Пересчитать права доступа" .
- изменено измерение СторонниеСистемы - > Пользователь в РС "СообщенияДляСтороннихСистем"