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