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

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

При разработке отчетов на базе Системы компоновки данных (СКД) в «1С:Предприятии» программисты часто сталкиваются со специфическим поведением механизмов расчета итогов. Одна из наиболее распространенных и трудноуловимых проблем — расчет вычисляемых полей, которые зависят от ресурсов с ролями «Начальный остаток» и «Конечный остаток». Типичный пример: нам необходимо пересчитать остатки по курсу валюты на каждый день или умножить остаток номенклатуры на коэффициент упаковки прямо в отчете.

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

Почему СКД некорректно рассчитывает итоги по вычисляемым полям-остаткам?

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

Благодаря этим настройкам компоновщик использует особый алгоритм вычисления итогов:

  1. Для группировок по периодам (день, неделя, месяц) система берет значение первой детальной записи (для начального остатка) или последней детальной записи (для конечного остатка).
  2. Для группировок по измерениям (склад, организация, номенклатура) система суммирует эти полученные крайние значения по всем веткам иерархии.

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

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

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

Этот метод по праву считается стандартом разработки среди специалистов по 1С. Его суть заключается в том, чтобы «обмануть» СКД: мы объявляем поля с нужными нам ролями остатков непосредственно в схеме запроса, но сами вычисления переносим на уровень ресурсов СКД.

Разберем этот процесс по шагам:

Шаг 1. Модификация текста запроса

В тексте запроса (на вкладке «Наборы данных») нам нужно добавить два фиктивных поля со значениями по умолчанию. Назовем их, например, ВычисляемыйНачОст и ВычисляемыйКонОст. Текст запроса будет выглядеть следующим образом:


ВЫБРАТЬ
    ТоварыНаСкладахОстаткиИОбороты.Склад КАК Склад,
    ТоварыНаСкладахОстаткиИОбороты.Номенклатура КАК Номенклатура,
    ТоварыНаСкладахОстаткиИОбороты.Период КАК Период,
    ТоварыНаСкладахОстаткиИОбороты.Влажность КАК Влажность,
    ТоварыНаСкладахОстаткиИОбороты.В QUANTITYНачальныйОстаток КАК НачальныйОстаток,
    ТоварыНаСкладахОстаткиИОбороты.В QUANTITYКонечныйОстаток КАК КонечныйОстаток,
    0 КАК ВычисляемыйНачОст,
    0 КАК ВычисляемыйКонОст
ИЗ
    РегистрНакопления.ТоварыНаСкладах.ОстаткиИОбороты(&НачалоПериода, &КонецПериода, День, , ) КАК ТоварыНаСкладахОстаткиИОбороты

Шаг 2. Настройка ролей полей в СКД

Перейдем на вкладку «Наборы данных» схемы компоновки. Для только что созданных полей-пустышек необходимо вручную прописать роли в колонке «Роль»:

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

Шаг 3. Описание формул на вкладке «Ресурсы»

Теперь переходим на вкладку «Ресурсы». Добавляем наши фиктивные поля в список ресурсов. В колонке «Выражение» мы пишем реальные формулы расчета, которые нам требуются. Например, нам нужно скорректировать остатки на показатель влажности:

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

Способ 2. Использование функций «ВычислитьВыражение» в ресурсах

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

Рассмотрим ситуацию: мы создали вычисляемое поле СкорректированныйОстаток с выражением Остаток * Коэффициент. Теперь нам нужно правильно настроить его расчет на вкладке «Ресурсы» для различных уровней группировок.

Для корректного агрегирования нам придется использовать функции ВычислитьВыражение и ВычислитьВыражениеСГруппировкойМассив. Мы разделим логику расчета для группировок по периодам и по аналитическим измерениям.

1. Настройка расчета для группировок по периодам:

В строке ресурса СкорректированныйОстаток для группировок, представляющих собой временные периоды (например, ПериодДень, ПериодМесяц), мы указываем следующие формулы:

2. Настройка расчета для группировок по измерениям и общих итогов:

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

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

Способ 3. Расчет в запросе с помощью левого соединения (Наиболее производительный метод)

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

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

Для этого мы построим запрос следующим образом:

  1. Получим таблицу остатков и оборотов с детализацией по дням.
  2. Соединим ее левым соединением с регистром сведений КурсыВалют.СрезПоследних, связывая таблицы по валюте и по дате периода остатков.
  3. Прямо в запросе перемножим остаток на полученный курс валюты.

Пример реализации такого запроса:


ВЫБРАТЬ
    ОстаткиВалюты.Период КАК Период,
    ОстаткиВалюты.Договор КАК Договор,
    ОстаткиВалюты.СуммаОстаток КАК СуммаВВалюте,
    ОстаткиВалюты.СуммаОстаток * ЕСТЬNULL(КурсыВалют.Курс, 1) КАК СуммаВРублях
ИЗ
    РегистрНакопления.ДенежныеСредства.ОстаткиИОбороты(&НачалоПериода, &КонецПериода, День, , ) КАК ОстаткиВалюты
    ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.КурсыВалют КАК КурсыВалют
        ПО ОстаткиВалюты.Договор.ВалютаВзаиморасчетов = КурсыВалют.Валюта
        И КурсыВалют.Период = (
            ВЫБРАТЬ МАКСИМУМ(КурсыВалютСуб.Период)
            ИЗ РегистрСведений.КурсыВалют КАК КурсыВалютСуб
            ГДЕ КурсыВалютСуб.Валюта = ОстаткиВалюты.Договор.ВалютаВзаиморасчетов
                И КурсыВалютСуб.Период <= ОстаткиВалюты.Период
        )

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

Резюме и рекомендации по выбору метода

Выбор конкретного метода зависит от архитектуры вашего отчета:

← На главную