Как запретить редактирование справочников в периферийной базе РИБ, сохранив возможность программной загрузки

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

В процессе эксплуатации распределенных информационных баз (РИБ) часто возникает задача разграничения полномочий между центральным офисом и филиалами. Одной из наиболее острых проблем является необходимость запретить пользователям в периферийных узлах создавать или изменять элементы справочников (НСИ), чтобы избежать дублирования данных и нарушений ссылочной целостности при обмене. При этом крайне важно сохранить возможность автоматической загрузки данных из других систем (например, из ЗУП) и корректную работу самого механизма обмена данными. В этой статье мы подробно разберем, как реализовать такой механизм программно, не создавая дублей пользователей и не усложняя структуру ролей.

Анализ проблемы и выбор стратегии

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

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

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

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


Процедура ПроверитьПраваНаИзменениеНСИПередЗаписью(Источник, Отказ) Экспорт
    
    // 1. Проверяем, не идет ли загрузка данных (обмен или внешняя загрузка)
    Если Источник.ОбменДанными.Загрузка Тогда
        Возврат;
    КонецЕсли;

    // 2. Определяем, является ли текущая база периферийной
    Если ПланыОбмена.ГлавныйУзел() = Неопределено Тогда
        // Это центральная база, здесь изменения разрешены
        Возврат;
    КонецЕсли;

    // 3. Проверяем наличие специальной роли-исключения
    Если РольДоступна("РазрешитьРедактированиеВПериферии") Тогда
        Возврат;
    КонецЕсли;

    // 4. Если дошли до сюда, значит это попытка интерактивного изменения в РИБ
    Отказ = Истина;
    Сообщить("В данной базе создание и изменение справочников запрещено! Обратитесь в центральный офис.");
    
КонецПроцедуры

В данном коде мы используем свойство ОбменДанными.Загрузка. Это ключевой момент: при выполнении обмена данными или при программной загрузке из других систем (если разработчик обработки установил этот флаг), проверка будет проигнорирована. Метод ПланыОбмена.ГлавныйУзел() позволяет нам однозначно определить, что код выполняется именно в периферийной базе.

Использование события ОбработкаПроверкиЗаполнения

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

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


Процедура ОбработкаПроверкиЗаполнения(Источник, Отказ, ПроверяемыеРеквизиты) Экспорт
    
    // Проверка на периферийный узел
    Если ПланыОбмена.ГлавныйУзел() <> Неопределено Тогда
        Отказ = Истина;
        Сообщить("Интерактивное изменение справочников в филиалах заблокировано.");
    КонецЕсли;

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

Однако стоит учитывать, что этот метод менее надежен, чем ПередЗаписью, так как его можно обойти, если в коде сторонней обработки вызывается проверка заполнения. Поэтому первый вариант с ПередЗаписью является предпочтительным для обеспечения строгой безопасности данных.

Применение расширений для настройки интерфейса

Чтобы повысить удобство работы пользователей (User Experience), мы можем не просто выдавать ошибку при попытке записи, а превентивно блокировать возможность редактирования в интерфейсе. Для этого отлично подходят расширения конфигурации. В расширении можно перехватить событие ПриСозданииНаСервере для всех форм справочников.

Выполним следующие действия в расширении:

  1. Создадим общий модуль или добавим код в модуль формы справочника.
  2. Проверим признак периферийной базы.
  3. Установим свойство формы ТолькоПросмотр в значение Истина.

&НаСервере
Процедура ЗапретРедактирования_ПриСозданииНаСервереПосле(Отказ, СтандартнаяОбработка)
    
    Если ПланыОбмена.ГлавныйУзел() <> Неопределено Тогда
        // Проверяем, не является ли пользователь администратором
        Если Не РольДоступна("ПолныеПрава") Тогда
            ЭтаФорма.ТолькоПросмотр = Истина;
        КонецЕсли;
    КонецЕсли;
    
КонецПроцедуры

Этот подход хорош тем, что пользователь сразу видит: форма доступна только для чтения. Кнопки "Записать" и "ОК" становятся неактивными, что исключает напрасный ввод данных, который в итоге нельзя будет сохранить. При этом программная запись объекта через Объект.Записать() продолжит работать, так как формы при программной работе не создаются.

Использование функциональных опций

Рассмотрим более архитектурный подход с использованием функциональных опций. Мы можем создать константу ЗапретитьРедактированиеНСИ и связать ее с функциональной опцией, которая управляет доступностью элементов интерфейса. В центральной базе значение константы будет установлено в Ложь, а в периферийных — в Истина.

Преимущества этого метода:

Итоги и рекомендации

Мы проанализировали несколько способов решения задачи. Подведем итог: для обеспечения максимальной надежности стоит комбинировать подписку на событие ПередЗаписью (как гарант целостности данных на уровне сервера) и расширение форм (для удобства пользователя). Важно помнить про проверку ОбменДанными.Загрузка, чтобы не парализовать работу самой системы РИБ. Использование метода с определением главного узла через ПланыОбмена.ГлавныйУзел() избавляет нас от необходимости создавать сложные наборы ролей или дублировать учетные записи пользователей для разных филиалов. Такой подход делает конфигурацию более гибкой и легкой в поддержке.

← На главную