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