Как правильно запретить изменение документа в 1С по условию

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

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

Разбор типичных ошибок при сравнении данных

Рассмотрим ситуацию, когда разработчик пытается сравнить ссылочный тип (например, СправочникСсылка.Контрагенты) со строкой. Проанализируем пример неудачного кода:


Переменная1 = "Частный покупатель"; 
СтроковоеПредставление = Строка(Объект.Контрагент.ПолучитьОбъект()); 
Если Найти(Строка(ПользователиКлиентСервер.ТекущийПользователь), "Администратор") И СтроковоеПредставление = Переменная1 Тогда 
    Отказ = Истина; 
    Сообщить("Изменение запрещено!"); 
КонецЕсли;

В этом фрагменте допущено сразу несколько критических ошибок, которые мы сейчас разберем по шагам:

  1. Использование ПолучитьОбъект() для получения строки: Вызов метода ПолучитьОбъект() выгружает все данные элемента из базы данных в оперативную память. Если вам нужно просто получить наименование, это крайне непроизводительно. Для получения строкового представления ссылки достаточно использовать функцию Строка(Ссылка).
  2. Сравнение ссылки со строкой: Ссылка на объект базы данных и текстовая строка «Частный покупатель» — это разные типы данных. Сравнение Объект.Контрагент = "Частный покупатель" всегда будет давать Ложь.
  3. Поиск пользователя по имени: Проверка подстроки «Администратор» в имени пользователя — это ненадежно. Имя пользователя может быть изменено, или в системе может появиться пользователь «Иван Администраторов», который не обладает правами администратора, но подпадет под условие.

Где именно размещать код запрета

Выясним, где должен располагаться программный код для надежной защиты данных. Если мы разместим проверку только в модуле формы, то запрет можно будет легко обойти с помощью внешней обработки или группового изменения реквизитов.

Правильное решение: Размещать проверку в Модуле объекта в обработчике ПередЗаписью. Это гарантирует выполнение условия при любой попытке записи документа в базу данных.


Процедура ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)
    // Проверка на уровне объекта
    Если ЗначениеЗаполнено(Контрагент) И Контрагент.Код = "00001" Тогда
        Если НЕ РольДоступна("ПолныеПрава") Тогда
            Отказ = Истина;
            Сообщить("У вас нет прав на редактирование документов по данному контрагенту!");
        КонецЕсли;
    КонецЕсли;
КонецПроцедуры

Оптимальные способы идентификации объектов

Проанализируем ситуацию: как программе понять, что перед ней именно «тот самый» контрагент? Сравнение по наименованию — плохая практика, так как пользователь может исправить букву в названии, и проверка перестанет работать.

Рассмотрим альтернативные варианты:

  1. Поиск по уникальному коду: Реквизит Код в справочниках обычно уникален. Сравнение Объект.Контрагент.Код = "001" гораздо надежнее поиска по имени.
  2. Использование ИНН и КПП: Для юридических лиц это самый надежный способ идентификации, так как эти данные уникальны в рамках страны.
  3. Предопределенные элементы: Если «Частный покупатель» создан в конфигураторе как предопределенный элемент, код будет максимально лаконичным: Если Контрагент = Справочники.Контрагенты.ЧастныйПокупатель Тогда ...

Оптимизация производительности: обращение через точку

Посмотрим на распространенную конструкцию Объект.Контрагент.Наименование. В 1С обращение через точку от ссылки к реквизиту приводит к неявному запросу к базе данных, при котором считываются все поля объекта. Если таких проверок много, система начнет «тормозить».

Профессиональный подход заключается в использовании функций библиотеки стандартных подсистем (БСП) или получении только нужных полей:


// Если используется БСП
Наименование = ОбщегоНазначения.ЗначениеРеквизитаОбъекта(Объект.Контрагент, "Наименование");

// Если нужно просто строковое представление ссылки без лишних запросов
Представление = Строка(Объект.Контрагент);

Как сделать проверку гибкой: использование настроек

Представим, что завтра список «запрещенных» контрагентов изменится. Если вы «зашили» код или ИНН прямо в программный код, вам придется снова вызывать программиста и обновлять конфигурацию.

Проанализируем, как сделать решение гибким. Лучше всего создать Регистр сведений (например, «НастройкиЗапретаРедактирования»), куда администратор сможет сам добавлять контрагентов, по которым нужно ограничить доступ. В коде проверка будет выглядеть так:


МенеджерЗаписи = РегистрыСведений.НастройкиЗапретаРедактирования.СоздатьКлючЗаписи(Новый Структура("Контрагент", Объект.Контрагент));
Если РегистрыСведений.НастройкиЗапретаРедактирования.СоздатьМенеджерЗаписи().Выбрать().Следующий() Тогда
    // Если запись в регистре найдена, значит действует запрет
    Отказ = Истина;
КонецЕсли;

Визуальный контроль (User Experience)

Разобравшись с защитой на уровне записи, подумаем о пользователе. Очень неудобно заполнять огромный документ 20 минут, чтобы в конце получить сообщение «Низзя».

Посмотрим, как улучшить интерфейс. В модуле формы в процедуре ПриЧтенииНаСервере мы можем заблокировать форму для редактирования сразу при открытии:


&НаСервере
Процедура ПриЧтенииНаСервере(ТекущийОбъект)
    // Проверяем условия запрета
    Если ТекущийОбъект.Контрагент.Наименование = "Частный покупатель" Тогда
        ТолькоПросмотр = Истина;
    КонецЕсли;
КонецПроцедуры

Это сделает поля недоступными для ввода, и пользователь сразу увидит, что документ предназначен только для просмотра.

Заключение

Подводя итог, при реализации запрета изменения документа по условию, мы рекомендуем придерживаться следующих правил:

Соблюдение этих принципов позволит создать надежную и удобную систему разграничения прав доступа в ваших конфигурациях.

← На главную