Как правильно передать владелецформы.объект во внешний отчет в 1С?

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

При разработке внешних отчетов в системе «1С:Предприятие 8.3» на управляемых формах программисты часто сталкиваются с необходимостью передать данные текущего документа (или любого другого объекта) прямо из формы во внешний отчет. Это особенно актуально, когда документ еще не записан в базу данных, и нам нужно построить отчет на основе тех данных, которые пользователь видит на экране в данный момент.

В этой статье мы подробно разберем, как решить эту задачу правильно, проанализируем типичные ошибки, которые допускают разработчики при передаче объекта формы-владельца, и рассмотрим надежные проектные решения, соответствующие стандартам разработки фирмы «1С».

В чем заключается сложность и почему простое решение вызывает ошибки?

Начинающие разработчики часто пытаются решить задачу «в лоб»: передать интерфейсный объект типа ДанныеФормыСтруктура (которым является ВладелецФормы.Объект или просто Объект на клиенте) напрямую в настройки компоновщика данных или параметры формы отчета.

Например, в кодовой базе может появиться следующая конструкция:


// Небезопасный код на клиенте в форме отчета
Отчет.КомпоновщикНастроек.Настройки.ДополнительныеСвойства.Вставить("ДокументОбъект", ВладелецФормы.Объект);

Выясним причину, почему этот способ является ошибочным:

Свойство КомпоновщикНастроек.Настройки (включая его коллекцию ДополнительныеСвойства) регулярно сериализуется платформой «1С» в формат XML. Это происходит при открытии стандартных окон настройки отчета, сохранении вариантов или пользовательских настроек. Тип данных ДанныеФормыСтруктура предназначен исключительно для работы интерфейса управляемой формы. Он не поддерживает XDTO-сериализацию. При попытке пользователя открыть настройки отчета система выдаст критическую ошибку (например, «Итератор для значения не определен» или ошибку передачи данных между клиентом и сервером).

Кроме того, прямое обращение к свойству ВладелецФормы.Объект нарушает принцип отказоустойчивости. Если пользователь запустит отчет не из формы конкретного документа, а из панели отчетов или формы списка, программа завершится аварийно с ошибкой «Поле объекта не обнаружено».

Ниже мы рассмотрим два правильных, стабильных и безопасных способа передачи данных.

Способ №1: Использование временного хранилища (Рекомендуемый стандарт)

Если нам необходимо передать во внешний отчет именно **несохраненные** данные формы документа (то, что пользователь успел ввести на форме, но еще не записал), идеальным решением будет использование Временного хранилища. Вместо передачи тяжелого интерфейсного объекта мы преобразуем его на сервере в реальный прикладной объект, поместим во временное хранилище и передадим в отчет только строковый адрес этого хранилища.

Разберем этот процесс по шагам.

Шаг 1. Код в форме документа-источника

В форме документа, из которой вызывается внешний отчет, нам необходимо получить данные формы, преобразовать их в объект, поместить в хранилище и передать адрес при открытии отчета:


&НаКлиенте
Процедура СН_ВызовВнешнегоОтчета(Команда)
    
    // Получаем адрес временного хранилища с данными нашего документа
    АдресХранилища = ПолучитьАдресДанныхДокументаНаСервере();
    
    // Формируем параметры для открытия формы внешнего отчета
    ПараметрыОткрытия = Новый Структура;
    ПараметрыОткрытия.Вставить("АдресДанныхДокумента", АдресХранилища);
    
    // Открываем внешнюю форму отчета.
    // Обратите внимание: ИмяОбработкиСлужебное получается при регистрации/подключении механизмами БСП.
    ОткрытьФорму("ВнешнийОтчет." + ИмяОбработкиСлужебное + ".Форма", ПараметрыОткрытия, ЭтаФорма);
    
КонецПроцедуры

&НаСервере
Функция ПолучитьАдресДанныхДокументаНаСервере()
    
    // Преобразуем ДанныеФормыСтруктура в реальный ДокументОбъект.
    // Этот метод работает даже для новых, еще ни разу не записанных в базу документов!
    ДокументОбъект = РеквизитФормыВЗначение("Объект");
    
    // Помещаем объект во временное хранилище. 
    // Привязываем адрес к УникальномуИдентификатору формы, чтобы данные не удалились преждевременно.
    Возврат ПоместитьВоВременноеХранилище(ДокументОбъект, УникальныйИдентификатор);
    
КонецФункции

Шаг 2. Прием параметра в форме внешнего отчета

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


&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
    
    // Проверяем, передан ли параметр с адресом данных
    Если Параметры.Свойство("АдресДанныхДокумента") Тогда
        // Сохраняем строковый адрес в дополнительные свойства компоновщика настроек
        КомпоновщикНастроек.Настройки.ДополнительныеСвойства.Вставить(
            "АдресДанныхДокумента", 
            Параметры.АдресДанныхДокумента
        );
    КонецЕсли;
    
КонецПроцедуры

Шаг 3. Извлечение объекта в модуле внешнего отчета

Теперь в модуле объекта внешнего отчета в событии ПриКомпоновкеРезультата мы можем извлечь переданный документ и использовать его для построения отчета:


Процедура ПриКомпоновкеРезультата(ДокументРезультат, ДанныеРасшифровки, СтандартнаяОбработка)
    
    // Отключаем стандартный вывод, если планируем выводить данные программно
    СтандартнаяОбработка = Ложь;
    
    АдресДанных = "";
    Если КомпоновщикНастроек.Настройки.ДополнительныеСвойства.Свойство("АдресДанныхДокумента", АдресДанных) Тогда
        
        Если ЗначениеЗаполнено(АдресДанных) Тогда
            
            // Получаем полноценный ДокументОбъект из временного хранилища
            ДокументОбъект = ПолучитьИзВременногоХранилища(АдресДанных);
            
            // Проверяем тип полученного объекта для исключения ошибок
            Если ТипЗнч(ДокументОбъект) = Тип("ДокументОбъект.СчетНаОплатуПоставщику") Тогда
                
                // Теперь мы можем работать с табличными частями и реквизитами документа:
                // Например, использовать ДокументОбъект.Товары для программного заполнения коллекции данных
                // или передавать параметры в запрос СКД.
                
            КонецЕсли;
            
        КонецЕсли;
        
    КонецЕсли;
    
    // Далее следует стандартный шаблон вывода отчета СКД...
    Настройки = КомпоновщикНастроек.ПолучитьНастройки();
    КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
    МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаКомпоновкиДанных, Настройки, ДанныеРасшифровки);
    
    ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
    ПроцессорКомпоновки.Инициализировать(МакетКомпоновки, , ДанныеРасшифровки, Истина);
    
    ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;
    ПроцессорВывода.УстановитьДокумент(ДокументРезультат);
    ПроцессорВывода.Вывести(ПроцессорКомпоновки);
    
КонецПроцедуры

Способ №2: Передача ссылки (Стандарт БСП)

Если для работы отчета не требуются оперативные (несохраненные) изменения, внесенные пользователем на форме прямо сейчас, то передавать весь контекст объекта избыточно. Гораздо проще и надежнее использовать стандарт БСП для дополнительных отчетов и обработок, передавая только ссылки на объекты.

Рассмотрим этот сценарий:

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

Этот подход гарантирует полную изоляцию интерфейса от бизнес-логики и исключает любые проблемы клиент-серверного взаимодействия.

Обеспечение отказоустойчивости при проверке владельца формы

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


&НаКлиенте
Процедура ПриОткрытии(Отказ)
    
    // Проверяем, что у формы действительно задан владелец
    Если ВладелецФормы <> Неопределено Тогда
        
        // Безопасная проверка наличия реквизита "Объект" у формы-владельца
        // (Метод "ЕстьРеквизитФормы" является стандартным для конфигураций на БСП)
        Если ОбщегоНазначенияКлиент.ЕстьРеквизитФормы(ВладелецФормы, "Объект") Тогда
            
            // Если реквизит присутствует, выполняем нашу логику
            Сообщить("Отчет успешно инициализирован данными формы: " + ВладелецФормы.Объект.Ссылка);
            
        КонецЕсли;
        
    КонецЕсли;
    
КонецПроцедуры

Применение предложенных методик позволит вам создавать надежные внешние отчеты, которые не вызывают ошибок при работе с настройками компоновки данных и могут гибко использоваться в любых конфигурациях на платформе «1С:Предприятие 8.3».

← На главную