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