При разработке в среде 1С:Предприятие программисты часто сталкиваются с задачей ведения истории изменения каких-либо состояний объектов. Классический пример — история изменения статусов документов (например, договоров, заявок или дел по просроченной задолженности). Естественным желанием начинающего разработчика является создание периодического регистра сведений, подчиненного документу-регистратору, с записью движений непосредственно при проведении этого документа.
Однако при попытке реализовать это «в лоб» разработчик сталкивается с неприятным поведением платформы: при каждом повторном проведении документа старые записи по этому регистратору бесследно исчезают, а в регистре остается только одна, самая последняя строка. Изменение свойств проведения документа (например, отключение автоматического удаления движений) не приносит желаемого результата.
В этой статье мы подробно разберем, почему платформа 1С ведет себя именно так, выясним причину такого поведения и рассмотрим три архитектурно верных способа решения этой задачи, которые применяются в профессиональной разработке.
---
Для того чтобы понять суть проблемы, нам необходимо проанализировать логику работы платформы 1С с подчиненными регистрами. Когда регистр сведений имеет режим записи «Подчинение регистратору», его жизненный цикл становится жестко связанным с транзакционным циклом документа-регистратора.
Каждый раз, когда пользователь проводит или перезаписывает документ с формированием движений, платформа выполняет следующие действия:
ОбработкаПроведения в модуле объекта документа.Даже если вы зайдете в свойства документа на вкладку «Движения» и установите свойство «Удаление движений» в значение «Не удалять автоматически», это не решит проблему накопления истории. При вызове метода Движения.Записать() (или при автоматической записи движений платформой по окончании проведения) коллекция движений этого документа по регистру будет перезаписана целиком. Платформа 1С проектировалась исходя из концепции, что документ — это однократное событие в физическом времени, а не процесс, растянутый во времени. Документ должен фиксировать хозяйственную операцию в определенный момент времени, и его движения обязаны строго соответствовать реквизитам документа на этот момент.
Попытка использовать один и тот же документ в качестве регистратора для накопления истории его собственного жизненного цикла противоречит логике платформы. Если вам необходимо хранить историю изменения статусов одного объекта, следует использовать другие подходы. Ниже мы разберем три лучших решения.
---
Если вам нужно просто и быстро организовать хранение истории изменения статусов без создания дополнительных документов, использование независимого регистра сведений — это лучший выбор.
Проанализируем этот подход по шагам:
Дело (или любой другой ваш объект) с типом ссылки на ваш документ.Дело свойство Ведущее. Это гарантирует, что при удалении документа из базы данных платформа автоматически очистит все связанные записи в регистре сведений, предотвращая появление «битых» ссылок и сохраняя ссылочную целостность СУБД.СтатусДела (например, тип — перечисление или справочник).Запись в независимый регистр сведений должна выполняться вне транзакции проведения. Писать в независимые регистры из процедуры ОбработкаПроведения крайне не рекомендуется, так как это может приводить к избыточным блокировкам базы данных и нарушению логики проведения. Лучшим местом для этого является обработчик события ПриЗаписи в модуле объекта документа.
Рассмотрим пример кода, который необходимо разместить в модуле объекта вашего документа:
Процедура ПриЗаписи(Отказ)
// Предотвращаем выполнение кода при обмене данными или если запись отменена
Если ОбменДанными.Загрузка Или Отказ Тогда
Возврат;
КонецЕсли;
// Нам нужно записывать статус только в том случае, если он действительно изменился.
// Для этого можно сравнить текущее значение реквизита со значением в базе данных.
СсылкаНаБазу = ОбщегоНазначения.ЗначенияРеквизитовОбъекта(Ссылка, "СтатусДела");
Если СсылкаНаБазу.СтатусДела <> СтатусДела Тогда
// Создаем менеджер записи для работы с одной строкой независимого регистра
МенеджерЗаписи = РегистрыСведений.СтатусыДелОПросроченнойЗадолженности.СоздатьМенеджерЗаписи();
// Заполняем ключевые поля (период и измерения)
МенеджерЗаписи.Период = ТекущаяДата();
МенеджерЗаписи.Дело = Ссылка;
// Заполняем ресурсы и реквизиты
МенеджерЗаписи.СтатусДела = СтатусДела;
МенеджерЗаписи.Пользователь = ПараметрыСеанса.ТекущийПользователь;
Попытка
// Истина означает замещение записи, если на эту же секунду уже существует запись
МенеджерЗаписи.Записать(Истина);
Исключение
ЗаписьЖурналаРегистрации("РегистрацияСтатуса", УровеньЖурналаРегистрации.Ошибка,,, ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
Отказ = Истина;
КонецПопытки;
КонецЕсли;
КонецПроцедуры
Используя этот метод, при каждом изменении реквизита СтатусДела в формуляр документа и последующем сохранении в регистр будет добавляться новая строка с актуальным временем, именем пользователя и новым статусом, при этом старые записи за прошлые периоды останутся нетронутыми.
---
Этот метод является стандартом для крупных корпоративных систем на платформе 1С (ERP, КА, УТ). Он применяется тогда, когда смена статуса сама по себе является важным бизнес-событием, требующим согласования, указания дополнительных аналитик или фиксации ответственных лиц.
Рассмотрим структуру этого решения:
УстановкаСтатусаДела.УстановкаСтатусаДела в процедуре ОбработкаПроведения формируется стандартное движение в подчиненный регистр сведений. При этом период записи будет равен дате проведения этого вспомогательного документа.Разберем преимущества данного подхода:
---
Если ваша задача состоит исключительно в аудите изменений (выяснить, кто, когда и какой статус установил) и эти данные не требуются для использования в тяжелых запросах, динамических списках или для логики проведения других документов, создавать регистр вообще не нужно.
Начиная с версии платформы 8.3.11, в 1С доступен мощный встроенный механизм «История данных» (версионирование на уровне платформы). Чтобы задействовать его, выполните следующие шаги:
СтатусДела убедитесь, что версионирование также включено.После этого платформа автоматически при каждом сохранении документа будет записывать его версию в специальную системную таблицу. Пользователи смогут просматривать всю историю изменения полей документа (включая автора изменений, дату и старые/новые значения статусов) через стандартную команду «История изменений» непосредственно на форме документа.
---
Выбор конкретного метода зависит от требований к вашей системе: