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

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

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

В этой статье мы подробно разберем, как правильно организовать логику прерывания стандартных событий, как передать ответ пользователя с клиента на сервер и как реализовать подобные проверки не только в формах документов, но и в списках.

Разберем причину проблемы: почему стандартная процедура не ждет?

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

Решение 1: Классический метод через ОписаниеОповещения и параметры записи

Рассмотрим пошагово наиболее универсальный способ, который работает на большинстве версий платформы 8.3. Логика строится на событии ПередЗаписью на стороне клиента.

Шаг 1. Перехват события записи. Мы должны проверить, не задавали ли мы вопрос ранее. Для этого используем структуру ПараметрыЗаписи. Если флаг подтверждения отсутствует, мы отменяем текущую запись и выводим вопрос.


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

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

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

Шаг 2. Обработка ответа пользователя. В отдельной процедуре-обработчике мы анализируем результат. Если пользователь нажал «Да», мы программно вызываем метод Записать(), передавая в него структуру параметров с нашим флагом.


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

Решение 2: Современный подход с использованием Асинхронности (8.3.18+)

Если ваша конфигурация работает на версии платформы 18 и выше (и режим совместимости это позволяет), мы можем использовать оператор Ждать. Это позволяет писать код линейно, что значительно упрощает чтение и поддержку.

Проанализируем пример использования асинхронного вызова:


&НаКлиенте
Асинх Процедура ПередЗаписью(Отказ, ПараметрыЗаписи)
    
    Если ПараметрыЗаписи.Свойство("ВопросЗадан") Тогда
        Возврат;
    КонецЕсли;

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

Передача информации на уровень сервера (ДополнительныеСвойства)

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

Разберем, как пробросить данные. Когда вы вызываете Записать(ПараметрыЗаписи) на клиенте, содержимое ПараметрыЗаписи автоматически попадает в обработчик ПриКопированииДанныхФормыВОбъект на сервере. Но более надежный способ — использовать событие ПередЗаписьюНаСервере в форме:


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

Теперь в модуле самого документа вы можете обратиться к свойству ЭтотОбъект.ДополнительныеСвойства и выполнить необходимую бизнес-логику в транзакции.

Решение для списков документов

Выясним, как быть с динамическими списками (формами списков и журналов). В них событие ПередЗаписью формы не срабатывает при нажатии кнопки «Установить пометку удаления». Рассмотрим два варианта:

  1. Переопределение стандартной команды. Вы можете отключить стандартную кнопку удаления в командной панели, создать свою собственную команду «Пометить на удаление» и прописать в ней всю логику с вопросами. Это самый надежный способ контроля.
  2. Использование событий формы списка. В некоторых конфигурациях (особенно на базе БСП) можно вклиниться в обработку команд через расширение, перехватив выполнение команды списка. Однако платформа не предоставляет прямого события "ПередУстановкойПометки" в динамическом списке, которое можно было бы легко отменить с вопросом без программирования собственных кнопок.

Важные рекомендации при работе с транзакциями

Важно: Никогда не пытайтесь вызывать интерактивные вопросы внутри серверных процедур модуля объекта. Это приведет к ошибке выполнения, так как серверный код не может взаимодействовать с пользователем. Кроме того, помните о транзакциях: пока висит вопрос, транзакция не должна быть открыта, иначе вы рискуете заблокировать таблицы базы данных для других пользователей на все то время, пока ваш пользователь «ходит пить кофе», не ответив на вопрос.

Именно поэтому мы используем схему: Клиент (Проверка + Вопрос) -> Отказ от записи -> Повторная запись с флагом. Это единственный корректный способ работы с интерактивностью в управляемом интерфейсе 1С.

← На главную