Книга знаний

1С:Предприятие / Объекты конфигурации / Документы

История изменений реквизитов документа, реквизитов табличных частей документа

Фиксация изменений реквизитов До и После записи документа, сравнение табличных частей документа(До и После записи) по ключевым полям, сравнение ТЗАвтор статьи: Stim | Редакторы: withoutname,
Последняя редакция №4 от 04.03.10 | История
URL: http://kb.mista.ru/article.php?id=783

Ключевые слова: история изменения реквизитов, версионирование


1.    Зачем это нужно


Стандартный журнал регистрации в 1С фиксирует только изменения объектов, без указания конкретного реквизита и значения реквизита.  А как быть, если хочется узнать, например, кто и когда в документе изменил склад, изменил количество материала в табличной части и удалил строку из табличной части? Собственно для этого и был написан данный модуль.

2.    Как это работает


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

3.    Ключевые колонки ТЧ


Ключевые колонки – гарантия того, что в табличной части не будет повторяющихся строк.
Если все-таки будут – ищите другие пути.
Ключевые колонки – это колонки, по которым происходит сравнение ТЧ документов(при открытии и при записи).
Например, если у вас ТЧ вида:
 
Материал КоличествоЦена Сумма


и вы знаете, что в одной табличной части никогда не будет одинаковых материалов – выбираете одну ключевую колонку «Материал». Если будут одинаковые материалы, но с разными ценами – ключевых колонок должно быть две: «Материал,Цена».  Можно указать ключевыми колонками все 4, и в таком случае не должно быть полностью одинаковых строк в документе(собственно, в такой записи нет никакой необходимости).
Ключевые поля указываются через запятую в вызове процедуры
ФиксацияРеквизитовДокумента(ДокОбъект, СписокКлючевыхПолей), где ДокОбъект-  это ЭтотОбъект документа, СписокКлючевыхПолей – это те ключевые поля, в разрезе которых будет происходить сравнение таблиц До и После записи. Указывается строкой, перечислением(через запятую) колонок с указанием номера табличной части. («Материал1,Цена1», если две табличной части: «Материал1,Цена1,Тара2». Тара2 – означает, что у второй табличной части нас интересует только колонка «Тара»)
Записи измененных значений в РС записываются в виде строки.

4.   Код модуля

ПРоцедура ФиксацияРеквизитовДокумента(ДокОбъект, СписокКлючевыхПолей) Экспорт

    Ссылка = ДокОбъект.Ссылка;
    //--Реквизиты объекта
    СтруктураДо = Новый Структура;
    Для каждого Реквизит из Ссылка.Метаданные().Реквизиты Цикл
        СтруктураДо.Вставить(Реквизит.Имя,Ссылка[Реквизит.Имя]);    
    КОнецЦикла;
    СтруктураПосле = Новый СТруктура;
    Для каждого Реквизит из ДокОбъект.Метаданные().Реквизиты Цикл
        СтруктураПосле.Вставить(Реквизит.Имя,ДокОбъект[Реквизит.Имя]);    
    КОнецЦикла;
    //--проверка и запись
    Для каждого КлючИЗначение из СтруктураДо Цикл
        Если КлючИЗначение.Значение <> СтруктураПосле[КлючИЗначение.Ключ] Тогда
            Изменение = Перечисления.ВидДействияСОбъектом.Изменение;
            РегистрацияВРегистр(ДокОбъект,Изменение,КлючИЗначение.Ключ, Строка(СтруктураДо[КлючИЗначение.Ключ]),Строка(СтруктураПосле[КлючИЗначение.Ключ]))
        КонецЕсли;
    КонецЦикла;        
    //++Проверка и запись
    //++Реквизиты объекта    
   
    //--Реквизиты ТЧ объекта
    СчетчикТЧ = 1;    
    ДЛя каждого ТЧ ИЗ Ссылка.Метаданные().ТабличныеЧасти  Цикл
        ТАблицаЗначенийДо = Ссылка[ТЧ.Имя].Выгрузить();
        ТаблицаЗначенийПосле = ДокОбъект[ТЧ.Имя].Выгрузить();
        Запрос = Новый Запрос;
        Текст = "ВЫБРАТЬ
        |    *
        |ПОМЕСТИТЬ Первая
        |ИЗ
        |    &ТаблицаЗначенийДо КАК ЛотТЧлота
        |;
        |
        |////////////////////////////////////////////////////////////////////////////////
        |ВЫБРАТЬ
        |    *
        |ПОМЕСТИТЬ Вторая
        |ИЗ
        |    &ТаблицаЗначенийПосле КАК ЛотТЧлота
        |;
        |
        |////////////////////////////////////////////////////////////////////////////////
        |ВЫБРАТЬ
        |    *
        |ИЗ
        |    Первая КАК Первая
        |        ПОЛНОЕ СОЕДИНЕНИЕ Вторая КАК Вторая
        |ПО";
        СоюзИ = "";
        ИзменяемоеЗначение ="";
        списокКолонок = СписокКлючевыхПолей+",";
        СписокКолонок = Новый СписокЗначений;
        Если Найти(СписокКлючевыхПолей,Строка(СчетчикТЧ)) Тогда //Если поля по текущей ТЧ указаны
            Пока Найти(СокрЛП(СписокКлючевыхПолей),Строка(СчетчикТЧ)) Цикл//то добавляем их в условие соединения
                КОлонкаТЧ = Сред(СписокКлючевыхПолей,1,Найти(СписокКлючевыхПолей,Строка(СчетчикТЧ))-1);
                СписокКолонок.Добавить(КОлонкаТЧ);
                СписокКлючевыхПолей = СтрЗаменить(СписокКлючевыхПолей, КолонкаТЧ+Строка(СчетчикТЧ)+",","");
                Текст = Текст+СоюзИ+"        
                |         Первая."+КолонкаТЧ+" = Вторая."+КолонкаТЧ;                      
                СоюзИ ="
                |И";
            КонецЦикла;
        Иначе
            ПРервать;
        КонецЕСли;
        Запрос.Текст = Текст;
        Запрос.УстановитьПараметр("ТаблицаЗначенийДо",ТаблицаЗначенийДо);
        Запрос.УстановитьПараметр("ТаблицаЗначенийПосле",ТаблицаЗначенийПосле);
        Выборка = Запрос.Выполнить().Выбрать();
        Пока выборка.Следующий() Цикл
            Если Выборка[КолонкаТЧ] = NULL тогда //Добавили
                ВИдДействия = Перечисления.ВидДействияСОбъектом.Добавление;
                Добавлено = "1";
            КонецЕсли;
            Если Выборка[КолонкаТЧ+"1"] = NULL тогда //Удалили
                ВидДействия = Перечисления.ВидДействияСОбъектом.Удаление;
                Добавлено = "";
            КонецЕсли;            
            Если Выборка[КолонкаТЧ] = Выборка[КолонкаТЧ+"1"] тогда    //Изменили
                ВидДействия = перечисления.ВидДействияСОбъектом.Изменение;
                Добавлено = "";
            КонецЕсли;
            Для каждого Колонка из ТаблицаЗначенийДо.КОлонки Цикл
                Если Колонка.Имя <> "НомерСтроки" Тогда   //не учитывая сортировку строк
                    Если выборка[Колонка.Имя]<>выборка[Колонка.Имя+"1"]  Тогда
                        Для каждого Поле из СписокКолонок Цикл
                            ИзменяемоеЗначение = ИзменяемоеЗначение + "_"+Строка(выборка[Строка(Поле)+Добавлено]);
                        КонецЦикла;
РегистрацияВРегистр(ДокОбъект,ВидДействия,Тч.Имя+"_"+ИзменяемоеЗначение+"("+Колонка.Имя+")", Строка(Выборка[Колонка.Имя]),Строка(Выборка[Колонка.Имя+"1"]));
                        ИзменяемоеЗначение = "";
                    КонецЕсли;    
                КонецЕсли;
            КонецЦикла;
        КонецЦикла;
        СчетчикТЧ= СчетчикТЧ+1;
    КОнецЦикла;    
    //++Реквизиты ТЧ объекта


Процедура записи в регистр :

Процедура РегистрацияВРегистр(ДокОбъект,ВидДействия,ИзменяемоеЗначение, ЗначениеДо,ЗначениеПосле)

    Ссылка = ДокОбъект.Ссылка;
    WshShell= Новый COMОбъект("Wscript.Shell");
    Имя = WshShell.ExpandEnvironmentStrings("%username%");
    Клиент = WshShell.ExpandEnvironmentStrings("%clientname%");
     ТекущийПользователь = УправлениеПользователями.ОпределитьТекущегоПользователя();
    //--Регистрация в Регистр        
    НаборЗаписей = РегистрыСведений.КонтрольИзмененийДокументов.СоздатьНаборЗаписей();    
    НаборЗаписей.Отбор.ПериодЗаписи.Установить(ТекущаяДата());
    НаборЗаписей.Отбор.ИзменяемоеЗначение.Установить(ИзменяемоеЗначение);
    НаборЗаписей.Отбор.ПОльзовательWindows.Установить(Имя);    
    НаборЗаписей.Отбор.Клиент.Установить(Клиент);
    НаборЗаписей.Отбор.Пользователь1С.Установить(ТекущийПользователь);
    НаборЗаписей.Отбор.ИзменяемоеЗначение.Установить(ИзменяемоеЗначение);
    НоваяЗапись = НаборЗаписей.Добавить();
    НоваяЗапись.ПериодЗаписи = ТекущаяДата();
    Если ДокОбъект.ЭтоНовый() Тогда
        НоваяЗапись.Дополнительно = "Создание нового документа: "+Строка(ДокОбъект)    ;
        НоваяЗапись.ВидДействия = Перечисления.ВидДействияСОбъектом.Добавление;
    Иначе
        новаяЗапись.ВидДействия = ВидДействия;
        НоваяЗапись.ДокументРегистратор = Ссылка;
    Конецесли;      
    НоваяЗапись.ИзменяемоеЗначение = ИзменяемоеЗначение;
    НоваяЗапись.СтароеЗначение = ЗначениеДо;
    НоваяЗапись.НовоеЗначение = ЗначениеПосле;
    НоваяЗапись.ПользовательWindows = Имя;
    НоваяЗапись.Клиент = Клиент;
    НоваяЗапись.Пользователь1С = ТекущийПользователь;
    НаборЗаписей.Записать();            
    //++Регистрация в регистр    
   
КонецПроцедуры

в модуль документа в процедуру ПередЗаписью() записывается вызов процедуры общего модуля как(пример):
УправленческийКОнтроль.ФиксацияРеквизитовДокумента(ЭтотОбъект,"ОбъектВид1,Материал1,Период1,ОБъектВид2,НаименованиеРаботы2");


примеры результатов записи в регистр(таблица разделена по длине на две части)




Периодзаписи     Документ регистратор                            Пользователь1С ПользовательWindows ИзменяемоеЗначение
04.03.2010.10:56:18 ЗаявкаОтПользователя000000090От.30.10.2009 12:06:15    Администратор        admin1C           ТаблицаМатериалов__Текущий ремонт ТС_Авторезина_01.03.2009 0:00:00(Количество)








Виддействия Клиент      СтароеЗначение   НовоеЗначение  Дополнительно
Изменение   COMPNAME       1 200             12

Описание | Рубрикатор | Поиск | ТелепатБот | Захваченные статьи | Установки | Форум
© Станислав Митичкин (Волшебник), 2005-2025 | Mista.ru

Яндекс.Метрика