diff --git a/.vscode/Бэктик.code-snippets b/.vscode/Бэктик.code-snippets index 64442d5..9d94cd7 100644 --- a/.vscode/Бэктик.code-snippets +++ b/.vscode/Бэктик.code-snippets @@ -79,7 +79,7 @@ }, "Таблица 2 колонки": { - "prefix": "таблица", + "prefix": "таблица2", "body": [ "| Заголовок 1 | Заголовок 2 |", "|-------------|-------------|", @@ -89,7 +89,7 @@ }, "Таблица 3 колонки": { - "prefix": "таблица", + "prefix": "таблица3", "body": [ "| Заголовок 1 | Заголовок 2 | Заголовок 3 |", "|-------------|-------------|-------------|", @@ -99,7 +99,7 @@ }, "Таблица 4 колонки": { - "prefix": "таблица", + "prefix": "таблица4", "body": [ "| Заголовок 1 | Заголовок 2 | Заголовок 3 | Заголовок 4 |", "|-------------|-------------|-------------|-------------|", @@ -109,7 +109,7 @@ }, "Таблица 5 колонки": { - "prefix": "таблица", + "prefix": "таблица5", "body": [ "| Заголовок 1 | Заголовок 2 | Заголовок 3 | Заголовок 4 | Заголовок 5 |", "|-------------|-------------|-------------|-------------|-------------|", @@ -119,7 +119,7 @@ }, "Таблица 6 колонки": { - "prefix": "таблица", + "prefix": "таблица6", "body": [ "| Заголовок 1 | Заголовок 2 | Заголовок 3 | Заголовок 4 | Заголовок 5 | Заголовок 6 |", "|-------------|-------------|-------------|-------------|-------------|-------------|", diff --git a/public/obmen-dannymi/rib/1.png b/public/obmen-dannymi/rib/1.png new file mode 100644 index 0000000..7dba111 Binary files /dev/null and b/public/obmen-dannymi/rib/1.png differ diff --git a/public/obmen-dannymi/rib/2.png b/public/obmen-dannymi/rib/2.png new file mode 100644 index 0000000..d6479e6 Binary files /dev/null and b/public/obmen-dannymi/rib/2.png differ diff --git a/public/obmen-dannymi/rib/3.png b/public/obmen-dannymi/rib/3.png new file mode 100644 index 0000000..8811f3b Binary files /dev/null and b/public/obmen-dannymi/rib/3.png differ diff --git a/public/obmen-dannymi/rib/4.png b/public/obmen-dannymi/rib/4.png new file mode 100644 index 0000000..58cd967 Binary files /dev/null and b/public/obmen-dannymi/rib/4.png differ diff --git a/src/content/docs/knowledge-base/Общие/Обмен данными/Планы обмена/Распределенная информационная база/Подключение и отключение базы к РИБ.md b/src/content/docs/knowledge-base/Общие/Обмен данными/Планы обмена/Распределенная информационная база/Подключение и отключение базы к РИБ.md new file mode 100644 index 0000000..ee8eeae --- /dev/null +++ b/src/content/docs/knowledge-base/Общие/Обмен данными/Планы обмена/Распределенная информационная база/Подключение и отключение базы к РИБ.md @@ -0,0 +1,16 @@ +--- +title: Подключение и отключение базы к РИБ +slug: общие-обмен-данными-планы-обмена-распределенная-информационная-база/подключение-и-отключение-базы-к-риб +--- + +## Подключение базы +```bsl +УзелЦентральнойБазы = ПланыОбмена.Полный.НайтиПоКоду("ЦБ"); +ПланыОбмена.УстановитьГлавныйУзел(УзелЦентральнойБазы); +``` + +## Отключение базы +```bsl +ПланыОбмена.УстановитьГлавныйУзел(Неопределено); +``` +или запустить базу с аргументом `/ResetMasterNode` \ No newline at end of file diff --git a/src/content/docs/knowledge-base/Общие/Обмен данными/Планы обмена/Распределенная информационная база/Получить главный узел.md b/src/content/docs/knowledge-base/Общие/Обмен данными/Планы обмена/Распределенная информационная база/Получить главный узел.md new file mode 100644 index 0000000..d26bd17 --- /dev/null +++ b/src/content/docs/knowledge-base/Общие/Обмен данными/Планы обмена/Распределенная информационная база/Получить главный узел.md @@ -0,0 +1,9 @@ +--- +title: Получить главный узел +slug: общие-обмен-данными-планы-обмена-распределенная-информационная-база/получить-главный-узел +--- + + +```bsl +ГлавныйУзел = ПланыОбмена.ГлавныйУзел(); +``` \ No newline at end of file diff --git a/src/content/docs/knowledge-base/Общие/Обмен данными/Планы обмена/Распределенная информационная база/Реализация/Реализация РИБ в базах без БСП.md b/src/content/docs/knowledge-base/Общие/Обмен данными/Планы обмена/Распределенная информационная база/Реализация/Реализация РИБ в базах без БСП.md new file mode 100644 index 0000000..57b074b --- /dev/null +++ b/src/content/docs/knowledge-base/Общие/Обмен данными/Планы обмена/Распределенная информационная база/Реализация/Реализация РИБ в базах без БСП.md @@ -0,0 +1,178 @@ +--- +title: Реализация РИБ в базах без БСП +slug: общие-обмен-данными-планы-обмена-распределенная-информационная-база-реализация/реализация-риб-в-базах-без-бсп +--- +# Перед началом работы + +## Что это такое +Распределенная информационная база (РИБ) - это совокупность связанных информационных баз, в которых поддерживается синхронизация `конфигураций` и `данных` +РИБ служит для обмена идентичных информационных баз «1С: Предприятие 8». Чаще всего задача обменов между узлами РИБ сводится к выгрузке данных из **периферийных** узлов в **центральную базу** + +В РИБ все конфигурации объеденены по строгой иерархии - центральная база может быть **только одна**, от которой создаются подчиненные узлы +![описание](/obmen-dannymi/rib/1.png) + +## Особенности работы с РИБ + +- Обмен данными выполняется в формате ХML документов. Изменения конфигурации распространяются в сообщениях обмена вместе с изменениями данных. +- Внесение изменений в конфигурацию возможно только в одном (корневом) узле распределённой системы. Изменения конфигурации передаются от главного узла к подчинённым +- Внесение изменений в данные возможно в любом узле системы. Изменения данных передаются между любыми связанными узлами. +- При выгрузке данных на всех объектах (справочники, документы и т. д.) невозможно внесение изменений (устанавливается блокировка). Это может парализовать рабочий процесс на длительное время. Чтобы избежать этого, рекомендуется включать обмен после работы либо выгружать небольшой объём информации за один раз. +- При обмене данными в случае, если объект был изменен в корневом и подчиненном узлах одновременно (коллизия), **ГЛАВНАЯ база перетирает изменения ПОДЧИНЕННОЙ** + +# Пример работы в базах без БСП + +## Создание подчиненных баз + +1. Создаем план обмена. Во вкладке `Основное` устанавливаем флаги `Распределенная информационная база` и `Включать расширения конфигурации` +2. Настраиваем состав плана обмена. `Авторегистрацию` запрещаем, т.к. необходимо будет **вручную управлять регистрацией изменений**. (Мы же не хотим отправить документы дочернего узла 2 в дочерний узел 1 и наоборот) +![описание](/obmen-dannymi/rib/2.png) +3. Реализуем префиксацию объектов любым способом. Главное, чтобы коды и номера элементов в базах в РИБ не пересекались. + +
+Пример создания + +Колхозное решение "на коленке" + +- Создаем константу `ПрефиксИнформационнойБазы` (строка, 2 символа), **не включаем ее в план обмена**. Нам не нужно, чтобы она затиралась +- Создаем подписки на события: + +| Имя подписки | Источник | Событие | Обработчик | +|-------------|-------------|-------------|-------------| +|`УстановитьПрефиксИнформационнойБазыНомеруДокумента`| все объекты `ДокументОбъект`, которые участвуют в обмене |`ПриУстановкеНовогоНомера`|`ПрефиксацияОбъектовСобытия.УстановитьПрефиксИнформационнойБазы` (реализуем ниже)| +|`УстановитьПрефиксИнформационнойБазыКодуСправочника`|все объекты `СправочникОбъект`, которые участвуют в обмене|`ПриУстановкеНовогоКода`|`ПрефиксацияОбъектовСобытия.УстановитьПрефиксИнформационнойБазы` (реализуем ниже)| + +- В общем модуле реализуем метод префиксации: + +```bsl + +#Область ПрограммныйИнтерфейс + +Процедура УстановитьПрефиксИнформационнойБазы(Источник, СтандартнаяОбработка, Префикс) Экспорт + + ПрефиксИБ = Константы.ПрефиксИнформационнойБазы.Получить(); + + Если Не ЗначениеЗаполнено(ПрефиксИБ) Тогда + Префикс = "00-"; + Иначе + Префикс = ПрефиксИБ + "-"; + КонецЕсли; + +КонецПроцедуры + +#КонецОбласти + +``` + +Все) + +
+ +4. Создаем начальные образы подчиненных баз +В пользовательском режиме открываем созданный план обмена, настраиваем предопределенный узел текущей базы +Все созданные узлы в этом плане будут **подчинены** текущей базе. +![описание](/obmen-dannymi/rib/3.png) + +Нажимаем команду `Создать начальный образ`, выбираем каталог, куда будет сохранен файл `.1cd` для файлового варианта или указываем параметры ИБ для серверного варианта +После этого просто создаем базу с теми параметрами подключения, которые указали выше (путь до папки в файловом варианте или строка подключения в серверном варианте) + +В подчиненных базах для в пользовательском режиме можно будет посмотреть, какому узлу база подчинена +![описание](/obmen-dannymi/rib/4.png) + +## Реализация выборочной регистрации изменений +Создаем подписки на событие: +| Имя подписки | Источник | Событие | Обработчик | +|-------------|-------------|-------------|-------------| +|`РегистрацияИзменений`| все **объекты**, которые участвуют в обмене |`ПриЗаписи`|`ОбменДаннымиРегистрацияСобытий.РИБ_РегистрацияПриЗаписи` (реализуем ниже)| +|`РегистрацияУдалений`| все **объекты**, которые участвуют в обмене |`ПередУдалением`|`ОбменДаннымиРегистрацияСобытий.РИБ_РегистрацияУдаленияПередУдалением` (реализуем ниже)| + +Создаем общий модуль `ОбменДаннымиРегистрацияСобытий`, в котором определяем алгоритмы регистрации: + +```bsl + +#Область ПрограммныйИнтерфейс + +Процедура РИБ_РегистрацияПриЗаписи(Источник, Отказ) Экспорт + + ЗарегистрироватьИзменениеОбъекта(Источник, Отказ); + +КонецПроцедуры + +Процедура РИБ_РегистрацияУдаленияПередУдалением(Источник, Отказ) Экспорт + + ЗарегистрироватьУдалениеОбъекта(Источник, Отказ); + +КонецПроцедуры + +#КонецОбласти + + +Процедура ЗарегистрироватьИзменениеОбъекта(Источник, Отказ) + + Если Отказ Тогда + Возврат; + КонецЕсли; + + ЭтоДокумент = Документы.ТипВсеСсылки().СодержитТип(ТипЗнч(Источник.Ссылка)); + + // В примере подразумевается, что у всех документов есть реквизит "Магазин", по которому будем фильтровать подчиненные базы + Магазин = ?(ЭтоДокумент, Источник.Магазин, Неопределено); + + // Получаем узлы, которые должны получить изменения выбранных документов + УзлыОбмена = ОпределитьПолучателейОбъекта(Магазин); + + ПланыОбмена.ЗарегистрироватьИзменения(УзлыОбмена, Источник); + +КонецПроцедуры + +Процедура ЗарегистрироватьУдалениеОбъекта(Источник, Отказ) + + Если Отказ Тогда + Возврат; + КонецЕсли; + + ЭтоДокумент = Документы.ТипВсеСсылки().СодержитТип(ТипЗнч(Источник.Ссылка)); + Магазин = ?(ЭтоДокумент, Источник.Магазин, Неопределено); + УзлыОбмена = ОпределитьПолучателейОбъекта(Магазин); + + ПланыОбмена.ЗарегистрироватьИзменения(УзлыОбмена, Новый УдалениеОбъекта(Источник.Ссылка)); + +КонецПроцедуры + +Функция ОпределитьПолучателейОбъекта(Магазин = Неопределено) + + УзлыОбмена = Новый Массив; + + Запрос = Новый Запрос; + Запрос.Текст = + "ВЫБРАТЬ + | РИБ.Ссылка КАК Ссылка + |ИЗ + | ПланОбмена.РИБ КАК РИБ + |ГДЕ + | НЕ РИБ.ПометкаУдаления + | И НЕ РИБ.ЭтотУзел"; + + // "РИБ.Магазин = &Магазин" - + // для простоты примера принимается, что в плане обмена есть реквизит "Магазин", который заполняется для каждого узла + // На практике можно сделать соответствие "Узел-Магазин" любым другим способом, регистром сведений, например + Если Магазин <> Неопределено Тогда + Запрос.Текст = Запрос.Текст + " + |И РИБ.Магазин = &Магазин"; + Запрос.УстановитьПараметр("Магазин", Магазин); + КонецЕсли; + + РезультатЗапроса = Запрос.Выполнить(); + + Выборка = РезультатЗапроса.Выбрать(); + + Пока Выборка.Следующий() Цикл + УзлыОбмена.Добавить(Выборка.Ссылка); + КонецЦикла; + + Возврат УзлыОбмена; + +КонецФункции + +#КонецОбласти + +``` \ No newline at end of file diff --git a/src/content/docs/knowledge-base/Общие/Обмен данными/Планы обмена/Распределенная информационная база/Создать начальный образ.md b/src/content/docs/knowledge-base/Общие/Обмен данными/Планы обмена/Распределенная информационная база/Создать начальный образ.md new file mode 100644 index 0000000..70fbce0 --- /dev/null +++ b/src/content/docs/knowledge-base/Общие/Обмен данными/Планы обмена/Распределенная информационная база/Создать начальный образ.md @@ -0,0 +1,19 @@ +--- +title: Создать начальный образ +slug: общие-обмен-данными-планы-обмена-распределенная-информационная-база/создать-начальный-образ +--- + + +```bsl + +// Создание нового узла обмена +НовыйУзел = ПланыОбмена.РИБ.СоздатьУзел(); +НовыйУзел.Код = "М2"; +НовыйУзел.Наименование = "Магазин № 2"; +НовыйУзел.Записать(); + +// Создание начального образа для нового узла обмена +ПутьКБазеУзла = "File=""S:\Bases_1C\rib_bases\m2"""; +ПланыОбмена.СоздатьНачальныйОбраз(НовыйУзел.Ссылка, ПутьКБазеУзла); + +``` \ No newline at end of file diff --git a/src/content/docs/knowledge-base/Общие/Обмен данными/Планы обмена/Распределенная информационная база/Чтение и запись сообщения обмена.md b/src/content/docs/knowledge-base/Общие/Обмен данными/Планы обмена/Распределенная информационная база/Чтение и запись сообщения обмена.md new file mode 100644 index 0000000..b0337ac --- /dev/null +++ b/src/content/docs/knowledge-base/Общие/Обмен данными/Планы обмена/Распределенная информационная база/Чтение и запись сообщения обмена.md @@ -0,0 +1,177 @@ +--- +title: Чтение и запись сообщения обмена +slug: общие-обмен-данными-планы-обмена-распределенная-информационная-база/чтение-и-запись-сообщения-обмена +--- + +## Запись сообщения обмена +```bsl + +УзелОтправитель = ПланыОбмена.РИБ.ЭтотУзел(); +УзелПолучатель = ПланыОбмена.РИБ.НайтиПоКоду("М1"); + +ИмяФайлаСообщения = СтрШаблон("C:\temp\demo_exchange\Message_%1_%2.xml", + УзелОтправитель.Код, УзелПолучатель.Код); + +// Открываем файл для записи +ЗаписьXML = Новый ЗаписьXML(); +ЗаписьXML.ОткрытьФайл(ИмяФайлаСообщения); + +// Создаем запись сообщения +ЗаписьСообщения = ПланыОбмена.СоздатьЗаписьСообщения(); +ЗаписьСообщения.НачатьЗапись(ЗаписьXML, УзелПолучатель); + +// Записываем изменения в файл +ПланыОбмена.ЗаписатьИзменения(ЗаписьСообщения); + +ЗаписьСообщения.ЗакончитьЗапись(); + +// Закрываем файл +ЗаписьXML.Закрыть(); + +Сообщение = Новый СообщениеПользователю; +Сообщение.Текст = "Сообщение обмена успешно сформировано!"; +Сообщение.Сообщить(); + +``` + +## Чтение сообщения обмена +### Вариант 1 + +```bsl +УзелОтправитель = ПланыОбмена.РИБ.НайтиПоКоду("М1"); +УзелПолучатель = ПланыОбмена.РИБ.ЭтотУзел(); + +ИмяФайлаСообщения = СтрШаблон("C:\temp\demo_exchange\Message_%1_%2.xml", + УзелОтправитель.Код, УзелПолучатель.Код); + +// Открываем файл для чтения +ЧтениеXML = Новый ЧтениеXML; +ЧтениеXML.ОткрытьФайл(ИмяФайлаСообщения); + +// Создаем чтение сообщения +ЧтениеСообщения = ПланыОбмена.СоздатьЧтениеСообщения(); + +// Чтение сообщения обмена +Попытка + ЧтениеСообщения.НачатьЧтение(ЧтениеXML); + ПланыОбмена.ПрочитатьИзменения(ЧтениеСообщения); +Исключение + ТекстОшибки = ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке()); + Сообщение = Новый СообщениеПользователю; + Сообщение.Текст = ТекстОшибки; + Сообщение.Сообщить(); +КонецПопытки; + +// Завершить чтение сообщения +ЧтениеСообщения.ЗакончитьЧтение(); +ЧтениеXML.Закрыть(); +``` + +### Вариант 2 +```bsl +Функция ПрочитатьИПрименитьСообщениеОбмена(УзелОбмена, ИмяФайла) Экспорт + + Результат = Новый Структура; + Результат.Вставить("Успешно", Ложь); + Результат.Вставить("ОписаниеОшибки", ""); + Результат.Вставить("КоличествоОбъектов", 0); + + Попытка + // Проверяем существование файла + Файл = Новый Файл(ИмяФайла); + Если НЕ Файл.Существует() Тогда + ВызватьИсключение "Файл сообщения не найден"; + КонецЕсли; + + // Открываем файл для чтения + ЧтениеXML = Новый ЧтениеXML; + ЧтениеXML.ОткрытьФайл(ИмяФайла); + + // Создаем чтение сообщения + ЧтениеСообщения = ПланыОбмена.СоздатьЧтениеСообщения(); + ЧтениеСообщения.НачатьЧтение(ЧтениеXML); + + // Проверяем соответствие узлов + Если ЧтениеСообщения.Отправитель <> УзелОбмена Тогда + ВызватьИсключение СтрШаблон( + "Сообщение от другого узла. Ожидается: %1, Получено: %2", + УзелОбмена, + ЧтениеСообщения.Отправитель); + КонецЕсли; + + // Проверяем номер сообщения + НомерПринятого = УзелОбмена.НомерПринятого; + НомерСообщения = ЧтениеСообщения.НомерСообщения; + + Если НомерСообщения <= НомерПринятого Тогда + ВызватьИсключение СтрШаблон( + "Сообщение уже было принято. Номер сообщения: %1, Последний принятый: %2", + НомерСообщения, + НомерПринятого); + КонецЕсли; + + // Начинаем транзакцию + НачатьТранзакцию(); + + Попытка + // Читаем и записываем объекты + Пока ЧтениеСообщения.Прочитать() Цикл + + Данные = ЧтениеСообщения.Данные; + + // Устанавливаем режим загрузки + Если ТипЗнч(Данные) <> Тип("УдалениеОбъекта") Тогда + Данные.ОбменДанными.Загрузка = Истина; + Данные.ОбменДанными.Отправитель = УзелОбмена; + Данные.Записать(); + Иначе + // Удаление объекта + Попытка + УдаляемыйОбъект = Данные.Ссылка.ПолучитьОбъект(); + Если УдаляемыйОбъект <> Неопределено Тогда + УдаляемыйОбъект.ОбменДанными.Загрузка = Истина; + УдаляемыйОбъект.Удалить(); + КонецЕсли; + Исключение + // Объект уже удален + КонецПопытки; + КонецЕсли; + + Результат.КоличествоОбъектов = Результат.КоличествоОбъектов + 1; + + КонецЦикла; + + // Обновляем номер принятого сообщения + УзелОбъектОбмена = УзелОбмена.ПолучитьОбъект(); + УзелОбъектОбмена.НомерПринятого = НомерСообщения; + УзелОбъектОбмена.Записать(); + + // Фиксируем транзакцию + ЗафиксироватьТранзакцию(); + + Результат.Успешно = Истина; + + Исключение + ОтменитьТранзакцию(); + ВызватьИсключение; + КонецПопытки; + + // Закрываем чтение + ЧтениеСообщения.ЗакончитьЧтение(); + ЧтениеXML.Закрыть(); + + Исключение + Результат.ОписаниеОшибки = ОписаниеОшибки(); + + // Записываем в журнал регистрации + ЗаписьЖурналаРегистрации("Обмен.ЧтениеСообщения", + УровеньЖурналаРегистрации.Ошибка, + , + УзелОбмена, + Результат.ОписаниеОшибки); + КонецПопытки; + + Возврат Результат; + +КонецФункции +``` \ No newline at end of file