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