1 мая 2013 г.

Простая подсистема записи истории изменений реквизитов

Тестовая конфигурация будет содержать следующие объекты:
  • Справочники данных Контрагенты, КонтактныеЛица, служебный справочник ХранимыеРеквизиты;
  • Документ ОплатаПокупателя;
  • Периодический регистр сведений ИсторияРеквизитов.
Обращаться к  процедуре сохранения истории реквизитов будем через подписку на события ЗаписьИстории, чтобы не прописывать код вызова в модуль каждого объекта.

Реквизиты справочников данных и документа создаем по своему усмотрению. Служебный справочник ХранимыеРеквизиты дополнительных реквизитов не имеет, иерархия групп и элементов, ограничение по количеству уровней - 2. Заполняем его следующим образом: наименование группы представляет собой полное имя метаданных объекта (например, "Справочник.Контрагенты"), в наименовании элементов содержатся имена реквизитов объектов идентично именам в конфигураторе. Это позволяет организовать выборочную фиксацию истории реквизитов конкретных объектов.


Создаем регистр сведений ИсторияРеквизитов, периодический, в пределах секунды. Тип для  реквизита "Объект" - составной: ДокументСсылка, СправочникСсылка, для "Реквизит" - СправочникСсылка.ХранимыеРеквизиты, "Значение" - составной: Булево, Строка, Дата, Число, ЛюбаяСсылка.


Весь код вынесен в общий модуль ИсторияРеквизитов:
Процедура ОбновитьИсторию(Ссылка, Период = Неопределено) Экспорт
 
 мТекущие = ПолучитьРеквизиты(Ссылка, Период);
 
 Запрос = Новый Запрос;
 Запрос.Текст = 
  "ВЫБРАТЬ
  | ХранимыеРеквизиты.Ссылка,
  | ХранимыеРеквизиты.Наименование
  |ИЗ
  | Справочник.ХранимыеРеквизиты КАК ХранимыеРеквизиты
  |ГДЕ
  | НЕ ХранимыеРеквизиты.ПометкаУдаления
  | И ХранимыеРеквизиты.Родитель.Наименование = &Родитель
  |АВТОУПОРЯДОЧИВАНИЕ";

 Запрос.УстановитьПараметр("Родитель", Ссылка.Метаданные().ПолноеИмя()); 
 Результат = Запрос.Выполнить();
 Если Результат.Пустой() Тогда
  Возврат;
 КонецЕсли;

 Выборка = Результат.Выбрать();

 ПериодЗаписи = ТекущаяДата();
 
 мНабор = РегистрыСведений.ИсторияРеквизитов.СоздатьНаборЗаписей();
 мНабор.Отбор.Объект.Установить(Ссылка);
 мНабор.Отбор.Период.Установить(ПериодЗаписи);
 мНабор.Прочитать();
 
 Пока Выборка.Следующий() Цикл
  
  //контроль изменения значений реквизитов
  Если мТекущие[Выборка.Ссылка] = Ссылка[Выборка.Наименование] Тогда
   Продолжить;
  КонецЕсли;
  
  мЗапись = мНабор.Добавить();
  мЗапись.Период = ПериодЗаписи;
  мЗапись.Объект = Ссылка;
  мЗапись.Реквизит = Выборка.Ссылка;
  мЗапись.Значение = Ссылка[Выборка.Наименование];
  
 КонецЦикла;
 
 Если мНабор.Количество() = 0 Тогда
  Возврат;
 КонецЕсли;
 
 мНабор.Записать();
 
КонецПроцедуры

Функция ПолучитьРеквизиты(Ссылка, Период = Неопределено) Экспорт

 Запрос = Новый Запрос;
 Запрос.Текст = 
  "ВЫБРАТЬ
  | ИсторияРеквизитовСрезПоследних.Реквизит КАК Реквизит,
  | ИсторияРеквизитовСрезПоследних.Значение
  |ИЗ
  | РегистрСведений.ИсторияРеквизитов.СрезПоследних(&Период, Объект = &Ссылка) КАК ИсторияРеквизитовСрезПоследних
  |
  |УПОРЯДОЧИТЬ ПО
  | Реквизит
  |АВТОУПОРЯДОЧИВАНИЕ";

 Запрос.УстановитьПараметр("Ссылка", Ссылка);
 Запрос.УстановитьПараметр("Период", Период);

 мРеквизиты = Новый Соответствие;
 Результат = Запрос.Выполнить().Выбрать();
 Пока Результат.Следующий() Цикл
  мРеквизиты.Вставить(Результат.Реквизит, Результат.Значение);
 КонецЦикла;
 
 Возврат мРеквизиты;
 
КонецФункции

//обработка подписки на событие ЗаписьИстории
Процедура ЗаписьИсторииПриЗаписи(Источник, Отказ) Экспорт
 
 ОбновитьИсторию(Источник.Ссылка);
 
КонецПроцедуры 
В конце оформляем подписку на событие ПриЗаписи.


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


Так же можно завести справочник пользователей и дополнительно фиксировать автора изменений.

Комментариев нет:

Отправить комментарий