При работе с распределенными информационными базами (РИБ) иногда возникают ситуации, когда часть данных не передается между узлами обмена. Это может происходить из-за сбоев в сети, отключения авторегистрации, особенностей правил коллизий или сброса номеров сообщений. В результате остатки между центральной и периферийными базами рассинхронизируются. Для выравнивания учета возникает необходимость повторно зарегистрировать документы вместе со всеми их движениями (наборами записей регистров) для выгрузки в нужный узел плана обмена.
Рассмотрим, как правильно решить эту задачу программным путем, изучим работу ключевых методов платформы 1С и разберем готовые примеры кода.
Для регистрации любых объектов или наборов записей в платформе «1С:Предприятие» используется синтаксический метод ПланыОбмена.ЗарегистрироватьИзменения(). Выясним основные параметры работы этой функции:
Синтаксис метода:
ПланыОбмена.ЗарегистрироватьИзменения(<Узлы>, <Данные>)
Разберем параметры подробнее:
ПланОбменаСсылка.<ИмяПланаОбмена>) или массив таких ссылок, для которых необходимо выгрузить изменения.Неопределено.Важно понимать, как платформа обрабатывает параметр Данные:
РегистрНакопленияНаборЗаписей, РегистрСведенийНаборЗаписей и т. д.) с установленным отбором по регистратору, платформой регистрируются только движения по данному конкретному регистру.Метаданные.Документы.РеализацияТоваровУслуг), изменения регистрируются для всех элементов данного типа в базе.Рассмотрим классическую задачу: необходимо зарегистрировать документ и список его движений по конкретным регистрам накопления для передачи через план обмена.
Проанализируем пример кода, выполняющий регистрацию документа и его наборов записей по списку регистров:
Процедура ЗарегистрироватьОбъектИДвижения(СыллкаНаДокумент, УзелПланаОбмена)
// 1. Регистрируем сам документ (шапку и табличные части)
ПланыОбмена.ЗарегистрироватьИзменения(УзелПланаОбмена, СыллкаНаДокумент);
// 2. Регистрируем движения документа по необходимым регистрам
ЗарегистрироватьНаборЗаписейРегистра("ТоварыВРознице", СыллкаНаДокумент, УзелПланаОбмена);
ЗарегистрироватьНаборЗаписейРегистра("Продажи", СыллкаНаДокумент, УзелПланаОбмена);
ЗарегистрироватьНаборЗаписейРегистра("ПартииТоваровНаСкладах", СыллкаНаДокумент, УзелПланаОбмена);
ЗарегистрироватьНаборЗаписейРегистра("СвободныеОстатки", СыллкаНаДокумент, УзелПланаОбмена);
ЗарегистрироватьНаборЗаписейРегистра("ВзаиморасчетыСКонтрагентами", СыллкаНаДокумент, УзелПланаОбмена);
ЗарегистрироватьНаборЗаписейРегистра("РасчетыСКонтрагентами", СыллкаНаДокумент, УзелПланаОбмена);
ЗарегистрироватьНаборЗаписейРегистра("ДвиженияДенежныхСредств", СыллкаНаДокумент, УзелПланаОбмена);
КонецПроцедуры
Процедура ЗарегистрироватьНаборЗаписейРегистра(ИмяРегистра, СыллкаНаДокумент, УзелПланаОбмена)
Попытка
Набор = РегистрыНакопления[ИмяРегистра].СоздатьНаборЗаписей();
Набор.Отбор.Регистратор.Установить(СыллкаНаДокумент);
// Для регистрации набора записей считывать данные из базы не требуется
ПланыОбмена.ЗарегистрироватьИзменения(УзелПланаОбмена, Набор);
Исключение
// Регистр может не содержать данный документ или не входить в состав плана обмена
КонецПопытки;
КонецПроцедуры
В приведенном коде для каждого регистра создается набор записей через СоздатьНаборЗаписей(), устанавливается отбор по свойству Регистратор, после чего набор передается в ПланыОбмена.ЗарегистрироватьИзменения().
Чтобы не перечислять имена регистров вручную (как в примере выше), можно использовать свойства метаданных документа. У каждого документа в конфигурации есть коллекция Метаданные.Движения, содержащая все регистры, по которым документ может делать записи.
Разберем универсальную процедуру, которая автоматически определяет движения любого документа и регистрирует их:
Процедура ЗарегистрироватьДокументИВсеЕгоДвиженияУниверсально(ДокументСсылка, УзелПланаОбмена)
// Регистрируем сам документ
ПланыОбмена.ЗарегистрироватьИзменения(УзелПланаОбмена, ДокументСсылка);
МетаданныеДокумента = ДокументСсылка.Метаданные();
// Обходим все регистры, указанные в движениях документа
Для Каждого ДвижениеМетаданные Из МетаданныеДокумента.Движения Цикл
ИмяРегистра = ДвижениеМетаданные.Имя;
ВидРегистра = ДвижениеМетаданные.Родитель().Имя; // РегистрыНакопления, РегистрыСведений и т.д.
Попытка
МенеджерРегистра = Регистры[ВидРегистра][ИмяРегистра];
Набор = МенеджерРегистра.СоздатьНаборЗаписей();
Набор.Отбор.Регистратор.Установить(ДокументСсылка);
ПланыОбмена.ЗарегистрироватьИзменения(УзелПланаОбмена, Набор);
Исключение
// Обработка возможных ошибок доступа или отсутствия регистра в плане обмена
КонецПопытки;
КонецЦикла;
КонецПроцедуры
При выполнении массовой регистрации объектов на информационных базах большого объема (100 ГБ и более) следует учитывать ряд технических ограничений:
ПланыОбмена.ЗарегистрироватьИзменения() выполняется мгновенно, так как оно лишь делает запись в системные таблицы изменений _Changes..Прочитать() у набора записей. Для регистрации изменений в плане обмена достаточно установить отбор по регистратору. Вызывать метод чтения данных с диска не нужно, это сэкономит ресурсы сервера.ЗаписатьИзменения(). Выполняйте обработку небольшими пакетами (например, по 500–1000 документов) и запускайте обмен между пакетами.