Почему не заполняются данные в печатной форме отчета и как правильно получать реквизиты в 1С 8.3

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

При переходе к разработке на управляемых формах многие начинающие программисты сталкиваются с ситуацией, когда код, написанный по логике обычного приложения, перестает работать. Типичный пример: создание печатной формы в модуле формы отчета, где параметры макета остаются пустыми, несмотря на то что пользователь заполнил все поля на экране. Давайте подробно разберем, почему это происходит, проанализируем архитектуру управляемых форм и выясним, как правильно обращаться к данным.

Разбор основной ошибки: Создание нового объекта вместо использования данных формы

Рассмотрим ситуацию, с которой столкнулся автор темы. В процедуре СформироватьНаСервере он использует следующий код:


ОтчетОбъект = Отчеты.НачислениеЗПНаВыбор.Создать();
ОбластьШапка.Параметры.Организация = ОтчетОбъект.Организация;

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

Проанализируем архитектуру: в управляемом приложении данные на форме — это не сам объект базы данных или объект метаданных, а специальная структура ДанныеФормыСтруктура. Чтобы получить данные, которые ввел пользователь, нам не нужно ничего "создавать" заново, нам нужно обратиться к существующему реквизиту формы.

Решение №1: Прямое обращение к основному реквизиту формы

В управляемой форме отчета по умолчанию создается основной реквизит с именем Отчет. Именно он является хранилищем всех данных, которые пользователь редактирует на экране. Если процедура выполняется &НаСервере в модуле формы, нам доступны все реквизиты этого объекта напрямую.

Исправленный код будет выглядеть следующим образом:


&НаСервере
Процедура СформироватьНаСервере(ТабДок)
    // Получаем макет напрямую из метаданных или через этот объект
    Макет = Отчеты.НачислениеЗПНаВыбор.ПолучитьМакет("Макет1");
    
    ОбластьШапка = Макет.ПолучитьОбласть("Шапка");
    
    // Прямое обращение к реквизитам формы
    ОбластьШапка.Параметры.Организация = Отчет.Организация;
    ОбластьШапка.Параметры.Поликлиника = Отчет.Поликлиника;
    ОбластьШапка.Параметры.Сотрудник   = Отчет.Сотрудник;
    ОбластьШапка.Параметры.Период      = Отчет.ДатаНачала;
    
    ТабДок.Вывести(ОбластьШапка);
КонецПроцедуры

Важный момент: если вы переименовали основной реквизит формы (он выделен жирным шрифтом в списке реквизитов редактора формы), то вместо Отчет нужно использовать ваше имя. Часто в документах это Объект, а в отчетах — Отчет. Ошибка "Переменная не определена", упомянутая в обсуждении, возникает именно тогда, когда разработчик пытается обратиться к Объект.Организация в форме отчета, где реквизит называется иначе.

Решение №2: Использование метода РеквизитФормыВЗначение

Иногда логика формирования отчета настолько сложна, что ее неудобно держать в модуле формы. В этом случае ее выносят в модуль объекта. Но как передать данные из формы в модуль объекта? Для этого существует механизм трансформации данных формы в полноценный объект.

Рассмотрим по шагам, как это работает:

  1. Метод РеквизитФормыВЗначение("Отчет") берет данные из экранной формы и создает на их основе объект типа ОтчетОбъект.
  2. У этого объекта доступны все экспортные методы модуля объекта и стандартные функции, такие как ПолучитьМакет().
  3. После выполнения действий данные можно вернуть в форму методом ЗначениеВРеквизитФормы (если они изменились).

Пример кода в модуле формы:


&НаСервере
Процедура СформироватьНаСервере()
    // Превращаем данные формы в объект отчета
    ОбъектОтчета = РеквизитФормыВЗначение("Отчет");
    
    // Теперь мы можем вызвать процедуру из модуля объекта
    // или получить макет так:
    Макет = ОбъектОтчета.ПолучитьМакет("Макет1");
    
    // Заполняем параметры, используя данные уже "настоящего" объекта
    Область = Макет.ПолучитьОбласть("Шапка");
    ЗаполнитьЗначенияСвойств(Область.Параметры, ОбъектОтчета);
КонецПроцедуры

Почему использование "Ссылки" в отчетах — это тупиковый путь?

В процессе обсуждения упоминался вариант СсылкаНаОбъект.ПолучитьОбъект(). Выясним, почему для отчетов это чаще всего неприменимо. В системе 1С объекты делятся на ссылочные (справочники, документы) и нессылочные (отчеты, обработки).

Документ записывается в базу данных и имеет уникальный идентификатор (ссылку). Мы можем в любой момент по этой ссылке прочитать данные из базы. Отчет же — это инструмент. Он не "лежит" в базе данных как запись. Пользователь открыл отчет, заполнил параметры, нажал кнопку — данные существуют только в этот момент в памяти. Поэтому у отчета (как экземпляра данных) нет "Ссылки".

Исключение составляют внешние отчеты, зарегистрированные в справочнике "Дополнительные отчеты и обработки", но и там работа через ссылку требует понимания того, что вы получите настройки по умолчанию, а не те, что пользователь только что ввел на экране.

Рекомендации по работе с внешними отчетами

Если вы разрабатываете отчет, который будет подключаться как внешний (файл .erf), использование жестких конструкций вида Отчеты.НачислениеЗПНаВыбор.ПолучитьМакет() приведет к ошибке, так как в конфигурации объекта с таким именем может не существовать. Для обеспечения универсальности всегда используйте:

1. В модуле объекта: ЭтотОбъект.ПолучитьМакет("Имя").

2. В модуле формы: через преобразование РеквизитФормыВЗначение, как было рассмотрено выше.

Система компоновки данных (СКД) как альтернатива ручному выводу

Проанализируем ситуацию глобально: ручное заполнение областей макета (Шапка, Строка, Подвал), как делает автор вопроса, — это технология времен 1С 7.7 и 8.1. В современной платформе 8.3 для создания отчетов настоятельно рекомендуется использовать СКД.

Почему СКД лучше:

Даже если вам нужна специфическая печатная форма, ее можно реализовать через "Макеты" внутри СКД, сохранив при этом все преимущества автоматического получения данных из реквизитов формы.

Выводы

Подведем итог нашего разбора. Если вы пишете код в модуле управляемой формы отчета и вам нужны данные, введенные пользователем:

  1. Никогда не используйте Отчеты.ИмяОтчета.Создать() для получения текущих данных.
  2. Обращайтесь напрямую к реквизиту Отчет (например, Отчет.Организация).
  3. Проверяйте имя основного реквизита на закладке "Реквизиты" в конструкторе формы.
  4. Для сложной логики используйте РеквизитФормыВЗначение.

Соблюдение этих правил позволит избежать пустых строк в печатных формах и сделает ваш код стабильным и понятным.

← На главную