1С:Шина
07.07.2022
В данной статье описан пример настройки обмена между базой на платформе "1С:Предприятие" и базой на MS SQL Server через "1С:Шину". В качестве примера будет смоделирован процесс обмена данными, который обычно используются для организации взаимодействия между информационной базой и системой контроля и управления доступом (СКУД).
Для примера будут использованы конфигурация "Зарплата и управление персоналом КОРП" редакции 3.1 (3.1.18.484) и база, созданная на MS SQL Server 2019 (далее "база SQL").
Для начала необходимо создать базу SQL с названием "test_skud", которая будет выполнять роль базы СКУД. В ней будет храниться следующая информация:
Для этого создадим в базе SQL три таблицы следующего содержания:
№ |
Поле |
Тип данных |
Описание |
---|---|---|---|
1 |
_AccessDatetime |
[datetime2](0) |
Дата и время |
2 |
_PointCode |
[nvarchar](9) |
Код контрольной точки |
3 |
_Code |
[nvarchar](20) |
Код посетителя |
Скрипт для создания таблицы в MS SQL 2019:
CREATE TABLE [dbo].[CheckPointLog]( [_AccessDatetime] [datetime2](0) NOT NULL, [_PointCode] [nvarchar](9) NOT NULL, [_Code] [nvarchar](20) NOT NULL)
№ |
Поле |
Тип данных |
Описание |
---|---|---|---|
1 |
_Marked |
[numeric](1, 0) |
Пометка удаления |
2 |
_Code |
[nvarchar](9) |
Код контрольной точки |
3 |
_Description |
[nvarchar](150) |
Наименование контрольной точки |
Скрипт для создания таблицы в MS SQL 2019:
CREATE TABLE [dbo].[CheckPoints]( [_Marked] [numeric](1, 0) NOT NULL, [_Code] [nvarchar](9) NOT NULL, [_Description] [nvarchar](150) NOT NULL)
№ |
Поле |
Тип данных |
Описание |
---|---|---|---|
1 |
_Marked |
[datetime2](0) |
Пометка удаления |
2 |
_Code |
[nvarchar](9) |
Код посетителя |
3 |
_Description |
[nvarchar](20) |
Наименование посетителя |
Скрипт для создания таблицы в MS SQL 2019:
CREATE TABLE [dbo].[Visitors]( [_Marked] [numeric](1, 0) NOT NULL, [_Code] [nvarchar](20) NOT NULL, [_Description] [nchar](250) NOT NULL)
После создания базы SQL необходимо перейти к настройкам в "1С:Шине".
В среде разработки "1С:Шины" необходимо:
В настройках приложения "1С:Шины":
Для создания проекта нужно открыть панель управление сервером шины, выбрать пункт меню "Приложения", далее "+ Новое приложение":
В открывшемся окне указать "Новый проект", заполнить ключевые поля, такие как:
Указать режим разработки, выбрать тип СУБД (в нашем примере это будет Microsoft SQL Server) и нажать кнопку "Создать". Пример настройки приложения:
Новое приложение появится в списке со статусом "Создается". Через некоторое время статус приложения изменится на "Работает":
Для настройки процесса интеграции необходимо открыть приложение в среде разработки, для этого нужно в списке приложений нажать на кнопку "Редактировать":
Откроется новая вкладка браузера для среды разработки, в ней необходимо повторно ввести пароль администратора, который был указан при установке сервера, и нажать "Войти":
Откроется редактор среды разработки:
Далее нужно добавить в проект новый элемент – общий модуль, в котором будут расположены методы для работы с SQL. Для этого нужно выбрать подсистему "Основной", далее нажать правую кнопку мыши – откроется контекстное меню, в котором нужно выбрать "New", далее "Project Element".
Откроется меню выбора для добавления элемента проекта, в нем нужно выбрать вид добавляемого элемента проекта – "Общий модуль", задать имя и нажать "Ввод":
Добавим таким образом общим модуль "ОбработчикиSQL", в котором будут размещаться методы для выполнения запросов к SQL-базе.
Для получения журнала контрольных точек необходимо добавить метод "ПолучитьЖурналКонтрольныхТочек", в котором будет выполняться запрос "SELECT" для получения информации из таблицы "CheckPointLog". Полученный ответ будет отправлен в информационную базу в виде сообщения в формате JSON:
Копировать в буфер обмена@проект метод ПолучитьЖурналКонтрольныхТочек(Сообщение: ExchangeSQL.Сообщение, Соединение: СоединениеSql): СообщениеИнтеграции попытка исп ТелоСообщения = Сообщение.ПолучитьТелоКакПоток() пер ТелоСообщенияСоответствие = СериализацияJson.ПрочитатьОбъект(ТелоСообщения) как Соответствие<Строка, Объект?> пер ТекстЗапроса = "SELECT [_AccessDatetime] AS ДатаСобытия, [_PointCode] AS КодКонтрольнойТочки, [_Code] AS КодФизическогоЛица FROM [test_skud].[dbo].[CheckPointLog] WHERE [_AccessDatetime] between &StartDate and &FinishDate" пер Запрос = Соединение.СоздатьЗапросСВыборкой(ТекстЗапроса) Запрос.УстановитьЗначениеПараметра("StartDate", ТелоСообщенияСоответствие.Получить("ОтборДатаНачала")) Запрос.УстановитьЗначениеПараметра("FinishDate", ТелоСообщенияСоответствие.Получить("ОтборДатаОкончания")) исп РезультатЗапроса = Запрос.Выполнить() исп Поток = новый ВременныйПотокЗаписи() знч Json = новый ЗаписьJson(Поток) Json.ЗаписатьНачалоМассива() пока РезультатЗапроса.Следующий() пер РезультатЗапросаСоответствие = РезультатЗапроса.КакСоответствие() СериализацияJson.ЗаписатьОбъект(Поток, РезультатЗапросаСоответствие) ; Json.ЗаписатьКонецМассива() возврат Сообщение.УстановитьТелоИзПотока(Поток.ОткрытьПотокЧтения()) поймать Исключение: любой пер ТекстОшибки = Исключение.Description + "\n" + Исключение.Cause + "\n" + Исключение.Info() + "\n" + Исключение.StackTrace возврат Сообщение.УстановитьПараметр("ОбнаруженаОшибка", Истина).УстановитьПараметр("ТекстОшибки", ТекстОшибки) ; ;
Далее необходимо добавить метод "ЗагрузитьСправочники", с помощью которого будут загружаться справочники "Контрольные точки" и "Посетители" в базу SQL:
Копировать в буфер обмена@проект метод ЗагрузитьСправочники(Сообщение: ExchangeSQL.Сообщение, Соединение: СоединениеSql): СообщениеИнтеграции попытка исп ТелоСообщения = Сообщение.ПолучитьТелоКакПоток() пер МассивСправочников = СериализацияJson.ПрочитатьОбъект(ТелоСообщения) как Массив<Объект?> для Спр из МассивСправочников пер СпрСоответствие = Спр как Соответствие<Строка, Объект?> пер ИмяСправочника = СпрСоответствие.Получить("ВидСправочника") как Строка пер МассивЗначений = СпрСоответствие.Получить("МассивЗначений") как Массив<Объект?> пер СтрЗнч = "" для Стр из МассивЗначений пер СтрСоответствие = Стр как Соответствие<Строка, Объект?> СтрЗнч = СтрЗнч + "('" + СтрСоответствие.Получить("ПометкаУдаления") + "','" + СтрСоответствие.Получить("Код") + "','" + СтрСоответствие.Получить("Наименование") + "')," + Символы.НОВАЯ_СТРОКА ; если СтрЗнч != "" СтрЗнч = СтрЗнч.ПодстрокаСНачала(СтрЗнч.Длина()-2)+";" пер ТекстЗапроса = ПолучитьТекстЗапросаДляСправочника(ИмяСправочника, СтрЗнч) пер Запрос = Соединение.СоздатьЗапросБезВыборки(ТекстЗапроса) Запрос.Выполнить() ; ; исп Поток = новый ВременныйПотокЗаписи() возврат новый СообщениеИнтеграции({"РезультатЗагрузки":"Справочники успешно обновлены."}, Поток.ОткрытьПотокЧтения()) поймать Исключение: любой пер ТекстОшибки = Исключение.Description + "\n" + Исключение.Cause + "\n" + Исключение.Info() + "\n" + Исключение.StackTrace возврат Сообщение.УстановитьПараметр("ОбнаруженаОшибка", Истина).УстановитьПараметр("ТекстОшибки", ТекстОшибки) ; ;
Так как запрос на обновление достаточно объемный, создадим для него отдельный метод "ПолучитьТекстЗапросаДляСправочника":
Копировать в буфер обмена@проект метод ПолучитьТекстЗапросаДляСправочника(ИмяСправочника: Строка, СтрЗнч: Строка): Строка пер ТекстЗапроса = "DROP TABLE IF EXISTS #TempTable; DROP TABLE IF EXISTS #TempTable2; CREATE TABLE #TempTable(_Marked numeric(1,0), _Code nvarchar(20), _Description nchar(250)); INSERT INTO #TempTable(_Marked, _Code, _Description) VALUES" ТекстЗапроса = ТекстЗапроса + СтрЗнч + "SELECT #TempTable._Marked, #TempTable._Code, #TempTable._Description, Reference._Code AS ReferenceCode INTO #TempTable2 FROM #TempTable LEFT JOIN [test_skud].[dbo].[" + ИмяСправочника + "] AS Reference ON #TempTable._Code = Reference._Code ; INSERT INTO [test_skud].[dbo].[" + ИмяСправочника + "] (_Marked, _Code, _Description) SELECT #TempTable2._Marked, #TempTable2._Code, #TempTable2._Description FROM #TempTable2 WHERE #TempTable2.ReferenceCode IS NULL ; UPDATE [dbo].[" + ИмяСправочника + "] SET _Marked = TempTable2._Marked, _Code = TempTable2._Code, _Description = TempTable2._Description FROM (SELECT #TempTable2._Marked, #TempTable2._Code, #TempTable2._Description FROM #TempTable2 WHERE #TempTable2.ReferenceCode IS NOT NULL) AS TempTable2 WHERE [dbo].[" + ИмяСправочника + "]._Code = TempTable2._Code ;" возврат ТекстЗапроса ;
После добавления общего модуля необходимо добавить новый элемент проекта – процесс интеграции.
Для этого нужно выбрать подсистему "Основной", далее нажать правую кнопку мыши – откроется контекстное меню, в котором нужно выбрать "New", далее "Project Element".
Откроется меню выбора для добавления элемента проекта, в нем нужно выбрать вид добавляемого элемента проекта – "Процесс интеграции", задать имя и нажать "Ввод".
"1С:Шина" создаст в проекте новый процесс интеграции и откроет редактор для создания его схемы. В тестовом примере имя процесса интеграции – "ExchangeSQL".
Для тестового примера необходимо создать следующую схему:
Для узла "SQL" необходимо выполнить следующие настройки:
Копировать в буфер обменаjdbc:sqlserver://имя сервера СУБД;databaseName=имя базы данных; user=пользователь; password=пароль;
Ниже приведен листинг обработчика сообщений, в котором в зависимости от переданного параметра будет происходить вызов метода из общего модуля "ОбработчикиSQL".
Копировать в буфер обменаметод ОбработкаСообщения(Контекст: ExchangeSQL.КонтекстВызова, Сообщение: ExchangeSQL.Сообщение, Соединение: СоединениеSql): СообщениеИнтеграции если Сообщение.СодержитПараметр("ПолучитьЖурналКонтрольныхТочек") возврат ОбработчикиSQL.ПолучитьЖурналКонтрольныхТочек(Сообщение, Соединение) иначе если Сообщение.СодержитПараметр("ВыгрузитьСправочники") возврат ОбработчикиSQL.ЗагрузитьСправочники(Сообщение, Соединение) иначе возврат Сообщение ; ;
Для соединения узла "Базы1С" с каналами "из1СвSQL" и "изSQLв1С" нужно использовать элемент "Связь". Для соединения каналов "из1СвSQL" и "изSQLв1С" с узлом "SqlConnector" необходимо использовать элемент "Маршрут".
Сообщения поступают в шину через узел вида "Канал1СИсточник" (узел "из1СвSQL") и доставляются в узел "SqlConnector". В узле "SqlConnector" происходит обработка сообщения, в зависимости от переданного параметра выполняется запрос к базе SQL, далее подготовленный ответ отправляется в "Канал1СНазначение" (узел "изSQLв1С").
Информационные системы – участники процесса интеграции (в роли которых выступают информационные базы "1С:Предприятия") объединяются в группы участников (в нашем примере – "Базы1С"), которые, в свою очередь, связываются с каналами. Отправлять сообщения в каналы вида "Канал1СИсточник" и получать сообщения из каналов вида "Канал1СНазначение" будут только те информационные системы, которые включены в группы участников, связанные с соответствующим каналом.
Какие именно информационные системы будут участвовать во взаимодействии, их названия, параметры подключения и в какие группы участников они будут входить – определяется позднее, уже после публикации процесса интеграции на сервере, с помощью веб-интерфейса сервера "1С:Шины".
После настройки схемы интеграции ее необходимо опубликовать. Для этого нужно нажать клавишу F9 либо в контекстном меню процесса интеграции выбрать пункт "Publish Project":
В левом углу строки состояния среды разработки появится статус публикации. Если статус "updating" изменился на "running", значит, приложение обновлено и запущено.
Для того что открыть опубликованное приложение из среды разработки, нужно, нажав правую кнопку мыши, открыть контекстное меню процесса и выбрать пункт "Open Application":
Сервер запросит имя пользователя и пароль. Для аутентификации используйте учетную запись администратора и пароль, который был задан при установке сервера.
После успешной авторизации откроется вкладка приложения "1С:Шины", на ней будет отображен список процессов интеграции, существующих в приложении. В тестовом примере будет единственный процесс интеграции "Основной::ExchangeSQL":
Для добавления информационных систем в приложении "1С:Шины" необходимо перейти на вкладку "Инфосистемы" и нажать на кнопку "+Добавить систему":
Откроется окно добавления информационной системы:
Необходимо добавить информационную базу "1С", которая будет участвовать в обмене, указав код "ЗУП", наименование "Зарплата и управление персоналом".
Идентификация получателя в "1С:Шине" осуществляется с использованием кода информационной системы – это буквенно-цифровой код, который указывается в свойстве "Код" в процессе регистрации информационной системы на сервере "1С:Шины".
После добавления информационной системы необходимо получить ключ, который она будет использовать при подключении к серверу "1С:Шины". Чтобы получить ключ, нужно выбрать информационную систему, а затем нажать кнопку "Выдать ключ API":
Скопируйте и сохраните идентификатор ключа и секрет клиента. Позднее эти настройки будут использоваться при подключении информационной базы "1С" к серверу "1С:Шины".
Для включения информационной системы в состав приложения необходимо перейти на вкладку "Процессы" и выбрать процесс "Основной::ExchangeSQL":
На этом настройки в "1С:Шине" завершены, далее можно переходить к настройке информационных баз "1С".
Необходимо выполнить следующие доработки:
Для создания расширения откроем конфигуратор информационной базы "1С:Зарплаты и управления персоналом КОРП" и создадим расширение, в котором выполним необходимые доработки для взаимодействия с "1С:Шиной".
В тестовом примере необходимо задать следующие параметры:
В созданном расширении необходимо добавить подсистему "Интеграция", у которой нужно установить флажок "Включать в командный интерфейс". В эту подсистему будут добавляться доработки, которые необходимы для обмена:
Далее нужно добавить сервис интеграции: именно этот объект отвечает за взаимодействие с "1С:Шиной", в нем задаются параметры подключения к серверу шины. Для создания нового сервиса интеграции нужно раскрыть ветку "Общие", выбрать "Сервисы интеграции" и добавить новый объект. В тестовом примере его название будет "Интеграция_СКУД".
Далее требуется загрузить информацию о доступных каналах интеграции из опубликованного приложения шины. Для этого в меню "Действия" внизу формы сервиса интеграции необходимо выбрать пункт "Загрузить каналы":
В открывшейся форме требуется указать:
Затем нужно нажать кнопку "Получить каналы сервиса".
Список заполнится каналами вида "Канал1СИсточник" и "Канал1СНазначение", созданными на этапе настройки конфигурации шины (см. раздел 2.1 "Создание проекта"):
В списке необходимо установить отметки для полученных каналов, далее нажать на кнопку "Загрузить" и перейти на вкладку "Каналы" – в список должны добавиться те каналы, которые были выбраны:
Для удобства можно переименовать название канала в "1С", при этом имя канала внешнего сервиса интеграции необходимо оставить прежним:
Одновременно при загрузке входящего канала в модуле сервиса интеграции будет создан обработчик получения сообщений из каналов:
Можно заменить наименование обработчика, например:
Так как список контрольных точек будет храниться в информационной базе "1С:Зарплаты и управления персоналом КОРП", создадим для этого отдельный справочник "Интеграция_КонтрольныеТочки" без дополнительных реквизитов и включим его в подсистему "Интеграция". Этот справочник будет выгружаться в таблицу SQL "CheckPoints":
Для регистрации объектов к обмену нужно добавить план обмена "Интеграция_СКУД", в состав которого включить справочники "Физические лица" и "Контрольные точки". Также в план обмена необходимо добавить реквизиты, которые понадобятся для связки плана обмена и сервиса интеграции:
Данные из таблицы SQL "CheckPointLog" будут загружаться в информационную базу "1С:Зарплаты и управления персоналом КОРП" в регистр сведений "Журнал контрольных точек (СКУД)". Для этого добавим соответствующий периодический ("в пределах секунды") независимый регистр сведений с измерением "КонтрольнаяТочка" (тип СправочникСсылка. Интеграция_КонтрольныеТочки) и ресурсом "ФизическоеЛицо (тип СправочникСсылка.ФизическиеЛица):
Для регистра создадим "Форму списка", на которую выведем кнопку "ЗагрузитьЖурналИзСКУД":
Ниже приведен листинг модуля формы списка:
Копировать в буфер обмена&НаКлиенте Процедура ЗагрузитьЖурналИзСКУД(Команда) Оповещение = Новый ОписаниеОповещения("ВыборПериодаЗавершение", ЭтотОбъект); ОткрытьФорму("РегистрСведений.Интеграция_ЖурналКонтрольныхТочек.Форма.ФормаВыбораПериода", , ЭтаФорма, , , , Оповещение, РежимОткрытияОкнаФормы.БлокироватьОкноВладельца); КонецПроцедуры &НаКлиенте Процедура ВыборПериодаЗавершение(ВыбранноеЗначение, ДополнительныеПараметры) Экспорт Если ВыбранноеЗначение <> Неопределено Тогда СформироватьЗапросЖурналаКонтрольныхТочекСКУД(ВыбранноеЗначение); ПодключитьОбработчикОжидания("ОбновитьСписок", 5, Истина); КонецЕсли; КонецПроцедуры &НаСервереБезКонтекста Процедура СформироватьЗапросЖурналаКонтрольныхТочекСКУД(ПериодОтбора) Интеграция_Обработчики.СформироватьЗапросЖурналаКонтрольныхТочекИзSQL(ПериодОтбора); КонецПроцедуры &НаКлиенте Процедура ОбновитьСписок() Элементы.Список.Обновить(); КонецПроцедуры
При нажатии на кнопку "ЗагрузитьЖурналИзСКУД" будет открываться форма выбора периода для загрузки, ее тоже требуется создать:
Листинг модуля "Формы выбора периода":
Копировать в буфер обмена&НаКлиенте Процедура КомандаОК(Команда) Закрыть(ПериодОтбора); КонецПроцедуры
Если период задан, то будет сформировано сообщение для запроса данных из таблицы SQL через "1С:Шину".
Для реализации обработчиков отправки и получения сообщений, а также вспомогательных методов необходимо создать в расширении общий серверный модуль "Интеграция_Обработчики":
Добавить в общий модуль:
Процедура ОбработатьВходящееСообщение(Сообщение, Отказ) Экспорт СобытиеЖурналаРегистрации = "Сервисы интеграции.Обработка"; ТекстСообщения = "Обрабатывается сообщение 1C:Шины, ID:" + Сообщение.Идентификатор + Символы.ВК + " От : " + Сообщение.КодОтправителя; ЗаписьЖурналаРегистрации(СобытиеЖурналаРегистрации, УровеньЖурналаРегистрации.Информация, , , ТекстСообщения); Попытка Если Сообщение.Параметры.Получить("ОбнаруженаОшибка") <> Неопределено Тогда СобытиеЖурналаРегистрации = "Сервисы интеграции.Обработка"; ТекстСообщения = "Ошибка при обработке сообщения в 1С:Шине:" + Сообщение.Параметры.Получить("ТекстОшибки"); ЗаписьЖурналаРегистрации(СобытиеЖурналаРегистрации, УровеньЖурналаРегистрации.Ошибка, , , ТекстСообщения); ИначеЕсли Сообщение.Параметры.Получить("РезультатЗагрузки") <> Неопределено Тогда СобытиеЖурналаРегистрации = "Сервисы интеграции.Обработка"; ТекстСообщения = "Результат выполнения SQL запроса: " + Сообщение.Параметры.Получить("РезультатЗагрузки"); ЗаписьЖурналаРегистрации(СобытиеЖурналаРегистрации, УровеньЖурналаРегистрации.Информация, , , ТекстСообщения); ИначеЕсли Сообщение.Параметры.Получить("ПолучитьЖурналКонтрольныхТочек") <> Неопределено Тогда РазмерСообщения = Сообщение.Параметры.Получить("РазмерСообщения"); Если РазмерСообщения <> Неопределено Тогда РазмерБуфера = Число(РазмерСообщения); Иначе РазмерБуфера = 1024; КонецЕсли; Тело = Новый БуферДвоичныхДанных(0); Буфер = Новый БуферДвоичныхДанных(РазмерБуфера); Поток = Сообщение.ПолучитьТелоКакПоток(); Пока Истина Цикл Прочитано = Поток.Прочитать(Буфер, 0, РазмерБуфера); Если Прочитано > 0 Тогда Тело = Тело.Соединить(Буфер); КонецЕсли; Если Прочитано < РазмерБуфера Тогда Прервать; КонецЕсли; КонецЦикла; ВходящееСообщение = ПолучитьСтрокуИзБуфераДвоичныхДанных(Тело); Если ВходящееСообщение <> "" Тогда ЗагрузитьЖурналКонтрольныхТочек(ВходящееСообщение); КонецЕсли; КонецЕсли; Исключение Отказ = Истина; СобытиеЖурналаРегистрации = "Сервисы интеграции.Обработка"; ТекстСообщения = ОписаниеОшибки() + ". Не удалось обработать сообщение ID:" + Сообщение.Идентификатор + " от : " + Сообщение.КодОтправителя; ЗаписьЖурналаРегистрации(СобытиеЖурналаРегистрации, УровеньЖурналаРегистрации.Ошибка, , , ТекстСообщения); КонецПопытки; КонецПроцедуры
С помощью этих методов будут формироваться сообщения для выгрузки справочников "Физические лица" и "Контрольные точки":
Копировать в буфер обменаПроцедура ВыгрузитьДанныеДляЗагрузкиВSQL() Экспорт СобытиеЖурналаРегистрации = "Сервисы интеграции.Обработка"; ТекстСообщения = "Формирование сообщений 1С:Шины."; ЗаписьЖурналаРегистрации(СобытиеЖурналаРегистрации, УровеньЖурналаРегистрации.Информация, , , ТекстСообщения); Запрос = Новый Запрос; Запрос.Текст = "ВЫБРАТЬ | Интеграция_СКУД.Ссылка КАК УзелОбмена, | Интеграция_СКУД.СервисИнтеграции КАК СервисИнтеграции, | Интеграция_СКУД.ИсходящийКаналИнтеграции КАК ИсходящийКаналИнтеграции |ИЗ | ПланОбмена.Интеграция_СКУД КАК Интеграция_СКУД |ГДЕ | Интеграция_СКУД.СервисИнтеграции <> """""; РезультатЗапроса = Запрос.Выполнить(); Если НЕ РезультатЗапроса.Пустой() Тогда Выборка = РезультатЗапроса.Выбрать(); Пока Выборка.Следующий() Цикл УзелОбмена = Выборка.УзелОбмена; Отказ = Ложь; ЗаблокироватьУзелОбмена(УзелОбмена, Отказ); Если Отказ = Истина Тогда Возврат; КонецЕсли; СформироватьИсходящееСообщениеДляЗагрузкиВSQL(УзелОбмена, Выборка.СервисИнтеграции, Выборка.ИсходящийКаналИнтеграции); РазблокироватьУзелОбмена(УзелОбмена, Отказ); КонецЦикла; КонецЕсли; КонецПроцедуры Процедура СформироватьИсходящееСообщениеДляЗагрузкиВSQL(УзелОбмена, СервисИнтеграции, ИсходящийКаналИнтеграции) Попытка Запрос = Новый Запрос; Запрос.Текст = "ВЫБРАТЬ | ФизическиеЛицаИзменения.Ссылка КАК Ссылка, | ФизическиеЛица.ИНН КАК Код, | ФизическиеЛица.Наименование КАК Наименование, | ФизическиеЛица.ПометкаУдаления КАК ПометкаУдаления |ИЗ | Справочник.ФизическиеЛица.Изменения КАК ФизическиеЛицаИзменения | ЛЕВОЕ СОЕДИНЕНИЕ Справочник.ФизическиеЛица КАК ФизическиеЛица | ПО ФизическиеЛицаИзменения.Ссылка = ФизическиеЛица.Ссылка |ГДЕ | ФизическиеЛицаИзменения.Узел = &УзелОбмена | И ФизическиеЛица.ИНН <> """" |; | |//////////////////////////////////////////////////////////////////////////////// |ВЫБРАТЬ | КонтрольныеТочкиИзменения.Ссылка КАК Ссылка, | КонтрольныеТочки.Код КАК Код, | КонтрольныеТочки.Наименование КАК Наименование, | КонтрольныеТочки.ПометкаУдаления КАК ПометкаУдаления |ИЗ | Справочник.Интеграция_КонтрольныеТочки.Изменения КАК КонтрольныеТочкиИзменения | ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Интеграция_КонтрольныеТочки КАК КонтрольныеТочки | ПО КонтрольныеТочкиИзменения.Ссылка = КонтрольныеТочки.Ссылка |ГДЕ | КонтрольныеТочкиИзменения.Узел = &УзелОбмена"; Запрос.УстановитьПараметр("УзелОбмена", УзелОбмена); РезультатЗапроса = Запрос.ВыполнитьПакет(); МассивФизЛиц = ПолучитьМассивЗначенийИзРезультатаЗапроса(РезультатЗапроса[0]); МассивКонтрольныхТочек = ПолучитьМассивЗначенийИзРезультатаЗапроса(РезультатЗапроса[1]); Если МассивФизЛиц.Количество() <> 0 ИЛИ МассивКонтрольныхТочек.Количество() <> 0 Тогда Сообщение = СервисыИнтеграции[СервисИнтеграции].СоздатьСообщение(); Сообщение.Параметры.Вставить("ВыгрузитьСправочники", Истина); ТекстJSON = Новый ЗаписьJSON; ТекстJSON.ПроверятьСтруктуру = Ложь; ПараметрыЗаписиJSON = Новый ПараметрыЗаписиJSON(,Символы.Таб); ТекстJSON.УстановитьСтроку(ПараметрыЗаписиJSON); МассивСправочников = Новый Массив; Если МассивФизЛиц.Количество() <> 0 Тогда ДанныеДляВыгрузки = Новый Структура("ВидСправочника,МассивЗначений", "Visitors", МассивФизЛиц); МассивСправочников.Добавить(ДанныеДляВыгрузки); КонецЕсли; Если МассивКонтрольныхТочек.Количество() <> 0 Тогда ДанныеДляВыгрузки = Новый Структура("ВидСправочника,МассивЗначений", "CheckPoints", МассивКонтрольныхТочек); МассивСправочников.Добавить(ДанныеДляВыгрузки); КонецЕсли; ЗаписатьJSON(ТекстJSON, МассивСправочников); СтрокаJSON = ТекстJSON.Закрыть(); Тело = Сообщение.ПолучитьТелоКакПоток(); Буфер = ПолучитьБуферДвоичныхДанныхИзСтроки(СтрокаJSON); Тело.Записать(Буфер, 0, Буфер.Размер); Тело.Закрыть(); СервисыИнтеграции[СервисИнтеграции][ИсходящийКаналИнтеграции].ОтправитьСообщение(Сообщение); УдалитьРегистрациюИзмененийДляУзла(УзелОбмена, РезультатЗапроса[0]); УдалитьРегистрациюИзмененийДляУзла(УзелОбмена, РезультатЗапроса[1]); КонецЕсли; Исключение СобытиеЖурналаРегистрации = "Сервисы интеграции.Обработка"; ТекстСообщения = ОписаниеОшибки() + ". Не удалось сформировать исходящее сообщение"; ЗаписьЖурналаРегистрации(СобытиеЖурналаРегистрации, УровеньЖурналаРегистрации.Ошибка, , , ТекстСообщения); КонецПопытки; КонецПроцедуры
С помощью этого метода будет формироваться сообщение для запроса журнала контрольных точек:
Копировать в буфер обменаПроцедура СформироватьЗапросЖурналаКонтрольныхТочекИзSQL(ПериодОтбора) Экспорт СобытиеЖурналаРегистрации = "Сервисы интеграции.Обработка"; ТекстСообщения = "Формирование сообщений 1С:Шины."; ЗаписьЖурналаРегистрации(СобытиеЖурналаРегистрации, УровеньЖурналаРегистрации.Информация, , , ТекстСообщения); Запрос = Новый Запрос; Запрос.Текст = "ВЫБРАТЬ | Интеграция_СКУД.Ссылка КАК УзелОбмена, | Интеграция_СКУД.СервисИнтеграции КАК СервисИнтеграции, | Интеграция_СКУД.ИсходящийКаналИнтеграции КАК ИсходящийКаналИнтеграции |ИЗ | ПланОбмена.Интеграция_СКУД КАК Интеграция_СКУД |ГДЕ | Интеграция_СКУД.СервисИнтеграции <> """""; РезультатЗапроса = Запрос.Выполнить(); Если НЕ РезультатЗапроса.Пустой() Тогда Выборка = РезультатЗапроса.Выбрать(); Пока Выборка.Следующий() Цикл УзелОбмена = Выборка.УзелОбмена; Попытка Сообщение = СервисыИнтеграции[Выборка.СервисИнтеграции].СоздатьСообщение(); Сообщение.Параметры.Вставить("ПолучитьЖурналКонтрольныхТочек", Истина); ТекстJSON = Новый ЗаписьJSON; ТекстJSON.ПроверятьСтруктуру = Ложь; ПараметрыЗаписиJSON = Новый ПараметрыЗаписиJSON(,Символы.Таб); ТекстJSON.УстановитьСтроку(ПараметрыЗаписиJSON); СтруктураПараметров = Новый Структура; СтруктураПараметров.Вставить("ОтборДатаНачала", ПериодОтбора.ДатаНачала); СтруктураПараметров.Вставить("ОтборДатаОкончания", ПериодОтбора.ДатаОкончания); ЗаписатьJSON(ТекстJSON, СтруктураПараметров); СтрокаJSON = ТекстJSON.Закрыть(); Тело = Сообщение.ПолучитьТелоКакПоток(); Буфер = ПолучитьБуферДвоичныхДанныхИзСтроки(СтрокаJSON); Тело.Записать(Буфер, 0, Буфер.Размер); Тело.Закрыть(); СервисыИнтеграции[Выборка.СервисИнтеграции][Выборка.ИсходящийКаналИнтеграции].ОтправитьСообщение(Сообщение); Исключение СобытиеЖурналаРегистрации = "Сервисы интеграции.Обработка"; ТекстСообщения = ОписаниеОшибки() + ". Не удалось сформировать исходящее сообщение"; ЗаписьЖурналаРегистрации(СобытиеЖурналаРегистрации, УровеньЖурналаРегистрации.Ошибка, , , ТекстСообщения); КонецПопытки; КонецЦикла; КонецЕсли; КонецПроцедуры
С помощью данного метода будет производиться загрузка ответного сообщения из "1С:Шины" в регистр сведений "Интеграция_ЖурналКонтрольныхТочек":
Копировать в буфер обменаПроцедура ЗагрузитьЖурналКонтрольныхТочек(ВходящееСообщение) ЧтениеJSON = Новый ЧтениеJSON; ЧтениеJSON.УстановитьСтроку(ВходящееСообщение); МассивСоответствие = ПрочитатьJSON(ЧтениеJSON,Истина); Если МассивСоответствие.Количество() > 0 Тогда Для каждого Стр Из МассивСоответствие Цикл ФизЛицо = ПолучитьЗначениеСправочникаПоРеквизиту("ФизическиеЛица", "ИНН", Стр.Получить("КодФизическогоЛица")); Если ЗначениеЗаполнено(ФизЛицо) Тогда МенеджерЗаписи = РегистрыСведений.Интеграция_ЖурналКонтрольныхТочек.СоздатьМенеджерЗаписи(); МенеджерЗаписи.Период = ПрочитатьДатуJSON(Стр.Получить("ДатаСобытия"),ФорматДатыJSON.ISO); МенеджерЗаписи.ФизическоеЛицо = ФизЛицо; МенеджерЗаписи.КонтрольнаяТочка = ПолучитьЗначениеСправочникаПоРеквизиту("Интеграция_КонтрольныеТочки", "Код", Стр.Получить("КодКонтрольнойТочки")); МенеджерЗаписи.Записать(); КонецЕсли; КонецЦикла; КонецЕсли; КонецПроцедуры
Также необходимо добавить следующие вспомогательные методы для функционирования обмена:
Копировать в буфер обменаПроцедура УдалитьРегистрациюИзмененийДляУзла(УзелОбмена, РезультатЗапроса) Выборка = РезультатЗапроса.Выбрать(); Пока Выборка.Следующий() Цикл ПланыОбмена.УдалитьРегистрациюИзменений(УзелОбмена, Выборка.Ссылка); КонецЦикла; КонецПроцедуры Функция ПолучитьМассивЗначенийИзРезультатаЗапроса(РезультатЗапроса) МассивЗначений = Новый Массив; Выборка = РезультатЗапроса.Выбрать(); Пока Выборка.Следующий() Цикл СтруктураЗначений = Новый Структура; СтруктураЗначений.Вставить("Код", Выборка.Код); СтруктураЗначений.Вставить("Наименование", Выборка.Наименование); СтруктураЗначений.Вставить("ПометкаУдаления", ?(Выборка.ПометкаУдаления,1,0)); МассивЗначений.Добавить(СтруктураЗначений); КонецЦикла; Возврат МассивЗначений; КонецФункции Функция ПолучитьЗначениеСправочникаПоРеквизиту(НазваниеСправочника, НазваниеРеквизита, ЗначениеРеквизита) Запрос = Новый Запрос; Запрос.Текст = "ВЫБРАТЬ | Справочник.Ссылка КАК Значение |ИЗ | Справочник." + НазваниеСправочника + " КАК Справочник |ГДЕ | Справочник." + НазваниеРеквизита + " = &ЗначениеРеквизита"; Запрос.УстановитьПараметр("ЗначениеРеквизита", ЗначениеРеквизита); РезультатЗапроса = Запрос.Выполнить(); Если Не РезультатЗапроса.Пустой() Тогда Выборка = РезультатЗапроса.Выбрать(); Выборка.Следующий(); Возврат Выборка.Значение; КонецЕсли; Возврат Справочники[НазваниеСправочника].ПустаяСсылка(); КонецФункции Процедура ЗаблокироватьУзелОбмена(УзелОбмена, Отказ) Попытка ЗаблокироватьДанныеДляРедактирования(УзелОбмена); Исключение Отказ = Истина; ШаблонСообщения = НСтр("ru = 'Не удалось заблокировать узел плана обмена [%1]. |Вероятно, обмен данными уже выполняется. Повторите попытку позже.'", ОбщегоНазначения.КодОсновногоЯзыка()); СообщениеОбОшибке = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ШаблонСообщения, УзелОбмена); ЗаписьЖурналаРегистрации("Сервисы интеграции.Обработка", УровеньЖурналаРегистрации.Ошибка, УзелОбмена.Метаданные(), УзелОбмена, СообщениеОбОшибке); ВызватьИсключение СообщениеОбОшибке; КонецПопытки; КонецПроцедуры Процедура РазблокироватьУзелОбмена(УзелОбмена, Отказ) Попытка РазблокироватьДанныеДляРедактирования(УзелОбмена); Исключение Отказ = Истина; ШаблонСообщения = НСтр("ru = 'Не удалось разблокировать узел плана обмена [%1]. |Вероятно, обмен данными уже выполняется. Повторите попытку позже.'", ОбщегоНазначения.КодОсновногоЯзыка()); СообщениеОбОшибке = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ШаблонСообщения, УзелОбмена); ЗаписьЖурналаРегистрации("Сервисы интеграции.Обработка", УровеньЖурналаРегистрации.Ошибка, УзелОбмена.Метаданные(), УзелОбмена, СообщениеОбОшибке); ВызватьИсключение СообщениеОбОшибке; КонецПопытки; КонецПроцедуры
При получении сообщения в целевой информационной базе запускается фоновое задание, которое вызывает обработчик соответствующего канала, поэтому необходимо в модуле сервиса интеграции "Интеграция_СКУД" указать обработчик входящего сообщения.
При загрузке канала "изSQLв1С" в пункте 3.2 "Доработки конфигурации в расширении" был создан пустой обработчик "ОбработкаПолученногоСообщенияSQL" – в него необходимо добавить вызов созданной процедуры "ОбработатьВходящееСообщение" из модуля "Интеграция_Обработчики":
Копировать в буфер обменаПроцедура ОбработкаПолученногоСообщенияSQL (Сообщение, Отказ) Интеграция_Обработчики.ОбработатьВходящееСообщение(Сообщение, Отказ); КонецПроцедуры
Чтобы сформировать регламентные задания без доработки конфигурации, необходимо создать внешнюю обработку, в модуле которой будет реализован вызов серверных методов.
В тестовом примере обработка будет называться "ИнтеграцияСШиной.epf", ниже приведен код ее модуля:
Копировать в буфер обмена#Область СведенияОВнешнейОбработке Функция СведенияОВнешнейОбработке() Экспорт ПараметрыРегистрации = Новый Структура; ПараметрыРегистрации.Вставить("Вид", "ДополнительнаяОбработка"); ПараметрыРегистрации.Вставить("Назначение", ПолучитьНазначениеОбработки()); ПараметрыРегистрации.Вставить("Наименование", НСтр("ru = 'Интеграция с шиной'")); ПараметрыРегистрации.Вставить("Версия", "1.0"); ПараметрыРегистрации.Вставить("БезопасныйРежим", Ложь); ПараметрыРегистрации.Вставить("Информация", НСтр("ru = 'Интеграция с шиной'")); ТаблицаКоманд = ПолучитьТаблицуКоманд(); ДобавитьКоманду(ТаблицаКоманд, НСтр("ru = 'Формирование сообщений 1С:Шины (Регламентный запуск)'"), "ФормированиеСообщений", "ВызовСерверногоМетода", Истина, ""); ДобавитьКоманду(ТаблицаКоманд, НСтр("ru = 'Выполнить обработку сообщений 1С:Шины (Регламентный запуск)'"), "ОбработкаСообщений", "ВызовСерверногоМетода", Истина, ""); ПараметрыРегистрации.Вставить("Команды", ТаблицаКоманд); Возврат ПараметрыРегистрации; КонецФункции Функция ПолучитьНазначениеОбработки() Назначение = Новый Массив; Возврат Назначение; КонецФункции Функция ПолучитьТаблицуКоманд() Команды = Новый ТаблицаЗначений; Команды.Колонки.Добавить("Представление", Новый ОписаниеТипов("Строка")); Команды.Колонки.Добавить("Идентификатор", Новый ОписаниеТипов("Строка")); Команды.Колонки.Добавить("Использование", Новый ОписаниеТипов("Строка")); Команды.Колонки.Добавить("ПоказыватьОповещение", Новый ОписаниеТипов("Булево")); Команды.Колонки.Добавить("Модификатор", Новый ОписаниеТипов("Строка")); Возврат Команды; КонецФункции Процедура ДобавитьКоманду(ТаблицаКоманд, Представление, Идентификатор, Использование, ПоказыватьОповещение = Ложь, Модификатор = "") НоваяКоманда = ТаблицаКоманд.Добавить(); НоваяКоманда.Представление = Представление; НоваяКоманда.Идентификатор = Идентификатор; НоваяКоманда.Использование = Использование; НоваяКоманда.ПоказыватьОповещение = ПоказыватьОповещение; НоваяКоманда.Модификатор = Модификатор; КонецПроцедуры #КонецОбласти #Область СлужебныеОбработчики Процедура ВыполнитьКоманду(ИдентификаторКоманды) Экспорт Если ИдентификаторКоманды = "ФормированиеСообщений" Тогда Интеграция_Обработчики.ВыгрузитьДанныеДляЗагрузкиВSQL(); ИначеЕсли ИдентификаторКоманды = "ОбработкаСообщений" Тогда Попытка СервисыИнтеграции.ВыполнитьОбработку(); Исключение СобытиеЖурналаРегистрации = "Сервисы интеграции.Обработка"; ТекстСообщения = "Ошибка обработки сообщений шины; " + ОписаниеОшибки(); ЗаписьЖурналаРегистрации(СобытиеЖурналаРегистрации, УровеньЖурналаРегистрации.Ошибка, , , ТекстСообщения); КонецПопытки; КонецЕсли; КонецПроцедуры #КонецОбласти
После настройки конфигурации "1С:Зарплата и управление персоналом КОРП" необходимо задать настройки подключения этой базы к сервису интеграции в режиме "1С:Предприятие".
Для этого необходимо:
Чтобы настроить подключение к серверу "1С:Шины", необходимо нажать "Редактировать". В группе "Настройки внешнего сервиса интеграции" задать свойства:
Для сохранения настроек нужно нажать "ОК".
Чтобы запустить обмен сообщениями, нужно в форме списка сервисов интеграции установить флажок "Активность" у выбранного сервиса:
Перед запуском регламентных заданий необходимо создать узел в плане обмена "Интеграция_СКУД", созданном в разделе 3.2 "Доработки конфигурации в расширении".
Для этого необходимо перейти в раздел "Интеграция", открыть план обмена и создать новый элемент, заполнив его реквизиты следующим образом:
Указать название сервиса интеграции и каналов интеграции, которые были созданы в пункте 3.2.2 "Сервис интеграции".
Чтобы обмен выполнялся в автоматическом режиме, необходимо подключить созданную в разделе 3.4 обработку в информационной базе "1С:Зарплата и управление персоналом КОРП". Для этого необходимо выбрать раздел "Администрирование", далее выбрать "Печатные формы, отчеты и обработки", "Дополнительные отчеты и обработки", в открывшемся окне нажать на кнопку "Добавить из файла":
Далее необходимо выбрать обработку "ИнтеграцияСШиной.epf", созданную в разделе 3.4, после этого откроется форма:
В форме подключения внешней обработки необходимо задать расписание выполнения команд, для этого нужно установить флажок в колонке "Выполнять команду по расписанию".
При установке флажка "Выполнять команду по расписанию" откроется форма настройки расписания. Для тестового примера указываются следующие настройки:
После того как расписание будет задано, нужно нажать на кнопку "Записать и закрыть". После записи дополнительной обработки автоматически будут созданы соответствующие регламентные задания.
Чтобы убедиться, что регламентные задания созданы и функционируют, в информационной базе "1С:Зарплаты и управления персоналом КОРП" нужно выбрать раздел "Администрирование", далее "Обслуживание", выбрать пункт "Регламентные и фоновые задания".
В открывшемся списке необходимо найти задания, в названии которых указаны "Дополнительная обработка" и название команды. Если такие задания найдены, значит, настройки выполнены успешно:
Для проверки настроенного обмена выполним загрузку журнала контрольных точек в информационную базу "1С". Перед загрузкой необходимо заполнить таблицу "CheckPointLog" тестовым данными. Выполним для этого следующий скрипт в SQL:
Копировать в буфер обменаINSERT INTO [dbo].[CheckPointLog] ([_AccessDatetime] ,[_PointCode] ,[_Code]) VALUES ('2022-05-12 09:00:01', '000000001', '779937658504'), ('2022-05-12 18:00:05', '000000002', '779937658504'), ('2022-05-12 09:00:05', '000000001', '778172302637'), ('2022-05-12 18:10:05', '000000002', '778172302637'), ('2022-05-12 09:00:15', '000000001', '772482788663'), ('2022-05-12 18:20:05', '000000002', '772482788663');
После выполнения скрипта тестовая таблица должна заполниться тестовыми данными, для проверки можно выполнить скрипт:
Копировать в буфер обменаSELECT TOP (1000) [_AccessDatetime] ,[_PointCode] ,[_Code] FROM [test_skud].[dbo].[CheckPointLog]
Результат:
Перейдем в информационную базу "1С:Зарплаты и управления персоналом КОРП" и выполним загрузку журнала контрольных точек. Для этого необходимо открыть регистр "Журнал контрольных точек (СКУД)" и нажать на кнопку "Загрузить журнал из СКУД", указать период отбора и нажать на кнопку "ОК":
При выполнении регламентного задания "Выполнить обработку сообщений шины" в информационной базе "1С:Зарплаты и управления персоналом КОРП" исходящее сообщение будет передано в "1С:Шину" для обмена, счетчики каналов в приложении должны измениться.
Чтобы просмотреть счетчики каналов, необходимо в приложении "1С:Шины" щелкнуть на процессе интеграции "Основной:: ExchangeSQL", далее перейти на вкладку "Каналы":
Так как при отправке запроса на загрузку журнала контрольных точек был подключен обработчик ожидания для обновления формы, то через интервал времени, указанный в обработчике ожидания, на форме должны отобразиться записи, полученные из базы SQL:
Для удобства читателей мы прикладываем расширение для базы ЗУП КОРП, которое содержит добавленный код.
А также обработку, о которой идёт речь в статье.
Обработка находится в каталоге EXE/Scalability/i8106000/Интеграция_АнализКаналов_ЗУП.epf
Расширение находится в каталоге EXE/Scalability/i8106000/ИнтеграцияЗУП.cfe