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