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

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

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

Проанализируем выбор архитектуры: какой регистр сведений использовать?

Для начала рассмотрим варианты настройки регистра сведений. Главный выбор стоит между независимым регистром и регистром, подчиненным регистратору.

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

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

Посмотрим на альтернативу: механизм "История данных"

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

Разберем алгоритм защиты от лишних записей (дублей)

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

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

Разберем пример кода для записи статуса

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

Проанализируем пример кода с использованием набора записей:


// Создадим набор записей независимого регистра
НаборСтатусов = РегистрыСведений.ИсторияСтатусовЗаказов.СоздатьНаборЗаписей();

// Установим отбор по нашему документу и текущему времени
НаборСтатусов.Отбор.Заказ.Установить(ЭтотОбъект.Ссылка);
// Для независимого периодического регистра период задается явно при добавлении записи

НоваяЗапись = НаборСтатусов.Добавить();
НоваяЗапись.Период = ТекущаяДата();
НоваяЗапись.Заказ = ЭтотОбъект.Ссылка;
НоваяЗапись.Статус = ЭтотОбъект.Статус;

Попытка
    // Записываем набор, добавляя запись (ЛОЖЬ означает, что мы не затираем предыдущие записи по другим отборам)
    НаборСтатусов.Записать(ЛОЖЬ);
Исключение
    Сообщить("Ошибка при записи истории статуса: " + ОписаниеОшибки());
КонецПопытки;

В измерениях такого регистра нужно указать Заказ (тип ДокументСсылка.Заказ), а в ресурсах — Статус (соответствующее перечисление или справочник).

Оптимизация: проанализируем проблему производительности "Среза последних"

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

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

← На главную