Skip to content
Snippets Groups Projects
consumptionDataManagerService.ts 11.6 KiB
Newer Older
  • Learn to ignore specific revisions
  • Hugo NOUTS's avatar
    Hugo NOUTS committed
    import { DateTime } from 'luxon'
    import { Client } from 'cozy-client'
    import {
      IConsumptionDataManager,
      ITimePeriod,
      TimeStep,
      IDataload,
      IChartData,
      IPerformanceIndicator,
    } from './dataConsumptionContracts'
    import { FluidType } from 'enum/fluid.enum'
    import ConsumptionDataFormatter from './consumptionDataFormatterService'
    import { QueryRunner } from './queryRunnerService'
    import ConsumptionDataValidator from './consumptionDataValidatorService'
    import LoadToCurrencyConverter from './loadToCurrencyConverterService'
    
    // eslint-disable-next-line @typescript-eslint/interface-name-prefix
    export interface ISingleFluidChartData {
      chartData: IChartData | null
      chartFluid: FluidType
    }
    
    export default class ConsumptionDataManager implements IConsumptionDataManager {
      private readonly _client: Client
      private readonly _consumptionDataFormatter: ConsumptionDataFormatter
      private readonly _queryRunner: QueryRunner
      private readonly _consumptionDataValidator: ConsumptionDataValidator
    
      constructor(_client: Client) {
        this._client = _client
        this._consumptionDataFormatter = new ConsumptionDataFormatter()
        this._queryRunner = new QueryRunner(this._client)
        this._consumptionDataValidator = new ConsumptionDataValidator()
      }
    
      public async getGraphData(
        timePeriod: ITimePeriod,
        timeStep: TimeStep,
        fluidTypes: FluidType[],
        compareTimePeriod?: ITimePeriod
      ): Promise<IChartData | null> {
        const InputisValid: boolean = this._consumptionDataValidator.ValidateGetGraphData(
          timePeriod,
          timeStep,
          fluidTypes,
          compareTimePeriod
        )
    
        if (!InputisValid) return null
    
        let mappedData = null
    
        if (fluidTypes.length === 1) {
          //TODO validating input data
    
          //TODO applying buisness logic to the query arguments
    
          // running the query
          const fetchedData = await this.fetchSingleFLuidGraphData(
            timePeriod,
            timeStep,
            fluidTypes[0],
            compareTimePeriod
          )
    
          // formatting data
          const formattedData = this.formatGraphDataManage(
            fetchedData,
            timeStep,
            timePeriod,
            compareTimePeriod || null
          )
    
          // validating output data
    
          // mapping result to contract
          mappedData = formattedData
        } else if (fluidTypes.length > 1) {
          const toBeAgreggatedData: ISingleFluidChartData[] = []
          for (const fluidType of fluidTypes) {
            const fetchedData = await this.fetchSingleFLuidGraphData(
              timePeriod,
              timeStep,
              fluidType,
              compareTimePeriod
            )
    
            // formatting data
            const formattedData = this.formatGraphDataManage(
              fetchedData,
              timeStep,
              timePeriod,
              compareTimePeriod || null
            )
            // validating output data
    
            toBeAgreggatedData.push({
              chartData: formattedData,
              chartFluid: fluidType,
            })
          }
    
          const aggregatedData = this.aggregateGraphData(toBeAgreggatedData)
    
          // mapping result to contract
          mappedData = aggregatedData
    
          return mappedData
        } else return null
    
        return mappedData
      }
    
      public async getPerformanceIndicators(
        timePeriod: ITimePeriod,
        timeStep: TimeStep,
        fluidTypes: FluidType[],
        compareTimePeriod?: ITimePeriod
      ): Promise<IPerformanceIndicator[]> {
        //const result = {};
        const performanceIndicators: IPerformanceIndicator[] = []
    
        for (const fluideType of fluidTypes) {
          const graphData: IChartData | null = await this.getGraphData(
            timePeriod,
            timeStep,
            [fluideType],
            compareTimePeriod
          )
    
          if (graphData) {
            const performanceIndicator: IPerformanceIndicator = {
              value: null,
              compareValue: null,
              percentageVariation: null,
            }
    
            const actualDataIsValid = this.PerformanceIndicatorsDataIsValid(
              graphData.actualData
            )
    
            if (actualDataIsValid)
              performanceIndicator.value = this.calculatePerformanceIndicatorValue(
                graphData.actualData
              )
    
            if (
              actualDataIsValid &&
              graphData.comparisonData &&
              this.PerformanceIndicatorsDataIsValid(graphData.comparisonData)
            ) {
              const comparisonSumValue = this.calculatePerformanceIndicatorValue(
                graphData.comparisonData
              )
              performanceIndicator.compareValue = comparisonSumValue
              performanceIndicator.percentageVariation = this.calculatePerformanceIndicatorVariationPercentage(
                performanceIndicator.value || 0,
                comparisonSumValue
              )
            }
    
            performanceIndicators[fluideType] = performanceIndicator
          }
        }
    
        return performanceIndicators
      }
    
      private PerformanceIndicatorsDataIsValid(data: IDataload[]): boolean {
        if (!data) return false
    
        const missingValue = data.find(element => element.value === -1)
        if (missingValue) return false
    
        return true
      }
    
      private calculatePerformanceIndicatorValue(data: IDataload[]): number {
        return data.reduce((a, b) => a + b.value, 0)
      }
    
      private calculatePerformanceIndicatorVariationPercentage(
        dataSum: number,
        comparisonDataSum: number
      ): number {
        return 1 - dataSum / comparisonDataSum
      }
    
      private async fetchSingleFLuidGraphData(
        timePeriod: ITimePeriod,
        timeStep: TimeStep,
        fluidType: FluidType,
        compareTimePeriod?: ITimePeriod
      ): Promise<IChartData | null> {
        let actualData: IDataload[] | null = []
        let comparisonData: IDataload[] | null = []
        let singleFluidGraphData: IChartData | null = null
    
        if (compareTimePeriod) {
          const result = await Promise.all([
            this._queryRunner.fetchFluidData(timePeriod, timeStep, fluidType),
            this._queryRunner.fetchFluidData(
              compareTimePeriod,
              timeStep,
              fluidType
            ),
          ])
          actualData = result[0]
          comparisonData = result[1]
        } else
          actualData = await this._queryRunner.fetchFluidData(
            timePeriod,
            timeStep,
            fluidType
          )
    
        if (actualData) {
          singleFluidGraphData = {
            actualData: actualData,
            comparisonData: comparisonData,
          }
        }
        return singleFluidGraphData
      }
    
      private formatGraphDataManage(
        data: IChartData | null,
        timeStep: TimeStep,
        timePeriod: ITimePeriod,
        compareTimePeriod: ITimePeriod | null
      ): IChartData | null {
        if (!data) return null
    
        const formattedActualData: IDataload[] = this._consumptionDataFormatter.formatGraphData(
          data.actualData,
          timePeriod,
          timeStep
        )
    
        let formattedComparisonData: IDataload[] | null = null
        if (compareTimePeriod)
          formattedComparisonData = this._consumptionDataFormatter.formatGraphData(
            data.comparisonData ? data.comparisonData : [],
            compareTimePeriod,
            timeStep
          )
    
        const result: IChartData = {
          actualData: formattedActualData,
          comparisonData: formattedComparisonData,
        }
    
        return result
      }
    
      public async fetchLastDateData(
        fluidTypes: FluidType[],
        allFluids?: boolean
      ): Promise<DateTime | null> {
        let lastDay = null
        if (fluidTypes.length === 1) {
          lastDay = (await this._queryRunner.getLastDateData(fluidTypes[0])) || null
        } else if (fluidTypes.length > 1) {
          const lastDays = []
          for (const fluidType of fluidTypes) {
            lastDay = (await this._queryRunner.getLastDateData(fluidType)) || null
    
            if (lastDay) {
              lastDays.push(lastDay)
            }
          }
          if (lastDays.length < 1) {
            return null
          }
          if (allFluids) {
            lastDay = lastDays.reduce(function(a, b) {
              return a < b ? a : b
            })
          } else {
            lastDay = lastDays.reduce(function(a, b) {
              return a > b ? a : b
            })
          }
        }
        //validate input
        // validate output
        return lastDay
      }
    
    
      public async checkDoctypeEntries(
        fluideType: FluidType[],
        timeStep: TimeStep
    
      ): Promise<boolean> {
    
        //GET RELEVANT DOCTYPE
        //QUERY RUNNER THIS DOCTYPE AND CHECK LENGTH
    
        const queryResult = await this._queryRunner.getEntries(fluideType, timeStep)
        return false
    
    Hugo NOUTS's avatar
    Hugo NOUTS committed
      private aggregateGraphData(
        singleFluidCharts: ISingleFluidChartData[]
        //,withComparison: boolean = true
      ): IChartData | null {
        if (singleFluidCharts && singleFluidCharts[0].chartData) {
          const ltcc = new LoadToCurrencyConverter()
          const resultChartData: IChartData = {
            actualData: [],
            comparisonData: [],
          }
    
          let length = 0
          if (singleFluidCharts[0].chartData.comparisonData) {
            length = Math.max(
              singleFluidCharts[0].chartData.comparisonData.length,
              singleFluidCharts[0].chartData.actualData.length
            )
          } else length = singleFluidCharts[0].chartData.actualData.length
    
          for (let i = 0; i < length; i++) {
            //const agreggatedDate=  singleFluidCharts[0].chartData.actualData[i].;
    
            let agreggatedConvertedValue = 0
            let comparisonAgreggatedConvertedValue = 0
    
            let noDataCount = 0
            let comparisonNoDataCount = 0
    
            const convertedValueDetail = []
            const comparisonConvertedValueDetail = []
    
            for (const singleFluidChart of singleFluidCharts) {
              if (!singleFluidChart.chartData) break
              const value = singleFluidChart.chartData.actualData[i].value
    
              if (
                !singleFluidChart.chartData.comparisonData ||
                !singleFluidChart.chartData.comparisonData[i]
              )
                break
              const comparisonValue =
                singleFluidChart.chartData.comparisonData[i].value
    
              let convertedValue = -1
              if (value === -1) noDataCount++
              else {
                convertedValue = ltcc.Convert(value, singleFluidChart.chartFluid)
                agreggatedConvertedValue += convertedValue
              }
    
              let convertedComparisonValue = -1
              if (comparisonValue === -1) comparisonNoDataCount++
              else {
                convertedComparisonValue = ltcc.Convert(
                  comparisonValue,
                  singleFluidChart.chartFluid
                )
                comparisonAgreggatedConvertedValue += convertedComparisonValue
              }
    
              convertedValueDetail[singleFluidChart.chartFluid] = convertedValue
              comparisonConvertedValueDetail[
                singleFluidChart.chartFluid
              ] = convertedComparisonValue
            }
    
            if (singleFluidCharts.length === noDataCount)
              agreggatedConvertedValue = -1
            if (singleFluidCharts.length === comparisonNoDataCount)
              comparisonAgreggatedConvertedValue = -1
    
            if (singleFluidCharts[0].chartData.actualData[i]) {
              const acutaldataLoad: IDataload = {
                date: singleFluidCharts[0].chartData.actualData[i].date,
                value: agreggatedConvertedValue,
                valueDetail:
                  agreggatedConvertedValue === -1 ? null : convertedValueDetail,
              }
              resultChartData.actualData.push(acutaldataLoad)
            }
    
            if (
              singleFluidCharts[0].chartData.comparisonData &&
              resultChartData.comparisonData &&
              singleFluidCharts[0].chartData.comparisonData[i]
            ) {
              const comparisondataLoad: IDataload = {
                date: singleFluidCharts[0].chartData.comparisonData[i].date,
                value: comparisonAgreggatedConvertedValue,
                valueDetail:
                  comparisonAgreggatedConvertedValue === -1
                    ? null
                    : comparisonConvertedValueDetail,
              }
              resultChartData.comparisonData.push(comparisondataLoad)
            }
          }
          return resultChartData
        }
    
        return null
      }
    }