При настройке обменов данными между базами 1С часто возникает ситуация, которая кажется парадоксальной: мы загружаем документы, явно отключаем для них авторегистрацию в плане обмена, проверяем, что загрузка идет в режиме ОбменДанными.Загрузка = Истина, но система все равно регистрирует эти документы как измененные для последующей выгрузки. Давайте разберем эту проблему подробно, проанализируем причины такого поведения и рассмотрим методы отладки, которые помогут найти "виновника".
Рассмотрим типичный сценарий. Вы используете обработку "Универсальный обмен данными в формате XML" (или стандартные механизмы обмена БСП) для загрузки пакета документов. В метаданных Плана обмена для этого вида документа свойство Авторегистрация установлено в значение Запретить.
Логика подсказывает, что при записи документа в базу он не должен попадать в таблицу регистрации изменений. Более того, при загрузке данных свойство ОбменДанными.Загрузка устанавливается в значение Истина. Это платформенный флаг, который говорит системе: "Это не создание нового документа пользователем, это перенос данных, не нужно запускать лишние проверки и регистрации".
Однако на практике мы видим, что после загрузки таблица изменений плана обмена (ПланыОбмена.ВыбратьИзменения) содержит записи по этим документам. Почему так происходит?
Если авторегистрация отключена на уровне платформы (в свойствах объекта метаданных), значит, регистрация происходит программно. Есть несколько мест, где может скрываться этот код:
ПланыОбмена.ЗарегистрироватьИзменения в процедурах ПередЗаписью или ПриЗаписи.Как выяснилось в ходе разбора ситуации, наиболее коварным является третий пункт — подписки на события.
Когда вы не знаете, где именно происходит вызов кода регистрации, обычная расстановка точек останова (breakpoints) может быть неэффективной. Вы можете ставить точки в модуле плана обмена или в модуле документа, но если регистрация происходит в общем модуле через подписку, вы просто не попадете туда отладчиком, если не знаете точного места.
В таких случаях самым действенным инструментом является Замер производительности. Давайте рассмотрим алгоритм действий:
Система выдаст таблицу всех выполненных строк кода. В строке поиска (Ctrl+F) наберите ключевое слово ЗарегистрироватьИзменения. Это позволит вам мгновенно найти тот участок кода, который фактически выполнил запись в таблицу регистрации, даже если он находится в неочевидном месте.
В анализируемой нами ситуации причиной оказалась неочевидная подписка на события. В конфигурациях часто создают подписки, где в качестве источника (Тип источника) выбирают не конкретный документ (например, ДокументОбъект.РеализацияТоваровУслуг), а общий тип — ДокументОбъект.
Это означает, что обработчик этой подписки будет вызываться при записи абсолютно любого документа в системе. Часто разработчики забывают добавить в такие обработчики проверку на режим загрузки. Рассмотрим пример ошибочного кода:
// ОШИБОЧНЫЙ КОД в подписке на событие
Процедура ПриЗаписиВсехДокументов(Источник, Отказ) Экспорт
// Здесь разработчик хочет зарегистрировать документ для выгрузки в какую-то внешнюю систему
ПланыОбмена.ЗарегистрироватьИзменения(ПланыОбмена.МойОбмен.НайтиПоКоду("001"), Источник);
КонецПроцедуры
В этом коде отсутствует критически важная проверка. Когда работает "Универсальный обмен", он записывает документ, срабатывает эта подписка, и документ принудительно регистрируется в плане обмена, игнорируя настройки авторегистрации.
Чтобы избежать подобных проблем, в любом обработчике событий (будь то подписка или модуль объекта), который выполняет действия, не связанные с целостностью данных самого объекта, необходимо проверять свойство ОбменДанными.Загрузка.
Правильный код должен выглядеть так:
Процедура ПриЗаписиВсехДокументов(Источник, Отказ) Экспорт
// Если документ загружается из другой базы, прерываем выполнение
Если Источник.ОбменДанными.Загрузка Тогда
Возврат;
КонецЕсли;
// Далее следует логика регистрации
Попытка
ПланыОбмена.ЗарегистрироватьИзменения(ПланыОбмена.МойОбмен.НайтиПоКоду("001"), Источник);
Исключение
// Обработка ошибок
КонецПопытки;
КонецПроцедуры
Помимо описанной выше причины с подписками, давайте рассмотрим еще несколько нюансов, которые могут приводить к неожиданной регистрации изменений при использовании универсального обмена.
Обработка "Универсальный обмен данными" выполняет правила конвертации, написанные в конфигурации "Конвертация данных 2.0". Внутри xml-файла правил могут содержаться обработчики событий на языке 1С, например ПослеЗагрузки (AfterLoad). Разработчик правил мог явно прописать там регистрацию:
// Пример кода внутри правил обмена (обработчик "ПослеЗагрузки")
ПланыОбмена.ЗарегистрироватьИзменения(УзелОбмена, Объект);
Такой код сложно отловить, так как он выполняется динамически через метод Выполнить(), и обычный отладчик может его пропустить, если не включена отладка внешних обработок. Замер производительности, однако, покажет этот вызов.
Важно помнить, что план обмена может регистрировать не только сам документ, но и его движения (записи регистров). Если в правилах обмена стоит флаг "Проводить документ при загрузке", то система запишет наборы записей регистров.
Если для регистров включена авторегистрация, то изменение набора записей вызовет регистрацию этого изменения. А в некоторых конфигурациях (особенно на базе БСП) существует логика: "Если изменился регистр, зарегистрируй к обмену и документ-регистратор". Это делается для того, чтобы поддержать целостность данных в базе-приемнике.
Если вы столкнулись с "мистической" регистрацией объектов при загрузке:
ЗарегистрироватьИзменения.ДокументОбъект без уточнения вида документа.Если ОбменДанными.Загрузка Тогда Возврат; КонецЕсли; в свои подписки, чтобы не ломать механизмы обмена.