Перейти к списку статей

() Мониторинг истории изменений объектов

Автор:  Рэйв

Краткое содержание:

Мониторинг изменений объектов.

Однажды на работе у меня возникла следующая ситуация.

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

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



1.В объект метаданных, который необходимо мониторить добавляем реквизит  История, тип строка неограниченной дины. (можно конечно ограничить, но я не стал)



2.В процедуру модуля объекта  ПередЗаписью()

Добавляем следующий код



  Если ЗначениеЗаполнено(История) Тогда   //Если история уже есть, то будем добавлять

       тПроверка=ЗначениеИзСтрокиВнутр(История);      //поднимаем таблицу из строки

      

Иначе  //Если до этого ничего не писалось, то начнем новую запись

       тПроверка=Новый ТаблицаЗначений;

       тПроверкаолонки.Добавить("Автор");

       тПроверкаолонки.Добавить("Реквизит");

       тПроверкаолонки.Добавить("СтароеЗначение");

       тПроверкаолонки.Добавить("НовоеЗначение");

       тПроверкаолонки.Добавить("Время");

КонецЕсли;

Если ТипЗнч(тПроверка)<>Тип("ТаблицаЗначений") Тогда //если поднялось криво из строки, то тоже начнем новую

       тПроверка=Новый ТаблицаЗначений;

       тПроверкаолонки.Добавить("Автор");

       тПроверкаолонки.Добавить("Реквизит");

       тПроверкаолонки.Добавить("СтароеЗначение");

       тПроверкаолонки.Добавить("НовоеЗначение");

       тПроверкаолонки.Добавить("Время");

      

КонецЕсли;  

Если ЗначениеЗаполнено(Ссылка) Тогда  //если объект  уже был записан раньше

      

       //дата и номер не являются реквизитами, поэтому их отследим отдельно

       Если Ссылкаата<>ЭтотОбъект.Дата  Тогда

             НовСтр=тПроверкаобавить();

             НовСтрвтор=Строка(глТекущийПользователь);

             НовСтреквизит="Дата";

             НовСтртароеЗначение=Строка(Ссылка.Дата);

             НовСтровоеЗначение=Строка(ЭтотОбъект.Дата);

             НовСтрремя=Строка(ТекущаяДата());

       КонецЕсли;  

       Если Ссылкаомер<>ЭтотОбъект.Номер  Тогда

             НовСтр=тПроверкаобавить();

             НовСтрвтор=Строка(глТекущийПользователь);

             НовСтреквизит="Номер";

             НовСтртароеЗначение=Строка(Ссылка.Номер);

             НовСтровоеЗначение=Строка(ЭтотОбъект.Номер);

             НовСтрремя=Строка(ТекущаяДата());

       КонецЕсли;  

      

       //проверка реквизитов шапки

       Мета=ЭтотОбъектетаданные();

      

       Для Каждого Рек Из Метаеквизиты Цикл

             ИмяРек=Рекмя;

             Если ИмяРек="История" Тогда// саму историю не нужно проверять

                    Продолжить;

             КонецЕсли;  

            

             Если Ссылка[ИмяРек]<>ЭтотОбъект[ИмяРек] Тогда

                    НовСтр=тПроверкаобавить();

                    НовСтрвтор=Строка(глТекущийПользователь);

                    НовСтреквизит=Рек.Имя;

                    НовСтртароеЗначение=Строка(Ссылка[ИмяРек]);

                    НовСтровоеЗначение=Строка(ЭтотОбъект[ИмяРек]);

                    НовСтрремя=Строка(ТекущаяДата());

             КонецЕсли;  

       КонецЦикла;

       //проверка таб частей

       Для Каждого ТЧ Из МетаабличныеЧасти Цикл

             ИмяТЧ=ТЧмя;

             Если Ссылка[ИмяТЧ].Количество()<>ЭтотОбъект[ИмяТЧ].Количество() Тогда

                    НовСтр=тПроверкаобавить();

                    НовСтрвтор=Строка(глТекущийПользователь);

                    НовСтреквизит="ТЧ."+ИмяТЧ;

                    НовСтртароеЗначение="--->";

                    НовСтровоеЗначение="Изменено кол.строк";

                    НовСтрремя=Строка(ТекущаяДата());

                    Продолжить;    //если количество строк не совпадает уже наш клиент, не будем все перебирать

             КонецЕсли;  

             КолСтр=Ссылка[ИмяТЧ].Количество();

             ЕстьИзм=Ложь;

             Для НомСтр=0  По КолСтр-1  Цикл

                    ДЛя Каждого РекТЧ Из МетаабличныеЧасти[ИмяТЧ].Реквизиты Цикл

                           ИмяРек=РекТЧмя;

                          

                           Если Ссылка[ИмяТЧ][НомСтр][ИмяРек]<>ЭтотОбъект[ИмяТЧ][НомСтр][ИмяРек] Тогда

                                  НовСтр=тПроверкаобавить();

                                  НовСтрвтор=Строка(глТекущийПользователь);

                                  НовСтреквизит="ТЧ."+ИмяТЧ;

                                  НовСтртароеЗначение="--->";

                                  НовСтровоеЗначение="Изменен реквизит Таб части";

                                  НовСтрремя=Строка(ТекущаяДата());

                                  ЕстьИзм=Истина;

                                  Прервать;//все изменения таб частей детално отслеживать не будемросто фиксируем факт, но при желании можно доработать до построчного мониторинга

                           КонецЕсли;  

                    КонецЦикла;

                    Если ЕстьИзм Тогда

                           Прервать;

                    КонецЕсли;  

                          

             КонецЦикла; 

       КонецЦикла; 

       //проведение и отмену проведения тоже мониторим отдельно, как и пометку удаления

       Если СсылкаометкаУдаления<>ЭтотОбъект.ПометкаУдаления  Тогда

             НовСтр=тПроверкаобавить();

             НовСтрвтор=Строка(глТекущийПользователь);

             НовСтреквизит="ПометкаУдаления";

             НовСтртароеЗначение=Строка(Ссылка.ПометкаУдаления);

             НовСтровоеЗначение=Строка(ЭтотОбъект.ПометкаУдаления);

             НовСтрремя=Строка(ТекущаяДата());

       КонецЕсли;  

       Если РежимЗаписи=РежимЗаписиДокументароведение Тогда

             НовСтр=тПроверкаобавить();

             НовСтрвтор=Строка(глТекущийПользователь);

              НовСтреквизит="Проведение";

             НовСтртароеЗначение="--->";

             НовСтровоеЗначение="Проведен";

             НовСтрремя=Строка(ТекущаяДата());

       КонецЕсли;  

      

       Если РежимЗаписи=РежимЗаписиДокументатменаПроведения  Тогда

             НовСтр=тПроверкаобавить();

             НовСтрвтор=Строка(глТекущийПользователь);

             НовСтреквизит="Проведение";

             НовСтртароеЗначение="<---";

             НовСтровоеЗначение="Отмена";

             НовСтрремя=Строка(ТекущаяДата());

       КонецЕсли;  

      

      

Иначе  //Если документ только что создан и еще не записан, то просто отметим факт его создания

       тПроверка=Новый ТаблицаЗначений;

       тПроверкаолонки.Добавить("Автор");

       тПроверкаолонки.Добавить("Реквизит");

       тПроверкаолонки.Добавить("СтароеЗначение");

       тПроверкаолонки.Добавить("НовоеЗначение");

       тПроверкаолонки.Добавить("Время");

      

       НовСтр=тПроверкаобавить();

       НовСтрвтор=Строка(глТекущийПользователь);

       НовСтреквизит="<Документ создан>";

       НовСтртароеЗначение="---";

       НовСтровоеЗначение="---";

       НовСтрремя=Строка(ТекущаяДата());

      

КонецЕсли ;

История=ЗначениеВСтрокуВнутр(тПроверка);//все данные сворачиваем в строку и обратно в архив

 

Т.е с записью истории разобрались.

 

3. Теперь настроим ее извлечение.



Создаем общий макет МониторИзмененийДокументов.



Делаем секцию Шапка, где рисуем шапку отчета с колонками :



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



Вся ячейки соответственно  с видом заполнения -  «Параметр»



4.Теперь осталось только организовать заполнение отчета



В форме объекта в любое удобное место помещаем кнопку «История», по которой будет выводиться в виде отчета история изменений

Я добавил пункт в стандартные «Действия» объекта



 

Потом просто организовываем вызов следующей процедуры:

 

 

 

 

 

Процедура ДействияФормыИстория(Кнопка)

           //<-------------.Просмотр истории работы пользователей с документом

           МакетМонитора="";

             Попытка

                    МакетМонитора=ПолучитьОбщийМакет("МониторИзмененийДокументов");

             Исключение

                   

             КонецПопытки;

             Если ЗначениеЗаполнено(История) Тогда

                    тПроверка=ЗначениеИзСтрокиВнутр(История);

                    Если ТипЗнч(тПроверка)=Тип("ТаблицаЗначений") Тогда

                           Если МакетМонитора="" Тогда//если что-то случилось с макетомо пойдем по запасному пути

                                  Для Каждого Стр из тПроверка Цикл

                                         Сообщить(""+Стрремя+"...Автор:"+Стрвтор+",Рекв:"+Стр.Реквизит+",Ст.зн:"+Стр.СтароеЗначение+",Нов.зн:"+Стр.НовоеЗначение);

                                  Конеццикла; 

                           Иначе// печатаем красивый отчет  

                                  Таб=Новый ТабличныйДокумент;

                                  Область=МакетМонитораолучитьОбласть("Шапка");

                                  Областьараметры.Док=Ссылка;

                                  Табывести(Область);

                                  Область=МакетМонитораолучитьОбласть("Строка");

                                  Для Каждого Стр из тПроверка Цикл

                                        Областьараметры.Автор           =Стр.Автор;

                                        Областьараметры.ДатаИзм  =Стр.Время;

                                        Областьараметры.ИмРек        =Стр.Реквизит;

                                        Областьараметры.СтарЗнач =Стр.СтароеЗначение;

                                        Областьараметры.НовЗнач   =Стр.НовоеЗначение;

                                        Табывести(Область);

                                  Конеццикла; 

                                  ТабтображатьГруппировки=Ложь;

                                  ТабтображатьЗаголовки=Ложь;

                                  ТабтображатьСетку=Ложь;

                                  Табоказать("Мониторинг");

                           КонецЕсли;

                    КонецЕсли;  

             КонецЕсли;

             //------------------------------------------>

      

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

 

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

 

В конце хочу добавить, что пользователя? который постоянно менял документы я с помощью этого монитора отловил в течении нескольких дней.  Уверяю вас, вывести его на чистую воду, схватить за руку и отвести к высокому начальству – было ни с чем не сравнимое удовольствие : -)




Перейти к списку статей


Хостинг от uCoz