Как построить отчет с накопленными баллами студентов в 1С без задвоения записей?

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

Уважаемые коллеги, давайте вместе разберем распространенную проблему, с которой сталкиваются разработчики и пользователи 1С при попытке агрегировать данные из нескольких источников: задвоение записей в отчете при использовании регистра сведений для накопления баллов студентов. Мы рассмотрим, почему первоначальные подходы могут быть неэффективны, и предложим оптимальное решение.

Анализ исходной проблемы и неверных подходов

Автор задачи столкнулся с необходимостью построить отчет, где по строкам будут перечислены ФИО студентов, а в столбцах — итоговые баллы, полученные ими за участие в различных мероприятиях (город, вуз, область и т.д.) из нескольких документов. Каждый документ содержит поле с суммой баллов. Изначальная попытка использовать регистр сведений привела к задвоению фамилий студентов. Причина этого заключается в том, что если один и тот же студент получает баллы за разные критерии или на разных уровнях участия, для каждого такого события в регистр сведений записывается отдельная строка. Регистр сведений по своей природе хранит отдельные факты, а не агрегированные или накопительные данные.

Когда автор упоминает использование «СрезПоследних» в конструкторе запроса и то, что сведения являются периодическими, это только усугубляет проблему для накопительного учета. Периодический регистр сведений хранит значение на определенную дату или период. Если студент набрал 27 баллов сегодня, а завтра ему начисляют еще, и мы просто записываем новое значение в тот же регистр сведений на текущую дату, то «срез последних» покажет только последнее значение, а не сумму. Если же для каждого события создается новая запись, то для получения общей суммы приходится вручную агрегировать множество записей, что неэффективно и может быть медленным, особенно на больших объемах данных.

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

Почему регистр накопления — правильное решение?

Очевидно, что нам нужен механизм для накопления баллов. Для этого в системе 1С существуют регистры накопления. Это специализированные объекты метаданных, предназначенные для хранения числовых показателей в разрезе аналитик (измерений) и обеспечения быстрого получения итогов (остатков или оборотов).

Существует два основных вида регистров накопления:

  1. Регистр накопления остатков: Используется для учета ресурсов, которые могут как приходить, так и расходоваться, и по которым важно знать текущий "остаток" на определенный момент времени (например, товары на складе, денежные средства). Для него имеет смысл понятие "приход" и "расход".
  2. Регистр накопления оборотов: Используется для учета изменений ресурсов, которые не имеют "остатка" в классическом смысле, а представляют собой накопленную сумму или объем за период (например, выручка от продаж, объем производства). Для него нет явного понятия "приход" или "расход"; он просто накапливает величину изменения ресурсов.

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

Выбор вида регистра накопления для баллов

В нашей ситуации баллы студентов только начисляются (увеличиваются) и никогда не уменьшаются или обнуляются сами по себе. Это ключевой момент, который определяет выбор вида регистра накопления:

  1. Регистр накопления оборотов (Оптимальный выбор):
    • Идеально для накопления: Поскольку баллы только добавляются, и нам нужна их общая сумма за период (или за все время), регистр накопления оборотов является наиболее подходящим. Он предназначен именно для сбора "оборотов" – то есть, сумм изменений за определенный период.
    • Простота использования: Нет необходимости в механизмах "прихода" и "расхода" в привычном смысле, что упрощает логику движений. Мы просто записываем сумму баллов, и система их накапливает.
    • Эффективность: Для получения итоговых сумм мы используем виртуальную таблицу Обороты, которая является очень производительной для запросов по сумме за период.
    • Корректное поведение при перепроведении документов: Важно понимать, что при повторном проведении документа, который делает движения по регистру накопления, система 1С работает следующим образом: сначала удаляются все движения, ранее сделанные этим же документом, а затем записываются новые движения. Это обеспечивает актуальность данных и предотвращает многократное увеличение баллов от одного и того же документа. Опасения, что баллы будут постоянно увеличиваться при каждом перепроведении документа, необоснованны при корректной реализации движений. Документ можно проводить сколько угодно раз, и данные в регистре останутся актуальными.
    • Долгосрочное хранение: Если речь идет о рейтинге вуза или общих достижениях студента, которые не должны обнуляться, оборотный регистр эффективно хранит всю историю начислений.
  2. Регистр накопления остатков (Менее оптимальный):
    • Несоответствие сути: Хотя технически можно использовать регистр остатков, делая только "приходные" движения, это не совсем соответствует его назначению. У нас нет понятия "остатка баллов", который может закончиться или обнулиться.
    • Сложности с обнулением: Если в будущем возникнет необходимость "обнулить" баллы (например, по окончании учебного года), это потребует создания специальных документов для списания ("расхода"), что усложнит логику.
    • Потенциальное разрастание таблицы итогов: Регистры остатков поддерживают таблицы итогов, которые могут разрастаться, если для каждого студента постоянно создаются новые записи (даже если он давно закончил обучение) без соответствующих расходных операций. Это может снизить производительность при определенных сценариях работы с виртуальными таблицами остатков.

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

Структура регистра накопления оборотов для баллов студентов

Давайте спроектируем структуру нашего регистра накопления БаллыСтудентов:

  1. Вид регистра: Устанавливаем в свойстве конфигурации регистра «Обороты».
  2. Измерения: Измерения определяют аналитику, в разрезе которой будут накапливаться баллы. Они формируют уникальный ключ записи.
    • Студент (тип СправочникСсылка.Студенты или аналогичный, если у вас есть справочник с ФИО студентов). Это измерение крайне важно, так как оно позволит нам группировать данные по каждому студенту и избежать задвоений в отчете.
    • УровеньМероприятия (тип СправочникСсылка.УровниМероприятий или ПеречислениеСсылка.УровниМероприятий). Этот реквизит позволит нам в отчете разделять баллы по категориям (ВУЗ, Город, Область и т.д.) или выводить их в отдельные колонки.
  3. Ресурсы: Ресурсы — это числовые показатели, которые будут накапливаться.
    • КоличествоБаллов (тип Число, точность и длина на ваше усмотрение, например, 10, 2). Здесь будет храниться сумма баллов за конкретное событие.
  4. Реквизиты (опционально): Реквизиты хранят дополнительную информацию о движении, но не влияют на накопление итогов.
    • ДокументОснование (тип ДокументСсылка.НачислениеБалловСтуденту или соответствующий тип вашего документа). Это полезно для связи движения с документом, который его создал, и для удобства отладки или перехода к регистратору.
    • ВидМероприятия (например, СправочникСсылка.ВидыМероприятий) – для дополнительной детализации, если это требуется в отчетах.

Создание движений в документе

Теперь рассмотрим, как ваш документ, который начисляет баллы, должен формировать движения по новому регистру накопления БаллыСтудентов. Это делается в обработчике события ОбработкаПроведения документа.

  1. Инициализация движений: В начале процедуры ОбработкаПроведения мы должны указать, что наш документ будет делать движения по регистру БаллыСтудентов.
  2. Заполнение движений: Далее, в цикле по табличной части документа (если баллы начисляются по нескольким строкам) или однократно (если документ начисляет общие баллы), мы создаем записи движений.

Предположим, у нас есть документ НачислениеБалловСтуденту с табличной частью БаллыПоУровням, которая содержит колонки Студент, УровеньМероприятия и Баллы.


Процедура ОбработкаПроведения(Отказ, РежимПроведения)

    // Указываем, что документ будет делать движения по регистру накопления
    Движения.БаллыСтудентов.Записывать = Истина;

    // Очищаем существующие движения документа перед записью новых
    // Это стандартное поведение для регистров накопления,
    // гарантирующее, что при перепроведении данные будут актуальны, а не дублированы
    Движения.БаллыСтудентов.Очистить(); 

    // Перебираем данные из табличной части документа и формируем движения
    Для Каждого СтрокаТЧ Из Объект.БаллыПоУровням Цикл
        Движение = Движения.БаллыСтудентов.Добавить();
        Движение.Период               = Объект.Дата; // Дата документа
        Движение.Студент             = СтрокаТЧ.Студент;
        Движение.УровеньМероприятия  = СтрокаТЧ.УровеньМероприятия;
        Движение.КоличествоБаллов    = СтрокаТЧ.Баллы;
        Движение.ДокументОснование   = Объект.Ссылка; // Для связи с регистратором
    КонецЦикла;

КонецПроцедуры

Важный нюанс: Для регистров накопления оборотов свойство ВидДвижения (Приход или Расход) не используется, так как они накапливают только объемы, а не остатки.

Построение отчета по регистру накопления оборотов

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

  1. Создание отчета: Создайте новый объект конфигурации Отчет и откройте его СхемуКомпоновкиДанных.
  2. Выбор набора данных: В конструкторе набора данных выберите Тип набора данных: «Запрос».
  3. Написание запроса к регистру накопления:

    Наш запрос будет использовать виртуальную таблицу Обороты регистра накопления БаллыСтудентов. Эта таблица уже содержит агрегированные данные по нашим измерениям за указанный период.

    
    ВЫБРАТЬ
        БаллыСтудентовОбороты.Студент КАК Студент,
        БаллыСтудентовОбороты.УровеньМероприятия КАК УровеньМероприятия,
        БаллыСтудентовОбороты.КоличествоБаллов КАК Баллы
    ИЗ
        РегистрНакопления.БаллыСтудентов.Обороты(
            &НачалоПериода,
            &КонецПериода,
            Авто, // Периодичность: Авто (по регистратору)
            // Отбор: Если нужно ограничить по конкретным параметрам, например, по студенту
            // Измерения: Здесь можно указать измерения, по которым нужны обороты, 
            // если не указывать, то обороты будут по всем измерениям регистра
            Студент, УровеньМероприятия
        ) КАК БаллыСтудентовОбороты
    

    Здесь &НачалоПериода и &КонецПериода — это параметры отчета, которые пользователь сможет указывать. Авто означает, что обороты будут рассчитываться по движениям регистраторов.

  4. Настройка полей СКД:

    Перенесите выбранные поля (Студент, УровеньМероприятия, Баллы) на закладку «Поля».

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

      На закладке «Выбранные поля» добавьте Студент и Баллы. Чтобы получить сумму баллов, для поля Баллы установите функцию Сумма().

    • Итоги:

      Для поля Баллы на закладке «Итоги» также установите функцию Сумма() для общих итогов.

    • Разбиение по колонкам (если нужно):

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

      1. В структуре отчета добавьте группировку по Студент (Детальные записи).
      2. На этой же группировке перейдите на вкладку «Выбранные поля» и добавьте Студент.
      3. Теперь, чтобы вывести УровеньМероприятия в колонки, на вкладке «Другие настройки» (или в свойствах макета группировки) найдите «Поля группировок макета» и укажите, что УровеньМероприятия должно быть в колонках.
      4. В выбранных полях добавьте Баллы и установите для него Сумма(). СКД автоматически сгруппирует баллы по уровням мероприятий и выведет их в отдельные колонки.

Таким образом, мы сможем получить отчет, где по строкам будет ФИО студента, а в колонках — суммы баллов по каждому уровню участия (ВУЗ, Город, Область) и общая сумма баллов.

Заключение

Мы выяснили, что для эффективного и корректного учета накопительных баллов студентов в 1С наиболее подходящим решением является использование регистра накопления оборотов. Этот подход позволяет избежать задвоений записей в отчетах, обеспечивает актуальность данных при повторном проведении документов и предоставляет мощные инструменты для анализа с помощью Системы Компоновки Данных. Запомните: регистры накопления — это мощный инструмент, который требует понимания их принципов работы, чтобы избежать распространенных ошибок и строить производительные и точные отчеты.

← На главную