Как правильно организовать и отобразить историю изменений реквизитов справочника (владельца, госномер) на форме элемента в 1С?

Программист 1С v8.3 (Управляемые формы) Управленческий учет
← На главную

При разработке информационных систем на платформе 1С часто возникает задача по отслеживанию истории изменений определённых реквизитов справочников или документов. Это позволяет видеть, кто, когда и как изменил важные данные, что критически важно для управленческого учёта и анализа. В нашей задаче мы рассмотрим, как хранить историю владельцев и государственных номеров автомобилей, прикреплённых к элементам справочника, и как эффективно отобразить эту историю на форме элемента.

Представленная проблема заключается в создании справочника "АвтомобилиКлиентов" с необходимостью отслеживания истории владельцев (контрагентов) и государственных номеров. Изначально предлагалось использовать регистры сведений, но возникли вопросы о правильности их структуры и способах отображения истории на форме элемента справочника. Давайте вместе разберем, как спроектировать решение таким образом, чтобы оно было масштабируемым, надёжным и удобным в использовании.

Правильное проектирование регистров сведений для хранения истории

Для хранения истории изменений реквизитов, которые меняются со временем, идеальным решением в платформе 1С являются периодические регистры сведений. Это объект платформы, специально предназначенный для фиксации значений на определённую дату или момент времени.

Давайте проанализируем, почему именно периодические регистры сведений и какая структура будет оптимальной для нашей задачи.

Почему периодические регистры сведений?

Ключевая особенность периодических регистров сведений состоит в том, что уникальность записи определяется совокупностью измерений и поля "Период". Это означает, что для одного и того же набора измерений в один и тот же момент времени может существовать только одна запись. В нашей ситуации, у одного автомобиля в определённый момент времени может быть только один владелец и только один государственный номер. Если бы мы использовали непериодический регистр, нам пришлось бы вручную следить за уникальностью записей, что усложнило бы логику и могло привести к ошибкам.

Структура регистра сведений "ВладельцыАвтомобилей"

Для отслеживания истории владельцев автомобиля, мы создадим периодический регистр сведений ВладельцыАвтомобилей со следующей структурой:

  1. Периодичность: Установим периодичность в пределах дня или секунды. Это позволит нам фиксировать смену владельца с точностью до дня или даже до секунды, если такая детализация необходима. Обычно для смены владельца достаточно точности в пределах дня.
  2. Измерение:
    • Автомобиль (Тип: СправочникСсылка.АвтомобилиКлиентов). Это измерение будет однозначно идентифицировать автомобиль, для которого фиксируется владелец. Критически важно установить флаг "Ведущее" для этого измерения. Это значительно упростит отображение истории на форме элемента, как мы рассмотрим позже.
  3. Ресурс:
    • Владелец (Тип: СправочникСсылка.Контрагенты). Именно здесь мы будем хранить ссылку на контрагента, который является владельцем автомобиля на указанный период.

Почему Владелец должен быть ресурсом, а не измерением? Представим ситуацию, описанную в обсуждении: Вася продал машину Маше, а потом Маша снова продала машину Васе. Если бы Владелец был измерением, то для связки "Автомобиль - Вася" мы могли бы сделать только одну запись. Повторная запись Васи как владельца (но уже с другой датой) была бы невозможна, так как ключ уникальности (Автомобиль + Владелец + Период) уже существует, если мы не учтем период. Сделав Владелец ресурсом, мы можем иметь записи вида:

  1. 10.01.2024 - Автомобиль "Лада Гранта" - Владелец "Вася"
  2. 01.02.2025 - Автомобиль "Лада Гранта" - Владелец "Маша"
  3. 01.03.2025 - Автомобиль "Лада Гранта" - Владелец "Вася"

Такая структура корректно отражает последовательную смену владельцев, позволяя одному и тому же лицу становиться владельцем несколько раз.

Структура регистра сведений "ГосНомераАвтомобилей"

Аналогично, для отслеживания истории государственных номеров автомобиля, мы создадим периодический регистр сведений ГосНомераАвтомобилей:

  1. Периодичность: В пределах дня или секунды.
  2. Измерение:
    • Автомобиль (Тип: СправочникСсылка.АвтомобилиКлиентов). Также ведущее измерение для связи с формой элемента.
  3. Ресурс:
    • ГосНомер (Тип: Строка). Здесь будет храниться значение государственного номера.

Логика здесь та же: в определённый момент времени у автомобиля есть только один государственный номер, и сам номер может меняться со временем, но в каждый момент он уникален для автомобиля.

Запись данных в регистры сведений

После того как мы спроектировали регистры, нам необходимо обеспечить запись данных в них при изменении соответствующих реквизитов справочника "АвтомобилиКлиентов". Наиболее подходящим местом для такой логики является модуль объекта справочника, в обработчике события ПриЗаписи.

Логика записи

В обработчике ПриЗаписи мы должны сравнить текущие значения реквизитов "Владелец" и "ГосНомер" со значениями, которые были до начала записи (т.е. старыми значениями, хранящимися в базе данных). Если какое-либо из значений изменилось, мы создаём новую запись в соответствующем периодическом регистре сведений на текущую дату.

Для получения старых значений реквизитов мы используем свойство ПредыдущееЗначение, доступное в обработчике ПриЗаписи, или выполняем чтение данных из базы перед записью. Давайте рассмотрим пример кода:


// В модуле объекта справочника "АвтомобилиКлиентов"

Процедура ПриЗаписи(Отказ)
    // Получаем текущие значения реквизитов
    ТекущийВладелец = ЭтотОбъект.Владелец;
    ТекущийГосНомер = ЭтотОбъект.ГосНомер;

    // Определяем, изменился ли владелец
    ИзменилсяВладелец = Ложь;
    Если ЭтоНовый() Тогда
        // Для нового элемента всегда создаем запись об первом владельце
        ИзменилсяВладелец = Истина;
    Иначе
        // Для существующего элемента сравниваем с предыдущим значением
        СтарыйВладелец = ПредыдущееЗначение("Владелец");
        Если ТекущийВладелец <> СтарыйВладелец Тогда
            ИзменилсяВладелец = Истина;
        КонецЕсли;
    КонецЕсли;

    // Определяем, изменился ли госномер
    ИзменилсяГосНомер = Ложь;
    Если ЭтоНовый() Тогда
        // Для нового элемента всегда создаем запись об первом гос. номере
        ИзменилсяГосНомер = Истина;
    Иначе
        // Для существующего элемента сравниваем с предыдущим значением
        СтарыйГосНомер = ПредыдущееЗначение("ГосНомер");
        Если ТекущийГосНомер <> СтарыйГосНомер Тогда
            ИзменилсяГосНомер = Истина;
        КонецЕсли;
    КонецЕсли;

    // Запись в регистр сведений "ВладельцыАвтомобилей"
    Если ИзменилсяВладелец Тогда
        Движение = Движения.ВладельцыАвтомобилей.Добавить();
        Движение.Период    = ТекущаяДата();
        Движение.Автомобиль = Ссылка;
        Движение.Владелец  = ТекущийВладелец;
    КонецЕсли;

    // Запись в регистр сведений "ГосНомераАвтомобилей"
    Если ИзменилсяГосНомер Тогда
        Движение = Движения.ГосНомераАвтомобилей.Добавить();
        Движение.Период    = ТекущаяДата();
        Движение.Автомобиль = Ссылка;
        Движение.ГосНомер  = ТекущийГосНомер;
    КонецЕсли;

КонецПроцедуры

В этом коде мы сначала проверяем, является ли элемент новым. Если да, то предполагаем, что текущие значения владельца и госномера являются первыми, и записываем их. Если элемент уже существует, мы сравниваем текущие значения с их ПредыдущееЗначение. Если есть изменения, создаются новые записи в соответствующих регистрах сведений на текущий момент времени. Важно использовать ТекущаяДата() для поля Период, так как регистры у нас периодические.

Отображение истории на форме элемента справочника

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

1. Автоматический механизм (свойство "Ведущее" измерения)

Это самый простой и быстрый способ, если вы хотите получить базовый функционал без написания кода. Как мы уже упоминали, для измерения Автомобиль в обоих регистрах сведений установите флаг "Ведущее".

  1. Откройте конфигуратор.
  2. Перейдите к регистру сведений ВладельцыАвтомобилей (и ГосНомераАвтомобилей).
  3. В измерениях найдите Автомобиль и в свойствах этого измерения установите флаг "Ведущее".
  4. Обновите конфигурацию базы данных.

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

Преимущества: Минимум усилий, стандартный интерфейс.

Недостатки: В некоторых случаях (особенно в более сложных конфигурациях или на сильно модифицированных формах) панель навигации может быть скрыта или иметь не самый очевидный вид. Пользователь может не сразу заметить эти ссылки. Как было отмечено в одном из сообщений, "на нынешней платформе панель навигации может просто прятать, опираясь на фазы луны и юпитера", что подчёркивает возможную нестабильность такого подхода в некоторых условиях.

2. Динамический список на форме

Этот подход позволяет отображать историю непосредственно на форме элемента, что обеспечивает более наглядный и интегрированный интерфейс.

  1. Откройте форму элемента справочника "АвтомобилиКлиентов" в конфигураторе.
  2. На панели элементов формы добавьте новую страницу (если хотите разместить историю на отдельной вкладке) или группу, а затем в неё добавьте элемент "Таблица".
  3. В свойствах этой новой таблицы укажите "Тип данных" как "Динамический список".
  4. Создайте новый динамический список для этой таблицы. В его свойствах:
    • Основная таблица: Выберите соответствующий регистр сведений, например, РегистрСведений.ВладельцыАвтомобилей.
    • Настройка списка: Откройте конструктор запроса или вручную добавьте поля, которые хотите отображать (Период, Владелец, Автомобиль).
    • Настройка отбора: Это самый важный шаг. Добавьте новый элемент отбора для поля Автомобиль. Установите "Вид сравнения" как "Равно", а в качестве "Значения" укажите ссылку на текущий объект формы. Для этого можно использовать выражение, например, Объект.Ссылка или &ТекущийАвтомобиль, если вы предварительно определили параметр формы.
  5. Перетащите поля из динамического списка на колонки таблицы на форме.
  6. Повторите шаги для регистра ГосНомераАвтомобилей.

Этот способ позволяет пользователю видеть историю, не покидая форму элемента, и обеспечивает гибкость в настройке внешнего вида.

3. Кнопка или гиперссылка с программным открытием

Если вы хотите предоставить пользователю возможность просматривать историю по требованию, можно добавить на форму кнопку или гиперссылку, которая программно будет открывать форму списка регистра сведений, уже отфильтрованную по текущему автомобилю.

  1. Откройте форму элемента справочника "АвтомобилиКлиентов" в конфигураторе.
  2. Добавьте на форму кнопку (например, "История владельцев") или элемент типа "Надпись" с включённым свойством "Гиперссылка".
  3. Создайте обработчик события "Нажатие" для этой кнопки (или "Нажатие" для гиперссылки).
  4. В обработчике напишите код для открытия формы списка регистра сведений с заданным отбором. Пример кода:

// В модуле формы справочника "АвтомобилиКлиентов"

&НаКлиенте
Процедура ИсторияВладельцев(Команда)
    ПараметрыОткрытия = Новый Структура("Отбор", Новый Структура("Автомобиль", Объект.Ссылка));
    ОткрытьФорму("РегистрСведений.ВладельцыАвтомобилей.ФормаСписка", ПараметрыОткрытия);
КонецПроцедуры

&НаКлиенте
Процедура ИсторияГосномеров(Команда)
    ПараметрыОткрытия = Новый Структура("Отбор", Новый Структура("Автомобиль", Объект.Ссылка));
    ОткрытьФорму("РегистрСведений.ГосНомераАвтомобилей.ФормаСписка", ПараметрыОткрытия);
КонецПроцедуры

Этот подход даёт полный контроль над поведением и внешним видом, но требует написания небольшого объёма кода.

Альтернативный подход: Механизм версионирования платформы 1С

Помимо ручного создания регистров сведений, платформа 1С предоставляет встроенный механизм версионирования объектов, также известный как "История изменений". Этот функционал является мощной альтернативой и позволяет отслеживать изменения любых реквизитов объекта без дополнительного программирования.

Как это работает?

  1. Включение опции: В общих настройках программы (обычно в разделе "Администрирование" - "Общие настройки" или "Настройки пользователя и прав") включается опция "Хранить историю изменений".
  2. Настройка объектов: После включения общей опции, вы можете детально настроить, для каких справочников, документов или других объектов необходимо хранить историю. Для каждого объекта можно указать, когда сохранять новую версию (например, "При записи" или "При проведении").
  3. Автоматическая фиксация: После настройки для справочника "АвтомобилиКлиентов" любое изменение и сохранение его элемента будет автоматически фиксироваться платформой.

Преимущества версионирования платформы:

  1. Минимум программирования: Вам не нужно создавать регистры сведений и писать код для записи в них. Платформа делает всё автоматически.
  2. Полнота информации: Сохраняется не только новое значение реквизита, но и старое, а также пользователь, внесший изменение, и точное время изменения.
  3. Стандартный интерфейс: Платформа предоставляет готовую, унифицированную форму для просмотра истории изменений, сравнения версий и даже отката к предыдущей версии объекта. Это значительно упрощает работу пользователя и разработчика.

Недостатки версионирования платформы:

  1. Увеличение размера базы данных: Хранение версий всех изменений по всем настроенным объектам может значительно увеличить объем информационной базы. Это особенно критично для объектов с частыми изменениями.
  2. Избыточность: Механизм сохраняет изменения всех реквизитов объекта. Если вам нужно отслеживать только один или два конкретных реквизита из многих, это может привести к хранению избыточной информации.
  3. Сложность для отчетов: Получить данные для аналитических отчетов (например, "Кто владел автомобилем в прошлом году?") из данных версионирования сложнее, чем из специально созданного периодического регистра сведений. Данные версионирования хранятся в специфической структуре, оптимизированной для сравнения версий, но не для аналитических запросов.

При выборе между специализированными регистрами сведений и механизмом версионирования платформы следует учитывать конкретные требования к задаче. Если вам нужна детальная аналитика по изменениям конкретных реквизитов и минимальный объем хранения, то регистры сведений могут быть предпочтительнее. Если же вам требуется общее отслеживание всех изменений объекта без глубокой аналитики и важна скорость реализации, то версионирование платформы — отличный выбор.

В типовых конфигурациях 1С, например, в справочнике "Физические лица", история ФИО часто реализуется именно через специализированные периодические регистры сведений (например, ИсторияФИОФизЛиц), что подтверждает надёжность и применимость данного подхода для конкретных, целенаправленных задач по отслеживанию истории реквизитов.

← На главную