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