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