Книга знаний

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

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

Фиксация изменений реквизитов До и После записи документа, сравнение табличных частей документа(До и После записи) по ключевым полям, сравнение ТЗАвтор статьи: Stim | Редакторы: withoutname
Последняя редакция №20 от 07.02.11 | История
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



с картинками  http://infostart.ru/public/66851/

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

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