Как узнать, какие реквизиты были изменены в документе через регистр «ВерсииОбъектов» в 1С

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

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

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

Причина проблем при прямом декодировании Base64

В ресурсе ВерсияОбъекта данные хранятся в типе ХранилищеЗначения. Внутри него находится сериализованный объект в формате XML, который перед сохранением сжимается алгоритмом Deflate. Если просто попытаться декодировать Base64-строку из файла или структуры, то на выходе получится сжатый двоичный поток. При попытке отобразить его как обычный текст программа выведет несчитываемый набор символов.

Способ 1. Программное извлечение данных с помощью API БСП

Проанализируем штатный механизм работы подсистемы «Версионирование объектов». Для получения разницы между версиями или распаковки содержимого версии не нужно писать собственные алгоритмы распаковки. В БСП предусмотрены готовые функции в общем модуле ВерсионированиеОбъектов.

Для прочтения состава конкретной версии используем следующий алгоритм:

  1. Извлекаем двоичные данные из ресурса ВерсияОбъекта с помощью метода Получить().
  2. Десериализуем данные через объект ЧтениеXML или используем функции общего модуля БСП.

Пример кода для программного чтения сохраненной версии объекта:


// Получаем ХранилищеЗначения из регистра
ДвоичныеДанныеВерсии = Выборка.ВерсияОбъекта.Получить();

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

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

Почему регистр «ВерсииОбъектов» не подходит для массовой аналитики

Выясним, с какими ограничениями можно столкнуться, если использовать данный регистр для постоянного отслеживания активности пользователей (например, для подсчета количества отредактированных документов за день):

  1. Невозможность использования в запросах: Поле ВерсияОбъекта имеет тип ХранилищеЗначения. Язык запросов 1С не умеет работать с содержимым хранилища данных. Чтобы проанализировать реквизиты, придется выбирать все записи в выборку и распаковывать каждую версию в цикле на сервере.
  2. Высокая нагрузка на сервер: Процесс декомпрессии и десериализации XML-структур каждого документа требует значительных ресурсов процессора и памяти. Анализ сотен документов за день вызовет существенное замедление работы базы.
  3. Риск потери данных при очистке: В типовых решениях настроено фоновое задание по регулярной очистке устаревших версий объектов. Исторические данные могут быть удалены согласно регламенту базы.

Способ 2. Оптимальное решение задачи через подписку на событие

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

Разберем по шагам реализацию этого подхода:

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

Пример кода в модуле подписки на событие:


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

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

Преимущества такого подхода: данные записываются в плоском виде, легко индексируются СУБД, а итоговый отчет по работе пользователей строится одним простым и быстрым запросом без распаковки ХранилищеЗначения.

← На главную