⟨/⟩ Ntr/55_Backend/Handlers/ActualConsumption/GetActualConsumptionHandler.cs

91 строк · в начало

using System;
using Rugrid.Sdaid.Notation.Documents;
using Rugrid.Sdaid.Epas.Ntr.Api.Endpoints.ActualConsumption;

namespace Rugrid.Sdaid.Epas.Ntr.Backend.Handlers.ActualConsumption
{
    /// <summary>
    /// Что происходит при вызове
    /// <see cref="Rugrid.Sdaid.Epas.Ntr.Api.Endpoints.ActualConsumption.DOC_GetActualConsumptionEndpoint"/>:
    /// отбор записей расхода, построение иерархии организационных объектов и подсчёт итогов.
    /// </summary>
    public class DOC_GetActualConsumptionHandler : IHandlerDocument, IHasStructuralLinks, IFolder<NtrBackendFolder>
    {
        public SdaidLink[] Links => new[]
        {
            Rel.Uses<Rugrid.Sdaid.Epas.Ntr.Domain.ActualConsumptionModel.DOC_EeConsumption>(),
            Rel.Uses<Rugrid.Sdaid.Epas.Ntr.Domain.ActualConsumptionModel.DOC_TeConsumption>(),
            Rel.Uses<Rugrid.Sdaid.Epas.Ntr.Domain.Reference.DOC_Period>(),
            Rel.Uses<Rugrid.Sdaid.Epas.Ntr.Domain.BuildingModel.DOC_Building>(),
            Rel.Uses<Rugrid.Sdaid.Epas.Ntr.Domain.OrgObjectModel.DOC_OrgObject>(),
        };

        public static string _refName = "Хендлер запроса расхода энергии";

        public string Name => "Хендлер запроса расхода энергии от сторонних источников";

        public string Description =>
            "Отбирает записи расхода за год, строит иерархию организационных объектов по зданиям с данными и считает итоги.";

        public string Version => "0.1";
        public string Status => "draft";
        public string[] Comments => new string[0];
    }

    /// <summary>
    /// Обработка запроса расхода энергии от сторонних источников. Класс — спецификация поведения,
    /// в runtime не используется.
    /// </summary>
    public class GetActualConsumptionHandler
    {
        /// <summary>
        /// Возвращает расход за календарный год: строки иерархии от запрошенного объекта вниз до
        /// зданий и перечень лет, за которые есть данные. Данные не изменяет.
        /// </summary>
        /// <param name="query">Запрос: объект или здание, вид ТЭР, год, признак «с потомками»</param>
        public GetActualConsumptionQueryResult Handle(GetActualConsumptionQuery query)
        {
            var spec = @"
КАК выполнить:
1. Проверить вход: задан ровно один из `NavId` и `BuildingId`. Если оба или ни одного —
   ошибка валидации запроса.
2. Ограничить выборку периметром пользователя: организационные объекты вне периметра и их
   здания в результат не попадают. Если запрошенный объект или здание вне периметра —
   результат пустой, как если бы данных не было.
3. Выбрать сущность по `ResourceKind`: электрическая энергия — «Фактическое потребление ЭЭ»,
   тепловая — «Фактическое потребление ТЭ».
4. Определить состав зданий:
   - задан `BuildingId` — одно это здание;
   - задан `NavId` и `WithDescendants` — здания этого объекта и всех подчинённых ему;
   - задан `NavId` без `WithDescendants` — только здания самого объекта.
5. Заполнить `AvailableYears`: годы записей расхода по этим зданиям, по возрастанию.
6. Определить год: из `Year`, а если не задан — год, предшествующий текущему. Год возвращается
   в `Year` результата, в том числе когда записей за него нет.
7. Отобрать записи расхода этих зданий за определённый год.
8. Разложить записи по месяцам: номер месяца — из учётного периода записи.
9. Построить строки:
   - по одной строке на здание, у которого есть хотя бы одна запись за год;
   - над зданиями — строки организационных объектов, которым они подчинены, вплоть до
     запрошенного объекта; объект без зданий с данными в результат не попадает;
   - `Level` считать от запрошенного объекта или здания: у него `Level` = 0;
   - строки одного уровня упорядочить по наименованию;
   - вернуть строки обходом сверху вниз: объект, затем его подчинённые объекты и здания.
10. Посчитать значения строк:
    - у здания — значения его записей по месяцам;
    - у организационного объекта — суммы по зданиям ниже, помесячно;
    - `Total` — сумма заданных значений месяцев строки.

ЧЕГО НЕ ДЕЛАТЬ:
- Не подставлять ноль вместо незаданного значения: незаданный месяц остаётся незаданным и в
  строке здания, и при суммировании — он не занижает итог, а не участвует в нём.
- Не возвращать здания без записей за год и организационные объекты, под которыми таких зданий
  нет.
- Не пересчитывать единицы измерения: значения возвращаются в единицах хранения.
- Не сохранять посчитанные суммы: итоги считаются при каждом запросе.
- Не смешивать виды ТЭР в одном ответе: запрос возвращает один вид.
";
            throw new NotImplementedException(spec);
        }
    }
}