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