Как проверить модифицированность документа в 1С 8.3 для фиксации автора изменений

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

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

Особенности работы метода Модифицированность() в управляемом приложении

Первым делом проанализируем поведение платформы. В управляемом приложении работа с данными разделена между клиентом (формой) и сервером (объектом базы данных). Когда мы находимся в модуле объекта в процедуре ПередЗаписью, платформа уже подготовила объект к записи. В этот момент метод Модифицированность() объекта практически всегда возвращает значение Истина. Это происходит потому, что данные уже переданы из формы в объект, и состояние объекта в памяти отличается от того, что записано в базе данных.

Рассмотрим ситуацию: пользователь открыл документ, ничего не менял и нажал кнопку "Записать". На уровне формы флаг модифицированности может быть Ложь, но при передаче управления на сервер для выполнения транзакции записи объект инициализируется, и механизмы платформы зачастую взводят флаг изменения. Поэтому проверка внутри ПередЗаписью модуля объекта напрямую через Модифицированность() не дает достоверного результата для определения интерактивных правок.

Решение 1: Проверка на уровне модуля формы

Самый простой и очевидный способ — выполнить проверку в модуле формы документа. На клиенте состояние ЭтаФорма.Модифицированность четко отражает, вносил ли пользователь изменения в элементы управления, связанные с реквизитами.

Разберем алгоритм действий:

  1. В модуле формы находим предопределенную процедуру ПередЗаписьюНаСервере.
  2. Проверяем свойство формы Модифицированность.
  3. Если данные изменены, передаем эту информацию в модуль объекта.

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

Пример кода в модуле формы:


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

Теперь в модуле объекта мы можем легко считать этот флаг:


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

Решение 2: Сравнение объекта со ссылкой (универсальный метод)

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

Для этого в модуле объекта в процедуре ПередЗаписью мы можем получить "старую" версию документа по ссылке и сравнить реквизиты. Однако стоит помнить, что метод Ссылка.ПолучитьОбъект() создает дополнительную нагрузку на сервер БД, так как выполняется еще один запрос на чтение.

Посмотрим на пример реализации такого сравнения:


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

    Если Изменено Тогда
        // Фиксируем изменения
    КонецЕсли;
    
КонецПроцедуры

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

Решение 3: Использование системного механизма «История данных»

Начиная с версии платформы 8.3.11, компания 1С представила мощный встроенный инструмент — История данных. Это развитие идеи версионирования, но реализованное на уровне ядра платформы, что работает значительно быстрее любых самописных функций.

Выясним преимущества этого подхода:

Чтобы включить этот механизм, выполните следующие шаги:

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

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

Решение 4: Подсистема БСП «Версионирование объектов»

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

Проанализируем, как его задействовать:

  1. Добавьте ваш документ в определяемый тип ОбъектВерсионирования.
  2. В режиме "1С:Предприятие" перейдите в раздел "Администрирование" — "Общие настройки" — "История изменений".
  3. Настройте расписание и выберите ваш документ для версионирования (например, "Версионировать при записи").

Этот метод хорош тем, что он предоставляет пользователю удобный интерфейс для сравнения версий "было / стало" без написания кода.

Резюме и рекомендации

Подведем итог: выбор метода зависит от ваших конкретных целей.

1. Если нужно быстро и только для интерактивной работы — используйте ДополнительныеСвойства и ПередЗаписьюНаСервере в форме.

2. Если требуется строгий контроль при любых видах записи (включая обмены и обработки) — применяйте сравнение объекта со ссылкой в модуле объекта, но помните о нагрузке на БД.

3. Если проект современный и требует полноценного аудита — используйте системную Историю данных. Это наиболее технологичный путь, который снимает с программиста задачу по ручному сравнению реквизитов.

4. Для типовых решений на базе БСП лучшим выбором будет стандартная подсистема Версионирование объектов.

← На главную