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

Программист 1С v8.3 (Обычные формы)
← На главную

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

Базовый подход: Использование события ПередЗаписью в модуле объекта

Рассмотрим самый распространенный вариант реализации задачи. Основная логика должна располагаться в модуле объекта документа, чтобы она срабатывала независимо от того, записывается документ из формы или программно. Разберем ситуацию на примере документа ЗаказПокупателя.

Наиболее надежным местом для вставки кода является обработчик события ПередЗаписью. Проанализируем, как проверить, является ли документ новым, и заполнить реквизит СоздательДокумента только в этот момент.


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

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

В данном примере функция ЭтоНовый() возвращает Истина, если документ еще ни разу не был записан в базу данных. Это гарантирует, что при втором и последующем нажатии кнопки «Записать», условие не выполнится и старое значение реквизита СоздательДокумента не будет перезаписано текущим (уже другим) пользователем.

Нюансы для обычных форм и старых конфигураций

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

Зачастую в таких базах не используются параметры сеанса напрямую в коде объектов, а применяются глобальные переменные или функции общего модуля. Рассмотрим пример кода для старых конфигураций:


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

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

Обратите внимание на использование функции ЗначениеЗаполнено(). Это «страховочный» метод. Если по какой-то причине документ был создан программно и записан без автора, при первом же интерактивном пересохранении система подставит текущего пользователя. Однако будьте осторожны: если пользователь намеренно очистит это поле, система снова его заполнит при записи.

Учет обмена данными (Data Exchange)

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

Когда документ прилетает через обмен, он также считается «новым» для принимающей базы. Если не добавить проверку, то автором документа в «Бухгалтерии» станет не тот человек, который его создал в «Торговле», а пользователь «Робот обмена» или администратор, под которым запущен транспортный узел. Разберем, как этого избежать:


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

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

Использование свойства ОбменДанными.Загрузка позволяет коду игнорировать изменения, вносимые механизмами синхронизации, сохраняя оригинальные данные из источника.

Улучшение пользовательского опыта (UX) через ОбработкуЗаполнения

Если мы прописываем код только в ПередЗаписью, пользователь увидит свое имя в поле «Создатель» только после того, как нажмет кнопку «Записать». С точки зрения интерфейса это не всегда удобно. Посмотрим, как сделать так, чтобы имя автора появлялось сразу при нажатии кнопки «Создать».

Для этого воспользуемся обработчиком ОбработкаЗаполнения в модуле объекта:


Процедура ОбработкаЗаполнения(ДанныеЗаполнения, ТекстЗаполнения, СтандартнаяОбработка)
    
    // Заполняем автора сразу при создании нового объекта в памяти
    СоздательДокумента = Пользователи.ТекущийПользователь();
    
КонецПроцедуры

Теперь, как только откроется форма нового документа, поле «Создатель» уже будет заполнено. Это дает пользователю визуальное подтверждение того, что система его идентифицировала.

Профессиональное решение: Подписки на события

Представим, что у вас в конфигурации 50 видов документов, и в каждом нужно фиксировать автора. Копировать один и тот же код в 50 модулей — плохая практика (так называемый «anti-pattern»). Проанализируем более элегантный способ — Подписки на события.

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

Пример кода в общем модуле для подписки:


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

Такой подход позволяет управлять логикой заполнения автора во всей системе из одного места. Если завтра руководство попросит записывать еще и дату создания, вам достаточно будет изменить одну процедуру в общем модуле.

Защита реквизита от редактирования

Мало просто записать автора, нужно еще запретить пользователям менять его вручную на форме. Рассмотрим, как это сделать правильно. Мы не будем просто отключать доступность поля в конфигураторе, так как иногда администратору может понадобиться исправить автора. Мы сделаем это программно.

В модуле формы документа добавим код:


&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
    
    // Если документ уже существует, запрещаем редактировать создателя всем, кроме администраторов
    Если ЗначениеЗаполнено(Объект.Ссылка) Тогда
        Если НЕ РольДоступна("ПолныеПрава") Тогда
            Элементы.СоздательДокумента.ТолькоПросмотр = Истина;
        КонецЕсли;
    КонецЕсли;
    
КонецПроцедуры

Различие между Пользователем ИБ и Справочником Пользователи

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

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

← На главную