Как правильно формировать движения регистра накопления остатков и почему нельзя записывать в него нарастающий итог?

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

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

В чем заключается ошибка записи остатка в ресурс регистра

Рассмотрим типовую ситуацию. При проведении документа поступления денежных средств разработчик пытается вычислить остаток денег в кошельке и записать его в ресурс регистра:


Процедура ОбработкаПроведения(Отказ, Режим)
    Движения.РегистрОстатков.Записывать = Истина;
    Движение = Движения.РегистрОстатков.Добавить();
    Движение.ВидДвижения = ВидДвиженияНакопления.Приход;
    Движение.Период = Дата;
    Движение.Кошелек = КошелекПоступления;
    
    // Ошибочный подход: попытка рассчитать и записать нарастающий итог
    Фильтр = Новый Структура("Кошелек", Движение.Кошелек);
    Остаток = РегистрыНакопления.РегистрОстатков.Остатки(Дата, Фильтр, "Кошелек", "Сумма").Итог("Сумма");
    Движение.Сумма = Сумма + Остаток;
КонецПроцедуры

Такой подход приводит к неконтролируемому умножению данных. Выясним причину: при проведении первого документа на 1000 рублей остаток составит 1000. При проведении второго на 500 рублей код считывает остаток 1000, прибавляет 500 и записывает в регистр 1500. Платформа 1С для вычисления остатков автоматически суммирует все движения в регистре: 1000 + 1500 = 2500 рублей вместо реальных 1500.

Архитектурный принцип работы регистров накопления

Регистры накопления остатков физически состоят из двух связанных таблиц:

  1. Таблица движений — хранит только атомарные факты изменений (приход или расход с указанием точной суммы конкретной хозяйственной операции).
  2. Таблица итогов (агрегатов) — платформа автоматически рассчитывает и хранит в ней промежуточные остатки на начало каждого месяца для быстрого получения сальдо.

В ресурс регистра всегда должна записываться только дельта (сумма текущей операции). Платформа 1С сама берет на себя задачу вычисления остатков на любой момент времени с помощью виртуальной таблицы Остатки.

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

Запись остатка вместо дельты порождает критические сбои в работе конфигурации:

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

Правильное формирование движений документа

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


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

Как вывести актуальный остаток пользователю в интерфейсе

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

Вариант 1. Отображение остатка в форме документа

Создадим реквизит формы (не реквизит документа) с типом Число и заполним его при выборе кошелька на клиенте через серверный вызов:


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

Вариант 2. Отображение остатков в списках и отчетах

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

Когда использовать другие объекты метаданных

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

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

← На главную