При настройке обмена данными между конфигурациями (например, Управление торговлей и Бухгалтерия предприятия) с помощью «1С:Конвертация данных 2.0», часто возникает задача: запретить изменение объекта в базе-приемнике, если он соответствует определенным критериям. Например, если бухгалтер уже проверил документ в приемнике и установил в нем какой-то флаг или изменил статус, мы не хотим, чтобы повторная выгрузка из источника затерла эти изменения.
В этой статье мы подробно разберем, как реализовать такую логику правильно, используя стандартные механизмы обработчиков событий, и почему стоит избегать сложных «велосипедов» с использованием COM-соединений.
Для начала проанализируем, как работает загрузка данных в системе 1С:Предприятие. Когда файл обмена XML попадает в базу-приемник, обработка УниверсальныйОбменДаннымиXML начинает чтение объектов. Для каждого объекта в Правилах Конвертации Объектов (ПКО) последовательно срабатывают несколько обработчиков событий. Для решения нашей задачи наиболее критичны два из них: При загрузке и После загрузки.
Многие начинающие разработчики совершают ошибку, пытаясь проверить значения реквизитов через параметр Объект. Рассмотрим, почему это не всегда эффективно и как получить доступ к «старым» данным, которые уже хранятся в базе приемника до момента записи.
Это самый гибкий и мощный способ. Рассмотрим ситуацию: данные уже прочитаны из файла и помещены в переменную Объект, но они еще не записаны в информационную базу. В этом обработчике нам доступны два ключевых параметра:
Важный нюанс: при обращении к реквизитам через Ссылка.ИмяРеквизита, 1С обращается напрямую к данным в таблицах БД, а не к переменной в памяти. Это позволяет нам сравнить то, что «было», с тем, что «пришло».
Разберем пример кода для обработчика После загрузки. Допустим, мы не хотим обновлять документ, если в базе-приемнике он уже проведен:
Если ОбъектНайден Тогда
// Обращаемся к данным в базе по ссылке
Если Ссылка.Проведен Тогда
// Устанавливаем флаг отказа от загрузки объекта
Отказ = Истина;
Сообщить("Документ " + Ссылка + " проведен в приемнике. Загрузка отменена.");
КонецЕсли;
КонецЕсли;
Если мы установим Отказ = Истина, объект не будет записан, и данные в базе-приемнике останутся нетронутыми. Мы можем использовать более сложные условия, например, проверку табличных частей, как в примере автора темы. Проанализируем ситуацию, когда нужно проверить наличие записей в табличной части ВыплатаЗаработнойПлаты:
Если ОбъектНайден Тогда
// Проверяем, заполнена ли табличная часть в существующем документе
Если Ссылка.ВыплатаЗаработнойПлаты.Количество() > 0 Тогда
Отказ = Истина;
КонецЕсли;
КонецЕсли;
Рассмотрим другой вариант. Если нам нужно запретить перезапись объекта целиком, независимо от значений конкретных полей (просто по факту того, что объект уже существует), мы можем использовать обработчик При загрузке.
В ПКО существует специальный параметр НеЗамещатьОбъект. Если установить его в значение Истина, система найдет объект, но не будет обновлять его реквизиты данными из XML. Это работает быстрее, так как не происходит даже заполнения объекта в памяти.
// В обработчике "При загрузке"
Если ОбъектНайден Тогда
// Если объект уже есть, просто не будем его трогать
НеЗамещатьОбъект = Истина;
КонецЕсли;
Этот метод хорош для нормативно-справочной информации (НСИ), где база-приемник является эталонной по наполнению реквизитов.
Проанализируем решение, предложенное в сообщении №6. Автор пытался создать COMConnector внутри обработчика Перед выгрузкой, чтобы подключиться к приемнику и проверить наличие документа там. Выясним, почему это «костыль»:
Вывод: всегда старайтесь переносить логику проверки на сторону того узла, который владеет информацией. Если нужно проверить состояние приемника — делайте это в обработчиках загрузки в самом приемнике.
Иногда решение о записи в приемнике должно приниматься на основе данных, которых в самом объекте приемника нет. В этом случае мы можем использовать коллекцию ПараметрыОбъекта.
Разберем по шагам:
Перед выгрузкой) добавляем данные:
// Передаем произвольный параметр
ПередатьОбъект.Вставить("ЗапретитьПерезапись", Истина);
После загрузки) считываем их:
ЗначениеПараметра = Неопределено;
Если ПараметрыОбъекта <> Неопределено Тогда
ЗначениеПараметра = ПараметрыОбъекта.Получить("ЗапретитьПерезапись");
КонецЕсли;
Если ЗначениеПараметра = Истина И ОбъектНайден Тогда
Отказ = Истина;
КонецЕсли;
Мы выяснили, что наиболее эффективным и правильным способом отказа от передачи изменений является использование обработчика После загрузки в сочетании с параметром Ссылка. Это позволяет сравнивать текущее состояние базы данных с входящими данными из файла обмена без лишних затрат ресурсов. Помните, что использование Отказ = Истина в загрузке — это штатный механизм, который предотвращает только запись объекта, не нарушая целостность всего процесса обмена.
Совет: если вы работаете с большими объемами данных, всегда проверяйте флаг ОбъектНайден прежде чем обращаться к Ссылка, чтобы избежать лишних запросов к базе данных для новых объектов.