Как вывести список зависимых объектов при установке пометки на удаление в управляемой форме?

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

В практике разработки на платформе 1С:Предприятие 8 часто возникает задача: пользователь помечает на удаление элемент непосредственно из формы списка (не открывая форму элемента), а система должна предупредить его о том, где данный элемент уже задействован, или вовсе заблокировать операцию. Разберем ограничения платформы, особенности работы клиент-серверной архитектуры и надежные способы решения этой задачи.

Ограничения платформы в управляемом интерфейсе

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

  1. Отсутствие клиентского события пометки в динамическом списке. В обычном приложении у табличного поля существовало событие ПередУстановкойПометкиУдаления. В управляемом интерфейсе у таблицы формы с источником «Динамический список» такого события нет. Стандартное событие таблицы ПередУдалением вызывается исключительно при физической попытке удаления записи (комбинация Shift + Del), но не реагирует на обычное нажатие клавиши Del или команду контекстного меню «Пометить на удаление / Снять пометку».
  2. Невозможность интерактива на сервере. Процедуры модуля объекта (ПередЗаписью, ПриЗаписи) и подписки на события выполняются строго на стороне сервера внутри транзакции записи. В этом контексте запрещены любые интерактивные вызовы: ОткрытьФорму, ПоказатьВопрос или Предупреждение. Сервер не может приостановить выполнение кода и ожидать ответа пользователя на клиенте.

Способ 1. Контроль в модуле объекта и вывод через СообщениеПользователю

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

Для корректной работы алгоритма необходимо соблюдать важные условия:

  1. Проверять свойство ОбменДанными.Загрузка, чтобы проверка не блокировала синхронизацию данных и пакетные обмены.
  2. Проверять факт установки пометки: текущее состояние ЭтотОбъект.ПометкаУдаления должно быть истинным, а исходное состояние в базе ЭтотОбъект.Ссылка.ПометкаУдаления — ложным.
  3. Использовать объект СообщениеПользователю или функцию ОбщегоНазначения.СообщитьПользователю из Библиотеки стандартных подсистем (БСП). Установка свойства КлючДанных превращает сообщение на клиенте в гиперссылку, по клику на которую открывается использующий документ.

Посмотрим на пример реализации в модуле объекта:


Процедура ПередЗаписью(Отказ)
	
	Если ОбменДанными.Загрузка Тогда
		Возврат;
	КонецЕсли;
	
	// Проверяем, что пометка именно устанавливается, а не снимается
	Если ЭтотОбъект.ПометкаУдаления И НЕ ЭтотОбъект.Ссылка.ПометкаУдаления Тогда
		
		// Получаем ссылки, где используется текущий объект
		МассивСсылок = Новый Массив;
		МассивСсылок.Добавить(Ссылка);
		
		ТаблицаСсылок = НайтиПоСсылкам(МассивСсылок);
		
		Если ТаблицаСсылок.Количество() > 0 Тогда
			
			// Ограничиваем вывод первыми несколькими записями, чтобы не перегружать интерфейс
			МаксКоличество = Мин(ТаблицаСсылок.Количество(), 5);
			
			Для Индекс = 0 По МаксКоличество - 1 Цикл
				СтрокаДанных = ТаблицаСсылок[Индекс];
				
				Сообщение = Новый СообщениеПользователю;
				Сообщение.Текст = "Объект используется в: " + Строка(СтрокаДанных.Данные);
				Сообщение.КлючДанных = СтрокаДанных.Данные;
				Сообщение.Сообщить();
			КонецЦикла;
			
			Если ТаблицаСсылок.Количество() > МаксКоличество Тогда
				ОбщегоНазначения.СообщитьПользователю(
					СтрШаблон("И еще в %1 местах...", ТаблицаСсылок.Количество() - МаксКоличество)
				);
			КонецЕсли;
			
			// Если требуется полностью запретить установку пометки:
			// Отказ = Истина;
			
		КонецЕсли;
		
	КонецЕсли;
	
КонецПроцедуры

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

Опасность НайтиПоСсылкам и оптимизация производительности

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

Чтобы избежать проблем с производительностью, заменим универсальный поиск ссылок прямым точечным запросом к ключевым регистрам или документам, где появление объекта критично:


Запрос = Новый Запрос;
Запрос.Текст = 
	"ВЫБРАТЬ ПЕРВЫЕ 5
	|	Таблица.Ссылка КАК Ссылка
	|ИЗ
	|	Документ.ЗаказКлиента.Товары КАК Таблица
	|ГДЕ
	|	Таблица.Номенклатура = &Номенклатура";

Запрос.УстановитьПараметр("Номенклатура", Ссылка);
Выборка = Запрос.Выполнить().Выбрать();

Пока Выборка.Следующий() Цикл
	ОбщегоНазначения.СообщитьПользователю(
		"Товар найден в заказе!", 
		Выборка.Ссылка
	);
КонецЦикла;

Способ 2. Замена стандартной команды в форме списка

Если бизнес-требования диктуют интерактивный сценарий: открыть диалоговое окно со списком ссылок и спросить пользователя «Объект используется в 10 документах. Вы уверены, что хотите пометить его на удаление?», перехватывать событие в модуле объекта нельзя. Всю цепочку потребуется перенести на клиентский уровень формы списка.

Разберем пошаговый алгоритм настройки формы списка:

  1. Открываем форму списка справочника или документа в конфигураторе.
  2. В свойствах командной панели таблицы отключаем видимость стандартной команды ПометитьНаУдаление (или убираем автозаполнение командной панели).
  3. Создаем собственную команду формы, например, УстановитьПометкуУдаленияПользовательская, выносим её на командную панель и назначаем ей сочетание клавиш Del.
  4. В клиентском обработчике команды получаем текущую строку таблицы (выделенный элемент) и обращаемся к серверной функции для анализа связанных объектов.
  5. Если связи найдены, открываем модальную или блокирующую форму со списком ссылок либо выводим вопрос через ПоказатьВопрос.
  6. Если пользователь подтвердил действие или ссылки отсутствуют, вызываем серверную процедуру, которая программно устанавливает пометку методом Объект.УстановитьПометкуУдаления(Истина).

Посмотрим на пример клиентского кода в форме списка:


&НаКлиенте
Процедура КомандаПометитьНаУдаление(Команда)
	
	ТекущиеДанные = Элементы.Список.ТекущиеДанные;
	Если ТекущиеДанные = Неопределено Тогда
		Возврат;
	КонецЕсли;
	
	ВыбраннаяСсылка = ТекущиеДанные.Ссылка;
	
	// Проверяем наличие связей на сервере
	КоличествоСсылок = ПроверитьИспользованиеНаСервере(ВыбраннаяСсылка);
	
	Если КоличествоСсылок > 0 Тогда
		Оповещение = Новый ОписаниеОповещения("ПослеОтветаНаВопросОПометке", ЭтотОбъект, ВыбраннаяСсылка);
		ТекстВопроса = СтрШаблон("Объект используется в других данных (%1 мест). Все равно пометить на удаление?", КоличествоСсылок);
		ПоказатьВопрос(Оповещение, ТекстВопроса, РежимДиалогаВопрос.ДаНет);
	Иначе
		УстановитьПометкуНаСервере(ВыбраннаяСсылка, Истина);
	КонецЕсли;

КонецПроцедуры

&НаКлиенте
Процедура ПослеОтветаНаВопросОПометке(Результат, ДополнительныеПараметры) Экспорт
	Если Результат = КодВозвратаДиалога.Да Тогда
		УстановитьПометкуНаСервере(ДополнительныеПараметры, Истина);
		Элементы.Список.Обновить();
	КонецЕсли;
КонецПроцедуры

Таким образом, для простых сценариев и жестких запретов оптимально использовать серверный метод СообщениеПользователю в процедуре ПередЗаписью. Для сценариев с интерактивным выбором и подтверждением пользователя следует переопределять стандартную команду удаления в форме списка.

← На главную