При разработке учетных механизмов на платформе 1С начинающие разработчики нередко совершают концептуальную ошибку: пытаются сохранить в ресурсе регистра накопления не сумму текущей операции, а текущий остаток по измерению на момент проведения документа. Проанализируем, почему этот подход ломает логику системы, как устроена работа регистров накопления и как правильно формировать движения и выводить остатки пользователю.
Рассмотрим типовую ситуацию. При проведении документа поступления денежных средств разработчик пытается вычислить остаток денег в кошельке и записать его в ресурс регистра:
Процедура ОбработкаПроведения(Отказ, Режим)
Движения.РегистрОстатков.Записывать = Истина;
Движение = Движения.РегистрОстатков.Добавить();
Движение.ВидДвижения = ВидДвиженияНакопления.Приход;
Движение.Период = Дата;
Движение.Кошелек = КошелекПоступления;
// Ошибочный подход: попытка рассчитать и записать нарастающий итог
Фильтр = Новый Структура("Кошелек", Движение.Кошелек);
Остаток = РегистрыНакопления.РегистрОстатков.Остатки(Дата, Фильтр, "Кошелек", "Сумма").Итог("Сумма");
Движение.Сумма = Сумма + Остаток;
КонецПроцедуры
Такой подход приводит к неконтролируемому умножению данных. Выясним причину: при проведении первого документа на 1000 рублей остаток составит 1000. При проведении второго на 500 рублей код считывает остаток 1000, прибавляет 500 и записывает в регистр 1500. Платформа 1С для вычисления остатков автоматически суммирует все движения в регистре: 1000 + 1500 = 2500 рублей вместо реальных 1500.
Регистры накопления остатков физически состоят из двух связанных таблиц:
В ресурс регистра всегда должна записываться только дельта (сумма текущей операции). Платформа 1С сама берет на себя задачу вычисления остатков на любой момент времени с помощью виртуальной таблицы Остатки.
Запись остатка вместо дельты порождает критические сбои в работе конфигурации:
Разберем по шагам, как должен выглядеть эталонный модуль проведения документа. В ресурс Сумма передается исключительно реквизит Сумма из документа:
Процедура ОбработкаПроведения(Отказ, Режим)
// Устанавливаем признак необходимости записи движений
Движения.РегистрОстатков.Записывать = Истина;
// Формируем движение прихода
Движение = Движения.РегистрОстатков.Добавить();
Движение.ВидДвижения = ВидДвиженияНакопления.Приход;
Движение.Период = Дата;
Движение.Кошелек = КошелекПоступления;
Движение.Сумма = Сумма; // Записываем только сумму документа!
КонецПроцедуры
Если требуется отобразить текущий остаток по кошельку для удобства пользователя, это делается на уровне интерфейса (в форме), а не через искажение данных регистра.
Вариант 1. Отображение остатка в форме документа
Создадим реквизит формы (не реквизит документа) с типом Число и заполним его при выборе кошелька на клиенте через серверный вызов:
&НаСервереБезКонтекста
Функция ПолучитьОстатокПоКошельку(Кошелек, ДатаОстатков)
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ЕСТЬNULL(РегистрОстатковОстатки.СуммаОстаток, 0) КАК Остаток
|ИЗ
| РегистрНакопления.РегистрОстатков.Остатки(&Период, Кошелек = &Кошелек) КАК РегистрОстатковОстатки";
Запрос.УстановитьПараметр("Период", ДатаОстатков);
Запрос.УстановитьПараметр("Кошелек", Кошелек);
Выборка = Запрос.Выполнить().Выбрать();
Если Выборка.Следующий() Тогда
Возврат Выборка.Остаток;
КонецЕсли;
Возврат 0;
КонецФункции
Вариант 2. Отображение остатков в списках и отчетах
Для просмотра динамики изменения остатка с нарастающим итогом создается отчет на базе Системы компоновки данных (СКД) с обращением к виртуальной таблице ОстаткиИОбороты, где платформа рассчитывает начальный остаток, приход, расход и конечный остаток.
Если перед вами стоит задача хранить состояние объекта во времени (например, статус договора, курс валюты на дату или фамилию ответственного), для этого используется не регистр накопления, а периодический регистр сведений. В нем для получения актуального состояния на конкретный момент времени применяется виртуальная таблица СрезПоследних.
Для учета материальных ценностей, денежных средств и взаиморасчетов всегда используется регистр накопления, где каждое движение фиксирует только изменение величины ресурса.