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