При разработке внешних отчетов или обработок на платформе 1С:Предприятие 8.3 (Управляемое приложение) начинающие разработчики часто сталкиваются с дилеммой: где именно должен располагаться код формирования табличного документа. Попытка вызвать метод ПолучитьМакет() напрямую из модуля формы приводит к ошибке, а использование метода РеквизитФормыВЗначение() часто ошибочно воспринимается как «костыль» или признак плохой архитектуры, хотя современный статический анализатор кода проектов (полезным инструментом будет инструментарий разработчика для анализа метаданных и отладки) подтвердит, что это стандартный механизм платформы. В этой статье мы подробно разберем, почему это не так, проанализируем внутреннее устройство системы и научимся проводить глубокий анализ отчетов и обработок на наличие ошибок в экспортных методах.
Для начала проанализируем, почему в управляемом приложении существует такое строгое разделение. В обычных формах (1С 8.2 и ранее) форма была частью объекта, и вы имели прямой доступ ко всем его методам через ключевое слово ЭтотОбъект. В управляемом приложении всё изменилось.
Рассмотрим основные сущности:
Объект в модуле формы — это не сам отчет, а лишь его «легкая» проекция. Она содержит значения реквизитов (строки, числа, даты), чтобы их можно было быстро передавать между клиентом и сервером. У этой структуры нет методов для работы с метаданными, таких как ПолучитьМакет() или ВыполнитьЗапрос().Таким образом, когда нам нужно сформировать печатную форму, используя макет (для этой задачи есть конструктор печатных форм и отчетов без программирования), нам необходимо на мгновение превратить «легкие» данные формы в «тяжелый» объект. Именно для этого предназначен метод РеквизитФормыВЗначение(). Это не костыль, а штатный шлюз десериализации данных.
Рассмотрим стандартную схему реализации формирования табличного документа. Мы будем использовать связку: кнопка на форме — серверный метод формы — метод модуля объекта. В качестве фундамента будущей разработки можно взять готовый шаблон дополнительной обработки с сохранением параметров, который уже содержит правильную структуру.
Шаг 1. Подготовка модуля объекта.
Вся логика формирования должна находиться именно здесь. Это позволяет вызывать формирование отчета не только из текущей формы, но и из других мест конфигурации или через внешние соединения. Создадим экспортную функцию:
// В модуле объекта
Функция СформироватьТабличныйДокумент() Экспорт
ТабДок = Новый ТабличныйДокумент;
// Получаем макет. Здесь этот метод доступен напрямую!
Макет = ПолучитьМакет("Макет");
// Получаем области
ОбластьШапка = Макет.ПолучитьОбласть("Шапка");
ОбластьСтрока = Макет.ПолучитьОбласть("Строка");
// Заполняем параметры из реквизитов самого объекта
ОбластьШапка.Параметры.Заголовок = "Отчет по данным на " + Формат(ДатаОтчета, "ДЛФ=D");
ТабДок.Вывести(ОбластьШапка);
// Пример простого цикла формирования
Для Каждого ТекСтрока Из ДанныеОтчета Цикл
ЗаполнитьЗначенияСвойств(ОбластьСтрока.Параметры, ТекСтрока);
ТабДок.Вывести(ОбластьСтрока);
КонецЦикла;
Возврат ТабДок;
КонецФункции
Шаг 2. Вызов из модуля формы.
Теперь выясним, как правильно связать форму и объект. В модуле формы нам понадобится серверная процедура, которая выполнит преобразование.
// В модуле формы
&НаКлиенте
Процедура Сформировать(Команда)
// Вызываем серверный метод для получения документа
ТабличныйДокумент = СформироватьНаСервере();
// Выводим результат пользователю
ТабличныйДокумент.Показать("Ваш отчет");
КонецПроцедуры
&НаСервере
Функция СформироватьНаСервере()
// Преобразуем данные формы (реквизит "Объект") в реальный объект обработки
// Второй параметр "Истина" позволяет вернуть измененные данные назад в форму (если нужно)
ОбработкаОбъект = РеквизитФормыВЗначение("Объект");
// Теперь нам доступны все экспортные методы модуля объекта
Результат = ОбработкаОбъект.СформироватьТабличныйДокумент();
Возврат Результат;
КонецФункции
Рассмотрим ситуацию, если вы принципиально не хотите использовать РеквизитФормыВЗначение. Можно ли обойтись без него? Да, но это часто приводит к менее удачным решениям.
Вариант А: Перенос кода в модуль формы.
Вы можете написать весь код в процедуре &НаСервере модуля формы. Однако там не работает метод ПолучитьМакет(). Вам придется использовать конструкцию вида ЭтотОбъект.ПолучитьМакет(), которая внутри платформы все равно инициирует неявное преобразование контекста. Чтобы лучше ориентироваться в этих тонкостях, стоит изучить, как развивалась объектная модель печатной формы в процессе эволюции платформы.
Вариант Б: Использование менеджера.
Для встроенных в конфигурацию отчетов можно использовать менеджер: Отчеты.МойОтчет.ПолучитьМакет("Макет"). Но для внешних отчетов этот способ не подходит, так как файл отчета физически не зарегистрирован в метаданных и платформа не знает, где искать макет без обращения к самому объекту .erf или .epf.
Выясним, почему некоторые разработчики боятся метода РеквизитФормыВЗначение. Основной аргумент — затраты времени на создание объекта. Действительно, если на форме сотни реквизитов и огромные табличные части, сериализация может занять время.
Посмотрим на способы оптимизации:
РеквизитФормыВЗначение("Объект", Ложь). Если вы только читаете данные для отчета и не планируете менять реквизиты объекта (например, дату или настройки) программно в модуле объекта, установите Ложь. Это избавит платформу от необходимости выполнять обратное преобразование при завершении серверного вызова.ВнешниеОтчеты.Создать().Подводя итог нашему анализу, можно уверенно сказать: использование РеквизитФормыВЗначение("Объект") во внешних отчетах — это золотой стандарт 1С. Именно так написаны тысячи процедур в типовых конфигурациях (ERP, УТ 11, БП 3.0).
Основные выводы:
Помните, что чистота кода и следование стандартам 1С важнее, чем попытка избежать штатных механизмов платформы (контролировать стандарты поможет автоматический анализатор архитектуры кода и зависимостей). Разделяя интерфейс и логику, вы делаете свою разработку надежной и легкой в поддержке.