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

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

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

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

Выясним причину проблемы с дублированием документов

В исходной ситуации автора темы бухгалтеры обнаружили две расходные накладные по одному заказу в базе «1С:Бухгалтерия предприятия» (БП), хотя в «1С:Управление нашей фирмой» (УНФ) все выглядело корректно. Проанализируем ситуацию: почему при снятии флага выгрузки и повторных действиях пользователя в БП создается копия, а не обновляется существующий документ?

Такое поведение связано с архитектурными особенностями правил конвертации данных (ПКО) и правил регистрации объектов (ПРО):

  1. Отсутствие сопоставления по Уникальному Идентификатору (GUID): Если в правилах обмена отключен поиск по GUID, а сопоставление настроено по ключевым полям поиска (например, «Номер + Дата + Организация»), то при изменении номера или даты в источнике система создаст в БП новый документ вместо обновления существующего.
  2. Динамическая генерация GUID при разделении документов: Если по логике обмена один документ источника должен превращаться в два документа в приемнике (например, одна накладная разделяется на документ для клиента и документ для производства), разработчики могли генерировать новые GUID программно «на лету» (например, через вызов Новый УникальныйИдентификатор()). При каждой повторной выгрузке генерируются новые идентификаторы, что и приводит к лавинообразному созданию дублей в базе БП.

Для предотвращения дублирования идентификаторы документов-приемников всегда должны формироваться детерминировано (например, на основании GUID исходного документа с добавлением фиксированного префикса или суффикса).

Способ 1. Программная регистрация удаления через событие ПередЗаписью

Рассмотрим подробнее самый гибкий и контролируемый вариант решения проблемы — отслеживание изменения флага выгрузки в коде базы-источника с последующей принудительной регистрацией специального виртуального объекта платформы — УдалениеОбъекта.

Наша задача — поймать момент, когда транзакция записи еще не завершена, сравнить старое значение флага (из базы данных) с новым значением (которое записывает пользователь) и принять решение о регистрации.

Для этого мы можем использовать подписку на событие ПередЗаписью для нужного типа документа. Посмотрим на пример кода:


Процедура ПередЗаписьюДокументаДляРегистрацииУдаления(Источник, Отказ, РежимЗаписи, РежимПроведения) Экспорт

    // Проверяем, что это не новый документ, так как для нового документа предыдущего состояния в БД нет
    Если Источник.ОбменДанными.Загрузка Или Источник.ЭтоНовый() Тогда
        Возврат;
    КонецЕсли;

    // Получаем текущее состояние флага из базы данных до записи объекта
    СтароеЗначениеБУ = ОбщегоНазначения.ЗначениеРеквизитаОбъекта(Источник.Ссылка, "БУ");
    НовоеЗначениеБУ  = Источник.БУ;

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

КонецПроцедуры

Важный нюанс: Создание конструкции Новый УдалениеОбъекта(Источник.Ссылка) никак не влияет на состояние самого документа в базе-источнике. Документ в УНФ остается проведенным и доступным для пользователей. Однако платформа регистрирует на узле обмена команду удаления. При следующей сессии выгрузки в XML-файл обмена запишется только этот GUID с тегом удаления, и база БП корректно пометит на удаление связанный документ.

Способ 2. Использование стандартных Правил регистрации объектов (ПРО) в БСП

Если обмен построен на современных стандартах Библиотеки стандартных подсистем (БСП) и технологии EnterpriseData, разберем, как решить задачу без изменения программного кода конфигурации.

В составе БСП есть мощный инструмент — Правила регистрации объектов (ПРО), которые настраиваются в специализированной конфигурации «Конвертация данных 3» (или «Конвертация данных 2.1»). Настроим автоматическую регистрацию удаления при изменении реквизитов.

Проанализируем шаги настройки ПРО для нашего документа:

  1. Откроем правила регистрации для конкретного документа в Конвертации данных.
  2. В настройках фильтрации объектов добавим отбор: БУ Равно Истина.
  3. В свойствах правила регистрации установим флаг «Регистрировать удаление при невыполнении свойств» (в некоторых версиях БСП эта опция называется «Выгружать удаление при изменении соответствия отбору»).

При включении этой настройки БСП автоматически берет на себя всю рутину: во время записи любого документа система сама проверяет, изменилось ли выполнение условий отбора. Если документ перестал соответствовать правилу (флаг сняли), система автоматически сформирует запись УдалениеОбъекта в таблице изменений плана обмена.

Способ 3. Перехват выгрузки в модуле плана обмена (Событие ПриОтправкеДанных)

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

Для этого используется обработчик ПриОтправкеДанныхПодчиненному (или ПриОтправкеДанныхАдресату в зависимости от типа обмена) в модуле менеджера плана обмена. Проанализируем код этого обработчика:


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

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

Что произойдет в базе-приемнике БП 3.0 при получении удаления?

Безопасно ли отправлять команду удаления для проведенных документов? Нам не нужно переживать, что база-приемник безвозвратно удалит важную информацию. Стандартные механизмы БСП в БП 3.0 обрабатывают входящую команду УдалениеОбъекта по строгому и безопасному алгоритму:

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

← На главную