При разработке внешних отчетов и обработок на платформе 1С:Предприятие 8.3 начинающие разработчики часто сталкиваются с загадочным поведением системы: значение, только что записанное в реквизит объекта в коде формы, внезапно исчезает (становится Неопределено или пустым) при переходе в модуль объекта, например, в процедуру ПриКомпоновкеРезультата. Рассмотрим подробнее, почему это происходит, и разберем правильные способы передачи данных.
Основная причина проблемы заключается в специфике работы с внешними файлами (.erf для отчетов и .epf для обработок). Когда мы вызываем команду открытия внешнего отчета, система выполняет следующие действия:
ОткрытьФорму или программном обращении к внешней форме через МенеджерВнешнихОтчетов, система может создать новый экземпляр объекта.Проанализируем ситуацию: в процедуре ВыполнитьКоманду разработчик записывает ссылку в Отчет.СсылкаНаДок. Однако, если после этого происходит открытие формы без явной передачи этого значения, создается новый контекст. Внешний отчет «забывает» то, что было записано в переменные другого экземпляра. Кроме того, существует разрыв между клиентом и сервером: данные формы (реквизит Отчет) синхронизируются с сервером только в рамках вызовов текущей формы. Если вызывается новый процесс формирования, не связанный с текущим сеансом данных формы, мы получим пустой реквизит.
Это наиболее корректный путь, если мы хотим передать данные (например, ссылку на документ-основание) в открываемый отчет. Рассмотрим по шагам, как это реализовать в коде команды.
Вместо того чтобы просто присваивать значение реквизиту Отчет.Документ на клиенте, мы упаковываем все необходимые данные в структуру параметров и передаем их при открытии. Посмотрим на пример правильной реализации:
&НаКлиенте
Процедура ВыполнитьКоманду(ИдентификаторКоманды, ОбъектыНазначенияМассив) Экспорт
// Подготавливаем параметры для открытия формы
ПараметрыОткрытия = Новый Структура;
// Передаем ссылку на выбранный документ (например, первый из массива)
ПараметрыОткрытия.Вставить("ДокументСсылка", ОбъектыНазначенияМассив[0]);
// Можно сразу дать команду на формирование отчета
ПараметрыОткрытия.Вставить("СформироватьПриОткрытии", Истина);
// Указываем путь к форме внешнего отчета
// Используем ЭтаФорма.ИмяФормы или явный путь
ОткрытьФорму("ВнешнийОтчет.ИмяВашегоОтчета.Форма.ФормаОтчета", ПараметрыОткрытия);
КонецПроцедуры
После этого в модуле формы отчета в процедуре ПриСозданииНаСервере нам необходимо принять этот параметр и записать его в реквизит отчета, чтобы он стал доступен серверному контексту модуля объекта:
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
Если Параметры.Свойство("ДокументСсылка") Тогда
Отчет.СсылкаНаДок = Параметры.ДокументСсылка;
КонецЕсли;
КонецПроцедуры
Если ваша задача — получить данные из табличной части документа (как в примере с СсылкаНаДок.Товары), то ручной перебор строк в коде ПриКомпоновкеРезультата — не самый эффективный метод. Система компоновки данных (СКД) создана именно для того, чтобы автоматизировать такие выборки.
Выясним, как сделать это профессионально:
П_ДокументСсылка с типом нужного документа.ГДЕ Ссылка = &П_ДокументСсылка.Пример программной установки параметра в компоновщике настроек:
&НаСервере
Процедура УстановитьПараметрСКД(ЗначениеСсылки)
ПараметрСКД = Отчет.КомпоновщикНастроек.Настройки.ПараметрыДанных.Элементы.Найти("П_ДокументСсылка");
Если ПараметрСКД <> Неопределено Тогда
ПараметрСКД.Значение = ЗначениеСсылки;
ПараметрСКД.Использование = Истина;
КонецЕсли;
КонецПроцедуры
Преимущество этого метода: вам не нужно вручную создавать ТаблицуЗначений и заполнять ее колонки. СКД сама обратится к базе данных, выберет товары и выведет их в результат. Это значительно повышает производительность и упрощает поддержку кода.
Иногда требуется передать не одну ссылку, а сложный объект или целую таблицу, сформированную «на лету», которой еще нет в базе данных. В этом случае мы используем ВременноеХранилище. Проанализируем алгоритм:
Адрес = ПоместитьВоВременноеХранилище(МояТаблица, ЭтаФорма.УникальныйИдентификатор);Адрес как параметр при открытии формы отчета.ПриКомпоновкеРезультата) извлекаем данные: Данные = ПолучитьИзВременногоХранилища(АдресПараметра);Разберем еще несколько моментов, которые часто путают разработчиков:
Ошибка синхронизации: Помните, что Отчет в модуле формы — это ДанныеФормыСтруктура. А ЭтотОбъект в модуле объекта — это сам программный объект. В типовых конфигурациях при нажатии кнопки «Сформировать» на форме, платформа автоматически сериализует данные формы в объект. Но если вы программно создаете объект в коде (например, через ВнешниеОтчеты.Создать(...)), это будет совершенно другой экземпляр с пустыми реквизитами.
СтандартнаяОбработка = Ложь: Если вы устанавливаете этот флаг в ПриКомпоновкеРезультата, вы полностью отключаете автоматический механизм формирования отчета. Убедитесь, что вы действительно хотите формировать результат вручную через ПроцессорКомпоновкиДанных. Если вам нужно просто добавить фильтр, лучше использовать КомпоновщикНастроек без отключения стандартной обработки.
Подведем итог: для того чтобы реквизиты внешнего отчета не пропадали, всегда контролируйте цепочку передачи данных. Используйте параметры формы для «прокидывания» значений извне и параметры СКД для фильтрации данных внутри отчета. Это сделает ваш код надежным и понятным для других разработчиков.