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