В процессе разработки и сопровождения конфигураций на платформе 1С:Предприятие 8, особенно таких как УПП 1.3 или других решений на обычных формах, часто возникает задача ограничить создание подчиненных документов. Типичный сценарий: пользователю нужно запретить ввод на основании, если документ-родитель находится в определенном статусе или не заполнены важные реквизиты. При этом разработчики часто стремятся найти решение, которое не потребует внесения изменений в десятки модулей подчиненных объектов.
В данной статье мы подробно проанализируем ситуацию, разберем причины технических сложностей с обычными формами и изучим несколько эффективных способов реализации запрета — от манипуляций с интерфейсом до глобального перехвата на уровне объектов.
Рассмотрим ситуацию, когда нам необходимо скрыть или деактивировать кнопку Ввести на основании непосредственно в форме документа-источника. Основная сложность в обычных формах заключается в том, что кнопка ввода на основании часто является частью системного подменю, создаваемого платформой автоматически.
Выясним причину, по которой стандартное свойство Доступность может не работать для подменю. Как было замечено в обсуждении, свойства кнопок в конфигураторе могут быть «затенены», а программное изменение ЭлементыФормы.КоманднаяПанель.Кнопки.Подменю.Доступность = Ложь; не приносит результата. Это связано с тем, что платформенные механизмы отрисовки обычных форм жестко управляют составом стандартных команд при включенном свойстве Автозаполнение.
Чтобы обойти это ограничение, проанализируем следующий алгоритм действий:
Автозаполнение у командной панели (если это допустимо) и сформируйте кнопки вручную.Посмотрим на пример кода, который позволяет найти и отключить нужную кнопку в процедуре ПриОткрытии или в специализированной процедуре обновления интерфейса:
Процедура ОбновитьДоступностьКнопокВводаНаОсновании()
// Определим условие, при котором ввод запрещен
Если ДокументОбъект.Статус = Перечисления.СтатусыДокументов.Заблокирован Тогда
// Перебираем кнопки основной командной панели формы
Для Каждого Кнопка Из ЭлементыФормы.ОсновныеДействияФормы.Кнопки Цикл
// Кнопка "Ввести на основании" может быть подменю
Если Кнопка.ТипКнопки = ТипКнопкиКоманднойПанели.Подменю Тогда
// В типовых решениях имя кнопки часто "ПодменюВвестиНаОсновании"
// Если имя не задано, можно проверять текст или состав вложенных кнопок
Если Найти(Кнопка.Текст, "Ввести на основании") > 0 Тогда
Кнопка.Доступность = Ложь;
КонецЕсли;
КонецЕсли;
КонецЦикла;
КонецЕсли;
КонецПроцедуры
Важно помнить, что в обычных формах существует также системное меню Действия, которое дублирует основные команды. Управление его элементами программно ограничено, поэтому визуальное скрытие кнопок не является 100% гарантией защиты от ввода, так как пользователь может воспользоваться горячими клавишами или системным меню окна.
Разберем более надежный и «чистый» с точки зрения архитектуры метод. Если задача стоит в запрете создания 10 различных видов документов на основании одного «родителя», то изменять каждый из 10 документов крайне неэффективно. Вместо этого мы можем использовать механизм Подписки на события.
Проанализируем шаги по реализации этого метода:
ДокументОбъект для максимального охвата).ОбработкаЗаполнения.Этот метод хорош тем, что он срабатывает всегда, независимо от того, как инициирован ввод: через кнопку в форме, через меню «Действия» или программно методом Заполнить(). Посмотрим на пример кода в общем модуле:
Процедура ПодпискаНаОбработкуЗаполнения(Источник, ДанныеЗаполнения, ТекстЗаполнения, СтандартнаяОбработка) Экспорт
// Проверяем, что заполнение происходит на основании другого документа
Если ТипЗнч(ДанныеЗаполнения) = Тип("ДокументСсылка.ЗаказПокупателя") Тогда
// Проверяем условие запрета в родительском документе
Если ДанныеЗаполнения.ЗаблокированДляНаследования Тогда
// В ОбработкеЗаполнения нет параметра "Отказ".
// Чтобы прервать процесс, вызываем исключение.
ТекстСообщения = "Ввод на основании этого документа запрещен согласно корпоративной политике!";
ВызватьИсключение ТекстСообщения;
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Важный нюанс: так как в событии ОбработкаЗаполнения отсутствует параметр Отказ, использование ВызватьИсключение — это единственный способ жестко прервать создание нового объекта и вывести пользователю информационное окно. Это решение является наиболее универсальным, так как оно централизованно описывает логику для всех подчиненных документов сразу.
Рассмотрим ситуацию, когда исключение (ошибка) кажется слишком резким методом, и мы хотим более мягко закрывать форму нового документа. В этом случае мы можем внедрить проверку в общие модули, которые отвечают за открытие форм в конфигурации (в УПП 1.3 это часто модули типа РаботаСДиалогами или механизмы управления интерфейсом).
Суть метода заключается в том, чтобы в процедуре ПередОткрытием создаваемого документа проанализировать наличие заполненного реквизита ДокументОснование. Если условие не соблюдается, мы устанавливаем Отказ = Истина.
Для реализации этого без изменения кода каждого документа, в УПП 1.3 можно использовать «точки входа» в общих модулях, которые вызываются из типовых шаблонов форм документов:
// В общем модуле, вызываемом из ПередОткрытием документов
Процедура ПроверитьВозможностьОткрытияНаОсновании(Форма, Отказ) Экспорт
ОбъектДок = Форма.ДокументОбъект;
// Проверяем наличие реквизита и его заполненность
Если Метаданные.Документы[ОбъектДок.Метаданные().Имя].Реквизиты.Найти("ДокументОснование") <> Неопределено Тогда
Основание = ОбъектДок.ДокументОснование;
Если ЗначениеЗаполнено(Основание) И ТипЗнч(Основание) = Тип("ДокументСсылка.КритичныйДокумент") Тогда
Если Основание.ЗапретитьНаследование Тогда
Сообщить("Создание документа на основании данного источника невозможно.");
Отказ = Истина;
КонецЕсли;
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Мы рассмотрели три основных подхода к решению задачи. Выбор метода зависит от ваших приоритетов:
Кнопки в каждой форме-родителе.Проанализировав все варианты, мы рекомендуем комбинировать Метод 1 (для визуальной чистоты интерфейса) и Метод 2 (для обеспечения реальной безопасности данных и предотвращения обхода ограничений через системные меню).