При разработке внешних обработок для современных конфигураций (например, УТ 11, ERP или КА) программисты часто сталкиваются с ситуацией, когда код, идеально работающий в «Толстом клиенте», выдает критическую ошибку в Web-клиенте. Сообщение «Интерактивные операции недоступны» является классическим индикатором нарушения архитектуры управляемого приложения. Давайте подробно разберем, почему это происходит и как правильно переписать код, чтобы он соответствовал современным стандартам 1С.
Проанализируем ситуацию: автор темы пытается вызвать форму выбора документа прямо из процедуры, выполняемой на сервере (&НаСервереБезКонтекста). В старых версиях платформы и в режиме обычного приложения это могло работать, но в управляемом приложении, особенно в Web-клиенте, это технически невозможно.
Рассмотрим ключевые причины:
ОткрытьМодально() и ПолучитьФормуВыбора() (в контексте ожидания результата) заблокированы на уровне платформы.В коде автора используется конструкция:
&НаСервереБезКонтекста
Процедура ВыполнитьКомандуНаСервере(ОбъектыНазначения, СозданныеОбъекты)
Форма = Документы.ПеремещениеТоваров.ПолучитьФормуВыбора(); // ОШИБКА!
ВыбранныйДокумент = Форма.ОткрытьМодально(); // КРИТИЧЕСКАЯ ОШИБКА!
КонецПроцедуры
Этот код пытается заставить сервер открыть окно выбора на компьютере пользователя, дождаться, пока пользователь нажмет кнопку, и вернуть результат обратно в ту же строчку кода. Это и вызывает исключение «Интерактивные операции недоступны».
Чтобы решить задачу, нам нужно полностью разделить процесс на три этапа:
Для этого в 1С используется объект ОписаниеОповещения. Давайте посмотрим, как должен выглядеть исправленный код в модуле формы внешней обработки.
Вместо того чтобы сразу уходить на сервер, мы должны сначала подготовить «инструкцию» для платформы: что делать, когда пользователь выберет документ. Рассмотрим пример функции ВыполнитьКоманду:
&НаКлиенте
Процедура ВыполнитьКоманду(ИдентификаторКоманды, ОбъектыНазначения, СозданныеОбъекты) Экспорт
// Подготавливаем описание процедуры, которая будет вызвана ПОСЛЕ выбора
ОповещениеОЗавершении = Новый ОписаниеОповещения("ПослеВыбораДокументаПеремещение", ЭтотОбъект, ОбъектыНазначения);
// Настройки открытия формы выбора
ПараметрыВыбора = Новый Структура;
ПараметрыВыбора.Вставить("ВыборОбъекта", Истина);
// Открываем форму выбора асинхронно
ОткрытьФорму("Документ.ПеремещениеТоваров.ФормаВыбора", ПараметрыВыбора, , , , , ОповещениеОЗавершении);
КонецПроцедуры
Теперь создадим процедуру, которая «подхватит» управление, когда пользователь выберет конкретное Перемещение товаров. Эта процедура должна быть экспортной и находиться в том же модуле.
&НаКлиенте
Процедура ПослеВыбораДокументаПеремещение(РезультатВыбора, ДополнительныеПараметры) Экспорт
// Если пользователь просто закрыл окно, ничего не выбрав
Если РезультатВыбора = Неопределено Тогда
Возврат;
КонецЕсли;
// Теперь у нас есть ссылка на выбранный документ (РезультатВыбора)
// И ссылка на исходный документ из ДополнительныеПараметры (ОбъектыНазначения)
ОбъектыНазначения = ДополнительныеПараметры;
// Вызываем серверную процедуру для переноса данных
ВыполнитьПереносДанныхНаСервере(ОбъектыНазначения[0], РезультатВыбора);
ПоказатьПредупреждение(, "Данные успешно дополнены!");
КонецПроцедуры
Только теперь мы переходим на сервер, чтобы работать с базой данных. Здесь мы используем стандартные методы ПолучитьОбъект() и записываем результат. Проанализируем пример реализации:
&НаСервереБезКонтекста
Процедура ВыполнитьПереносДанныхНаСервере(СсылкаИсточник, СсылкаПриемник)
// Получаем объекты документов
ДокИсточник = СсылкаИсточник.ПолучитьОбъект();
ДокПриемник = СсылкаПриемник.ПолучитьОбъект();
// Переносим строки ТЧ
Для Каждого СтрокаИсточника Из ДокИсточник.Товары Цикл
НоваяСтрока = ДокПриемник.Товары.Добавить();
ЗаполнитьЗначенияСвойств(НоваяСтрока, СтрокаИсточника);
КонецЦикла;
// Фиксируем изменения
Попытка
ДокПриемник.Записать(РежимЗаписиДокумента.Запись);
Исключение
Инфо = ИнформацияОбОшибке();
ЗаписьЖурналаРегистрации("ВнешняяОбработка", УровеньЖурналаРегистрации.Ошибка, , , ПодробноеПредставлениеОшибки(Инфо));
ВызватьИсключение "Не удалось сохранить документ перемещения!";
КонецПопытки;
КонецПроцедуры
Если вы подключаете обработку через механизм «Дополнительные отчеты и обработки», проанализируйте настройки в функции СведенияОВнешнейОбработке (модуль объекта). Существует два основных типа команд:
ВызовСерверногоМетода: Платформа сразу прыгает на сервер. Использовать формы здесь нельзя.ВызовКлиентскогоМетода: Платформа запускает код на клиенте в модуле формы. Это именно то, что нам нужно для Web-клиента.Посмотрим на пример правильной регистрации команды:
Команда = ТаблицаКоманд.Добавить();
Команда.Представление = "Дополнить перемещение из приобретения";
Команда.Идентификатор = "ЗаполнитьПеремещение";
Команда.Использование = ДополнительныеОтчетыИОбработкиКлиентСервер.ТипКомандыВызовКлиентскогоМетода();
Команда.ПоказыватьОповещение = Истина;
В ходе обсуждения упоминалось, что использование расширений не решило проблему. Это логично: расширение не меняет фундаментальные законы платформы. Если вы напишете &После к процедуре, которая выполняется на сервере, и внутри попытаетесь вызвать форму — вы получите ту же самую ошибку «Интерактивные операции недоступны».
Более того, при отладке в Web-клиенте часто возникают сложности с точками останова. Убедитесь, что:
-debug).Для корректной работы в Web-клиенте запомните три «НЕ»:
ОткрытьМодально() — используйте ОткрытьФорму() с оповещением.&НаСервере.ПолучитьФорму() на сервере.Проанализировав ситуацию, мы видим, что переход на асинхронную модель программирования — это не просто требование Web-клиента, а обязательный стандарт разработки на платформе 1С:Предприятие 8.3. Это делает интерфейс более отзывчивым: пока пользователь выбирает документ в окне, браузер не «зависает», а продолжает корректно взаимодействовать с пользователем.