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