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

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

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

Причина возникновения ошибки: Контекстное разделение

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

Решение 1: Использование инструкций препроцессора

Самый быстрый и простой способ — это ограничить выполнение интерактивного кода с помощью инструкций препроцессора. Это позволит компилятору «выкинуть» ненужный код при выполнении на сервере. Проанализируем ситуацию на примере:


#Если Клиент Тогда
    // Этот блок кода будет виден только в толстом или тонком клиенте
    Ответ = Вопрос("Вы уверены, что хотите продолжить проведение?", РежимДиалога.ДаНет);
    Если Ответ <> РежимДиалогаОтвет.Да Тогда
        Отказ = Истина;
        Возврат;
    КонецЕсли;
#КонецЕсли

Важно помнить, что использование #Если Клиент в модуле объекта может быть недостаточно, если вы используете переменные, которые должны быть определены в обоих контекстах. Поэтому лучше комбинировать препроцессор с проверкой типа соединения.

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

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

Шаг 1. Подготовка в форме документа или внешней обработке:

Перед тем как вызвать метод Записать(), мы добавляем в объект специальный флаг.


// В коде, который запускает проведение интерактивно
ДокументОбъект = РеквизитФормыВЗначение("Объект");
ДокументОбъект.ДополнительныеСвойства.Вставить("ЭтоИнтерактивноеПроведение", Истина);
ДокументОбъект.Записать(РежимЗаписиДокумента.Проведение);

Шаг 2. Проверка в модуле объекта:

В обработчике ОбработкаПроведения мы проверяем наличие этого флага. Если его нет — значит, документ проводится регламентным заданием, и вопросы задавать не нужно.


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

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

Решение 3: Использование признака ОбменДанными.Загрузка

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


// В регламентном задании
НовыйДок = Документы.ПоступлениеТоваровУслуг.СоздатьДокумент();
// Заполнение реквизитов...
НовыйДок.ОбменДанными.Загрузка = Истина; 
НовыйДок.Записать(РежимЗаписиДокумента.Проведение);

Важное предостережение: Установка Загрузка = Истина отключает не только вопросы, но и почти все встроенные проверки бизнес-логики. Используйте этот метод только если вы уверены, что данные, записываемые регламентным заданием, абсолютно корректны.

Решение 4: Рефакторинг и вынос логики в форму

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

  1. Перенесите вопрос в модуль формы: Используйте обработчик ПередЗаписью на клиенте.
  2. Асинхронность: В современных конфигурациях используйте ПоказатьВопрос() с описанием оповещения.
  3. Логика на сервере: Если серверу нужно сообщить о проблеме, используйте Сообщить() или записывайте информацию в Журнал Регистрации.

Пример правильной реализации в форме документа:


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

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

Рекомендация по проверке типа сеанса

Проанализируем ситуацию, когда вам нужно программно понять, запущено ли выполнение кода в фоновом задании. Для этого можно использовать метод ПолучитьТекущийСеансИнформационнойБазы(). Если свойство ИмяПриложения равно BackgroundJob (ФоновоеЗадание), выполнение любого интерактивного кода должно быть строго запрещено.

Подведем итог: Чтобы регламентные задания не «падали» с ошибкой, всегда проверяйте контекст исполнения. Лучшим решением будет использование ДополнительныеСвойства для передачи флагов управления или полный перенос диалогов в клиентские модули форм.

← На главную