Как правильно организовать хранение и изменение статусов документа в 1С?

Программист Управленческий учет
← На главную

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

Почему нельзя использовать Регистр Накопления для статусов?

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

Проанализируем причину. Регистры накопления (РегистрНакопления) предназначены для учета количественных показателей — остатков и оборотов (например, остатки товаров на складе, сумма задолженности контрагента). Для быстрого получения этих данных система использует агрегированные данные из специальных таблиц итогов. Структура этих таблиц напрямую зависит от набора измерений регистра.

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

Решение 1: Регистр Сведений — правильный и рекомендуемый подход

Наиболее правильным и широко используемым методом для хранения статусов и других состояний объектов является Регистр Сведений (РегистрСведений). Это эффективный механизм для хронологического хранения произвольных данных, чье основное назначение — хранить информацию в определенных разрезах на определенный момент времени.

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

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

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

Посмотрим на пример кода для записи нового статуса в периодический регистр сведений:


// Этот код можно разместить в команде формы документа
&НаКлиенте
Процедура СогласоватьДокумент(Команда)
    // Передаем на сервер ссылку на документ и новый статус
    СогласоватьДокументНаСервере(Объект.Ссылка, Перечисления.СтатусыСогласования.Согласован);
    
    // Обновляем форму, чтобы отобразить новый статус
    ОбновитьИнтерфейс();
КонецПроцедуры

&НаСервере
Процедура СогласоватьДокументНаСервере(ДокументСсылка, НовыйСтатус)
    // Создаем менеджер записи для регистра сведений
    // Он позволяет удобно работать с одной записью
    МенеджерЗаписи = РегистрыСведений.СтатусыДокументов.СоздатьМенеджерЗаписи();

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

Преимущества такого подхода:

Решение 2: Хранение статуса в реквизите документа

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

Как это реализуется? В объект документа добавляется новый реквизит, например, "Статус" (тип: ПеречислениеСсылка.СтатусыСогласования). При смене статуса мы просто меняем значение этого реквизита и перезаписываем объект документа.


&НаСервере
Процедура УстановитьНовыйСтатусНаСервере(ДокументСсылка, НовыйСтатус)
    // Получаем объект документа из базы данных
    ДокументОбъект = ДокументСсылка.ПолучитьОбъект();
    
    // Меняем значение реквизита
    ДокументОбъект.Статус = НовыйСтатус;
    
    // Просто перезаписываем документ, НЕ проводя его
    // РежимЗаписиДокумента.Запись не выполняет процедуру ОбработкаПроведения
    ДокументОбъект.Записать(РежимЗаписиДокумента.Запись);
КонецПроцедуры

Плюсы:

Минусы:

А что насчет перепроведения документа?

В изначальном вопросе была идея инициировать повторное проведение документа для смены статуса. Как мы выяснили, это избыточное и неверное действие для данной задачи. Однако, если по какой-то другой причине вам все же необходимо программно перепровести документ, это можно сделать так:


// Получаем объект документа
ДокОбъект = СсылкаНаДокумент.ПолучитьОбъект();

// Выполняем перепроведение. 
// Этот метод вызовет процедуру "ОбработкаПроведения" со всеми вытекающими последствиями:
// удалением старых движений и формированием новых.
ДокОбъект.Записать(РежимЗаписиДокумента.Проведение);

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

Итоги и рекомендации

Давайте подведем итог. Для реализации механизма статусов, состояний или любого другого отслеживания жизненного цикла документов в 1С придерживайтесь следующих правил:

  1. Используйте периодический Регистр Сведений. Это стандарт де-факто, обеспечивающий гибкость, производительность и архитектурную правильность решения.
  2. Никогда не используйте Регистр Накопления для хранения статусов. Это приведет к деградации производительности системы в будущем.
  3. Не перепроводите документ без необходимости. Смена статуса — это изменение метаданных, а не учетных данных. Эти операции должны быть разделены.

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

← На главную