Как исправить ошибки при получении макета внешней обработки и напечатать отчет из таблицы значений в 1С?

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

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

Разбор ошибок при получении макета внешней обработки на сервере

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

Ошибка 1. Попытка перезаписи зарезервированного свойства ЭтотОбъект

Посмотрим на пример ошибочного кода:


ЭтотОбъект = РеквизитФормыВЗначение("Объект");
Макет = ЭтотОбъект.ПолучитьМакет("СводныйОтчет");

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


ОбработкаОбъект = РеквизитФормыВЗначение("Объект");
Макет = ОбработкаОбъект.ПолучитьМакет("СводныйОтчет");

Ошибка 2. Неверное имя основного реквизита в методе РеквизитФормыВЗначение()

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

Макет = РеквизитФормыВЗначение("Отчет").ПолучитьМакет("СводныйОтчет");

В этом случае система возвращает ошибку: "Недопустимое значение параметра (параметр номер '1')". Почему так происходит? Имя основного реквизита на управляемой форме жестко привязано к типу создаваемого объекта. Если мы разрабатываем внешнюю обработку, то её основной реквизит по умолчанию всегда называется Объект. Если же мы пишем внешний отчет, то его реквизит называется Отчет. Передача строки "Отчет" во внешней обработке приводит к тому, что платформа пытается найти несуществующий реквизит формы и завершает работу аварийно. Всегда проверяйте имя основного реквизита на вкладке "Реквизиты" в конфигураторе.

Ошибка 3. Использование менеджера встроенных объектов для внешних файлов

Иногда программисты пытаются получить доступ к макету через менеджеры метаданных конфигурации:


СводныйОтчет = Отчеты.Сводный.Создать;
Макет = СводныйОтчет.ПолучитьМакет("СводныйОтчет");

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


ВнешнийОтчетОбъект = ВнешниеОтчеты.Создать(ПутьКФайлу);
Макет = ВнешнийОтчетОбъект.ПолучитьМакет("СводныйОтчет");

Почему метод ПолучитьОбласть() не находит область макета

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

Основная причина кроется в том, что разработчики часто путают имя параметра ячейки и имя самой области табличного документа:

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

Чтобы исправить эту ошибку и сделать область доступной для кода, выполним следующие шаги в конфигураторе:

  1. Откроем макет табличного документа нашей внешней обработки.
  2. Выделим строку (или диапазон ячеек), которую мы хотим сделать областью (например, строку, где расположен наш параметр).
  3. В главном меню выберем пункт Таблица -> Имена -> Назначить имя... (или воспользуемся быстрыми клавишами Ctrl + Shift + N).
  4. В открывшемся диаговолом окне укажем имя СписДок и нажмем "ОК".

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

Оптимальное построение клиент-серверного взаимодействия при печати

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

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

Давайте посмотрим на правильный шаблон клиент-серверного взаимодействия, который минимизирует количество переходов и исключает ошибки типов:


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

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

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

Современный подход к проектированию печатных форм с использованием БСП

Если мы работаем в современных типовых конфигурациях (таких как ERP, Управление торговлей, Бухгалтерия предприятия и др.), ручное создание кнопок на форме обработки считается устаревшим подходом. Библиотека стандартных подсистем (БСП) предоставляет мощный механизм подсистемы "Дополнительные отчеты и обработки".

Давайте рассмотрим, как адаптировать внешнюю обработку под стандарты БСП, чтобы избавиться от необходимости вручную проектировать формы и писать логику клиент-серверных переходов:

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

Посмотрим на пример реализации модуля объекта внешней печатной формы по стандартам БСП:


Функция СведенияОВнешнейОбработке() Экспорт
    ПараметрыРегистрации = Новый Структура;
    ПараметрыРегистрации.Вставить("Вид", "ДополнительнаяПечатнаяФорма");
    ПараметрыРегистрации.Вставить("Наименование", "Сводный отчет по номенклатуре");
    ПараметрыРегистрации.Вставить("Версия", "1.0");
    ПараметрыРегистрации.Вставить("БезопасныйРежим", Истина);
    
    // Описываем команды
    ТаблицаКоманд = ПолучитьТаблицуКоманд();
    НоваяКоманда = ТаблицаКоманд.Добавить();
    НоваяКоманда.Представление = "Печать сводного отчета";
    НоваяКоманда.Идентификатор = "СводныйОтчет";
    НоваяКоманда.Использование = "ВызовСерверногоМетода";
    НоваяКоманда.ПоказыватьОповещение = Истина;
    
    ПараметрыРегистрации.Вставить("Команды", ТаблицаКоманд);
    Возврат ПараметрыРегистрации;
КонецФункции

Процедура Печать(МассивОбъектов, КоллекцияПечатныхФорм, ОбъектыПечати, ПараметрыВывода) Экспорт
    // Метод вызывается подсистемой БСП автоматически на сервере
    ТабличныйДокумент = СформироватьСводныйОтчет(МассивОбъектов);
    
    // Регистрируем печатную форму в коллекции БСП
    ПечатнаяФорма = УправлениеПечатью.СведенияОПечатнойФорме(КоллекцияПечатныхФорм, "СводныйОтчет");
    ПечатнаяФорма.ТабличныйДокумент = ТабличныйДокумент;
КонецПроцедуры

Такой подход делает наши разработки гибкими, профессиональными и полностью соответствующими современным стандартам разработки фирмы "1С". Мы избавляемся от лишнего кода на формах и передаем рутинные задачи по выводу на печать и экспорту файлов проверенным системным механизмам.

← На главную