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