В процессе разработки часто возникает ситуация, когда при проведении документа необходимо уточнить что-то у пользователя. Например: "Остаток товара на складе меньше нормы. Все равно продолжить?" или "Изделие уже было изготовлено. Продолжить?". Однако попытка вызвать функцию Вопрос непосредственно в процедуре ОбработкаПроведения приводит к ошибке: "Процедура или функция с указанным именем не определена". В этой статье мы разберем, почему так происходит, и как правильно реализовать подобную логику, соблюдая стандарты разработки 1С.
Для начала выясним причину этого ограничения. Процедура ОбработкаПроведения всегда выполняется в контексте &НаСервере. На сервере "нет монитора": там выполняется программный код, который не имеет прямого доступа к интерфейсу пользователя. Но главная причина кроется в архитектуре базы данных. Проведение документа всегда происходит внутри транзакции.
Разберем ситуацию: если бы сервер мог "повесить" окно вопроса, вся база данных (или её значительная часть) оказалась бы заблокированной до тех пор, пока пользователь не нажмет кнопку. Если пользователь уйдет пить чай, оставив окно вопроса открытым, другие сотрудники не смогут работать с заблокированными таблицами. Это приведет к ошибкам "Превышено время ожидания блокировки". Поэтому интерактивные действия внутри транзакции строго запрещены.
Самый простой и правильный путь — задать вопрос до того, как начнется транзакция записи и проведения. Мы проанализируем ситуацию на клиенте, в модуле формы документа. Для этого воспользуемся событием ПередЗаписью.
Рассмотрим пример кода в модуле формы документа:
&НаКлиенте
Процедура ПередЗаписью(Отказ, ПараметрыЗаписи)
// Если документ проводится, выполним проверку
Если ПараметрыЗаписи.РежимЗаписи = РежимЗаписиДокумента.Проведение Тогда
// Проверка условия (может быть серверной функцией)
Если ИзделиеУжеИзготовлено() Тогда
// Используем асинхронный метод для соответствия современным стандартам
ОписаниеОповещения = Новый ОписаниеОповещения("ПослеВопросаОПродолжении", ЭтотОбъект, ПараметрыЗаписи);
ПоказатьВопрос(ОписаниеОповещения, "Изделие уже было изготовлено. Продолжить?", РежимДиалогаВопрос.ДаНет);
// Отменяем текущую запись, чтобы дождаться ответа пользователя
Отказ = Истина;
Возврат;
КонецЕсли;
КонецЕсли;
КонецПроцедуры
&НаКлиенте
Процедура ПослеВопросаОПродолжении(Результат, ДополнительныеПараметры) Экспорт
Если Результат = КодВозвратаДиалога.Да Тогда
// Если пользователь согласился, записываем документ снова,
// но уже без повторного вопроса (нужно предусмотреть флаг)
ЭтаФорма.Записать(ДополнительныеПараметры);
КонецЕсли;
КонецПроцедуры
Иногда логика проверки сложная, и её невозможно полностью вынести на клиент. В таком случае мы можем использовать механизм ДополнительныеСвойства. Это "рюкзак", который передается вместе с объектом с клиента на сервер.
Посмотрим на алгоритм реализации этого метода:
ПоказатьВопрос.ПередЗаписью или ОбработкаПроведения мы проверяем наличие этого флага.Пример кода в модуле объекта:
Процедура ОбработкаПроведения(Отказ, РежимПроведения)
// Проверяем флаг подтверждения, переданный из формы
ПодтвержденоПользователем = Ложь;
Если ДополнительныеСвойства.Свойство("ПодтвержденоИзготовление", ПодтвержденоПользователем) Тогда
// Флаг есть, действуем согласно логике
КонецЕсли;
Если ПроверкаУсловия() И Не ПодтвержденоПользователем Тогда
Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = "Проведение отменено: требуется подтверждение изготовления.";
Сообщение.Сообщить();
Отказ = Истина;
Возврат;
КонецЕсли;
// Логика формирования движений
// ...
КонецПроцедуры
Проанализируем важный нюанс: ваш документ может проводиться не только пользователем вручную, но и регламентным заданием или обработкой "Групповое перепроведение документов". В этих случаях никакого "пользователя" нет, и ПоказатьВопрос на клиенте просто не сработает.
Для таких ситуаций профессиональные разработчики используют свойство ОбменДанными.Загрузка или анализируют ПараметрыСеанса. Если документ проводится программно, решение (проводить или нет при нарушении условий) должно приниматься автоматически на основе бизнес-логики, без вызова диалоговых окон.
Мы выяснили, что интерактивность на сервере невозможна из-за технических ограничений платформы и рисков блокировки базы данных. Чтобы реализовать вопрос пользователю при проведении, придерживайтесь следующих правил:
ПередЗаписью.ПоказатьВопрос, ОписаниеОповещения), так как модальные окна устарели.ДополнительныеСвойства объекта.Такой подход сделает вашу конфигурацию стабильной, быстрой и соответствующей стандартам разработки 1С:Предприятие 8.3.