Как при проведении документа определить, проводится ли он интерактивно или программно?

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

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

Особенности платформы: почему нет встроенного флага интерактивности

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

В платформе 1С отсутствует предопределенное свойство вроде Интерактивно в контексте модуля объекта. При проведении из формы документа сначала отрабатывают события формы (ПередЗаписью, ОбработкаПроверкиЗаполненияНаСервере), но если пользователь нажимает «Провести» в списке документов, контекст формы документа вообще не создается — управление сразу передается в модуль объекта. Поэтому стандартный и самый надежный способ передать контекст проведения — использовать встроенную коллекцию ДополнительныеСвойства.

Способ 1. Передача флага через ДополнительныеСвойства объекта

Рассмотрим основной и общепринятый подход, рекомендованный стандартами разработки. Свойство ДополнительныеСвойства представляет собой структуру, которая существует в памяти вместе с экземпляром объекта до окончания его записи и очищается при уничтожении объекта.

Разберем по шагам, как настроить передачу признака программного проведения:

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

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


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

Теперь проанализируем, как правильно обработать данный флаг внутри модуля проводимого документа:


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

КонецПроцедуры

Если конфигурация использует «Библиотеку стандартных подсистем» (БСП), обратите внимание на штатные свойства. Механизмы БСП часто проверяют типовые ключи в ДополнительныеСвойства, такие как ОтказПриОшибках или ВыводитьСообщения. Передавая эти флаги, можно стандартным образом глушить системные сообщения подсистем контроля остатков и взаиморасчетов.

Способ 2. Очистка очереди сообщений в вызывающем коде

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

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


ДокументОбъект = СсылкаНаДокумент.ПолучитьОбъект();
ДокументОбъект.Записать(РежимЗаписиДокумента.Проведение);

// Очищаем стек сообщений, накопленный за время выполнения проведения
НенужныеСообщения = ПолучитьСообщенияПользователю(Истина);

Параметр Истина указывает платформе, что полученные сообщения должны быть удалены из очереди сеанса и не дойдут до пользовательского интерфейса.

Способ 3. Проверка контекста сеанса (фоновые задания)

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

Для определения такого контекста внутри объекта используем платформенную проверку или методы БСП:


// Проверка средствами БСП:
ЭтоФоновыйПроцесс = ОбщегоНазначения.ЭтоФоновоеЗадание();

// Либо прямая проверка платформенным методом:
ЭтоФоновыйПроцесс = (ФоновыеЗадания.ПолучитьТекущее() <> Неопределено);

Если Не ЭтоФоновыйПроцесс Тогда
    // Выполняем вывод сообщений для интерактивного пользователя
КонецЕсли;

Почему проведение одного документа из другого считается нежелательным

Обратим внимание на архитектурные замечания участников обсуждения. Вызов ДокументОбъект.Записать(РежимЗаписиДокумента.Проведение) внутри обработчиков записи другого документа несет скрытые риски:

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

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

← На главную