Как обойти ошибку «Переменная не определена (РежимДиалогаВопрос)» при проведении документа через веб-сервис в закрытом модуле 1С?

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

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

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

---

Почему возникает ошибка и почему не помогает «ОбменДанными.Загрузка = Истина»?

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

Если в коде модуля объекта присутствует вызов интерактивного окна, написанный без использования директив препроцессора (таких как #Если Клиент Тогда), то при любой попытке сервера скомпилировать этот модуль произойдет аварийное завершение работы.

Многие разработчики надеются обойти проблему, используя стандартное свойство ОбменДанными.Загрузка = Истина. Рассмотрим, почему этот способ абсолютно бесполезен в данном сценарии:

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

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

---

Решение 1: Метод виртуальных заглушек (эмуляция контекста)

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

Выполним по шагам настройку заглушек в конфигураторе:

Шаг 1. Создание общего модуля «РежимДиалогаВопрос»

Создадим новый общий модуль в конфигурации:

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


Функция ДаНет() Экспорт
    Возврат Неопределено;
КонецФункции

Функция ДаНетОтмена() Экспорт
    Возврат Неопределено;
КонецФункции

Функция ОК() Экспорт
    Возврат Неопределено;
КонецФункции

Шаг 2. Создание общего модуля «КодВозвратаДиалога»

Точно так же создадим второй общий модуль для эмуляции кодов возврата диалоговых окон:

Пропишем в нем функции-заглушки:


Функция Да() Экспорт
    Возврат Истина; // Или другое дефолтное значение для прохождения проверок
КонецФункции

Функция Нет() Экспорт
    Возврат Ложь;
КонецФункции

Функция ОК() Экспорт
    Возврат Истина;
КонецФункции

Шаг 3. Создание глобального обработчика функции «Вопрос»

Если закрытый код вызывает саму функцию Вопрос(), нам потребуется переопределить её в глобальном контексте. Создадим общий модуль:

Внутри модуля определим функцию Вопрос(), которая перехватит вызовы на сервере:


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

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

---

Решение 2: Перенос проведения в регламентное задание (Архитектурный обход)

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

Поскольку проводить документ напрямую в контексте выполнения веб-сервиса нельзя из-за ошибок компиляции, мы разделим процесс на два независимых этапа:

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

Рассмотрим, как запустить проведение на стороне сервера/клиента, чтобы обойти ошибку:

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

  1. На сервере настраивается планировщик задач Windows или Cron, запускающий 1С под служебным пользователем в режиме толстого клиента: 1cv8.exe ENTERPRISE /F "ПутьКБазе" /N "РоботПроведения" /P "Пароль" /C "ЗапускОбработкиПроведения"
  2. В модуле управляемого приложения (или обычного приложения) в обработчике ПриНачалеРаботыСистемы пишем логику:
    
    Процедура ПриНачалеРаботыСистемы()
        ПараметрыЗапускаПереданы = ПараметрыЗапуска;
        Если ПараметрыЗапускаПереданы = "ЗапускОбработкиПроведения" Тогда
            // Вызываем обработку, которая выбирает документы из очереди и проводит их
            ОбработатьОчередьПроведения();
            ЗавершитьРаботуСистемы(Ложь);
        КонецЕсли;
    КонецПроцедуры
    

В режиме толстого клиента переменная РежимДиалогаВопрос определена на уровне платформы, поэтому проведение пройдет абсолютно штатно и без ошибок.

---

Решение 3: Декомпиляция и патчинг закрытого модуля

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

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


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

Если Ответ = КодВозвратаДиалога.Да Тогда
    // Основная логика проведения
КонецЕсли;

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

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

---

Резюме и рекомендации

Мы подробно разобрали проблему и изучили несколько путей ее решения. На практике рекомендуем придерживаться следующей последовательности действий:

← На главную