Как правильно настроить начальные и конечные остатки в СКД и убрать пустые строки по регистратору?

Программист 1С v8.3 (Управляемые формы) Управленческий учет IT и автоматизация бизнеса
← На главную

Работа с виртуальными таблицами остатков и оборотов в Системе компоновки данных (СКД) часто преподносит сюрпризы начинающим разработчикам. Особенно остро проблемы проявляются при попытке пересчитать показатели по курсу валюты на лету или при детальной группировке по регистраторам. В этой статье мы подробно разберем, почему искажаются кастомные остатки, откуда берется пустая строка в отчете, в чем заключается смертельная опасность популярных форумных решений и как сделать все архитектурно правильно.

Почему «двоятся» и завышаются пользовательские остатки в СКД?

Рассмотрим классическую ситуацию: у нас есть стандартные поля остатков из виртуальной таблицы регистра накопления, а также новые поля, в которых мы пересчитываем стоимость по курсу валюты. Нам кажется логичным написать простую формулу пересчета стоимости в выражении поля. Однако при выводе отчета мы замечаем странную картину: стандартные остатки выводятся верно (например, равны нулю), а пересчитанные по формуле поля показывают огромные, явно завышенные суммы.

Выясним причину такого поведения компоновщика. Дело в том, что СКД — это интеллектуальный механизм, который по-разному рассчитывает итоги для обычных ресурсов и полей остатков:

  1. Если у поля в СКД не настроена роль остатка, система считает его простым ресурсом. При расчете итогов по группировкам СКД применит к нему банальное суммирование: СУММА(ВычисляемоеПоле).
  2. В детальных записях виртуальных таблиц остатков и оборотов значения остатков дублируются в технических целях. Обычное суммирование складывает эти остатки по всем строкам документов, приводя к огромному ложному завышению итогов.
  3. Когда мы явно указываем СКД, что поле является остатком, система переключает алгоритм расчета. Вместо арифметического сложения она берет значение из первой временной точки группировки (для начального остатка) и из последней (для конечного).

Чтобы решить эту проблему, перейдем на вкладку «Набор данных» в СКД. Найдем наши вычисляемые валютные поля остатков и настроим для них роли так же, как это сделано для стандартных полей:

Тайна первой пустой строки: откуда берется НЕОПРЕДЕЛЕНО в регистраторе

При выводе детальных записей с группировкой по регистратору пользователи часто видят в самом начале отчета пустую строку. В ней нет названия документа, но при этом могут быть заполнены начальные остатки.

Разберем физику этого процесса. Виртуальная таблица ОстаткиИОбороты при получении данных с детализацией по регистратору обязана вернуть так называемые «граничные строки». У этих строк поле Регистратор содержит значение НЕОПРЕДЕЛЕНО (или NULL). Именно через эти технические строки СКД получает информацию о начальном остатке на самую раннюю границу отчета и конечном остатке на самую позднюю границу.

Эта строка жизненно необходима СКД для того, чтобы корректно собрать общие итоги по отчету и вывести начальный остаток по группировкам выше регистратора.

Опасная ловушка: почему нельзя использовать фильтр «ГДЕ Регистратор <> Неопределено»

На форумах часто советуют «простое и быстрое» решение проблемы пустой строки: добавить в условие связи или секцию ГДЕ запроса ограничение вида ГДЕ Таблица.Регистратор <> Значение(Документ.ИмяДокумента.ПустаяСсылка) или ГДЕ Таблица.Регистратор НЕ ЕСТЬ NULL.

Внимание: это опаснейший «костыль» и мина замедленного действия! Рассмотрим, к каким катастрофическим последствиям в реальном учете это приведет:

  1. СУБД отсечет технические граничные строки еще на этапе выполнения SQL-запроса, до того, как данные попадут в компоновщик СКД.
  2. Если по какому-то контрагенту, складу или номенклатуре были остатки на начало периода, но не было движений (оборотов) за этот период, они просто исчезнут из отчета! Пользователь не увидит свои товары и долги.
  3. Общие итоги по отчету станут неверными, так как начальные остатки по объектам без движений не просуммируются.

Как правильно скрыть пустую строку регистратора

Разберем два методологически верных способа убрать пустую строку из отчета, не ломая при этом механизм расчета итогов СКД.

Способ 1. Использование свойств ролей полей (Рекомендуемый)

Мы можем преобразовать техническое значение НЕОПРЕДЕЛЕНО в полноценный NULL прямо в тексте запроса, а затем дать команду СКД игнорировать его при выводе.

Напишем в запросе следующее выражение для поля регистратора:


ВЫБОР 
    КОГДА ОстаткиПоКурсу.Регистратор = НЕОПРЕДЕЛЕНО ТОГДА NULL 
    ИНАЧЕ ОстаткиПоКурсу.Регистратор 
КОНЕЦ КАК Регистратор

После этого на вкладке «Набор данных» откроем роли для поля Регистратор и установим флаг «Игнорировать значения NULL». В этом случае СКД использует данную строку для внутренних расчетов итогов, но визуально в отчет ее выводить не будет.

Способ 2. Отбор на уровне группировки компоновки

Этот способ не требует изменения текста запроса. Мы оставляем выборку как есть, но скрываем пустую строку средствами настроек вывода:

  1. Перейдем на вкладку «Настройки» в СКД.
  2. Выберем группировку по регистратору (или детальные записи).
  3. Перейдем на вкладку «Отбор» именно для этой группировки (не для всего отчета!).
  4. Добавим условие отбора: Регистратор Заполнен (или Регистратор <> Неопределено).

В результате на уровне итогов данные будут учтены, но сама строка с пустым регистратором скроется из детальных записей.

Способ 3. Творческий подход с представлением

Иногда полезно не скрывать строку, а сделать ее понятной для пользователя. Мы можем задать выражение представления для поля Регистратор. В свойствах поля укажем выражение:


ВЫБОР 
    КОГДА Регистратор ЕСТЬ NULL ИЛИ Регистратор = НЕОПРЕДЕЛЕНО 
        ТОГДА "Начальный остаток на " + Формат(НачалоПериода, "ДФ=dd.MM.yyyy") 
    ИНАЧЕ Представление(Регистратор) 
КОНЕЦ

Методологическая ошибка при пересчете остатков по курсу валюты

Проанализируем формулу пересчета остатков, которую часто пытаются применить разработчики:

СтоимостьНачальныйОстаток * (КурсУчета / КурсПоДатам.Курс)

В этой формуле кроется серьезная математическая проблема. В технической строке начального остатка (где нет регистратора и, соответственно, нет даты документа) левое соединение по дате вернет NULL для поля КурсПоДатам.Курс. Наш пересчитанный начальный остаток в этой строке станет равен нулю или запишется некорректно.

Как делать правильно в валютных отчетах?

Вариант А. Динамический расчет остатков на основе оборотов. По курсу на дату документа нужно пересчитывать только обороты (приход и расход). Начальные и конечные остатки в валюте отчета должны рассчитываться СКД динамически как накопительный итог (для этого у полей остатков настраиваются соответствующие роли связи с оборотами).

Вариант Б. Жесткий пересчет по курсу на границы периода. Если методология учета требует пересчитать остатки напрямую:

Соединение с регистром курсов валют для остатков в таком случае должно идти не по дате документа, а по параметрам начала и конца периода отчета.

Обязательные правила настройки периодов в СКД

Чтобы СКД безошибочно сопоставляла начальные и конечные остатки при детализации до регистратора, необходимо соблюдать строгие правила настройки периодов в наборе данных:

  1. В запросе обязательно должны выбираться поля ПериодСекунда и Регистратор. Набор данных должен иметь периодичность Авто.
  2. В ролях полей им необходимо присвоить роли «Период» с непрерывной нумерацией:
    • Для поля ПериодСекунда — Роль: Период, Номер: 1 (родительский, более общий период).
    • Для поля Регистратор — Роль: Период, Номер: 2 (дочерний, уточняющий период).

Соблюдение этих правил гарантирует, что ваши отчеты в СКД будут работать быстро, а главное — показывать абсолютно достоверные данные по остаткам в любых разрезах.

← На главную