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

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

При разработке механизмов ввода на основании в конфигурациях на платформе 1С:Предприятие 8.3 (в частности, в 1С:Управление торговлей 11) разработчики часто сталкиваются с неочевидным поведением платформенных сообщений. Если логика проверки дублей реализована в подписке на событие ОбработкаЗаполнения, вызов метода ОбщегоНазначенияКлиентСервер.СообщитьПользователю или стандартного объекта СообщениеПользователю направляет уведомление не в создаваемый документ, а в окно, из которого была инициирована команда ввода (например, в форму документа-основания или форму списка).

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

Почему сообщение уходит в родительское окно

Выясним причину этой проблемы с точки зрения клиент-серверного взаимодействия управляемого интерфейса:

  1. Отсутствие контекста нового окна. В момент срабатывания подписки на событие ОбработкаЗаполнения окно создаваемого документа на стороне клиента физически еще не существует. У него отсутствует собственный уникальный идентификатор клиентского окна.
  2. Маршрутизация вызовов. Платформа 1С при формировании сообщений на сервере адресует их тому контексту, откуда поступил исходный вызов. Поскольку вызов команды ввода на основании был сделан из исходного документа, сообщение привязывается именно к нему.
  3. Отсутствие параметра Отказ в обработке заполнения. Стандартный обработчик ОбработкаЗаполнения и соответствующая подписка не содержат параметра Отказ. Прервать операцию штатным способом здесь нельзя — попытка применить ВызватьИсключение приведет к аварийной системной ошибке вместо мягкого и дружелюбного предупреждения.

Способ 1. Маркировка через дополнительные свойства и перехват в форме

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

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

Шаг 1. В обработчике подписки на событие ОбработкаЗаполнения проверяем наличие ранее созданных документов по основанию. Если дубль обнаружен, фиксируем признак в свойстве ДополнительныеСвойства объекта:


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

Шаг 2. Перехватываем контекст созданной формы. Для этого можно использовать расширение конфигурации с аннотацией &После("ПриСозданииНаСервере") модуля формы документа или воспользоваться единой точкой подключения БСП в общем модуле. Извлекаем сохраненные данные и выводим сообщение уже в контексте открываемой формы:


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

Так как вызов Сообщить() происходит на этапе ПриСозданииНаСервере формы документа, платформа связывает это сообщение именно с открывающимся окном.

Способ 2. Перехват и перенос сообщений из стека платформы

Если в подписке на событие уже сформирован большой объем информационных сообщений через ОбщегоНазначенияКлиентСервер.СообщитьПользователю, можно применить метод перехвата сообщений. Разберем, как собрать сформированные сервером сообщения и переадресовать их в новое окно:


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

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

Способ 3. Перехват команды ввода на основании на клиенте

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

В типовых решениях на базе БСП платформенные команды ввода на основании заменяются подключаемыми командами (механизм подсистемы «Подключаемые команды»). Перехватив выполнение команды в расширении клиентского модуля:

  1. Перед формированием параметров открытия формы выполняем быструю серверную функцию для проверки наличия подчиненных документов.
  2. Если документ уже существует, вызываем асинхронный диалог ПоказатьВопрос или ПоказатьПредупреждение.
  3. В диалоге можно предложить пользователю открыть уже существующий ранее созданный документ вместо ввода дубликата, либо запросить подтверждение на продолжение создания.

Такой подход полностью исключает появление лишних открытых форм в интерфейсе пользователя и экономит серверные ресурсы.

Способ 4. Использование обработчика ОбработкаПолученияФормы

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

  1. В обработчике анализируем параметр Параметры.ЗначениеЗаполнения.
  2. Если по переданному основанию документ уже введен, подменяем стандартную форму на специальную форму-предупреждение или форму списка существующих документов по этому основанию, передав ее имя в параметр ВыбраннаяФорма.
  3. Это позволяет централизованно управлять открытием окон без внесения изменений в форму самого документа.
← На главную