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

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

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

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

Ограничения поля «Выражение» в ресурсах СКД

Вкладка Ресурсы в схеме компоновки данных позволяет задавать формулы для расчета итогов по группировкам. Однако поле Выражение имеет жесткие синтаксические ограничения:

  1. Оно поддерживает только однострочные формулы.
  2. В нем нельзя объявлять переменные.
  3. В нем нельзя использовать операторы ветвления (Если ... Тогда ... КонецЕсли) и циклы.

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

Шаг 1. Создание функции в Общем модуле

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

Давайте напишем правильный алгоритм сложения стажа. Обычно в системах 1С (например, ЗУП) для таких расчетов принимается условность, что в месяце 30 дней. Это позволяет избежать путаницы с календарными днями (28, 29, 31) в общих итогах.

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


Функция СложитьСтаж(СуммаЛет, СуммаМесяцев, СуммаДней) Экспорт
    
    // 1. Нормализуем дни (каждые 30 дней превращаем в 1 месяц)
    ДопМесяцыИзДней = Цел(СуммаДней / 30);
    ОстатокДней = СуммаДней % 30; // Остаток от деления
    
    // 2. Добавляем полученные месяцы к общей сумме месяцев
    ВсегоМесяцев = СуммаМесяцев + ДопМесяцыИзДней;
    
    // 3. Нормализуем месяцы (каждые 12 месяцев превращаем в 1 год)
    ДопГодыИзМесяцев = Цел(ВсегоМесяцев / 12);
    ОстатокМесяцев = ВсегоМесяцев % 12;
    
    // 4. Считаем итоговые годы
    ИтогоЛет = СуммаЛет + ДопГодыИзМесяцев;
    
    // 5. Формируем строку представления
    // Здесь можно добавить склонение (год/года/лет) при необходимости
    Результат = Строка(ИтогоЛет) + " г. " + Строка(ОстатокМесяцев) + " мес. " + Строка(ОстатокДней) + " дн.";
    
    Возврат Результат;
    
КонецФункции

Шаг 2. Правильная настройка выражения ресурса

Это самый важный момент, в котором часто допускают ошибку. Рассмотрим два варианта записи выражения в СКД:

Вариант 1 (Ошибочный):

Сумма(РасчетСтажаСервер.СложитьСтаж(Лет, Месяцев, Дней))

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

Вариант 2 (Правильный):

РасчетСтажаСервер.СложитьСтаж(Сумма(Лет), Сумма(Месяцев), Сумма(Дней))

Разберем, что здесь происходит:

  1. СКД сначала суммирует все числа в колонке «Лет».
  2. СКД суммирует все числа в колонке «Месяцев».
  3. СКД суммирует все числа в колонке «Дней».
  4. Полученные три больших числа передаются в нашу экспортную функцию.
  5. Функция один раз выполняется для группировки и возвращает корректную строку итога.

Таким образом, в поле Выражение на вкладке «Ресурсы» необходимо прописать вызов функции, обернув поля набора данных в агрегатную функцию Сумма().

Шаг 3. Решение проблемы «кривого» расчета

Если вы заметили, что расчет выполняется неточно (как упоминалось в обсуждении), проверьте два момента:

  1. Математика функции: Убедитесь, что вы используете операцию «Остаток от деления» (%) для получения дней и месяцев, которые не перешли в старший разряд, а функцию Цел() — для переноса в старший разряд.
  2. Исходные данные: Проверьте, что находится в полях «Лет», «Месяцев» и «Дней» в запросе. Если вы получаете их разностью дат, помните, что функция РАЗНОСТЬДАТ(Дата1, Дата2, "Месяц") в языке запросов может давать не совсем тот результат, который ожидается для стажа (она считает переходы границ месяца, а не полные месяцы). Для точного расчета стажа в запросе рекомендуется использовать специализированные механизмы или рассчитывать стаж в днях, а разбивку делать уже при выводе.

Шаг 4. Управление порядком полей в отчете

В обсуждении также был поднят вопрос: «Почему в отчете даты лезут вперед?» (перед группировками или текстовыми полями).

Такое поведение связано с настройками макета СКД по умолчанию:

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

Подводя итог: для сложных расчетов в итогах СКД всегда используйте связку «Экспортная функция в общем модуле» + «Вызов функции с агрегатами внутри» (Функция(Сумма(Поле))). Это обеспечит чистоту кода и корректность вычислений.

← На главную