За свою практику работы 1C программистом я видел два варианта хранения истории изменения данных: в основной базе регистр сведений с полем типа хранилище значений, заполняется по подписке на событие записи и в отдельной базе, доступ к которой происходит по OLE. Стандартное решение - БСП, подсистема "Версионирование объектов". Возможность хранения истории данных очень полезна, когда нужно найти причину ошибки в данных или просто найти крайнего ответственного. И вот наконец такую возможность включили в платформу, по информации сайта Заметки из Зазеркалья.
Конечно, платформа версии 8.3.11 еще пока находится в тестировании, в типовых конфигурациях это решение появится еще не скоро, но любопытство побеждает.
Посмотрим, что за механизм такой. Устанавливаем на компьютер платформу версии 8.3.11.2831 Для тестирования подойдет каркасная конфигурация с сайта подготовки к экзаменам http://1c.ru/spec/questions.htm. Берем ведерко с попкорном, устраиваемся удобнее. Режим совместимости конфигурации - не использовать. Забегая вперед, заметим, что при сохранении базы обратно в режиме совместимости 8.3.10 выйдет сообщение: "Из базы будут удалены версии данных".
В синтакс-помощнике появился менеджер истории данных, видно его методы.
История данных поддерживается для объектов: общие реквизиты, справочники, документы, бизнес-процессы, задачи, регистры сведений. В свойствах полей появилась настройка "История данных" (внизу рисунка).
Для некоторых стандартных реквизитов настройка пока не появилась (например, Пометка удаления). Возможно, это глюк особенность тестовой версии. Для простоты будем считать, что в конфигураторе новой версии у всех объектов (документы, справочники) установлено История данных = НеИспользовать, у реквизитов История данных = Использовать. Для табличных частей это свойство не имеет смысла, поскольку задается отдельно для каждого реквизита табличной части.
Причем, настройки конфигуратора используются как значения "по умолчанию". Настройки в режиме предприятия могут отличаться от настроек в конфигураторе. Регистрация изменений учитывает приоритет настроек предприятия.
Откроем обработку "НастройкаХраненияДанных", которая позволяет изменять настройки в режиме предприятие и находить отличия.
- Кнопка "Заполнить метаданные" выводит дерево метаданных по конфигурации. Пока настройки предприятия не заданы, колонка "История данных" показывает настройки из конфигуратора. Содержимое колонки можно изменять.
- Кнопка "Установить настройки" применяет одноименный метод к каждому объекту метаданных из дерева.
- Кнопка "Обновить историю" записывает изменения данных из временного хранения на постоянное. В документации рекомендуют метод ИсторияДанных.ОбновитьИсторию() вызывать раз в сутки, регламентным заданием, желательно НЕ в транзакции.
После установки свойства "История данных" документа "Приходная накладная" изменения начинаются фиксироваться. Создаем документ "Приходная накладная" № 3, сохраняем, затем изменяем реквизит Сумма по документу: вместо 3 пишем 0, сохраняем.
Переходим в обработку "Восстановить данные", в качестве текущего объекта выбираем документ "Приходная накладная" № 3.
Метод "ВыбратьВерсии" пока не показывает ни одной версии. Нажимаем "Обновить историю" из первой обработки. Теперь метод "ВыбратьВерсии" возвращает нам таблицу значений. Две версии - две строки. Вид изменения имеет два значения по версиям: сначала мы создали документ, потом изменили. В таблице значений несколько колонок скрыты.
Выбираем в таблице нужную строку, нажимаем "Получить данные версии". Метод считывает данные версии в структуру. Для наглядности выведем сообщение об различающихся реквизитах. Что и требовалось доказать.
Вывод: механизм интересный, заявленные функции выполняет. Примеры кода, обработки внутри прикрепленого файла.
После первых 10 скачиваний - планирую повышение цены.
P.S. В комментариях подсказали, что если для объекта ведется история данных, то в его системном меню есть отчет по истории данных.
И в завершение предлагаю помедитировать над кодом, обслуживающим объекты ИсторияДанных (DataHistory) из файла mngbase_root.res, который входит в состав платформы 8.3.11. Такого кода там много, хватит на всех желающих. Открывал в Notepad++.
&AtServer
Function GetPreviousVersionNumber(VersionNumber)
Var PreviousVersionNumber;
ExcludeDeleted = New Array();
ExcludeDeleted.Add(DataChangeType.Create);
ExcludeDeleted.Add(DataChangeType.Update);
Result = DataHistory.SelectVersions(
New Structure(
""Data, DataChangeType"",
Parameters.Data,
ExcludeDeleted),
""VersionNumber"",
""VersionNumber Asc"");
For Each CheckVersionNumber In Result Do
If CheckVersionNumber[0] = VersionNumber Then
Return PreviousVersionNumber;
EndIf;
PreviousVersionNumber = CheckVersionNumber[0];
EndDo;
Return PreviousVersionNumber;
EndFunction
&AtServer
Function GetLastVersionNumber()
ExcludeDeleted = New Array();
ExcludeDeleted.Add(DataChangeType.Create);
ExcludeDeleted.Add(DataChangeType.Update);
// select 1 version, this is last
Result = DataHistory.SelectVersions(
New Structure(
""Data, DataChangeType"",
Parameters.Data,
ExcludeDeleted),
""VersionNumber"",
""VersionNumber Desc"",
1);
For Each CheckVersionNumber In Result Do
Return CheckVersionNumber[0];
EndDo;
Return Undefined;
EndFunction
&AtClient
Procedure VersionsDiff(Command)
If Items.Versions.CurrentData = Undefined Then
Return;
EndIf;
VersionBeforeChange = Undefined;
VersionAfterChange = Undefined;
For Each SelectedRow In Items.Versions.SelectedRows Do
Version = Items.Versions.RowData(SelectedRow);
If VersionBeforeChange = Undefined Then
VersionBeforeChange = Version;
ElsIf VersionBeforeChange.VersionNumber > Version.VersionNumber Then
VersionBeforeChange = Version;
EndIf;
If VersionAfterChange = Undefined Then
VersionAfterChange = Version;
ElsIf VersionAfterChange.VersionNumber < Version.VersionNumber Then
VersionAfterChange = Version;
EndIf;
EndDo;
// diff on deleted version not available
If VersionAfterChange.DataChangeType = 2 Then
ShowNotAllowedActionsOnDeletedVersion();
Return;
EndIf;
// diff on deleted version not available
If VersionBeforeChange.DataChangeType = 2 Then
ShowNotAllowedActionsOnDeletedVersion();
Return;
EndIf;
VersionNumberAfterChange = VersionAfterChange.VersionNumber;
VersionNumberBeforeChange = VersionBeforeChange.VersionNumber;
If VersionNumberBeforeChange = VersionNumberAfterChange Then
ShowMessageBox(,NStr(""en='Select two versions for comparison';SYS='DataHistory.SelectVersionsTwoVersions'"", ""en""));
Return;
EndIf;
OpenForm(""sysForm:DataHistoryVersionsDiff"",
New Structure(
""Data, VersionNumberAfterChange, VersionNumberBeforeChange"",
Parameters.Data,
VersionNumberAfterChange,
VersionNumberBeforeChange));
EndProcedure