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

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

При разработке внешних обработок заполнения табличных частей или обработок по модификации документов разработчики часто сталкиваются с необходимостью использовать уже существующие в конфигурации алгоритмы расчета. Нередко такие алгоритмы принимают на вход серверные объекты коллекций (ТаблицаЗначений, ДеревоЗначений), которые в самой форме документа формируются вызовом метода РеквизитФормыВЗначение. Попытка вызвать этот метод «снаружи» через полученный объект формы приводит к ошибке. Разберем, почему возникает данное ограничение платформы 1С:Предприятие 8.3 и какие существуют правильные способы решения этой задачи.

Почему нельзя вызвать РеквизитФормыВЗначение через объект формы

Проанализируем архитектуру управляемых форм. Метод РеквизитФормыВЗначение является методом неявного контекста серверного модуля управляемой формы. У типа УправляемаяФорма нет такого экспортного метода в его программном интерфейсе. Поэтому конструкция вида:


// Вызовет синтаксическую ошибку платформы
ЗначениеРеквизита = ПолученнаяФорма.РеквизитФормыВЗначение("Дерево");

не сработает ни на клиенте, ни на сервере. Кроме того, серверные процедуры модуля формы, даже если они объявлены с ключевым словом Экспорт, недоступны для вызова из внешнего кода (они предназначены только для вызова из клиентских процедур того же самого модуля формы).

Выясним, какие практические варианты реализации существуют для решения подобных задач во внешних обработках.

Вариант 1. Прямая работа с данными объекта без открытия формы

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

Разберем по шагам алгоритм работы с объектом:

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

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


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

Вариант 2. Программное создание типизированной коллекции для передачи в общий модуль

Если процедура общего модуля требует на вход именно объект типа ДеревоЗначений или ТаблицаЗначений, нет необходимости преобразовывать реквизит формы документа. Мы можем создать коллекцию требуемой структуры непосредственно в серверном коде обработки.

Рассмотрим пример создания и заполнения дерева значений:


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

Вариант 3. Использование реквизита в форме внешней обработки

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

  1. В форме внешней обработки создаем реквизит с таким же типом (например, ДанныеДерева с типом ДеревоЗначений).
  2. На клиенте копируем данные из реквизита формы документа в реквизит формы обработки с помощью КопироватьДанныеФормы.
  3. В серверном контексте формы обработки выполняем РеквизитФормыВЗначение("ДанныеДерева"), так как внутри собственной формы этот метод доступен.
  4. После выполнения расчетов переносим данные обратно в форму документа с помощью метода КопироватьДанныеФормы или ЗначениеВДанныеФормы.

Посмотрим на пример работы с данными формы:


&НаКлиенте
Процедура ОбработатьФормуДокумента(ФормаДокумента)
    // Копируем данные из формы документа в реквизит текущей формы обработки
    КопироватьДанныеФормы(ФормаДокумента.ДеревоНачислений, ЭтотОбъект.ДанныеДерева);
    
    // Выполняем преобразование и расчет на сервере формы обработки
    РассчитатьДанныеНаСервере();
    
    // Возвращаем результат обратно в форму документа
    КопироватьДанныеФормы(ЭтотОбъект.ДанныеДерева, ФормаДокумента.ДеревоНачислений);
КонецПроцедуры

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

Вариант 4. Расширение конфигурации

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

В расширении можно переопределить или дополнить модуль нужной формы с помощью аннотаций &Вместо, &После или &Перед. Внутри контекста расширенной формы метод РеквизитФормыВЗначение будет доступен напрямую.

← На главную