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

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

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

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

Причина проблемы: Асинхронность и отсутствие модальности

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

Для реализации корректного поведения нам потребуется выполнить следующие шаги:

  1. Прервать стандартный процесс записи в обработчике ПередЗаписью.
  2. Вывести вопрос пользователю.
  3. В случае положительного ответа инициировать запись повторно, но уже с «флагом», указывающим, что вопрос задавать больше не нужно.

Шаг 1. Подготовка процедуры ПередЗаписью на клиенте

Разберем ситуацию на примере документа «Оприходование товаров». Нам нужно использовать структуру ПараметрыЗаписи. Это стандартный контейнер, который «путешествует» между клиентскими и серверными процедурами записи. Мы добавим в него свойство, которое будет служить индикатором того, что пользователь уже сделал выбор.

Проанализируем пример кода для обработчика ПередЗаписью:


&НаКлиенте
Процедура ПередЗаписью(Отказ, ПараметрыЗаписи)

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

    // Останавливаем текущую стандартную запись
    Отказ = Истина;

    // Описываем оповещение, которое сработает после ответа пользователя
    ДополнительныеПараметры = Новый Структура;
    ДополнительныеПараметры.Вставить("ПараметрыЗаписи", ПараметрыЗаписи);
    
    Оповещение = Новый ОписаниеОповещения("ПослеОтветаНаВопросОКопии", ЭтотОбъект, ДополнительныеПараметры);

    ТекстВопроса = "Создать такой же документ на ИП?";
    ПоказатьВопрос(Оповещение, ТекстВопроса, РежимДиалогаВопрос.ДаНет);

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

Шаг 2. Обработка ответа пользователя

Теперь создадим процедуру, которая будет вызвана платформой, когда пользователь нажмет кнопку «Да» или «Нет». Здесь важно правильно передать решение пользователя дальше в процедуру ПослеЗаписи.


&НаКлиенте
Процедура ПослеОтветаНаВопросОКопии(Результат, ДополнительныеПараметры) Экспорт

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

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

Шаг 3. Реализация логики в ПослеЗаписи

Выясним, как использовать полученный ответ. Поскольку запись документа — процесс ответственный, создавать второй документ-копию лучше всего в процедуре ПослеЗаписи, когда мы уверены, что основной документ успешно сохранен в базе данных.


&НаКлиенте
Процедура ПослеЗаписи(ПараметрыЗаписи)

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

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

Нюансы работы с методом ВопросАсинх

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

Рассмотрим краткий пример с использованием асинхронных функций:


&НаКлиенте
Асинх Процедура ПередЗаписью(Отказ, ПараметрыЗаписи)

    Если ПараметрыЗаписи.Свойство("ПроверкаПройдена") Тогда
        Возврат;
    КонецЕсли;

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

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

Важные рекомендации

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

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

← На главную