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