Как заполнять реквизиты документа только при интерактивном изменении и не перезаписывать при перепроведении

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

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

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

Способ 1. Передача флага интерактивной записи через ДополнительныеСвойства

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

Рассмотрим реализацию по шагам:

  1. В модуле формы документа в обработчике ПередЗаписьюНаСервере устанавливаем специальный флаг в коллекцию дополнительных свойств передаваемого объекта:

&НаСервере
Процедура ПередЗаписьюНаСервере(Отказ, ТекущийОбъект, ПараметрыЗаписи)
    ТекущийОбъект.ДополнительныеСвойства.Вставить("ЗаписьИзФормы", Истина);
КонецПроцедуры
  1. В модуле объекта документа или в общем модуле обработчика подписки на событие ПередЗаписью проверяем наличие данного флага:

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

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

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

Способ 2. Заполнение реквизитов непосредственно в обработчике формы

Если нет необходимости выносить алгоритм в модуль объекта, можно заполнять реквизиты напрямую в контексте формы перед отправкой данных на сервер.

Проанализируем пример кода в модуле управляемой формы:


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

        ТекущийОбъект.АвторИзменения = ПользователиИнформационнойБазы.ТекущийПользователь();
        ТекущийОбъект.ДатаИзменения = ТекущаяДатаСеанса();
    КонецЕсли;
КонецПроцедуры

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

Способ 3. Сравнение текущего состояния объекта с данными в базе

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

Разберем пример реализации через подписку на событие ПередЗаписью:


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

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

    // Проверяем изменение ключевых полей (например, даты, суммы или ответственного)
    ДанныеИзменены = (Источник.Дата <> ДанныеБД.Дата) 
        ИЛИ (Источник.СуммаДокумента <> ДанныеБД.СуммаДокумента)
        ИЛИ (Источник.Контрагент <> ДанныеБД.Контрагент);

    Если ДанныеИзменены Тогда
        Источник.АвторИзменения = ПользователиИнформационнойБазы.ТекущийПользователь();
        Источник.ДатаИзменения = ТекущаяДатаСеанса();
    КонецЕсли;
КонецПроцедуры

Такой подход гарантирует, что если обработка просто вызывает метод Записать(РежимЗаписиДокумента.Проведение) без изменения реквизитов документа, данные об авторе последнего редактирования останутся неизменными.

Способ 4. Проверка контекста выполнения и фоновых процессов

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

  1. Проверка на выполнение в фоновом потоке: если функция ФоновыеЗадания.ТекущееФоновоеЗадание() возвращает значение, отличное от Неопределено, процесс запущен регламентным заданием.
  2. Анализ имени клиентского приложения с помощью выражения ПолучитьТекущийСеансИнформационнойБазы().ИмяПриложения, что позволяет исключить сеансы типов BackgroundJob, COMConnection или WS.

Альтернативные архитектурные решения

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

В типовых конфигурациях применяются более гибкие альтернативы:

  1. Подсистема «Версионирование объектов» БСП: автоматически сохраняет снимок объекта при каждом сохранении из пользовательского интерфейса, позволяя просматривать историю изменений и сравнивать любые две версии документа.
  2. Запись в независимый регистр сведений: фиксация автора и даты в отдельном регистре аудита, что исключает модификацию самого документа при служебных операциях.
← На главную