Почему после обновления платформы 1С на 8.3.24 обычные пользователи не видят, кто заблокировал документ, и как это исправить?

Программист 1С v8.3 (Обычные формы) 1С:Управление торговлей Управленческий учет Торговля и дистрибуция
← На главную

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

Особенно остро эта проблема стоит в конфигурациях на обычных формах, таких как «Управление торговлей 10.3», где оперативная работа менеджеров требует быстрого взаимодействия. Давайте разберем причины этого явления и реализуем надежное техническое решение, которое вернет пользователям необходимую информацию.

Разбираемся в причинах: почему исчезло имя пользователя?

Прежде чем приступать к написанию кода, давайте поймем, почему это произошло. Это не ошибка (баг), а намеренное изменение в политике безопасности платформы 1С (Security by Design).

Начиная с версии 8.3.24, информация о сеансе, удерживающем транзакционную или объектную блокировку (имя пользователя, имя компьютера, номер сеанса), считается конфиденциальной информацией. Платформа исходит из логики, что обычному пользователю не нужно знать внутреннюю структуру учетных записей или сетевые имена компьютеров коллег.

В результате:

  1. Если ошибку блокировки получает пользователь с полными правами (или правами администрирования), платформа отдает полный текст ошибки.
  2. Если прав нет, платформа «обрезает» детализацию ошибки перед передачей её на клиент, оставляя только сам факт неудачи.

Поэтому простые попытки перехватить исключение непосредственно в форме документа или в модуле объекта (который выполняется в контексте прав текущего пользователя) не принесут результата — текст ошибки будет уже очищен платформой.

Стратегия решения: Привилегированный режим

Чтобы обойти это ограничение и вернуть функциональность, нам необходимо выполнять проверку блокировки в контексте, где ограничения прав доступа не действуют. Для этого в 1С существует Привилегированный режим.

Наш план действий будет следующим:

  1. Мы создадим специальный серверный общий модуль.
  2. В этом модуле мы попытаемся заблокировать объект.
  3. Если возникнет ошибка, мы перехватим её внутри этого модуля (пока она еще содержит ФИО блокирующего).
  4. Мы «распарсим» (разберем) текст ошибки, извлечем имя пользователя.
  5. Вернем на клиент безопасную строку с именем, которую платформа не будет блокировать.

Шаг 1. Создание общего модуля

Откроем конфигуратор. Нам понадобится создать новый Общий модуль. Назовем его, например, УправлениеБлокировкамиПривилегированный.

В свойствах модуля обязательно установим следующие флаги:

Важно: Если вы работаете в «Управление торговлей 10.3» (обычное приложение), то вызов серверных модулей возможен. Однако, если база работает в файловом варианте, разделение на клиент/сервер условно, но флаг «Привилегированный» все равно даст эффект повышения прав для конкретной процедуры.

Шаг 2. Написание программного кода проверки

В созданном модуле напишем экспортную функцию. Она будет принимать ссылку на объект, который мы хотим проверить, и возвращать текст с именем пользователя (или пустую строку, если блокировки нет).

Давайте проанализируем код функции:


Функция ПолучитьИнформациюОБлокировке(СсылкаНаОбъект) Экспорт
	
	Результат = "";
	
	// Получаем объект для попытки блокировки
	// Важно: Мы не изменяем объект, только проверяем возможность блокировки
	Попытка
		ОбъектБД = СсылкаНаОбъект.ПолучитьОбъект();
		
		// Пытаемся заблокировать
		ОбъектБД.Заблокировать();
		
		// Если удалось - сразу разблокируем, так как мы только проверяли
		ОбъектБД.Разблокировать();
		
	Исключение
		// Перехватываем ошибку ВНУТРИ привилегированного модуля.
		// Здесь текст ошибки еще полный.
		Информация = ИнформацияОбОшибке();
		
		// Получаем подробное описание ошибки
		ТекстОшибки = ПодробноеПредставлениеОшибки(Информация);
		
		// Анализируем текст ошибки для поиска имени пользователя
		// Текст обычно выглядит так:
		// "...пользователь: Иванов Иван, сеанс:..."
		
		Результат = РаспарситьИмяПользователя(ТекстОшибки);
		
		// Если не удалось распарсить, вернем общее сообщение, 
		// но можно попробовать вернуть и сырой текст, 
		// так как это уже просто строка, а не объект Exception
		Если ПустаяСтрока(Результат) Тогда
			Результат = "Объект занят, но имя определить не удалось. Детали: " + Информация.Описание;
		КонецЕсли;
		
	КонецПопытки;
	
	Возврат Результат;

КонецФункции

Теперь нам нужна вспомогательная функция для разбора текста. Текст ошибки может меняться в зависимости от версии платформы и типа блокировки (СУБД или управляемая), но ключевые слова обычно сохраняются.


Функция РаспарситьИмяПользователя(Знач ТекстОшибки)
	
	ИмяПользователя = "";
	
	// Приведем к нижнему регистру для удобства поиска
	ТекстПоиска = НРег(ТекстОшибки);
	
	// Поищем ключевое слово "пользователь:"
	ПозицияНачала = Найти(ТекстПоиска, "пользователь:");
	
	Если ПозицияНачала > 0 Тогда
		// Сдвигаем позицию на длину ключевого слова (13 символов) и возможные пробелы
		ПозицияИмени = ПозицияНачала + 13;
		ОстатокСтроки = Сред(ТекстОшибки, ПозицияИмени);
		
		// Имя пользователя обычно заканчивается запятой (перед ", сеанс:")
		// или концом строки
		ПозицияКонца = Найти(ОстатокСтроки, ",");
		
		Если ПозицияКонца > 0 Тогда
			ИмяПользователя = СокрЛП(Лев(ОстатокСтроки, ПозицияКонца - 1));
		Иначе
			ИмяПользователя = СокрЛП(ОстатокСтроки);
		КонецЕсли;
		
	КонецЕсли;
	
	Возврат ИмяПользователя;
	
КонецФункции

Обратите внимание на использование функции НРег и СокрЛП. Текст ошибки может содержать спецсимволы, поэтому важно аккуратно вырезать именно имя.

Шаг 3. Использование в форме документа

Теперь перейдем к клиентской части. В форме документа (или списка), при открытии или по нажатию специальной кнопки, мы должны обратиться к нашему привилегированному модулю.

Рассмотрим пример кода для формы документа (процедура ПередОткрытием или отдельная кнопка "Проверить блокировку"):


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

Альтернативный вариант: Использование коллекции сеансов

Если разбор текста ошибки кажется вам ненадежным методом (текст ошибки действительно может меняться от релиза к релизу), в привилегированном модуле можно использовать другой подход. Однако он сложнее в реализации для пессимистичных блокировок форм.

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

Но для задачи "просто узнать, кто держит документ" парсинг текста ошибки (описанный в Шаге 2) остается самым быстрым и эффективным решением, так как платформа сама формирует эту строку с данными блокиратора в момент коллизии.

Особенности реализации в УТ 10.3

Поскольку «Управление торговлей 10.3» — это конфигурация на обычных формах, стоит учитывать нюанс с модальностью и обработкой ошибок при открытии.

Если вы хотите встроить проверку прямо в момент открытия формы документа, чтобы предупредить менеджера заранее, используйте предопределенную процедуру ПриОткрытии. Однако помните, что сама платформа пытается заблокировать объект перед открытием формы. Если объект уже занят, платформа выдаст стандартное окно (без имени в 8.3.24) и предложит открыть документ «Только для просмотра».

В этом случае, чтобы показать пользователю имя, вам придется:

  1. Либо смириться со стандартным окном, а имя показывать уже внутри открытой в режиме просмотра формы (например, вывести надпись на форму красным цветом: «Занято пользователем: Иванов»).
  2. Либо перехватывать открытие, пытаться заблокировать программно своим методом, и если занято — выдавать своё окно с вопросом и именем пользователя, и затем открывать форму с параметром «ТолькоПросмотр».

Второй вариант требует более глубокого изменения логики работы конфигурации, поэтому для быстрого решения проблемы чаще всего достаточно добавить информационную надпись на форму или кнопку «Кто заблокировал?», которая вызывает наш привилегированный метод.

Резюме

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

← На главную