Как в модуле объекта 1С определить интерактивное или программное проведение документа?

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

При разработке логики проведения документов в 1С:Предприятии 8.3 часто возникает задача разделения поведения системы: например, оптимизировать проверки при интерактивной работе пользователя в форме или скорректировать алгоритмы при массовом пакетном перепроведении документов. Рассмотрим, как устроена работа платформы в этом контексте, и разберем практические способы определения режима проведения внутри процедуры ОбработкаПроведения модуля объекта.

Ограничение платформы: в модуле объекта документа нет встроенного системного флага или свойства, которое бы однозначно сообщало, откуда вызвано проведение — по нажатию кнопки пользователем или через вызов метода Записать(РежимЗаписиДокумента.Проведение) из встроенного языка. Поэтому для передачи контекста используются управляемые параметры и служебные свойства.

Способ 1. Использование структуры «ДополнительныеСвойства» объекта

Разберем классический и наиболее надежный способ: передачу специального признака из формы документа в модуль объекта через системное свойство ДополнительныеСвойства.

Для реализации этого подхода выполним следующие шаги:

  1. В модуле управляемой формы документа перехватываем серверное событие записи и добавляем признак интерактивности в структуру объекта.
  2. В модуле объекта в процедуре ОбработкаПроведения проверяем наличие и значение этого флага с помощью безопасного метода Свойство().

Посмотрим на пример кода в модуле управляемой формы документа:


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

Теперь разберем, как обработать этот признак в модуле объекта документа:


Процедура ОбработкаПроведения(Отказ, Режим)
    
    ЭтоИнтерактивно = Ложь;
    Если ДополнительныеСвойства.Свойство("ИнтерактивноеПроведение") Тогда
        ЭтоИнтерактивно = ДополнительныеСвойства.ИнтерактивноеПроведение;
    КонецЕсли;
    
    Если ЭтоИнтерактивно Тогда
        // Выполняем алгоритмы, специфичные для интерактивной работы
    Иначе
        // Выполняем полный цикл проверок для программного проведения
    КонецЕсли;
    
КонецПроцедуры

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

Способ 2. Определение окружения и типа сеанса

Проанализируем ситуацию, когда необходимо отделить действия реального пользователя от системных фоновых процессов, регламентных заданий или обменов данными через веб-сервисы. Для этого не обязательно модифицировать формы — достаточно проанализировать параметры текущего сеанса прямо в модуле объекта.

Посмотрим на пример функции проверки типа сеанса:


Функция ЭтоФоновыйИлиРегламентныйСеанс()
    
    // Проверка на запуск внутри фонового задания
    ТекущийСеанс = ПолучитьТекущийСеансИнформационнойБазы();
    Если ТекущийСеанс.ФоновоеЗадание <> Неопределено Тогда
        Возврат Истина;
    КонецЕсли;
    
    // Проверка типа подключения клиента
    ТипКлиента = ИмяПриложения();
    Если ТипКлиента = "WebServiceClient" 
        ИЛИ ТипКлиента = "COMConnection" 
        ИЛИ ТипКлиента = "WSConnection" Тогда
        Возврат Истина;
    КонецЕсли;
    
    Возврат Ложь;
    
КонецФункции

Способ 3. Анализ стека вызовов

Начиная с версии платформы 8.3.18, разработчикам доступна функция ПолучитьСтекВызовов(). С ее помощью можно программно исследовать цепочку вызовов и определить, присутствует ли в ней модуль управляемой формы.


Функция ВызваноИзФормы()
    
    Стек = ПолучитьСтекВызовов();
    Для Каждого ЭлементСтека Из Стек Цикл
        Если СтрНайти(ЭлементСтека.Модуль, "Форма") > 0 Тогда
            Возврат Истина;
        КонецЕсли;
    КонецЦикла;
    
    Возврат Ложь;
    
КонецФункции

Обратите внимание: разбор стека вызовов является ресурсоемкой операцией. Не рекомендуется использовать этот метод в высоконагруженных транзакциях проведения и при пакетной обработке больших массивов данных.

Архитектурные рекомендации по разделению проверок

Рассмотрим, как правильно организовать архитектуру конфигурации, чтобы не нарушать целостность данных:

  1. Разделение проверок формы и модуля: базовые визуальные проверки и валидацию реквизитов формы целесообразно выполнять на клиенте перед отправкой данных на сервер, чтобы сэкономить ресурсы сервера. При этом в модуле объекта должна оставаться критически важная бизнес-логика.
  2. Передача кэша через ДополнительныеСвойства: если форма уже выполнила тяжелые расчеты или собрала сводные таблицы данных, их можно передать в модуль объекта внутри структуры ДополнительныеСвойства. В ОбработкаПроведения проверяем: если кэш передан — используем готовые данные; если кэш отсутствует (документ проводится программно) — модуль объекта рассчитывает эти данные самостоятельно по полному циклу.
  3. Проверка заполнения: помните, что при интерактивной записи платформа автоматически вызывает событие ОбработкаПроверкиЗаполнения, а при вызове метода Записать(РежимЗаписиДокумента.Проведение) из кода платформа не запускает проверку заполнения автоматически, если разработчик явно не вызвал метод ПроверитьЗаполнение().
← На главную