Как зарегистрировать документ и все его движения в плане обмена 1С?

Программист 1С v8.3 (Обычные формы) IT и автоматизация бизнеса
← На главную

При работе с распределенными информационными базами (РИБ) иногда возникают ситуации, когда часть данных не передается между узлами обмена. Это может происходить из-за сбоев в сети, отключения авторегистрации, особенностей правил коллизий или сброса номеров сообщений. В результате остатки между центральной и периферийными базами рассинхронизируются. Для выравнивания учета возникает необходимость повторно зарегистрировать документы вместе со всеми их движениями (наборами записей регистров) для выгрузки в нужный узел плана обмена.

Рассмотрим, как правильно решить эту задачу программным путем, изучим работу ключевых методов платформы 1С и разберем готовые примеры кода.

Базовый метод платформы: ПланыОбмена.ЗарегистрироватьИзменения

Для регистрации любых объектов или наборов записей в платформе «1С:Предприятие» используется синтаксический метод ПланыОбмена.ЗарегистрироватьИзменения(). Выясним основные параметры работы этой функции:

Синтаксис метода:

ПланыОбмена.ЗарегистрироватьИзменения(<Узлы>, <Данные>)

Разберем параметры подробнее:

  1. Узлы (обязательный) — ссылка на узел плана обмена (тип ПланОбменаСсылка.<ИмяПланаОбмена>) или массив таких ссылок, для которых необходимо выгрузить изменения.
  2. Данные (необязательный) — объект базы данных, ссылка, набор записей регистра, объект метаданных или Неопределено.

Важно понимать, как платформа обрабатывает параметр Данные:

  1. Если передана ссылка на документ или объект документа, регистрируется сам документ (его шапка и табличные части). Обратите внимание: движения документа по регистрам при этом автоматически не регистрируются, если не настроена соответствующая подписка или авторегистрация.
  2. Если передан набор записей регистра (тип РегистрНакопленияНаборЗаписей, РегистрСведенийНаборЗаписей и т. д.) с установленным отбором по регистратору, платформой регистрируются только движения по данному конкретному регистру.
  3. Если передан объект метаданных (например, Метаданные.Документы.РеализацияТоваровУслуг), изменения регистрируются для всех элементов данного типа в базе.

Практический пример программной регистрации документа и его движений

Рассмотрим классическую задачу: необходимо зарегистрировать документ и список его движений по конкретным регистрам накопления для передачи через план обмена.

Проанализируем пример кода, выполняющий регистрацию документа и его наборов записей по списку регистров:


Процедура ЗарегистрироватьОбъектИДвижения(СыллкаНаДокумент, УзелПланаОбмена)
    
    // 1. Регистрируем сам документ (шапку и табличные части)
    ПланыОбмена.ЗарегистрироватьИзменения(УзелПланаОбмена, СыллкаНаДокумент);
    
    // 2. Регистрируем движения документа по необходимым регистрам
    ЗарегистрироватьНаборЗаписейРегистра("ТоварыВРознице", СыллкаНаДокумент, УзелПланаОбмена);
    ЗарегистрироватьНаборЗаписейРегистра("Продажи", СыллкаНаДокумент, УзелПланаОбмена);
    ЗарегистрироватьНаборЗаписейРегистра("ПартииТоваровНаСкладах", СыллкаНаДокумент, УзелПланаОбмена);
    ЗарегистрироватьНаборЗаписейРегистра("СвободныеОстатки", СыллкаНаДокумент, УзелПланаОбмена);
    ЗарегистрироватьНаборЗаписейРегистра("ВзаиморасчетыСКонтрагентами", СыллкаНаДокумент, УзелПланаОбмена);
    ЗарегистрироватьНаборЗаписейРегистра("РасчетыСКонтрагентами", СыллкаНаДокумент, УзелПланаОбмена);
    ЗарегистрироватьНаборЗаписейРегистра("ДвиженияДенежныхСредств", СыллкаНаДокумент, УзелПланаОбмена);
    
КонецПроцедуры

Процедура ЗарегистрироватьНаборЗаписейРегистра(ИмяРегистра, СыллкаНаДокумент, УзелПланаОбмена)
    
    Попытка
        Набор = РегистрыНакопления[ИмяРегистра].СоздатьНаборЗаписей();
        Набор.Отбор.Регистратор.Установить(СыллкаНаДокумент);
        
        // Для регистрации набора записей считывать данные из базы не требуется
        ПланыОбмена.ЗарегистрироватьИзменения(УзелПланаОбмена, Набор);
    Исключение
        // Регистр может не содержать данный документ или не входить в состав плана обмена
    КонецПопытки;
    
КонецПроцедуры

В приведенном коде для каждого регистра создается набор записей через СоздатьНаборЗаписей(), устанавливается отбор по свойству Регистратор, после чего набор передается в ПланыОбмена.ЗарегистрироватьИзменения().

Универсальный обход всех движений документа через метаданные

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

Разберем универсальную процедуру, которая автоматически определяет движения любого документа и регистрирует их:


Процедура ЗарегистрироватьДокументИВсеЕгоДвиженияУниверсально(ДокументСсылка, УзелПланаОбмена)
    
    // Регистрируем сам документ
    ПланыОбмена.ЗарегистрироватьИзменения(УзелПланаОбмена, ДокументСсылка);
    
    МетаданныеДокумента = ДокументСсылка.Метаданные();
    
    // Обходим все регистры, указанные в движениях документа
    Для Каждого ДвижениеМетаданные Из МетаданныеДокумента.Движения Цикл
        
        ИмяРегистра = ДвижениеМетаданные.Имя;
        ВидРегистра = ДвижениеМетаданные.Родитель().Имя; // РегистрыНакопления, РегистрыСведений и т.д.
        
        Попытка
            МенеджерРегистра = Регистры[ВидРегистра][ИмяРегистра];
            Набор = МенеджерРегистра.СоздатьНаборЗаписей();
            Набор.Отбор.Регистратор.Установить(ДокументСсылка);
            
            ПланыОбмена.ЗарегистрироватьИзменения(УзелПланаОбмена, Набор);
        Исключение
            // Обработка возможных ошибок доступа или отсутствия регистра в плане обмена
        КонецПопытки;
        
    КонецЦикла;
    
КонецПроцедуры

Особенности работы с большими базами данных и РИБ

При выполнении массовой регистрации объектов на информационных базах большого объема (100 ГБ и более) следует учитывать ряд технических ограничений:

  1. Не перепроводите документы без необходимости. Перепроведение большого количества документов в крупных базах может занимать продолжительное время (до десятков минут на один документ со сложными проведениями) и блокировать работу пользователей. Использование прямого метода ПланыОбмена.ЗарегистрироватьИзменения() выполняется мгновенно, так как оно лишь делает запись в системные таблицы изменений _Changes.
  2. Не вызывайте метод .Прочитать() у набора записей. Для регистрации изменений в плане обмена достаточно установить отбор по регистратору. Вызывать метод чтения данных с диска не нужно, это сэкономит ресурсы сервера.
  3. Регистрируйте данные порциями. Одномоментная регистрация миллионов записей приведет к разрастанию системных таблиц регистраций, огромному размеру итогового XML-файла обмена и вероятным ошибкам по таймауту или нехватке памяти при выполнении ЗаписатьИзменения(). Выполняйте обработку небольшими пакетами (например, по 500–1000 документов) и запускайте обмен между пакетами.
← На главную