Одной из наиболее распространенных проблем при разработке отчетов на системе компоновки данных (СКД) является «исчезновение» остатков. Ситуация обычно выглядит так: пока отчет строится в целом по периоду или по группировкам (например, по Контрагентам), остатки отображаются корректно. Но стоит нам добавить в поля выбора Регистратор или выбрать дату, в которую не было движений, как строки с начальными и конечными остатками просто пропадают из результата. Сегодня мы подробно разберем, почему это происходит, и проанализируем несколько способов решения этой задачи.
Для начала проанализируем ситуацию: почему СКД ведет себя именно так? Когда мы используем виртуальную таблицу ОстаткиИОбороты, платформа 1С оптимизирует запрос. Если в выбранных полях появляется Регистратор, виртуальная таблица переходит в режим детальных записей. Если за выбранный день (например, «завтра» или пустой выходной) не было ни одного движения (оборота), то в физических таблицах базы данных просто нет записей, соответствующих этому периоду и условию наличия регистратора.
В итоге запрос возвращает пустое множество строк. СКД, не видя оборотов за конкретную секунду или день, «не знает», что ей нужно вывести строку с текущим остатком, так как она привыкла работать с данными, которые есть в выборке. Чтобы решить эту проблему, нам нужно заставить систему правильно интерпретировать временную шкалу и роли полей.
Рассмотрим самый простой и эффективный метод, который помогает в 90% случаев. Если нам нужна детализация до регистратора, мы должны правильно настроить параметры виртуальной таблицы и список выбираемых полей.
Выполним следующие шаги:
ОстаткиИОбороты установим параметр Периодичность в значение Авто.Регистратора, обязательно добавим поле ПериодСекунда.Почему это важно? Поле ПериодСекунда является ключевым для СКД. Именно по нему система выстраивает хронологическую цепочку. Когда установлена периодичность Авто, СКД сама анализирует состав полей. Если она видит Регистратор и ПериодСекунда, она понимает, как правильно «протянуть» остатки от одной записи к другой, даже если между ними есть временные разрывы.
Иногда даже правильный запрос не дает результата, если СКД не понимает, какое поле является остатком, а какое — оборотом. Разберем по шагам, как настроить роли:
СуммаНачальныйОстаток).Остаток.Сумма (оно должно быть одинаковым для начального и конечного остатка).Начальный.ПериодСекунда.СуммаКонечныйОстаток, указав тип остатка Конечный.После такой настройки СКД активирует свой внутренний механизм расчета остатков. Теперь она будет брать остаток на начало периода и математически прибавлять/вычитать обороты, выведенные в отчете, чтобы получить конечный остаток для каждой строки, включая строки с регистраторами.
Рассмотрим ситуацию из сообщения пользователя: «В 31.05 не было записей, и отчет пустой, хотя остаток с 30.05 должен быть». Если задача состоит в том, чтобы видеть остаток на каждый день периода, даже если движений не было, нам поможет дополнение периодов.
Проанализируем алгоритм настройки в интерфейсе СКД:
ПериодДень).Период.&НачалоПериода и &КонецПериода).В этом случае СКД искусственно создаст строки для всех дат, входящих в интервал. Для «пустых» дней, где не было регистраторов, система подставит значение остатка из предыдущего дня.
Если работа с виртуальной таблицей ОстаткиИОбороты вызывает сложности при сложной логике, мы можем использовать классический метод объединения. Мы разделим получение данных на три части: остатки на начало, движения и остатки на конец.
Посмотрим на пример структуры такого запроса:
ВЫБРАТЬ
Т.Поставщик КАК Поставщик,
Т.СуммаОстаток КАК СуммаНачальныйОстаток,
0 КАК СуммаПриход,
0 КАК СуммаРасход,
0 КАК СуммаКонечныйОстаток,
&НачалоПериода КАК ПериодСекунда,
НЕОПРЕДЕЛЕНО КАК Регистратор
ИЗ
РегистрНакопления.Взаиморасчеты.Остатки(&НачалоПериода, ) КАК Т
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
Т.Поставщик,
0,
Т.СуммаПриход,
Т.СуммаРасход,
0,
Т.Период,
Т.Регистратор
ИЗ
РегистрНакопления.Взаиморасчеты.Обороты(&НачалоПериода, &КонецПериода, Регистратор, ) КАК Т
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
Т.Поставщик,
0,
0,
0,
Т.СуммаОстаток,
&КонецПериода,
НЕОПРЕДЕЛЕНО
ИЗ
РегистрНакопления.Взаиморасчеты.Остатки(&КонецПериода, ) КАК Т
При таком подходе мы гарантированно получаем записи на начало и конец периода. Важно в СКД для этого набора данных так же настроить Роли полей, как мы разбирали во втором решении. Это позволит СКД корректно «схлопнуть» данные и показать остаток, который «течет» через регистраторы.
Проанализируем еще один технический момент — использование параметров Граница. Если вы формируете отчет на 31.05.2021 23:59:59, движения, сделанные ровно в эту секунду, могут не попасть в остаток, если параметр передан просто как дата.
В СКД для корректного получения остатков рекомендуется в выражении параметров виртуальной таблицы использовать следующий подход:
&НачалоПериодаГРАНИЦА(&КонецПериода, ВКЛЮЧАЯ)Это гарантирует, что все документы последней секунды дня будут учтены в расчетах оборотов и остатков. Также всегда используйте функцию ЕСТЬNULL(Поле, 0) в тексте запроса. СКД иногда может спотыкаться на значениях NULL при расчете ресурсов, особенно при использовании левых соединений с календарем или при объединении таблиц.
Подведем итог: чтобы остатки не исчезали, нужно обеспечить наличие поля ПериодСекунда, установить периодичность Авто и, самое главное, правильно прописать Роли для полей остатков в настройках набора данных СКД. Это заставит систему самостоятельно вычислять значения для каждого регистратора и каждой пустой даты в выбранном периоде.