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

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

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

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

Почему стандартными средствами КД 2.0 не получается отменить загрузку контрагента?

Разберем внутренний механизм работы обработчика «Универсальный обмен данными XML». Чтение файла обмена происходит последовательно сверху вниз. В структуре XML-файла данные о связанных объектах (справочник Контрагенты) обычно располагаются и обрабатываются парсером до того, как завершится создание самого документа-владельца. К моменту выполнения обработчика «После загрузки» для документа, объект контрагента уже успешно создан, заполнен и записан в информационную базу приемника.

Когда мы пишем в коде документа Отказ = Истина, платформа отменяет запись документа, но она не отслеживает связи и не откатывает транзакции по созданию элементов справочников, которые были записаны шагом ранее. В итоге в базе остаются «осиротевшие» новые контрагенты.

Рассмотрим рабочие варианты обхода этой проблемы.

Способ 1. Отложенное создание контрагента через параметры (наиболее надежный)

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

Выполним следующие шаги:

  1. В ПКС для реквизита Контрагент документа Заказ покупателя отключим стандартное правило конвертации (не указываем ПКО).
  2. В обработчике «Перед выгрузкой» этого ПКС передадим ключевые свойства контрагента (например, УИД, Наименование, ИНН, КПП) во временную коллекцию ПараметрыОбъекта.
  3. В базе-приемнике в обработчике «После загрузки» документа сначала выполним проверку нашего основного бизнес-условия.
  4. Если проверка провалена, устанавливаем Отказ = Истина. Документ не записывается, а контрагент даже не начинал создаваться.
  5. Если проверка пройдена, мы программно извлекаем параметры контрагента, выполняем поиск в базе (или создаем новый элемент при отсутствии) и подставляем полученную ссылку в реквизит документа.

Пример кода в обработчике «После загрузки» для ПКО документа:


Если Не ВыполнитьПроверкуУсловийЗагрузки(Объект) Тогда
    Отказ = Истина;
Иначе
    // Извлекаем параметры для поиска/создания контрагента
    ИННКонтрагента = ПараметрыОбъекта.Получить("Контрагент_ИНН");
    КППКонтрагента = ПараметрыОбъекта.Получить("Контрагент_КПП");
    Наименование   = ПараметрыОбъекта.Получить("Контрагент_Наименование");
    
    СсылкаНаКонтрагента = Справочники.Контрагенты.НайтиПоРеквизиту("ИНН", ИННКонтрагента);
    
    Если Не ЗначениеЗаполнено(СсылкаНаКонтрагента) Тогда
        НовыйКонтрагент = Справочники.Contragents.СоздатьЭлемент();
        НовыйКонтрагент.ИНН = ИННКонтрагента;
        НовыйКонтрагент.КПП = КППКонтрагента;
        НовыйКонтрагент.Наименование = Наименование;
        НовыйКонтрагент.Записать();
        СсылкаНаКонтрагента = НовыйКонтрагент.Ссылка;
    КонецЕсли;
    
    Объект.Контрагент = СсылкаНаКонтрагента;
КонецЕсли;

Способ 2. Настройка флага «Не создавать новый объект, если он НЕ найден»

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

Схема настройки выглядит так:

  1. В ПКО справочника Контрагенты устанавливаем флаг «Не создавать новый объект в приемнике, если он НЕ найден».
  2. При загрузке файла, если контрагента нет в приемнике, платформа не будет создавать новый элемент, а просто передаст в документ битую ссылку (Уникальный Идентификатор).
  3. В обработчике «После загрузки» документа мы проверяем наши условия. Если документ не проходит проверку, мы пишем Отказ = Истина. Документ не создается, а «битая» ссылка на контрагента просто исчезает из памяти вместе с объектом документа. В базе не остается никакого мусора.

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

Способ 3. Двухэтапная схема с использованием глобальной таблицы загруженных объектов

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

Для этого реализуем следующий алгоритм:

  1. В глобальном обработчике конвертации «Перед загрузкой данных» инициализируем таблицу значений в глобальной переменной Параметры:
    
    ТаблицаКонтрагентов = Новый ТаблицаЗначений;
    ТаблицаКонтрагентов.Колонки.Добавить("Контрагент", Новый ОписаниеТипов("СправочникСсылка.Контрагенты"));
    ТаблицаКонтрагентов.Колонки.Добавить("Загружен", Новый ОписаниеТипов("Бухущий"));
    Параметры.Вставить("ТаблицаКонтрагентов", ТаблицаКонтрагентов);
    
  2. В ПКО контрагента в событии «После загрузки» добавляем созданную ссылку в нашу таблицу со значением Загружен = Ложь.
  3. В ПКО документа в событии «После загрузки», если проверка документа прошла успешно и он записывается, находим строку с его контрагентом в глобальной таблице и меняем статус на Загружен = Истина.
  4. В глобальном обработчике конвертации «После загрузки данных» обходим созданную таблицу значений. Для всех строк, у которых статус остался Ложь, запускаем процедуру удаления (или пометки на удаление) элементов справочника, предварительно проверив, нет ли на них других ссылок в базе с помощью метода НайтиСсылки().

Способ 4. Использование транзакций (с ограничениями)

Мы можем попытаться изолировать процесс загрузки каждого отдельного документа и связанных с ним справочников в рамки одной транзакции СУБД.

Реализация выглядит следующим образом:

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

← На главную