При разработке отчетов по регистрам бухгалтерии и накопления разработчики часто сталкиваются с ситуацией, когда итоговая строка по полю конечного остатка вычисляется неверно или задваивается при выводе детализации по документам движения. Проанализируем, почему возникает эта ошибка и как правильно настроить получение остатков в разрезе регистратора в Системе компоновки данных (СКД) и в классических запросах.
Разберем первопричину проблемы: поле Регистратор формирует исключительно обороты за период. Остаток — это моментный показатель (состояние на определенную точку на оси времени), а не интервальный. Простое суммирование конечных остатков по строкам документов-регистраторов приводит к получению бессмысленного числа, так как складываются остатки на разные последовательные моменты времени. Корректный общий итог по остатку — это остаток на конец всего выбранного периода отчета, а в строке документа — это остаток строго после проведения данного конкретного регистратора.
Для того чтобы платформа автоматически рассчитывала начальные и конечные остатки на всех уровнях группировок без искажения общих итогов, выполним правильную настройку запроса и ролей полей в СКД. Разберем этот процесс по шагам.
В список полей виртуальной таблицы ОстаткиИОбороты необходимо обязательно добавить поля базовых периодов, начальный остаток и номер строки движения. Это обеспечит строгую хронологическую последовательность записей, даже если несколько документов проведены в одну секунду или один документ делает несколько проводок по одному счету.
Посмотрим на пример правильного запроса к регистру бухгалтерии:
ВЫБРАТЬ
ХозрасчетныйОстаткиИОбороты.ПериодСекунда КАК ПериодСекунда,
ХозрасчетныйОстаткиИОбороты.Регистратор КАК Регистратор,
ХозрасчетныйОстаткиИОбороты.НомерСтроки КАК НомерСтроки,
ХозрасчетныйОстаткиИОбороты.Субконто1 КАК РасчетныйСчет,
ХозрасчетныйОстаткиИОбороты.СуммаНачальныйОстаток КАК СуммаНачальныйОстаток,
ХозрасчетныйОстаткиИОбороты.СуммаОборотДт КАК СуммаОборотДт,
ХозрасчетныйОстаткиИОбороты.СуммаОборотКт КАК СуммаОборотКт,
ХозрасчетныйОстаткиИОбороты.СуммаКонечныйОстаток КАК СуммаКонечныйОстаток
ИЗ
РегистрБухгалтерии.Хозрасчетный.ОстаткиИОбороты(
&НачалоПериода,
&КонецПериода,
Авто,
,
Счет = &Счет,
&МассивСубконто,
{(Субконто1 = &РасчетныйСчет)}) КАК ХозрасчетныйОстаткиИОбороты
Перейдем на вкладку «Наборы данных» схемы компоновки данных и укажем роли для полей периодов и остатков:
ПериодСекунда: флажок «Период», порядковый номер 1.Регистратор: флажок «Период», порядковый номер 2, дополнительное поле (при необходимости).НомерСтроки: флажок «Период», порядковый номер 3.СуммаНачальныйОстаток: роль «Остаток», тип остатка — НачальныйОстаток, имя группы остатков — Сумма.СуммаКонечныйОстаток: роль «Остаток», тип остатка — КонечныйОстаток, имя группы остатков — Сумма.Перейдем на вкладку «Ресурсы». Для полей остатков не следует писать стандартное выражение Сумма(СуммаКонечныйОстаток) для всех группировок. Достаточно добавить поля СуммаНачальныйОстаток и СуммаКонечныйОстаток в список ресурсов — СКД автоматически применит специализированные алгоритмы расчета моментных показателей на основании ранее назначенных ролей полей.
Если отчет строится с помощью прямого выполнения запроса и вывода через ТабличныйДокумент без СКД, суммировать конечные остатки в секции ИТОГИ категорически нельзя. Рассмотрим, как правильно организовать расчет.
В секции ИТОГИ агрегатная функция СУММА() применяется только к оборотам (СуммаОборотДт, СуммаОборотКт). Итоговый остаток вычисляется вручную по формуле: для активного счета — НачальныйОстаток + СуммаОборотДт - СуммаОборотКт, для пассивного счета — НачальныйОстаток + СуммаОборотКт - СуммаОборотДт.
При обходе выборки запроса инициализируем переменную текущего остатка значением общего начального остатка. При выводе каждой строки регистратора изменяем текущий остаток на величину оборотов текущего документа и выводим полученное значение в колонку конечного остатка.
Посмотрим на пример алгоритма обхода выборки:
ТекущийОстаток = ВыборкаСчет.СуммаНачальныйОстаток;
Пока ВыборкаРегистратор.Следующий() Цикл
// Для активного счета расчет остатка после проведения строки:
ТекущийОстаток = ТекущийОстаток + ВыборкаРегистратор.СуммаОборотДт - ВыборкаРегистратор.СуммаОборотКт;
ОбластьСтрока.Параметры.Заполнить(ВыборкаРегистратор);
ОбластьСтрока.Параметры.ОстатокНаСчете = ТекущийОстаток;
ТабличныйДокумент.Вывести(ОбластьСтрока);
КонецЦикла;
Таким образом, для получения корректных итогов в разрезе регистратора всегда разделяйте оборотные и моментные показатели, обязательно включайте в выборку поля периодов (ПериодСекунда, НомерСтроки) и начальный остаток, а в СКД корректно заполняйте роли полей.