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