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

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

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

Анализ проблемы: почему сервер «не видит» клиентские методы

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

Когда программный код выполняется на стороне сервера, клиентский контекст для него полностью недоступен. Даже если процедура объявлена в одном и том же общем модуле, при компиляции на сервере все части кода, помеченные директивой &НаКлиенте, просто игнорируются. В результате сервер пытается вызвать метод ПолучитьНаКлиенте(), которого в его «памяти» не существует. Это приводит к ошибке выполнения (Runtime Error): «Процедура или функция не обнаружена».

Важно понимать: Серверная часть 1С — это процесс, который может работать вообще без участия пользователя (например, в регламентных заданиях). У него нет экрана, мыши и возможности «подождать», пока кто-то нажмет кнопку в диалоговом окне.

Решение 1: Перенос логики в форму документа

Самый правильный с точки зрения архитектуры Управляемого приложения способ — организовать интерактивное взаимодействие в модуле формы. Проанализируем, как это реализовать:

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

Рассмотрим пример кода для управляемой формы:


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

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

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

Решение 2: Использование ДополнительныхСвойств для передачи ответа на сервер

Если проверка должна выполняться в общем модуле (например, через подписку на события), мы можем использовать коллекцию ДополнительныеСвойства. Это «транспорт», который позволяет передать информацию от клиента к серверному коду объекта.

Разберем алгоритм по шагам:

  1. На клиенте в форме документа задаем вопрос.
  2. Если получен утвердительный ответ, устанавливаем флаг: Объект.ДополнительныеСвойства.Вставить("ПодтверждениеПолучено", Истина);.
  3. В серверной подписке на событие ПередЗаписью проверяем наличие этого флага.

Пример кода в серверном общем модуле:


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

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

Решение 3: Визуальная индикация вместо блокирующих вопросов

Как справедливо отмечено в обсуждении, постоянные вопросы "Уверены?" раздражают пользователей и со временем игнорируются (вырабатывается привычка нажимать "Да", не глядя). Рассмотрим альтернативные UX-подходы:

Подведем итоги

Мы выяснили, что архитектура 1С:Предприятия жестко разделяет контексты. Сервер никогда не может вызвать диалоговое окно на клиенте. Для решения вашей задачи мы проанализировали три пути:

  1. Перенос интерактивности в модуль формы через ПоказатьВопрос.
  2. Связка клиента и сервера через ДополнительныеСвойства объекта.
  3. Изменение логики интерфейса на более дружелюбную (запрет редактирования без кнопки).

Выбор конкретного метода зависит от того, насколько критично изменение данных и используете ли вы стандартные библиотеки, такие как БСП (Библиотека стандартных подсистем), где механизмы проверки и подтверждения уже частично реализованы в типовых модулях.

← На главную