Как обеспечить автоматическое проведение и синхронизацию статусов документов при обмене данными между базами 1С

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

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

Почему документ не проводится «сам» при загрузке?

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

  1. Отключаются практически все прикладные проверки в модулях объектов и подписках на события.
  2. Блокируется автоматическое проведение. Даже если вы передадите в файле признак Проведен = Истина, платформа просто установит этот флаг в базе данных, но движения по регистрам (бухгалтерские проводки, записи в регистрах накопления) созданы не будут.
  3. Метод Объект.Записать(РежимЗаписиДокумента.Проведение) в режиме загрузки выдаст ошибку, так как эти режимы являются взаимоисключающими.

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

Метод 1: Использование отложенного проведения через параметры обмена

Наиболее элегантный способ — это сбор всех загруженных документов в специальный массив и их массовое проведение в самом конце сеанса обмена, когда основной процесс загрузки уже завершен. Выясним, как это реализовать по шагам в «Конвертации данных». Для тестирования написанного в правилах кода можно использовать инструмент для отладки обработчиков «Конвертации данных».

Шаг 1. Инициализация контейнера в обработчике «Перед загрузкой данных» (глобальный обработчик правил)

Нам нужно подготовить массив, в который мы будем складывать ссылки на документы. Используем для этого структуру Параметры, которая доступна на протяжении всего процесса обмена.


// Инициализируем массив для хранения ссылок на документы, требующие проведения
Если Параметры.Свойство("СписокДокументовДляПроведения") = Ложь Тогда
    Параметры.Вставить("СписокДокументовДляПроведения", Новый Массив);
КонецЕсли;

Шаг 2. Наполнение массива в обработчике «После загрузки» (ПКО конкретного документа)

В правилах конвертации объектов (ПКО) для нужного нам типа документа пропишем логику добавления ссылки в наш список. Нам важно проводить только те документы, которые в источнике были проведены. Для более удобного написания кода в правилах обмена пригодится доработанная конфигурация «Конвертация данных» с подсказками.


// Проверяем, что объект — это документ и в источнике он был проведен
// При этом проверяем, что документ не помечен на удаление
Если Объект.Проведен И НЕ Объект.ПометкаУдаления Тогда
    Параметры.СписокДокументовДляПроведения.Добавить(Объект.Ссылка);
КонецЕсли;

Шаг 3. Обработка массива в обработчике «После загрузки данных» (глобальный обработчик)

Когда все объекты из файла загружены в базу, наступает время «магии». Мы перебираем наш массив и проводим документы уже в обычном режиме (без флага Загрузка = Истина).


Для Каждого СсылкаНаДокумент Из Параметры.СписокДокументовДляПроведения Цикл
    ДокументОбъект = СсылкаНаДокумент.ПолучитьОбъект();
    
    Если ДокументОбъект <> Неопределено Тогда
        // Отключаем режим загрузки, чтобы отработали механизмы проведения
        ДокументОбъект.ОбменДанными.Загрузка = Ложь;
        
        Попытка
            // Пытаемся провести документ
            ДокументОбъект.Записать(РежимЗаписиДокумента.Проведение, РежимСообщенийОбъекта.Нет);
        Исключение
            // Если проведение не удалось (например, не хватает остатков), 
            // записываем ошибку в журнал регистрации или выводим сообщение
            ЗаписьЖурналаРегистрации("ОбменДанными.Проведение", УровеньЖурналаРегистрации.Ошибка, , , 
                "Не удалось провести документ: " + Строка(СсылкаНаДокумент) + ". Ошибка: " + ОписаниеОшибки());
        КонецПопытки;
    КонецЕсли;
КонецЦикла;

Проблема зацикливания: Как избежать рекурсии?

Рассмотрим типичную ловушку. Если в обеих базах настроены подписки на событие ПриЗаписи, которые инициируют выгрузку документа обратно, возникнет бесконечный цикл: База А отправляет в Базу Б -> База Б записывает и отправляет в Базу А -> База А записывает и так далее.

Проанализируем способы защиты:

  1. Проверка пользователя. Если обмен идет через специального пользователя (например, «WebBot» или «ExchangeUser»), в коде подписки на выгрузку можно поставить условие: Если ИмяПользователя() = "ExchangeUser" Тогда Возврат; КонецЕсли;.
  2. Использование дополнительных свойств. Это более профессиональный метод. При программной записи документа перед вызовом Записать() можно добавить флаг: Объект.ДополнительныеСвойства.Вставить("ЗагрузкаИзОбмена", Истина);. В подписке на событие, которая отвечает за выгрузку, проверяйте наличие этого свойства.
  3. РежимОбменаДанными. Самый надежный способ — это стандартная проверка флага ОбменДанными.Загрузка в коде выгрузки. Если объект записывается из обмена, его не нужно регистрировать к повторной отправке.

Особенности синхронизации между разными конфигурациями (БП и ЗУП)

Когда мы переносим документы между разными конфигурациями, например, из Зарплаты и управления персоналом (ЗУП) в Бухгалтерию предприятия (БП), возникает проблема «недостающих данных». Документ в БП может требовать заполнения счетов учета, аналитики номенклатуры или статей затрат, которых просто нет в ЗУП.

В этом случае в обработчике ПослеЗагрузки (ПКО) нам необходимо программно дозаполнить объект значениями по умолчанию:


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

Без такого дозаполнения метод Записать(РежимЗаписиДокумента.Проведение) вернет ошибку, и документ останется непроведенным, что приведет к расхождению данных между базами.

Синхронизация отмены проведения и удаления

Не забудем про сценарий, когда в источнике документ был отменен с проведения или помечен на удаление. Если вы просто переносите реквизит ПометкаУдаления, платформа установит его в приемнике, но если документ был ранее проведен, он так и останется в состоянии «Проведен + Пометка на удаление» (в некоторых случаях), либо просто не сбросит свои движения.

Разберем, как это обработать. В том же цикле проведения в конце загрузки добавьте проверку:


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

Используя предложенные методы, мы обеспечиваем целостность данных в обеих информационных системах, гарантируем актуальность бухгалтерских и управленческих итогов и исключаем риск возникновения бесконечных циклов обмена.

← На главную