В практике разработки на платформе 1С часто возникают задачи аудита действий пользователей. Одна из таких нетривиальных задач — необходимость знать, сколько раз проводился конкретный документ, был ли он когда-либо проведен (даже если сейчас распроведен) и происходила ли отмена проведения. Рассмотрим различные способы реализации этого механизма, от простых до архитектурно сложных.
Самый простой и быстрый способ, предложенный в обсуждении, — добавить в сам документ служебные реквизиты. Это решение подходит, если нам нужно видеть информацию непосредственно в форме документа, использовать ее в простых запросах или формировать отчет об истории изменений за выбранный период.
Для реализации можно хранить изменения реквизитов во внешнем расширении или добавить в объект два реквизита:
СчетчикПроведений (Тип: Число) — будет хранить количество успешных проведений.БылВПроведении (Тип: Булево) — флаг, который устанавливается в Истину при первом проведении и никогда не сбрасывается.Логику заполнения лучше всего разместить в событии ПередЗаписью модуля объекта. Нам необходимо проанализировать режим записи и текущее состояние документа.
Процедура ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)
// Если документ записывается в режиме проведения
Если РежимЗаписи = РежимЗаписиДокумента.Проведение Тогда
// Увеличиваем счетчик
СчетчикПроведений = СчетчикПроведений + 1;
// Фиксируем исторический факт, что документ был проведен хотя бы раз
БылВПроведении = Истина;
КонецЕсли;
КонецПроцедуры
Важно понимать особенность транзакций: если в процессе проведения возникнет ошибка и транзакция откатится, значение счетчика также вернется к прежнему состоянию. Таким образом, этот метод считает только успешные проведения.
Часто требуется не просто считать, а понимать, что именно происходит в данный момент. Для этого мы можем сравнить текущий режим записи со старым состоянием документа (хранящимся в базе данных). Для этого обратимся к ссылке на объект.
Разберем логику определения состояния в процедуре ПередЗаписью:
Процедура ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)
// Проверяем, не является ли это загрузкой данных (чтобы не считать технические записи)
Если ОбменДанными.Загрузка Тогда
Возврат;
КонецЕсли;
ЭтоНовыйДокумент = ЭтоНовый();
// Получаем статус проведения, который сейчас записан в базе
// Для нового документа он всегда Ложь
УжеПроведенВБазе = ?(ЭтоНовыйДокумент, Ложь, Ссылка.Проведен);
Если РежимЗаписи = РежимЗаписиДокумента.Проведение Тогда
Если НЕ УжеПроведенВБазе Тогда
// Это ПЕРВИЧНОЕ проведение
// Можно зафиксировать дату первого проведения
Иначе
// Это ПЕРЕПРОВЕДЕНИЕ
// Можно увеличить счетчик изменений
КонецЕсли;
ИначеЕсли РежимЗаписи = РежимЗаписиДокумента.ОтменаПроведения Тогда
// Это ОТМЕНА проведения
// Здесь можно залогировать факт отмены
КонецЕсли;
КонецПроцедуры
Если задача состоит в том, чтобы хранить полную историю действий, не перегружая сам документ, архитектурно верным решением будет создание независимого периодического регистра или внедрение расширения для детального логирования изменений данных.
В этом случае при каждом значимом событии мы будем создавать запись в регистре. Это позволит нам:
Однако, если писать в регистр внутри транзакции документа, то при откате документа запись в регистре тоже исчезнет. Если вам нужно фиксировать даже попытки проведения (нажали кнопку, но получили ошибку), запись в журнал или регистр нужно производить в отдельной транзакции или использовать расширенный журнал действий пользователей.
Не стоит забывать про встроенные возможности платформы 1С, которые могут решить задачу без написания кода.
1. Журнал регистрации (ЖР)
В ЖР автоматически фиксируются события «Проведение» и «Отмена проведения».
Плюсы: не нужно программировать, фиксирует все попытки.
Минусы: сложно программно анализировать «на лету» (чтение журнала — медленная операция), журнал может быть очищен администратором.
2. История данных (Версионирование)
В современных конфигурациях (БСП) или на уровне платформы (История данных) можно включить хранение версий объектов. С помощью метода ИсторияДанных.ПолучитьВерсии() можно программно узнать количество версий объекта. Однако, это ресурсоемкая операция, и использовать ее при каждом проведении не рекомендуется.
При внедрении счетчиков или логирования обратите внимание на следующие моменты: