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