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

И
секцию Строка

Вся
ячейки соответственно с видом заполнения
- «Параметр»
4.Теперь осталось только
организовать заполнение отчета
В
форме объекта в любое удобное место помещаем кнопку «История», по которой будет
выводиться в виде отчета история изменений
Я
добавил пункт в стандартные «Действия» объекта

Потом
просто организовываем вызов следующей процедуры:
Процедура
ДействияФормыИстория(Кнопка)
//<-------------.Просмотр истории работы пользователей с документом
МакетМонитора="";
Попытка
МакетМонитора=ПолучитьОбщийМакет("МониторИзмененийДокументов");
Исключение
КонецПопытки;
Если ЗначениеЗаполнено(История) Тогда
тПроверка=ЗначениеИзСтрокиВнутр(История);
Если ТипЗнч(тПроверка)=Тип("ТаблицаЗначений") Тогда
Если МакетМонитора="" Тогда//если что-то случилось с макетом,то пойдем по запасному
пути
Для Каждого Стр из тПроверка
Цикл
Сообщить(""+Стр.Время+"...Автор:"+Стр.Автор+",Рекв:"+Стр.Реквизит+",Ст.зн:"+Стр.СтароеЗначение+",Нов.зн:"+Стр.НовоеЗначение);
Конеццикла;
Иначе// печатаем
красивый отчет
Таб=Новый ТабличныйДокумент;
Область=МакетМонитора.ПолучитьОбласть("Шапка");
Область.Параметры.Док=Ссылка;
Таб.Вывести(Область);
Область=МакетМонитора.ПолучитьОбласть("Строка");
Для Каждого Стр из тПроверка
Цикл
Область.Параметры.Автор =Стр.Автор;
Область.Параметры.ДатаИзм =Стр.Время;
Область.Параметры.ИмРек
=Стр.Реквизит;
Область.Параметры.СтарЗнач =Стр.СтароеЗначение;
Область.Параметры.НовЗнач =Стр.НовоеЗначение;
Таб.Вывести(Область);
Конеццикла;
Таб.ОтображатьГруппировки=Ложь;
Таб.ОтображатьЗаголовки=Ложь;
Таб.ОтображатьСетку=Ложь;
Таб.Показать("Мониторинг");
КонецЕсли;
КонецЕсли;
КонецЕсли;
//------------------------------------------>
КонецПроцедуры
Вот и
все. Теперь каждый объект этого вида будет хранить личную
историю, которую в любой момент можно поднять и посмотреть, кому же именно нужно
давать по голове и отрывать кривые шаловливые ручки : -)
В конце
хочу добавить, что пользователя? который постоянно менял документы я с помощью
этого монитора отловил в течении нескольких дней. Уверяю вас, вывести его на
чистую воду, схватить за руку и отвести к высокому начальству – было ни с чем
не сравнимое удовольствие : -)