Как задать вопрос пользователю при записи регистра сведений или проведении документа?

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

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

Выясним причину, по которой вызов диалога не работает из событий базы данных. Подписка на событие ПередЗаписью регистра или документа выполняется исключительно в серверном контексте внутри транзакции записи СУБД. В этом контексте пользовательский интерфейс принципиально недоступен. Любые попытки остановить серверный поток через циклы ожидания, функции типа ОбщегоНазначенияБТС.Пауза() или обработчики ожидания с опросом параметров сеанса грубо нарушают стандарты разработки. Удержание открытой транзакции приводит к эскалации блокировок таблиц, взаимным блокировкам (deadlock) и параличу работы всей базы при параллельной работе кадровиков. Кроме того, при групповом перепроведении документов попытка вывести модальный вопрос в транзакции полностью остановит пакетный процесс.

Рассмотрим подробнее типовые подходы к реализации интерактивных вопросов и обхода проверок.

Архитектурный шаблон «Проверка – Отмена – Вопрос – Повторная запись»

Единственным правильным местом для интерактивного общения с пользователем является клиентский контекст формы объекта до открытия транзакции записи. Рассмотрим типовой алгоритм реализации такого диалога:

  1. В обработчике формы ПередЗаписью проверяется флаг-признак подтверждения проверки.
  2. Если подтверждение еще не получено, вызывается серверная функция валидации данных.
  3. В случае обнаружения пересечения периодов или коллизий запись отменяется установкой флага Отказ = Истина.
  4. Пользователю выдается асинхронный вопрос через метод ПоказатьВопрос().
  5. В процедуре-обработчике оповещения, если пользователь нажал «Да», флаг подтверждения выставляется в значение Истина, а затем повторно программно вызывается запись документа.

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


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

&НаКлиенте
Процедура ПослеОтветаНаВопросОЗаписи(Результат, ДополнительныеПараметры) Экспорт
    Если Результат = КодВозвратаДиалога.Да Тогда
        НеВыполнятьПроверкиПередЗаписью = Истина;
        Записать(ДополнительныеПараметры);
        НеВыполнятьПроверкиПередЗаписью = Ложь;
    КонецЕсли;
КонецПроцедуры

Передача флага разрешения в подписку через ДополнительныеСвойства

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

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


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

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

Централизованное внедрение без ручной переделки всех форм

Если в системе задействовано множество кадровых документов (например, прием на работу, кадровый перевод, увольнение, отпуск, командировка), дорабатывать форму каждого объекта вручную нерационально. Разберем, как подключить логику ко всем формам централизованно:

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

Альтернативное решение: контроль через права доступа и статусы

Если требуется полностью исключить диалоговые окна и зависимость от клиентского контекста (что критично для стабильного группового перепроведения документов из списков или регламентными заданиями), применяют административное разделение прав:

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

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

← На главную