При обмене данными между конфигурациями 1С с помощью «Конвертации данных 2.1» (КД) часто возникает ситуация, когда документы загружаются в произвольном порядке. Это происходит из-за особенностей механизмов поиска ссылок и структуры XML-файла. В результате документ «Перемещение товаров» может попытаться провестись раньше, чем «Поступление товаров», что приведет к ошибкам проведения из-за отсутствия остатков на складе. Разберем, как решить эту проблему программным способом, используя возможности обработчиков конвертации.
Основная идея заключается в том, чтобы во время загрузки не проводить документы сразу, а собирать ссылки на них в специальный список (таблицу значений). После того как все данные из файла будут прочитаны и записаны в базу, мы отсортируем этот список по дате и времени, а затем запустим проведение документов в правильной последовательности. Проанализируем реализацию этого алгоритма по шагам.
Первым делом нам необходимо подготовить структуру, в которой будут храниться ссылки на документы. Для этого перейдем в глобальные обработчики конвертации и выберем событие «Перед загрузкой данных». Здесь мы создадим таблицу значений и поместим её в параметры обмена, чтобы она была доступна во всех последующих обработчиках.
ТаблицаДокументов = Новый ТаблицаЗначений;
ТаблицаДокументов.Колонки.Добавить("Документ");
ТаблицаДокументов.Колонки.Добавить("ДатаВремя");
Параметры.Вставить("ТаблицаДокументов", ТаблицаДокументов);
Обратите внимание, что мы добавляем колонку ДатаВремя. Она критически важна для последующей сортировки. Хотя у документа есть свойство Дата, обращение к нему в цикле проведения потребует обращения к базе данных, что замедлит процесс. Хранение даты в таблице позволит выполнить сортировку мгновенно.
Теперь нам нужно наполнить созданную таблицу. Рассмотрим обработчик «После загрузки» в правилах конвертации объектов (ПКО) для документов. Это событие выполняется после того, как объект был прочитан из файла, но до или сразу после его записи (в зависимости от настроек). Выясним, как правильно идентифицировать документ и добавить его в очередь.
// Проверяем, является ли загруженный объект документом
Если Найти(ИмяТипаОбъекта, "ДокументСсылка") > 0 Тогда
// Нас интересуют только те документы, которые в источнике были проведены
Если Объект.Проведен Тогда
НоваяСтрока = Параметры.ТаблицаДокументов.Добавить();
// Если объект новый, его нужно записать, чтобы получить ссылку
Если Объект.ЭтоНовый() Тогда
Объект.Записать();
КонецЕсли;
НоваяСтрока.Документ = Объект.Ссылка;
НоваяСтрока.ДатаВремя = Объект.Дата;
// Отключаем проведение "в потоке", чтобы провести позже по порядку
РежимЗаписи = "Записать";
КонецЕсли;
КонецЕсли;
Важный нюанс: если документ уже существует в базе и пришел из файла в статусе «Не проведен», а в базе он «Проведен», рекомендуется добавить условие для отмены проведения, чтобы синхронизировать состояния. Для этого можно использовать параметр ОбъектНайден.
Заключительный этап выполняется в глобальном обработчике «После загрузки данных». На этот момент все документы уже находятся в информационной базе, ссылки на них собраны в нашей таблице, и мы готовы восстановить хронологию. Разберем код проведения:
Если Параметры.ТаблицаДокументов.Количество() > 0 Тогда
// Сортируем документы по возрастанию даты
Параметры.ТаблицаДокументов.Сортировать("ДатаВремя Возр");
СчетчикПроведенных = 0;
Для каждого СтрокаИзТаблицы из Параметры.ТаблицаДокументов Цикл
Попытка
ДокументОбъект = СтрокаИзТаблицы.Документ.ПолучитьОбъект();
Если ДокументОбъект = Неопределено Тогда
Продолжить;
КонецЕсли;
// Пытаемся провести документ
ДокументОбъект.Записать(РежимЗаписиДокумента.Проведение, РежимПроведенияДокумента.Неоперативный);
СчетчикПроведенных = СчетчикПроведенных + 1;
Состояние("Проведение документов: " + СтрокаИзТаблицы.Документ);
Исключение
// В случае ошибки выводим сообщение в журнал регистрации или окно сообщений
Сообщить("Не удалось провести документ: " + СтрокаИзТаблицы.Документ + " - " + ОписаниеОшибки());
КонецПопытки;
КонецЦикла;
Сообщить("Всего документов в очереди: " + Параметры.ТаблицаДокументов.Количество());
Сообщить("Успешно проведено: " + СчетчикПроведенных);
КонецЕсли;
Рассмотрим несколько продвинутых советов, которые помогут сделать обмен более надежным:
ДатаВремя может быть недостаточно. Проанализируем ситуацию: два документа имеют время 12:00:00. В этом случае 1С определяет их порядок по ссылке. Для идеального результата в таблицу значений лучше сохранять Объект.МоментВремени() и сортировать по нему.ОчередьДокументовДляПроведения. Это позволит системе провести документы в фоновом режиме, не блокируя работу пользователя.Попытка ... Исключение. Если один документ не проведется (например, из-за нехватки товара), ваш цикл не должен прерываться. Все ошибки стоит записывать в лог, чтобы после обмена администратор мог оперативно их исправить.Таким образом, разделение процесса загрузки и процесса проведения позволяет полностью контролировать последовательность действий и избежать логических ошибок, связанных с отсутствием данных в базе в момент записи объекта. Мы проанализировали самый эффективный способ реализации этого механизма через стандартные средства «Конвертации данных».