Как запретить изменение ответственного в документах 1С?

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

При совместной работе пользователей в программах 1С часто возникает задача зафиксировать ответственного сотрудника за документ и исключить возможность его подмены другими пользователями. Разберем различные подходы к решению этой задачи: от использования прав доступа до программной блокировки через подписки на события.

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

Способ 1. Ограничение прав на уровне метаданных (роли и права)

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

  1. Откроем нужную пользовательскую роль в конфигураторе.
  2. Найдем требуемый документ и раскроем список его реквизитов.
  3. Для реквизита Ответственный снимем флаг Редактирование, оставив при этом флаг Просмотр.

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

Способ 2. Использование подписки на событие «ПередЗаписью»

Рассмотрим наиболее популярный и гибкий программный способ, который позволяет не снимать документы с типовой поддержки — создание общей подписки на события. Разберем по шагам процесс ее настройки:

  1. В дереве метаданных найдем ветку Общие > Общие модули и добавим новый модуль (например, МодификацияДокументовСобытия). В его свойствах обязательно установим флаг Сервер.
  2. Перейдем в ветку Общие > Подписки на события и создадим новую подписку.
  3. В свойстве Источник выберем составной тип данных и отметим документы, в которых требуется контролировать реквизит.
  4. В свойстве Событие укажем ПередЗаписью.
  5. В свойстве Обработчик выберем процедуру из созданного общего модуля.

Посмотрим на базовую реализацию проверки, когда при попытке изменения ответственного в уже существующем документе программа автоматически возвращает исходное сохраненное значение:


Процедура ЗапретСменыОтветственногоПередЗаписью(Источник, Отказ, РежимЗаписи, РежимПроведения) Экспорт

	// Игнорируем запись при обмене данными
	Если Источник.ОбменДанными.Загрузка Тогда
		Возврат;
	КонецЕсли;

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

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

Разберем логику работы данного обработчика. Метод ЭтоНовый() позволяет гарантировать, что при интерактивном создании автор не сможет выбрать коллегу вместо себя. Для ранее записанных документов обращение Источник.Ссылка.Ответственный считывает сохраненное значение из базы данных и возвращает его обратно в объект Источник, если пользователь попытался его скорректировать.

Способ 3. Выдача ошибки при попытке редактирования реквизита

Если бизнес-требования не допускают молчаливого возврата старого значения, а требуют уведомить пользователя о запрете, применим прерывание записи через параметр Отказ:


Процедура ПроверитьОтветственногоПередЗаписью(Источник, Отказ, РежимЗаписи, РежимПроведения) Экспорт

	Если Источник.ОбменДанными.Загрузка Тогда
		Возврат;
	КонецЕсли;

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

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

В этом случае платформа 1С отменит запись транзакции и выведет пользователю предупреждающее сообщение.

Особенности группового перепроведения и регламентных операций

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

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


Процедура КонтрольОтветственногоПередЗаписью(Источник, Отказ, РежимЗаписи, РежимПроведения) Экспорт

	// Пропускаем служебную загрузку данных и полные права
	Если Отказ ИЛИ Источник.ОбменДанными.Загрузка ИЛИ РольДоступна("ПолныеПрава") Тогда
		Возврат;
	КонецЕсли;

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

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

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

← На главную