Форум 1С
Программистам, бухгалтерам, администраторам, пользователям
Задай вопрос - получи решение проблемы
14 дек 2024, 02:56

История изменения таб. части документов

Автор KKnD, 23 окт 2014, 09:34

0 Пользователей и 1 гость просматривают эту тему.

KKnD

Всем доброго дня.
Понадобилось фиксировать изменения табличной части документа ЗаказПокупателя.
Покопался в интернете и нашел простенький код, но никак не могу с ним справиться:

хочу, что бы у меня фиксировалась история изменений табличный части «Товары» документа «ЗаказПокупателя»
Создаем справочник "История изменений"
Для начала создал элементарный справочник "ИсторияИзменений":

Справочник история изменений
Реквизиты:
Объект – ДокументСсылка, СправочникСсылка (По этому объекту в элементе справочника будет хранится история)
Табличная часть – изменения:
(тут тип значения ДокументСсылка.ЗаказПокупателя)
ДатаЗаписи – Дата (дата и время записи изменения)
(просто тип  дата состав  дата и время?)
НазваниеТабличнойЧасти – Строка (длина 50, Название табличной части по которой требуется фиксировать изменения)
(Тут тип строка и назвать ее Товары?)
ТаблицаИзменений – Строка (длина неограничена, тут будет хранится наша таблица значений)
(Тут тип строка и назвать ее ТаблицаИзменений?)
Автор – Пользователь (кто сделал изменения)
(тут тип значения СправочникиСсылка.Пользователи?)

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

Это основная функция которую будет вызывать для записи изменения
//Фиксируются только новые и измененные строки
//Табличная часть - в эту переменную передаем табличную часть документ
//НазваниеТабличнойЧасти - название табличной части. именно по этому параметру будет искаться предыдущее значение табличной части.
//Объект - объект, в принципе может и не поднадобиться
Процедура ЗафиксироватьИзменения(ТабличнаяЧасть, НазваниеТабличнойЧасти, Объект) Экспорт
СтараяТаблица = ПолучитьСтаруюТаблицу(НазваниеТабличнойЧасти); //Получаем старую таблицу
НоваяТаблица = ТабличнаяЧасть.Выгрузить();

Если ТипЗнч(СтараяТаблица)=Тип("ТаблицаЗначений") Тогда
//Если в новой таблице нет строк тогда просто записываем новую таблицу
Если НоваяТаблица.Количество()=0 и СтараяТаблица.Количество()>0 Тогда
ЗафиксироватьТаблицу(НоваяТаблица, НазваниеТабличнойЧасти);
ИначеЕсли НоваяТаблица.Количество()>0 и СтараяТаблица.Количество()>0 Тогда
//Надо сравнивать
Если ЕстьИзмененияВТаблицах(СтараяТаблица, НоваяТаблица) Тогда
ЗафиксироватьТаблицу(НоваяТаблица, НазваниеТабличнойЧасти);
КонецЕсли;
КонецЕсли;
Иначе
//Сравнивать не надо - это первая фиксация
//Фиксируем только если в таблице есть строки
Если НоваяТаблица.Количество()>0 Тогда
ЗафиксироватьТаблицу(НоваяТаблица, НазваниеТабличнойЧасти);
КонецЕсли;
КонецЕсли;
КонецПроцедуры


//Функция получает ТаблицуЗначений - предыдущее значение табличной части
Функция ПолучитьСтаруюТаблицу(НазваниеТабличнойЧасти) Экспорт       
МассивСтрок = Изменения.НайтиСтроки(Новый Структура("НазваниеТабличнойЧасти", НазваниеТабличнойЧасти));
Если МассивСтрок.Количество()>0 Тогда
ТаблицаИзменений = ЗначениеИзСтрокиВнутр(МассивСтрок.Получить(МассивСтрок.Количество()-1).ТаблицаИзменений);
Возврат ТаблицаИзменений;
Иначе
ТаблицаИзменений = Неопределено;
Возврат ТаблицаИзменений;
КонецЕсли;
КонецФункции


//Функция сравнивает две строки, которые являются предыдущим и текущим значением ТабличнойЧасти документа
Функция ЕстьИзмененияВТаблицах(СтараяТаблица, НоваяТаблица)
Если ЗначениеВСтрокуВнутр(СтараяТаблица)=ЗначениеВСтрокуВнутр(НоваяТаблица) Тогда
Возврат Ложь;
Иначе
Возврат Истина;
КонецЕсли;
КонецФункции


Фиксируем изменения, а именно записываем новую табличную часть документа в элемент справочника "ИсторияИзменений"
Функция ЗафиксироватьТаблицу(ТаблицаИзменений, НазваниеТабличнойЧасти) Экспорт
НоваяСтрока = Изменения.Добавить();
НоваяСтрока.ДатаЗаписи = ТекущаяДата();
НоваяСтрока.НазваниеТабличнойЧасти = НазваниеТабличнойЧасти;
НоваяСтрока.ТаблицаИзменений = ЗначениеВСтрокуВнутр(ТаблицаИзменений);
НоваяСтрока.Автор = ПараметрыСеанса.Пользователь;
Записать();
КонецФункции



   //Это основная функция которую будет вызывать для записи изменения
//Фиксируются только новые и измененные строки
//Табличная часть - в эту переменную передаем табличную часть документ
//НазваниеТабличнойЧасти - название табличной части. именно по этому параметру будет искаться предыдущее значение табличной части.
//Объект - объект, в принципе может и не поднадобиться
Процедура ЗафиксироватьИзменения(ТабличнаяЧасть, НазваниеТабличнойЧасти, Объект) Экспорт
СтараяТаблица = ПолучитьСтаруюТаблицу(НазваниеТабличнойЧасти); //Получаем старую таблицу
НоваяТаблица = ТабличнаяЧасть.Выгрузить();

Если ТипЗнч(СтараяТаблица)=Тип("ТаблицаЗначений") Тогда
//Если в новой таблице нет строк тогда просто записываем новую таблицу
Если НоваяТаблица.Количество()=0 и СтараяТаблица.Количество()>0 Тогда
ЗафиксироватьТаблицу(НоваяТаблица, НазваниеТабличнойЧасти);
ИначеЕсли НоваяТаблица.Количество()>0 и СтараяТаблица.Количество()>0 Тогда
//Надо сравнивать
Если ЕстьИзмененияВТаблицах(СтараяТаблица, НоваяТаблица) Тогда
ЗафиксироватьТаблицу(НоваяТаблица, НазваниеТабличнойЧасти);
КонецЕсли;
КонецЕсли;
Иначе
//Сравнивать не надо - это первая фиксация
//Фиксируем только если в таблице есть строки
Если НоваяТаблица.Количество()>0 Тогда
ЗафиксироватьТаблицу(НоваяТаблица, НазваниеТабличнойЧасти);
КонецЕсли;
КонецЕсли;
КонецПроцедуры


//Функция получает ТаблицуЗначений - предыдущее значение табличной части
Функция ПолучитьСтаруюТаблицу(НазваниеТабличнойЧасти) Экспорт       
МассивСтрок = Изменения.НайтиСтроки(Новый Структура("НазваниеТабличнойЧасти", НазваниеТабличнойЧасти));
Если МассивСтрок.Количество()>0 Тогда
ТаблицаИзменений = ЗначениеИзСтрокиВнутр(МассивСтрок.Получить(МассивСтрок.Количество()-1).ТаблицаИзменений);
Возврат ТаблицаИзменений;
Иначе
ТаблицаИзменений = Неопределено;
Возврат ТаблицаИзменений;
КонецЕсли;
КонецФункции


//Функция сравнивает две строки, которые являются предыдущим и текущим значением ТабличнойЧасти документа
Функция ЕстьИзмененияВТаблицах(СтараяТаблица, НоваяТаблица)
Если ЗначениеВСтрокуВнутр(СтараяТаблица)=ЗначениеВСтрокуВнутр(НоваяТаблица) Тогда
Возврат Ложь;
Иначе
Возврат Истина;
КонецЕсли;
КонецФункции


Фиксируем изменения, а именно записываем новую табличную часть документа в элемент справочника "ИсторияИзменений"
Функция ЗафиксироватьТаблицу(ТаблицаИзменений, НазваниеТабличнойЧасти) Экспорт
НоваяСтрока = Изменения.Добавить();
НоваяСтрока.ДатаЗаписи = ТекущаяДата();
НоваяСтрока.НазваниеТабличнойЧасти = НазваниеТабличнойЧасти;
НоваяСтрока.ТаблицаИзменений = ЗначениеВСтрокуВнутр(ТаблицаИзменений);
НоваяСтрока.Автор = ПараметрыСеанса.Пользователь;
Записать();
КонецФункции

По сути это весь код для фиксации изменений, осталось сделать глобальную процедуру, которая будет вызываться из любого документа или справочника, а также можно дописать интерфейс, чтобы была возможность удобно смотреть историю.
Код функции указанной ниже размещаем в любом общем модуле. именно эта функция будет вызываться из модуля формы любого документа или справочника, из процедуры "ПослеЗаписи" с требуемыми параметрами.

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

Запрос.Текст = ТекстЗапроса;
Запрос.Параметры.Вставить("ОбъектСсылка", ОбъектСсылка);

ТЗ = Запрос.Выполнить().Выгрузить();
Если ТЗ.Количество()>0 Тогда
СправочникИзменений = ТЗ.Получить(0).Ссылка;
СправочникИзменений = СправочникИзменений.ПолучитьОбъект();
Иначе
СправочникИзменений = Справочники.ИсторияИзменений.СоздатьЭлемент();
СправочникИзменений.Объект = ОбъектСсылка;
СправочникИзменений.Записать();
КонецЕсли;

СправочникИзменений.ЗафиксироватьИзменения(ТабличнаяЧасть, НазваниеТабличнойЧасти, ОбъектСсылка);
КонецЕсли;
КонецПроцедуры




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

Запрос.Текст = ТекстЗапроса;
Запрос.Параметры.Вставить("ОбъектСсылка", ОбъектСсылка);

ТЗ = Запрос.Выполнить().Выгрузить();
Если ТЗ.Количество()>0 Тогда
СправочникИзменений = ТЗ.Получить(0).Ссылка;
СправочникИзменений = СправочникИзменений.ПолучитьОбъект();
Иначе
СправочникИзменений = Справочники.ИсторияИзменений.СоздатьЭлемент();
СправочникИзменений.Объект = ОбъектСсылка;
СправочникИзменений.Записать();
КонецЕсли;

СправочникИзменений.ЗафиксироватьИзменения(ТабличнаяЧасть, НазваниеТабличнойЧасти, ОбъектСсылка);
КонецЕсли;
КонецПроцедуры

Создаем форму элемента справочника "История изменений"
Рисуем форму элемента:

История изменений 1С
Форма элемента справочника история изменений выглядит в начальном виде именно так. В поле старые значения будут показываться предыдущие значения, а в поле новые значения... ну вы догадались. В эти поля являются табличным полями с названиями соответственно "ТаблицаСтароеЗначение" и "ТаблицаНовоеЗначение".
А теперь код формы:

Процедура АнализироватьТаблицы()
Если (ТаблицаСтароеЗначение.Количество() = 0) или (ТаблицаНовоеЗначение.Количество() = 0) Тогда

Иначе
ТЗРезНовая = ТаблицаНовоеЗначение.Скопировать();
ТЗРезНовая.Очистить();
ТЗРезСтарая = ТЗРезНовая.Скопировать();
КоличествоКолонок = ТЗРезНовая.Колонки.Количество();

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

КонецЦикла;
н=н+1;
КонецЦикла;
КонецЕсли;
КонецПроцедуры


Процедура ИзмененияПриАктивизацииСтроки(Элемент)
Если Изменения.Количество() > 0 Тогда
ТаблицаНовоеЗначение = ЗначениеИзСтрокиВнутр(Элемент.ТекущиеДанные.ТаблицаИзменений);
ЭлементыФормы.ТаблицаНовоеЗначение.СоздатьКолонки();

ТаблицаСтароеЗначение = Неопределено;

Если Элемент.ТекущиеДанные.НомерСтроки > 1 Тогда
н = Элемент.ТекущиеДанные.НомерСтроки-1;
Пока н > 0 Цикл
Если Изменения.Получить(н-1).НазваниеТабличнойЧасти = Элемент.ТекущиеДанные.НазваниеТабличнойЧасти Тогда
ТаблицаСтароеЗначение = ЗначениеИзСтрокиВнутр(Изменения.Получить(н-1).ТаблицаИзменений);
Прервать;
КонецЕсли;
КонецЦикла;
КонецЕсли;

Если ТипЗнч(ТаблицаСтароеЗначение) = Тип("ТаблицаЗначений") Тогда
ЭлементыФормы.ТаблицаСтароеЗначение.СоздатьКолонки();
КонецЕсли;
КонецЕсли;

АнализироватьТаблицы();
КонецПроцедуры




Процедура АнализироватьТаблицы()
Если (ТаблицаСтароеЗначение.Количество() = 0) или (ТаблицаНовоеЗначение.Количество() = 0) Тогда

Иначе
ТЗРезНовая = ТаблицаНовоеЗначение.Скопировать();
ТЗРезНовая.Очистить();
ТЗРезСтарая = ТЗРезНовая.Скопировать();
КоличествоКолонок = ТЗРезНовая.Колонки.Количество();

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

КонецЦикла;
н=н+1;
КонецЦикла;
КонецЕсли;
КонецПроцедуры


Процедура ИзмененияПриАктивизацииСтроки(Элемент)
Если Изменения.Количество() > 0 Тогда
ТаблицаНовоеЗначение = ЗначениеИзСтрокиВнутр(Элемент.ТекущиеДанные.ТаблицаИзменений);
ЭлементыФормы.ТаблицаНовоеЗначение.СоздатьКолонки();

ТаблицаСтароеЗначение = Неопределено;

Если Элемент.ТекущиеДанные.НомерСтроки > 1 Тогда
н = Элемент.ТекущиеДанные.НомерСтроки-1;
Пока н > 0 Цикл
Если Изменения.Получить(н-1).НазваниеТабличнойЧасти = Элемент.ТекущиеДанные.НазваниеТабличнойЧасти Тогда
ТаблицаСтароеЗначение = ЗначениеИзСтрокиВнутр(Изменения.Получить(н-1).ТаблицаИзменений);
Прервать;
КонецЕсли;
КонецЦикла;
КонецЕсли;

Если ТипЗнч(ТаблицаСтароеЗначение) = Тип("ТаблицаЗначений") Тогда
ЭлементыФормы.ТаблицаСтароеЗначение.СоздатьКолонки();
КонецЕсли;
КонецЕсли;

АнализироватьТаблицы();
КонецПроцедуры



Процедура ПослеЗаписи()

// Попытка
ЗафиксироватьИзмененияТабличнойЧасти(Работы, "Работы", ЭтотОбъект.Ссылка);
Исключение

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



У меня соответственно не получается вставить верные реквизиты для функции "ЗафиксироватьИзмененияТабличнойЧасти".
Если кто-то может - заполните пожалуйста код или поделитесь ссылкой...

Luzer1C

Знаю, что в УПП есть "Версионирование". В остальных базах - не знаю. Лучше здесь использовать стандартный механизм через регистр сведений, а не справочник.
Халамбалам.

Теги:

Похожие темы (5)

Рейтинг@Mail.ru

Поиск