При обмене данными между различными конфигурациями 1С, особенно в связке 1С:Комплексная автоматизация (КА) и 1С:Розница (РТ), часто возникает задача, когда мы хотим, чтобы определенные объекты (например, номенклатура или физические лица), измененные в одной из баз, не перезаписывали аналогичные объекты в другой базе, а использовались уже существующие, либо новые объекты создавались, а существующие оставались без изменений. Мы рассмотрим, как добиться этого с помощью Конвертации Данных 3.0 (КД3) и расширений.
Прежде чем погрузиться в решения, давайте проанализируем, как работает обмен данными в 1С, особенно когда в дело вступают Конвертация Данных 3.0 и Библиотека Стандартных Подсистем (БСП). Основная идея обмена — это регистрация изменений объектов. Когда объект в базе-источнике изменяется, система регистрирует это изменение для каждого узла обмена, для которого этот объект разрешен к выгрузке. Затем при очередном сеансе обмена эти зарегистрированные изменения выгружаются в файл обмена и отправляются в базу-приемник.
В типовых конфигурациях, использующих БСП, логика регистрации изменений объектов очень развита и нередко довольно сложна. Изменения регистрируются с помощью подписок на события (например, ПриЗаписи, ПриУдалении), которые вызывают общие процедуры по регистрации изменений в планах обмена. Это может быть проблемой, если мы хотим изменить это поведение, не затрагивая типовую конфигурацию, чтобы избежать сложностей при обновлении.
Наиболее "правильный" и системный способ контроля выгрузки данных в КД3 — это настройка правил регистрации изменений для каждого типа объекта. Мы можем указать, какие объекты и при каких условиях будут регистрироваться для выгрузки в конкретный узел обмена. Если объект не должен выгружаться из базы-источника, мы можем настроить правила таким образом, чтобы его изменения не регистрировались.
Шаги по настройке правил регистрации:
КД3, через которую настраивается обмен.Номенклатура или ФизическиеЛица).Номенклатуры, созданной в РТ, не должны регистрироваться для обмена с КА.Этот метод позволяет гибко управлять тем, что попадает в выгрузку, но требует прямого изменения правил, что не всегда удобно при обновлениях, если эти правила не являются частью типового обмена.
Когда мы работаем с типовыми конфигурациями и хотим избежать их изменения напрямую, чтобы упростить процесс обновления, нам на помощь приходят расширения конфигурации. Расширения позволяют добавлять новые объекты, изменять существующие формы и модули, а также перехватывать вызовы процедур без снятия конфигурации с поддержки.
Почему используем расширения:
1С (начиная с 8.3.16) возможности расширений значительно расширены, позволяя создавать новые подписки на события и перехватывать процедуры типовых конфигураций.Как найти и перехватить процедуру регистрации изменений:
Для того чтобы предотвратить регистрацию изменений объекта для определенного узла обмена, нам нужно найти место в коде типовой конфигурации, где происходит эта регистрация. Чаще всего это подписки на события ПриЗаписи или ПриУдалении объектов, которые вызывают процедуры из общих модулей, отвечающие за регистрацию изменений в планах обмена.
Номенклатуры в РТ, мы можем установить точку останова на событии ПриЗаписи модуля объекта Номенклатура и проследить, какие процедуры вызываются далее, до момента фактической регистрации в плане обмена.БСП часто используются подписки на событие, например, ЗарегистрироватьИзмененияДляОбмена или аналогичные. Мы можем найти эти подписки в конфигураторе.Заимствовать с замещением) нужную процедуру в расширении.Пример перехвата процедуры регистрации (концептуально):
Предположим, мы выяснили, что процедура ОбменДаннымиСобытия.ЗарегистрироватьИзмененияОбъекта(Объект, Отказ, ЗаписываемыеСвойства) отвечает за регистрацию. Мы можем заместить ее в расширении и добавить нашу логику:
// В расширении, в общем модуле, замещающем типовой (или созданном для новой подписки)
Процедура ЗарегистрироватьИзмененияОбъекта(Объект, Отказ, ЗаписываемыеСвойства) Экспорт
Если ТипЗнч(Объект) = Тип("СправочникСсылка.Номенклатура") Или ТипЗнч(Объект) = Тип("СправочникСсылка.ФизическиеЛица") Тогда
// Проверяем, для какого узла обмена идет регистрация, если нужно
// Например, если текущий узел обмена является узлом для КА, и мы не хотим выгружать
// изменения Номенклатуры из РТ в КА
//
// Для демонстрации мы просто отказываем в регистрации для этих типов объектов
// без дополнительных условий для узла, но в реальной задаче проверка узла ОБЯЗАТЕЛЬНА!
Отказ = Истина;
Возврат;
КонецЕсли;
// Если это не те объекты, которые мы хотим исключить, вызываем типовую логику.
// Если это замещенная процедура, то обычно здесь будет вызов оригинальной процедуры
// с помощью специального синтаксиса, который зависит от версии платформы
// и способа замещения (например, вызов 'ПродолжитьВыполнение' или оригинальной процедуры с 'БезРасширения').
//
// В случае с новой подпиской, просто не делаем ничего и позволяем типовой подписке отработать,
// если Отказ не установлен.
//
// Для версии 8.3.16+ и замещения, это может выглядеть так:
#Если НЕ МодульСуществует("ОбменДаннымиСобытия", "БезРасширения") Тогда
// Этот код выполняется, если процедура 'ЗарегистрироватьИзмененияОбъекта'
// не замещена в расширении, и это, по сути, исходный код типовой процедуры
// или если мы хотим, чтобы после нашей логики отработала оригинальная процедура
ОбменДаннымиСобытияБезРасширения.ЗарегистрироватьИзмененияОбъекта(Объект, Отказ, ЗаписываемыеСвойства);
#Иначе
// Если процедура 'ЗарегистрироватьИзмененияОбъекта' замещена в расширении,
// этот блок не будет выполнен, так как мы сами управляем вызовом оригинальной логики.
// Если мы хотим вызвать оригинальную логику после наших проверок,
// нам нужно явно указать это, например, с помощью:
// ПродолжитьВыполнение(Объект, Отказ, ЗаписываемыеСвойства);
// Или если процедура замещена с "Вызывать вместо", то оригинальная не будет вызвана без явного указания.
// В данном примере, если Отказ установлен, то вызова типовой логики не будет.
// Если Отказ не установлен, значит, объект должен регистрироваться по типовым правилам.
// Для простоты примера, если Отказ не установлен, просто выходим, полагая, что оригинальная
// процедура отработает самостоятельно, или она будет вызвана после нашей логики.
#КонецЕсли
КонецПроцедуры
Важно: При таком подходе мы должны тщательно проверять тип объекта и узел обмена, чтобы не нарушить обмен для других объектов или других узлов (например, для РИБ, если он также используется). Отладка здесь является нашим лучшим другом.
Когда данные выгружаются из одной базы и загружаются в другую, КД3 использует механизм сопоставления объектов. Этот механизм основан на "ключевых полях". Мы должны понять, как это работает, чтобы правильно управлять тем, что "берется существующее".
КД3 при обмене, если объекты уже синхронизированы (например, после первоначальной выгрузки и загрузки), они получают внутренние GUID (уникальные идентификаторы), которые становятся "ссылками" между базами. Если объект в базе-источнике имеет GUID, который соответствует GUID существующего объекта в базе-приемнике, то система будет сопоставлять их именно по этой ссылке.GUID не совпадает (например, это совершенно новый объект, или объект был создан независимо в обеих базах), КД3 начинает искать соответствие по другим "ключевым полям", которые определены в правилах обмена. Это могут быть Код, Наименование, ИНН, КПП и т.д. Если по этим полям находится единственный совпадающий объект, то система сопоставит их.GUID в обеих базах), то при изменении, например, наименования объекта в базе-источнике, система все равно найдет соответствующий объект по GUID в базе-приемнике. Далее, если не настроены правила, запрещающие обновление этого поля, наименование в базе-приемнике будет обновлено. Для предотвращения этого нам и требуется управлять выгрузкой изменений (как в Методах 1 и 2).КА и РТ были правильно сопоставлены и получили единые GUID в рамках обмена. Это можно сделать через стандартные механизмы синхронизации или с помощью специальных обработок сопоставления.Понимание этого принципа позволяет нам осознанно подходить к вопросу: если объекты *уже* сопоставлены, то наша задача — *не допустить выгрузки* изменений из базы-источника, а не пытаться сопоставить их заново в базе-приемнике.
Даже если объект был выгружен из базы-источника, мы можем контролировать его загрузку в базе-приемнике. Этот метод особенно полезен, когда мы хотим создавать только новые объекты, а существующие оставлять без изменений, даже если в файле обмена есть данные для их обновления.
В КД3 и в типовых обменах есть возможность использовать обработчики событий при загрузке данных. Одним из таких событий может быть ПриЗагрузкеДанных или ПриЗагрузкеОбъекта в модуле объекта обмена (или в правилах обмена).
Пример кода из сообщения 26 для управления загрузкой:
Если НЕ ДанныеИБ = Неопределено Тогда // Не замещать существующие объекты в приемнике при загрузке, а только создавать новые и заполнять их
ПолученныеДанные = Неопределено;
КонецЕсли;
Разберем этот фрагмент подробнее:
ДанныеИБ: Эта переменная обычно содержит ссылку на объект в информационной базе-приемнике, если он уже существует (т.е., если КД3 смогла найти соответствующий объект по своим правилам сопоставления). Если объект не найден, ДанныеИБ будет Неопределено.Если НЕ ДанныеИБ = Неопределено Тогда: Это условие проверяет, существует ли уже объект в базе-приемнике, который соответствует выгруженному объекту из файла обмена.ПолученныеДанные = Неопределено;: Если объект уже существует в базе-приемнике (т.е. ДанныеИБ не Неопределено), мы устанавливаем переменную ПолученныеДанные в Неопределено. Это сигнализирует системе обмена, что для данного объекта нет необходимости обновлять его на основании данных из файла обмена. По сути, мы говорим: "Этот объект уже есть, и мы не хотим, чтобы он изменялся данными из выгрузки".Где использовать:
Этот код может быть вставлен в событие ПриЗагрузкеДанных в модуле правил конвертации, или в специальном обработчике события, который вызывается при загрузке объекта определенного типа. В зависимости от версии КД3 и используемых настроек, мы можем иметь доступ к этим обработчикам либо через визуальный редактор правил, либо через код модуля обмена.
Преимущества этого подхода:
Мы гарантируем, что если объект уже есть в базе-приемнике, он не будет изменен данными из источника. Это идеально подходит для сценариев, где мы хотим переносить только новые объекты, а изменения в существующих должны происходить только в самой базе-приемнике или через другой механизм.
Помимо перечисленных методов, существует еще один способ тонкой настройки процесса выгрузки: использование обработчика ПриОбработкеВыгрузкиДанных. Этот обработчик доступен в правилах обмена и позволяет нам вмешиваться в процесс выгрузки каждого объекта.
ПриОбработкеВыгрузкиДанных мы получаем доступ к выгружаемому объекту и его данным. Мы можем проанализировать его текущее состояние, историю изменений или любые другие параметры.Отказ = Истина. В этом случае объект не попадет в файл обмена.Этот метод предоставляет максимальную гибкость для управления выгрузкой на уровне конкретного объекта или его реквизитов, действуя как последний фильтр перед тем, как данные попадут в файл обмена. Однако он требует тщательного кодирования и тестирования, чтобы избежать нежелательных побочных эффектов.
Мы рассмотрели несколько подходов к решению задачи предотвращения выгрузки изменений из базы-источника и обеспечения использования существующих объектов в базе-приемнике. Оптимальный выбор метода или их комбинации будет зависеть от специфики нашей задачи, архитектуры обмена и требований к поддержке конфигурации. Всегда предпочтительно начинать с настройки правил регистрации и использования расширений, чтобы сохранить типовую конфигурацию. А методы контроля загрузки данных в приемнике являются отличным дополнением для гарантии целостности данных.