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

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

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

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

Причины некорректного поведения кода

Проанализируем две ключевые причины, из-за которых передача Отказ в немодальный диалог не работает:

  1. Асинхронная природа метода ПоказатьВопрос: процедура ПередЗаписью не ждет ответа пользователя. Вызов ПоказатьВопрос лишь регистрирует показ диалогового окна и завершает выполнение процедуры ПередЗаписью за доли миллисекунды. Платформа проверяет значение параметра Отказ сразу после выхода из процедуры, когда он еще равен Ложь, и благополучно продолжает запись или проведение объекта. Процедура-обработчик оповещения вызывается значительно позже — уже после того, как документ сохранен.
  2. Передача примитивных типов по значению: параметр Отказ имеет тип Булево. При добавлении его в структуру через ДополнительныеПараметры.Вставить("Отказ", Отказ) в структуру копируется только текущее значение флага. Последующее изменение ДополнительныеПараметры.Отказ = Истина модифицирует поле структуры, но никак не влияет на оригинальный параметр события Отказ.

Способ 1. Паттерн прерывания и повторного вызова записи (основной)

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

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

Посмотрим на пример реализации данного алгоритма:


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

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

Способ 2. Переопределение пользовательских команд проведения

Если логика подтверждения требуется исключительно при интерактивном нажатии на кнопки проведения в форме документа, удобнее перенести вопрос в обработчик команды, не перегружая событие ПередЗаписью.

Разберем по шагам реализацию через команду формы:

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

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


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

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

Итоги

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

← На главную