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