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