From 65ef63f8f5fe27fa799897f3949c1310fbb99d3a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?R=C3=A9mi=20PAILHAREY?= <rpailharey@grandlyon.com>
Date: Mon, 26 Feb 2024 13:01:39 +0000
Subject: [PATCH] fix: new DJU API

---
 manifest.webapp                               |  2 +-
 .../ProfileComparator/ProfileComparator.tsx   |  8 +-
 src/doctypes/remote/org.ecolyo.dju.ts         |  2 +-
 src/models/dju.model.ts                       |  7 +-
 src/services/profileType.service.spec.ts      | 80 ++++++++++++++++---
 src/services/profileType.service.ts           | 70 +++++++---------
 6 files changed, 107 insertions(+), 62 deletions(-)

diff --git a/manifest.webapp b/manifest.webapp
index f03b80e21..a18d8159d 100644
--- a/manifest.webapp
+++ b/manifest.webapp
@@ -240,7 +240,7 @@
       "verbs": ["GET"]
     },
     "ecolyo-dju": {
-      "type": "org.ecolyo.dju_v2",
+      "type": "org.ecolyo.dju_v3",
       "verbs": ["GET"]
     },
     "dacc": {
diff --git a/src/components/Analysis/ProfileComparator/ProfileComparator.tsx b/src/components/Analysis/ProfileComparator/ProfileComparator.tsx
index 7635f1ede..a4159281d 100644
--- a/src/components/Analysis/ProfileComparator/ProfileComparator.tsx
+++ b/src/components/Analysis/ProfileComparator/ProfileComparator.tsx
@@ -91,11 +91,10 @@ const ProfileComparator = ({
   useEffect(() => {
     let subscribed = true
     async function loadAverageConsumption() {
+      const analysisDate = analysisMonth.minus({ month: 1 }).startOf('month')
       const profileTypeEntityService = new ProfileTypeEntityService(client)
       const profileType: ProfileType | null =
-        await profileTypeEntityService.getProfileType(
-          analysisMonth.minus({ month: 1 }).startOf('month')
-        )
+        await profileTypeEntityService.getProfileType(analysisDate)
       if (profileType !== null) {
         const profileTypeService: ProfileTypeService = new ProfileTypeService(
           profileType,
@@ -104,7 +103,8 @@ const ProfileComparator = ({
         )
         const monthlyForecast: MonthlyForecast =
           await profileTypeService.getMonthlyForecast(
-            analysisMonth.minus({ month: 1 }).startOf('month').month
+            analysisDate.year,
+            analysisDate.month
           )
         if (subscribed) {
           setForecast(monthlyForecast)
diff --git a/src/doctypes/remote/org.ecolyo.dju.ts b/src/doctypes/remote/org.ecolyo.dju.ts
index ccc8e113b..8661a442a 100644
--- a/src/doctypes/remote/org.ecolyo.dju.ts
+++ b/src/doctypes/remote/org.ecolyo.dju.ts
@@ -1 +1 @@
-export const REMOTE_ORG_ECOLYO_DJU = '/remote/org.ecolyo.dju_v2'
+export const REMOTE_ORG_ECOLYO_DJU = '/remote/org.ecolyo.dju_v3'
diff --git a/src/models/dju.model.ts b/src/models/dju.model.ts
index b1cb16e08..f5f43d648 100644
--- a/src/models/dju.model.ts
+++ b/src/models/dju.model.ts
@@ -7,8 +7,7 @@ export interface DjuResult {
 }
 
 interface DjuMeasure {
-  horodate: string
-  measurement: number
-  observation: string
-  unit: string
+  month: string
+  average_measurement: number
+  identifiant: string
 }
diff --git a/src/services/profileType.service.spec.ts b/src/services/profileType.service.spec.ts
index 547c76c08..3c52e9a65 100644
--- a/src/services/profileType.service.spec.ts
+++ b/src/services/profileType.service.spec.ts
@@ -1,3 +1,5 @@
+/* eslint-disable camelcase */
+import heatingData from 'constants/consumptionConstants/heating.json'
 import {
   Floor,
   HotWaterEquipment,
@@ -9,6 +11,7 @@ import {
   WarmingType,
 } from 'enums'
 import { DateTime } from 'luxon'
+import { DjuResult } from 'models'
 import { ProfileType } from 'models/profileType.model'
 import mockClient from 'tests/__mocks__/client.mock'
 import {
@@ -68,6 +71,7 @@ describe('ProfileType service', () => {
       const monthConsumption =
         await profileTypeService.calculateWarmingMonthConsumption(
           mockCorrectedConsumption,
+          2023,
           3
         )
       expect(monthConsumption).toEqual(mockMonthConsumption)
@@ -76,7 +80,7 @@ describe('ProfileType service', () => {
 
   describe('getMonthHeating', () => {
     it('should get the heating consumption', async () => {
-      const monthConsumption = await profileTypeService.getMonthHeating(3)
+      const monthConsumption = await profileTypeService.getMonthHeating(2023, 3)
       expect(monthConsumption).toEqual(mockMonthConsumption)
     })
     it('should get the heating consumption for a flat with collective heating', async () => {
@@ -85,7 +89,10 @@ describe('ProfileType service', () => {
         mockClient,
         DateTime.now().year
       )
-      const monthConsumption = await profileTypeService1.getMonthHeating(2)
+      const monthConsumption = await profileTypeService1.getMonthHeating(
+        2023,
+        2
+      )
       expect(monthConsumption).toEqual(mockMonthConsumption1)
     })
     it('should get the heating consumption for a house with individual heating, facilities, installation and individual work', async () => {
@@ -94,7 +101,10 @@ describe('ProfileType service', () => {
         mockClient,
         DateTime.now().year
       )
-      const monthConsumption = await profileTypeService2.getMonthHeating(1)
+      const monthConsumption = await profileTypeService2.getMonthHeating(
+        2023,
+        1
+      )
       expect(monthConsumption).toEqual(mockMonthConsumption2)
     })
   })
@@ -185,7 +195,10 @@ describe('ProfileType service', () => {
         mockClient,
         DateTime.now().year
       )
-      const monthlyForecast = await profileTypeService1.getMonthlyForecast(1)
+      const monthlyForecast = await profileTypeService1.getMonthlyForecast(
+        2023,
+        1
+      )
       expect(monthlyForecast).toEqual(mockMonthlyForecastJanuaryTestProfile1)
     })
     it('should get the monthly forecast for test profile 2', async () => {
@@ -194,7 +207,10 @@ describe('ProfileType service', () => {
         mockClient,
         DateTime.now().year
       )
-      const monthlyForecast = await profileTypeService2.getMonthlyForecast(1)
+      const monthlyForecast = await profileTypeService2.getMonthlyForecast(
+        2023,
+        1
+      )
       expect(monthlyForecast).toEqual(mockMonthlyForecastJanuaryTestProfile2)
     })
     it('should get the monthly forecast for test profile 3', async () => {
@@ -203,7 +219,10 @@ describe('ProfileType service', () => {
         mockClient,
         DateTime.now().year
       )
-      const monthlyForecast = await profileTypeService3.getMonthlyForecast(1)
+      const monthlyForecast = await profileTypeService3.getMonthlyForecast(
+        2023,
+        1
+      )
       expect(monthlyForecast).toEqual(mockMonthlyForecastJanuaryTestProfile3)
     })
     it('should get the monthly forecast for test profile 1 with wall and roof and window insulation', async () => {
@@ -222,7 +241,10 @@ describe('ProfileType service', () => {
         mockClient,
         DateTime.now().year
       )
-      const monthlyForecast = await serviceThreeInsulation.getMonthlyForecast(1)
+      const monthlyForecast = await serviceThreeInsulation.getMonthlyForecast(
+        2023,
+        1
+      )
       expect(monthlyForecast).toEqual(
         mockMonthlyForecastJanuaryTest1WithFullArrays
       )
@@ -234,7 +256,10 @@ describe('ProfileType service', () => {
         mockClient,
         DateTime.now().year
       )
-      const monthlyForecast = await profileTypeService2.getMonthlyForecast(1)
+      const monthlyForecast = await profileTypeService2.getMonthlyForecast(
+        2023,
+        1
+      )
       expect(
         monthlyForecast.fluidForecast[0].detailsMonthlyForecast
           .heatingConsumption
@@ -522,9 +547,42 @@ describe('ProfileType service', () => {
   })
 
   describe('fetchDJU', () => {
-    it('should return default dju', async () => {
-      const result = await profileTypeService.fetchDJU(2)
-      expect(result).toEqual(363)
+    it('should return dju from remote doctype if it returns a value', async () => {
+      const mockDjuResult: DjuResult = {
+        fields: [],
+        layer_name: '',
+        nb_result: 1,
+        table_href: '',
+        values: [
+          {
+            month: '2024-01',
+            average_measurement: 10.5,
+            identifiant: '69029001',
+          },
+        ],
+      }
+      mockClient.getStackClient().fetchJSON.mockResolvedValueOnce(mockDjuResult)
+      const result = await profileTypeService.fetchDJU(2023, 2)
+      expect(result).toEqual(mockDjuResult.values[0].average_measurement)
+    })
+    it('should return default dju if remote doctype returns no value', async () => {
+      const mockDjuResult: DjuResult = {
+        fields: [],
+        layer_name: '',
+        nb_result: 0,
+        table_href: '',
+        values: [],
+      }
+      mockClient.getStackClient().fetchJSON.mockResolvedValueOnce(mockDjuResult)
+      const result = await profileTypeService.fetchDJU(2023, 2)
+      expect(result).toEqual(heatingData.dju_average_by_month[1])
+    })
+    it('should return default dju if remote doctype returns an error', async () => {
+      mockClient
+        .getStackClient()
+        .fetchJSON.mockRejectedValueOnce('Error during fetching DJU')
+      const result = await profileTypeService.fetchDJU(2023, 2)
+      expect(result).toEqual(heatingData.dju_average_by_month[1])
     })
   })
 })
diff --git a/src/services/profileType.service.ts b/src/services/profileType.service.ts
index 601b66c0f..814a340ed 100644
--- a/src/services/profileType.service.ts
+++ b/src/services/profileType.service.ts
@@ -26,6 +26,7 @@ import {
   ProfileType,
 } from 'models'
 import logApp from 'utils/logger'
+import { formatTwoDigits } from 'utils/utils'
 import ConverterService from './converter.service'
 
 const logStack = logger.namespace('profileTypeService')
@@ -176,9 +177,10 @@ export default class ProfileTypeService {
    */
   public async calculateWarmingMonthConsumption(
     correctedConsumption: number,
+    year: number,
     month: number
   ): Promise<number> {
-    const djuCurrentMonth = await this.fetchDJU(month)
+    const djuCurrentMonth = await this.fetchDJU(year, month)
     const monthConsumption =
       (correctedConsumption / heatingData.dju_annual) * djuCurrentMonth
 
@@ -188,12 +190,13 @@ export default class ProfileTypeService {
   /**
    * @returns {number} Month heating consumption in kw/h
    */
-  public async getMonthHeating(month: number): Promise<number> {
+  public async getMonthHeating(year: number, month: number): Promise<number> {
     const estimatedConsumption = this.calculateWarmingEstimatedConsumption()
     const correctedConsumption =
       this.calculateWarmingCorrectedConsumption(estimatedConsumption)
     const monthConsumption = await this.calculateWarmingMonthConsumption(
       correctedConsumption,
+      year,
       month
     )
     return monthConsumption
@@ -334,6 +337,7 @@ export default class ProfileTypeService {
    */
   public async getDetailsMonthlyForecast(
     fluidType: FluidType,
+    year: number,
     month: number
   ): Promise<DetailsMonthlyForecast> {
     const { cookingFluid, hotWaterFluid, warmingFluid } = this.profileType
@@ -351,8 +355,10 @@ export default class ProfileTypeService {
         warmingFluid !== null &&
         (fluidType as number) === (warmingFluid as number)
       ) {
-        detailsMonthlyForecast.heatingConsumption =
-          await this.getMonthHeating(month)
+        detailsMonthlyForecast.heatingConsumption = await this.getMonthHeating(
+          year,
+          month
+        )
       }
       if (
         hotWaterFluid !== null &&
@@ -379,10 +385,12 @@ export default class ProfileTypeService {
 
   public async getFluidForecast(
     fluidType: FluidType,
+    year: number,
     month: number
   ): Promise<FluidForecast> {
     const detailsMonthlyForecast = await this.getDetailsMonthlyForecast(
       fluidType,
+      year,
       month
     )
     let fluidLoad = 0
@@ -409,13 +417,21 @@ export default class ProfileTypeService {
    * getMonthlyForecast
    * @returns {Promise<MonthlyForecast>} MonthlyForecast
    */
-  public async getMonthlyForecast(month: number): Promise<MonthlyForecast> {
+  public async getMonthlyForecast(
+    year: number,
+    month: number
+  ): Promise<MonthlyForecast> {
     const elecForecast = await this.getFluidForecast(
       FluidType.ELECTRICITY,
+      year,
+      month
+    )
+    const waterForecast = await this.getFluidForecast(
+      FluidType.WATER,
+      year,
       month
     )
-    const waterForecast = await this.getFluidForecast(FluidType.WATER, month)
-    const gasForecast = await this.getFluidForecast(FluidType.GAS, month)
+    const gasForecast = await this.getFluidForecast(FluidType.GAS, year, month)
 
     const monthlyForecast = {
       month: month,
@@ -429,44 +445,16 @@ export default class ProfileTypeService {
    * Try to fetch dju from remote doctype, if no data or error, return default data
    * @returns {Promise<number>} monthDju
    */
-  public fetchDJU = async (month: number): Promise<number> => {
-    const startDate = DateTime.local()
-      .setZone('utc', {
-        keepLocalTime: true,
-      })
-      .set({ year: this.year })
-      .set({ month: month })
-      .startOf('month')
-      .toISO()
-    const endDate = DateTime.local()
-      .setZone('utc', {
-        keepLocalTime: true,
-      })
-      .set({ year: this.year })
-      .set({ month: month })
-      .endOf('month')
-      .toISO()
+  public fetchDJU = async (year: number, month: number): Promise<number> => {
+    const djuDate = `${year}-${formatTwoDigits(month)}`
     try {
       const result: DjuResult = await this._client
         .getStackClient()
-        .fetchJSON(
-          'GET',
-          `${REMOTE_ORG_ECOLYO_DJU}?startDate=${startDate}&endDate=${endDate}`
-        )
-      let monthDju = 0
-
-      if (result) {
-        const degreeDayObservations = result.values.filter(
-          value => value.observation === 'degreeDay'
-        )
-        for (const observation of degreeDayObservations) {
-          monthDju += observation.measurement
-        }
-      }
-      if (monthDju === 0) {
-        return heatingData.dju_average_by_month[month - 1]
+        .fetchJSON('GET', `${REMOTE_ORG_ECOLYO_DJU}?month=${djuDate}`)
+      if (result && result.nb_result !== 0) {
+        return result.values[0].average_measurement
       } else {
-        return monthDju
+        return heatingData.dju_average_by_month[month - 1]
       }
     } catch (error) {
       const errorMessage = `fetchDju error : ${JSON.stringify(error)}`
-- 
GitLab