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