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

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

В процессе работы с распределенными информационными базами (РИБ) или другими механизмами обмена данными в 1С, мы часто сталкиваемся с ситуацией, когда необходимо выборочно управлять регистрацией изменений объектов. Типичный сценарий: мы делаем корректировку записей регистра сведений или накопления с помощью какого-либо документа или обработки. При этом сам документ, который осуществляет эту корректировку, не участвует в обмене, но регистр, записи которого изменяются, включен в состав плана обмена. Наша задача — не допустить, чтобы эти конкретные записи регистра были зарегистрированы для выгрузки в периферийные базы или другие узлы обмена.

Давайте разберем подробнее, как мы можем решить эту задачу, используя программные средства 1С.

Метод 1: Предотвращение автоматической регистрации изменений при записи набора записей регистра

Один из наиболее эффективных способов предотвратить регистрацию изменений для конкретных записей регистра — это программно управлять процессом регистрации непосредственно перед их записью. Механизм обмена данными в 1С автоматически регистрирует изменения объектов, когда они записываются в базу. Однако у нас есть возможность "отключить" это автоматическое поведение для конкретной операции записи.

Для этого мы воспользуемся свойством АвтоЗаполнение коллекции узлов-приемников менеджера обмена и списком получателей изменений. Когда мы записываем набор записей регистра, система обмена проверяет, для каких узлов необходимо зарегистрировать изменения. Если мы вручную очистим список этих узлов и отключим автоматическое заполнение, то система не сможет определить получателей, и регистрация не произойдет.

  1. Получаем набор записей регистра: Сначала нам нужно получить объект НаборЗаписей для нужного регистра. Мы можем получить его через менеджер регистра (например, РегистрыСведений.МойРегистр.СоздатьНаборЗаписей()) или через объект, являющийся регистратором (ДокументОбъект.Движения.МойРегистр).
  2. Устанавливаем отбор (при необходимости): Если мы хотим работать с определенными записями, которые относятся, например, к конкретному регистратору или периоду, мы должны установить соответствующий отбор для нашего набора записей. Это гарантирует, что мы будем модифицировать или удалять только целевые записи.
  3. Отключаем автоматическое заполнение получателей: Перед вызовом метода Записать(), мы должны получить доступ к менеджеру обмена для нашего набора записей. Это делается через свойство ПланыОбмена.ПолучитьМенеджерЗаписиРегистрацииИзменений(). У этого менеджера есть коллекция узлов-приемников. Мы устанавливаем свойство АвтоЗаполнение этой коллекции в значение Ложь.
  4. Очищаем список получателей: После отключения автозаполнения, мы очищаем коллекцию Получатели. Это гарантирует, что список узлов, для которых будут регистрироваться изменения, будет пуст.
  5. Устанавливаем флаг загрузки данных (важно): Чтобы система обмена не пыталась восстановить получателей или не вызвала других нежелательных эффектов, часто рекомендуется установить свойство ЗагрузкаДанных = Истина для объекта или набора записей перед записью. Это "подсказывает" системе, что данная операция является частью загрузки данных, а не обычным интерактивным изменением.
  6. Записываем набор: После всех этих подготовительных шагов, мы вызываем метод Записать() для нашего набора записей. В результате записи изменения будут внесены в базу данных, но не будут зарегистрированы для обмена.

Давайте посмотрим на пример кода, как это можно реализовать:


// Предположим, что мы корректируем записи регистра сведений "МойРегистрСведений"
// и у нас есть ссылка на регистратор (например, документ) или мы работаем
// с независимым регистром.

// Пример для регистратора
// Если работаем с движениями документа:
// Движения = ДокументОбъект.Движения.МойРегистрСведений;
// Движения.Очистить(); // Очищаем существующие движения, если нужно

// Или создаем набор записей для независимого регистра:
НаборЗаписей = РегистрыСведений.МойРегистрСведений.СоздатьНаборЗаписей();

// Устанавливаем отбор по ключевым полям, если это необходимо
// Например, если хотим изменить или удалить записи, привязанные к определенному регистратору
// или по другим измерениям.
// В данном примере будем считать, что нам нужно обновить записи для
// определенного ключа или удалить их, не регистрируя это изменение.

// Отбор по регистратору (если регистр подчинен регистратору)
// НаборЗаписей.Отбор.Регистратор.Установить(МойДокументСсылка);

// Или отбор по конкретному измерению для независимого регистра:
// НаборЗаписей.Отбор.Измерение1.Установить("ЗначениеОтбора");

// Прочитаем записи, чтобы потом модифицировать или удалить их
// НаборЗаписей.Прочитать();

// В этом месте мы можем добавить новые записи в НаборЗаписей.Добавить()
// или изменить существующие, или просто оставить его пустым для удаления по отбору.

// *** Ключевой блок для предотвращения регистрации изменений ***
МенеджерРегистрацииИзменений = ПланыОбмена.ПолучитьМенеджерЗаписиРегистрацииИзменений(НаборЗаписей);
Если МенеджерРегистрацииИзменений.АвтоЗаполнение Тогда
    МенеджерРегистрацииИзменений.АвтоЗаполнение = Ложь;
КонецЕсли;
// Очищаем список получателей, чтобы не было зарегистрировано ни одного изменения
МенеджерРегистрацииИзменений.Получатели.Очистить();

// Также часто рекомендуется устанавливать флаг загрузки данных для подобных операций,
// чтобы избежать дополнительных проверок и триггеров обмена.
НаборЗаписей.ЗагрузкаДанных = Истина;

// Теперь записываем набор
НаборЗаписей.Записать();

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

Этот подход особенно полезен, когда мы создаем служебные или временные записи, которые не должны синхронизироваться с другими базами, или когда мы делаем внутренние корректировки, не имеющие отношения к обмену.

Метод 2: Удаление уже зарегистрированных изменений с помощью ПланыОбмена.УдалитьРегистрациюИзменений()

Что делать, если изменения уже были зарегистрированы для обмена, но мы передумали и хотим отменить их выгрузку? Например, в результате какой-либо ошибки или изменения логики, записи были зарегистрированы, но теперь нам нужно их исключить из обмена. В этом случае мы можем использовать метод ПланыОбмена.УдалитьРегистрациюИзменений().

Этот метод позволяет явно удалить регистрацию изменений для указанных объектов или наборов данных для определенных узлов плана обмена. Это мощный инструмент для "отката" регистрации, который дает нам полный контроль.

  1. Определяем план обмена: Нам нужно знать, из какого плана обмена мы хотим удалить регистрацию. Обычно это ссылка на элемент справочника ПланыОбмена (например, ПланыОбмена.Полный, ПланыОбмена.ПоОтправителю и т.д.).
  2. Идентифицируем узлы-получатели: Если мы хотим удалить регистрацию только для определенных узлов, мы можем указать их в виде массива ссылок на узлы плана обмена. Если мы хотим удалить регистрацию для *всех* узлов данного плана обмена, этот параметр можно не указывать или передать пустой массив.
  3. Идентифицируем данные: Самое главное — указать, для каких данных (объектов) нужно удалить регистрацию. Это может быть:
    • Ссылка на конкретный объект: Например, ссылка на элемент справочника, документ.
    • Массив ссылок на объекты: Несколько ссылок, регистрация которых должна быть отменена.
    • Набор записей регистра: Мы можем создать набор записей, установить отбор и передать его. В этом случае будут удалены регистрации для всех записей, входящих в этот набор.
  4. Вызываем метод: Мы вызываем ПланыОбмена.УдалитьРегистрациюИзменений(ПланОбмена, Данные, Узлы).

Давайте рассмотрим пример удаления регистрации для записей регистра, относящихся к определенному регистратору:


// Предположим, у нас есть ссылка на документ-регистратор,
// движения которого по регистру "МойРегистрНакопления" были ошибочно зарегистрированы.
Перем СсылкаНаРегистратор; // Пусть здесь хранится ссылка на документ

// Определяем план обмена, из которого нужно удалить регистрацию.
// Например, для полного обмена или для конкретного обмена по модели "центральный-периферийный".
ПланОбмена = ПланыОбмена.Полный; // Или ПланыОбмена.ПоОтправителю, в зависимости от вашей конфигурации

// 1. Создаем набор записей для нужного регистра.
НаборЗаписейРегистра = РегистрыНакопления.МойРегистрНакопления.СоздатьНаборЗаписей();

// 2. Устанавливаем отбор по регистратору, чтобы выбрать именно те записи,
// которые нам нужно "отменить" из регистрации.
НаборЗаписейРегистра.Отбор.Регистратор.Установить(СсылкаНаРегистратор);

// 3. Вызываем метод удаления регистрации изменений.
// В данном примере мы удаляем регистрацию для всех узлов, участвующих в ПланеОбмена.Полный.
// Если нужно удалить для конкретных узлов, передайте массив ссылок на эти узлы третьим параметром.
Попытка
    ПланыОбмена.УдалитьРегистрациюИзменений(ПланОбмена, НаборЗаписейРегистра);
    Сообщить("Регистрация изменений для записей регистра '" + НаборЗаписейРегистра.Имя +
             "' по регистратору " + СсылкаНаРегистратор + " успешно удалена.");
Исключение
    Сообщить("Ошибка при удалении регистрации изменений: " + ОписаниеОшибки(), СтатусСообщения.Важное);
КонецПопытки;

// Теперь эти записи не будут выгружены в другие базы при следующем обмене,
// даже если они были ошибочно зарегистрированы ранее.

Этот метод особенно полезен, когда мы исправляем ошибки или корректируем данные в уже проведенных документах, и не хотим, чтобы эти внутренние корректировки распространялись на другие базы данных, если они не являются частью общего бизнес-процесса обмена. Для таких сценариев также подойдёт обработка для отмены регистрации документов за период в плане обмена.

Метод 3: Использование набора записей регистра для удаления/изменения данных с последующей отменой регистрации

Иногда наша задача не просто отменить регистрацию, а удалить или модифицировать записи регистра, которые не должны были появиться или должны быть изменены особым образом. Если сам документ-регистратор не участвует в обмене, то мы можем гибко управлять его движениями.

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

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

Рассмотрим пример удаления записей регистра по регистратору с предотвращением регистрации:


// Допустим, мы хотим удалить все движения документа "МойДокумент"
// по регистру сведений "ЦеныНоменклатуры" и не регистрировать это удаление.
Перем СсылкаНаДокумент; // Пусть здесь хранится ссылка на документ

// 1. Получаем набор записей для регистра сведений.
НаборЗаписейЦен = РегистрыСведений.ЦеныНоменклатуры.СоздатьНаборЗаписей();

// 2. Устанавливаем отбор по регистратору.
// Это критично, чтобы удалить записи только для нашего конкретного документа.
НаборЗаписейЦен.Отбор.Регистратор.Установить(СсылкаНаДокумент);

// 3. Прочитываем текущие записи, если нам нужно их модифицировать.
// Для удаления всех записей по отбору, это не обязательно,
// можно сразу переходить к очистке и записи.
НаборЗаписейЦен.Прочитать();

// 4. Очищаем набор записей, чтобы при записи по установленному отбору
// все существующие записи, соответствующие отбору, были удалены.
НаборЗаписейЦен.Очистить();

// *** Ключевой блок для предотвращения регистрации изменений ***
МенеджерРегистрацииИзменений = ПланыОбмена.ПолучитьМенеджерЗаписиРегистрацииИзменений(НаборЗаписейЦен);
Если МенеджерРегистрацииИзменений.АвтоЗаполнение Тогда
    МенеджерРегистрацииИзменений.АвтоЗаполнение = Ложь;
КонецЕсли;
МенеджерРегистрацииИзменений.Получатели.Очистить();
НаборЗаписейЦен.ЗагрузкаДанных = Истина;

// 5. Записываем пустой набор с установленным отбором.
// Это приведет к удалению всех записей регистра "ЦеныНоменклатуры",
// которые были зарегистрированы данным документом "СсылкаНаДокумент".
НаборЗаписейЦен.Записать();

Сообщить("Записи регистра 'ЦеныНоменклатуры' по регистратору " + СсылкаНаДокумент +
         " удалены без регистрации изменений для обмена.");

Важно помнить, что если не установить отбор вовсе и записать пустой набор записей, это приведет к полной очистке всего регистра! Поэтому всегда будьте крайне внимательны с отборами при работе с наборами записей.

Метод 4: Настройка правил регистрации объектов обмена (конфигурационно)

Хотя в нашем случае документ не участвует в обмене, и мы работаем с записями регистра программно, иногда требуется запретить регистрацию изменений для какого-либо объекта (документа, элемента справочника или набора записей регистра) на этапе конфигурации правил обмена. Это более статичный и глобальный подход, но его также полезно рассмотреть.

Мы можем отредактировать правила регистрации объектов обмена в конфигурации. Для этого, в событии "ПередОбработкой" правила регистрации соответствующего объекта, мы можем программно установить Отказ = Истина. Это предотвратит его регистрацию к выгрузке на этапе работы стандартного механизма регистрации изменений.

Этот метод применяется, когда мы хотим, чтобы определенные объекты или их части никогда не регистрировались для обмена, независимо от того, как они были изменены. Он не подходит для динамического управления регистрацией в процессе выполнения кода, который создает или изменяет записи, но важен для общего понимания контроля обмена.


// Пример кода в обработчике события "ПередОбработкой" правила регистрации объекта:
// В данном контексте "Источник" - это объект, который был изменен и
// для которого планируется регистрация изменений.
// "Отказ" - булево свойство, устанавливая которое в Истина, мы отменяем регистрацию.

// Предположим, мы не хотим регистрировать изменения для документа "ВнутреннееПеремещение",
// если его поле "ТипОперации" установлено в "Служебная".
Если ТипЗнч(Источник) = Тип("ДокументОбъект.ВнутреннееПеремещение") Тогда
    Если Источник.ТипОперации = Перечисления.ТипыОперацийПеремещения.Служебная Тогда
        Отказ = Истина; // Отменяем регистрацию изменений для этого документа
    КонецЕсли;
КонецЕсли;

// Аналогично можно анализировать и записи регистров, если их регистрация
// обрабатывается через общие правила регистрации объектов.
// Например, если Источник является набором записей регистра.
// Но для точечного управления записями, описанные выше программные методы предпочтительнее.

Таким образом, мы видим, что для контроля над регистрацией изменений в 1С нам доступны как программные методы, позволяющие точечно управлять этим процессом при записи или после нее, так и конфигурационные настройки для более общего контроля. Выбор метода зависит от конкретной задачи и требуемой гибкости.

Важные моменты, которые следует всегда учитывать:

Применяя эти подходы, мы сможем гибко управлять потоками данных между базами, исключая из обмена служебную или ненужную информацию, что повышает надежность и эффективность нашей информационной системы.

← На главную