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