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