# Enedis SGE Konnector

This konnector fetches consumption measures from Enedis SGE SOAP API.

You should also check Cozy's official documentations for konnectors :
https://docs.cozy.io/en/tutorials/konnector/getting-started

## Enedis context

The API used by this konnector are the one used by all energy providers (edf, total...), this one is supposed to have a high availability. Contrary to enedis oauth konnector, this is a regular auth konnector.

## Technical overview

### Lib used

- xml2js: Lib allowing easy parsing to json
- easy-soap-request: Lib making soap request

### WSO2

For now enedis API are proxied by WSO2 api manager. You can find documentation and devportal [here](https://apis.grandlyon.fr/devportal).

### Scaffolding

- core/types: contains jsdoc types
- core/: requests wrapper with error handling logic
- helpers/ : contains helpers for aggregation, env and parsing
- requests/: contain all methods for : Parsing sge requests, Send/get backoffice data, interactions with cozy stack
- index.js: main file where default konnector methods are launch (start, ...)
- onDeleteAccount.js: hold consent suppression when a user delete an account. Automatically launched on delete.

### ts-check

In order to have better comfort while coding, we have enable ts-checking with vs-code. The verification is based on js-doc, please take time to maintain the js-doc.

:::info ts-check
The ts-check is none blocking. It will only put information in vs-code ide.
:::

### Local dev

In order to local test you have to copy the [konnector-dev-config.example.json](https://forge.grandlyon.com/web-et-numerique/factory/llle_project/enedis-sge-konnector/-/blob/dev/konnector-dev-config.example.json?ref_type=heads) to `konnector-dev-config.json` and replace values and corresponding secrets.

:::warning user consent
While running in dev mode, be sure to have user consent, either on production env or with enedis standard form.
:::

You can now run the following commands to run the konnector :

```sh
yarn standalone # Run inside shell with no cozy env dependencies
yarn standalone-no-data # Run inside shell without getting any data
yarn dev # Run with your local cozy. For this one you need local stack to run
yarn onDeleteAccount:standalone # Run onDeleteAccount script
yarn onDeleteAccount # Run onDeleteAccount script with real cozy
```

For standalone cmd you can find konnector results in `/data/importedData.json`

### Konnector Methods

| Method | Description |
| ------ | ------ |
| start | Main method of konnector. Handle global flow and init method with provided params |
| gatherData | Wrapper for getting daily, half-hour and max power data |
| getData | Get daily data |
| getMaxPowerData | Get daily Max Power data |
| getHalfHourData | Get half-hour data |
| getOffPeakHours | Get off-peak hours if activated in contract and store them in cozy.account  |
| processData | Given a doctype, parse and format data before storing and aggregating |
| setStartDate | Save startDate with the right time range |
| storeData | Save data to user's cozy |
| agregateMonthAndYearData | Sum daily data for months and years |
| isFirstStart | Check if it's first start or an alternate start base on boId in cozy.account |

## Dataflow

### Overview

Functional and technical flow chart:

[Lien du schema](https://whimsical.com/sge-tech-DxbYM8DdajRjTr6WZat1bV)

### Authentication

Information required:

- Name
- Surname
- PointID (PDL)
- Full address
- Postal Code
- City

#### Test with user invoices

To test user invoices, you will have to make a copy of `konnector-dev-config.example.json` to `konnector-dev-config.json` and fill out informations.

Then, to test the authentication flow of the konnector without fetching any data, launch the script `yarn standalone-no-data`

### Fetch Data

In order to get data from the SGE API we have to request the following route :

#### Get user contract startDate

Method : **POST**

Data Route : **enedis_SGE_ConsultationDonneesTechniquesContractuelles/1.0**

```xml
<soapenv:Body>
    <v2:consulterDonneesTechniquesContractuelles>
        <pointId>${pointId}</pointId>
        <loginUtilisateur>${userLogin}</loginUtilisateur>
        <autorisationClient>true</autorisationClient>
    </v2:consulterDonneesTechniquesContractuelles>
</soapenv:Body>
```

#### Get daily data and Get Half-hour data

Method : **POST**

Data Route : **enedis_SGE_ConsultationMesuresDetaillees/1.0**

```xml
<?xml version='1.0' encoding='utf-8'?>
  <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
     xmlns:v2="http://www.enedis.fr/sge/b2b/services/consultationmesuresdetaillees/v2.0"
     xmlns:v1="http://www.enedis.fr/sge/b2b/technique/v1.0">
     <soapenv:Header/>
     <soapenv:Body>
        <v2:consulterMesuresDetaillees>
           <demande>
              <initiateurLogin>${appLogin}</initiateurLogin>
              <pointId>${pointId}</pointId>
              <mesuresTypeCode>${mesureType}</mesuresTypeCode>
              <grandeurPhysique>${unit}</grandeurPhysique>
              <soutirage>true</soutirage>
              <injection>false</injection>
              <dateDebut>${startDate}</dateDebut>
              <dateFin>${endDate}</dateFin>
              <mesuresCorrigees>false</mesuresCorrigees>
              <accordClient>true</accordClient>
           </demande>
        </v2:consulterMesuresDetaillees>
     </soapenv:Body>
  </soapenv:Envelope>
```

#### Get Max Power data

Method : **POST**

Data Route : **enedis_SGE_ConsultationMesuresDetaillees/1.0**

```xml
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
     xmlns:v2="http://www.enedis.fr/sge/b2b/services/consultationmesuresdetaillees/v2.0"
     xmlns:v1="http://www.enedis.fr/sge/b2b/technique/v1.0">
      <soapenv:Header/>
      <soapenv:Body>
          <v2:consulterMesuresDetaillees>
              <demande>
                  <initiateurLogin>${appLogin}</initiateurLogin>
                  <pointId>${pointId}</pointId>
                  <mesuresTypeCode>${mesureType}</mesuresTypeCode>
                  <grandeurPhysique>${unit}</grandeurPhysique>
                  <soutirage>true</soutirage>
                  <injection>false</injection>
                  <dateDebut>${startDate}</dateDebut>
                  <dateFin>${endDate}</dateFin>
                  <mesuresPas>P1D</mesuresPas>
                  <mesuresCorrigees>false</mesuresCorrigees>
                  <accordClient>true</accordClient>
              </demande>
          </v2:consulterMesuresDetaillees>
      </soapenv:Body>
  </soapenv:Envelope>
```

#### Get contract information

Method : **POST**

Data Route : **enedis_SGE_enedis_SGE_ConsultationDonneesTechniquesContractuelles/1.0**

This route also gives off-peak hours, if the user chose a contract with off-peak hours

```xml
<?xml version='1.0' encoding='utf-8'?>
  <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
     xmlns:v2="http://www.enedis.fr/sge/b2b/services/consulterdonneestechniquescontractuelles/v1.0"
     xmlns:v1="http://www.enedis.fr/sge/b2b/technique/v1.0">
     <soapenv:Header/>
     <soapenv:Body>
        <v2:consulterDonneesTechniquesContractuelles>
           <pointId>${pointId}</pointId>
           <loginUtilisateur>${appLogin}</loginUtilisateur>
           <autorisationClient>true</autorisationClient>
        </v2:consulterDonneesTechniquesContractuelles>
     </soapenv:Body>
  </soapenv:Envelope>
```

Response :

```xml
<point id="12345678912345">
  <donneesGenerales>
    <etatContractuel code="SERVC">
      <libelle>En service</libelle>
    </etatContractuel>
    <adresseInstallation>
      <numeroEtNomVoie>208 BIS RUE GARIBALDI</numeroEtNomVoie>
      <codePostal>69003</codePostal>
      <commune code="69383">
        <libelle>LYON 3</libelle>
      </commune>
    </adresseInstallation>
    <niveauOuvertureServices>2</niveauOuvertureServices>
  </donneesGenerales>
  <situationComptage>
    <dispositifComptage>
      <relais>
        <plageHeuresCreuses>HC (22H00-6H00)</plageHeuresCreuses>
      </relais>
    </dispositifComptage>
  </situationComptage>
</point>
```

#### Get user PDL

Method : **POST**

Data Route : **enedis_SGE_RechercheServicesMesures/1.0**

```xml
<?xml version='1.0' encoding='utf-8'?>
  <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
     xmlns:v2="http://www.enedis.fr/sge/b2b/services/rechercherpoint/v2.0"
     xmlns:v1="http://www.enedis.fr/sge/b2b/technique/v1.0">
     <soapenv:Header/>
     <soapenv:Body>
        <v2:rechercherPoint>
           <criteres>
              <adresseInstallation>
                 <numeroEtNomVoie>${address}</numeroEtNomVoie>
                 <codePostal>${postalCode}</codePostal>
                 <codeInseeCommune>${inseeCode}</codeInseeCommune>
              </adresseInstallation>
              <nomClientFinalOuDenominationSociale>${name}</nomClientFinalOuDenominationSociale>
              <rechercheHorsPerimetre>true</rechercheHorsPerimetre>
           </criteres>
           <loginUtilisateur>${appLogin}</loginUtilisateur>
        </v2:rechercherPoint>
     </soapenv:Body>
  </soapenv:Envelope>
```

#### Get User services subscriptions

Method : **POST**

Data Route : **enedis_SGE_RechercheServicesMesures/1.0**

```xml
<?xml version='1.0' encoding='utf-8'?>
  <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
     xmlns:v2="http://www.enedis.fr/sge/b2b/rechercherservicessouscritsmesures/v1.0"
     xmlns:v1="http://www.enedis.fr/sge/b2b/technique/v1.0">
      <soapenv:Header/>
      <soapenv:Body>
          <v2:rechercherServicesSouscritsMesures>
            <criteres>
              <pointId>${pointId}</pointId>
              <contratId>${contractId}</contratId>
            </criteres>
            <loginUtilisateur>${appLogin}</loginUtilisateur>
          </v2:rechercherServicesSouscritsMesures>
      </soapenv:Body>
  </soapenv:Envelope>
```

#### Start user contract

Method : **POST**

Data Route : **enedis_SGE_CommandeCollectePublicationMesures/1.0**

```xml
<?xml version='1.0' encoding='utf-8'?>
  <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
     xmlns:v2="http://www.enedis.fr/sge/b2b/commandercollectepublicationmesures/v3.0"
     xmlns:v1="http://www.enedis.fr/sge/b2b/technique/v1.0">
      <soapenv:Header/>
      <soapenv:Body>
          <v2:commanderCollectePublicationMesures>
              <demande>
                  <donneesGenerales>
                      <objetCode>AME</objetCode>
                      <pointId>${pointId}</pointId>
                      <initiateurLogin>${appLogin}</initiateurLogin>
                      <contratId>${contractId}</contratId>
                  </donneesGenerales>
                  <accesMesures>
                      <dateDebut>${startDate}</dateDebut>
                      <dateFin>${endDate}</dateFin>
                      <declarationAccordClient>
                          <accord>true</accord>
                          <personnePhysique>
                              <nom>${name}</nom>
                          </personnePhysique>
                      </declarationAccordClient>
                      <mesuresTypeCode>CDC</mesuresTypeCode>
                      <soutirage>true</soutirage>
                      <injection>false</injection>
                      <mesuresPas>PT30M</mesuresPas>
                      <mesuresCorrigees>false</mesuresCorrigees>
                      <transmissionRecurrente>true</transmissionRecurrente>
                      <periodiciteTransmission>P1D</periodiciteTransmission>
                  </accesMesures>
              </demande>
          </v2:commanderCollectePublicationMesures>
      </soapenv:Body>
  </soapenv:Envelope>
```

#### Stop User contract

```xml
<?xml version='1.0' encoding='utf-8'?>
  <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
     xmlns:v2="http://www.enedis.fr/sge/b2b/commanderarretservicesouscritmesures/v1.0"
     xmlns:v1="http://www.enedis.fr/sge/b2b/technique/v1.0">
      <soapenv:Header/>
      <soapenv:Body>
          <v2:commanderArretServiceSouscritMesures>
              <demande>
                  <donneesGenerales>
                      <objetCode>ASS</objetCode>
                      <pointId>${pointId}</pointId>
                      <initiateurLogin>${appLogin}</initiateurLogin>
                      <contratId>${contractId}</contratId>
                  </donneesGenerales>
                  <arretServiceSouscrit>
                  <serviceSouscritId>${serviceSouscritId}</serviceSouscritId>
                  </arretServiceSouscrit>
              </demande>
          </v2:commanderArretServiceSouscritMesures>
      </soapenv:Body>
  </soapenv:Envelope>
```

The same endpoint is used to get the data. The soap body is the following:

Method : **POST**

Data Route : **enedis_SGE_ConsultationDonneesTechniquesContractuelles/1.0**

```xml
<soapenv:Body>
    <v2:consulterMesuresDetaillees>
        <demande>
            <initiateurLogin>${userLogin}</initiateurLogin>
            <pointId>${pointId}</pointId>
            <mesuresTypeCode>${mesureType}</mesuresTypeCode>
            <grandeurPhysique>${unit}</grandeurPhysique>
            <soutirage>true</soutirage>
            <injection>false</injection>
            <dateDebut>${startDt}</dateDebut>
            <dateFin>${endDt}</dateFin>
            <mesuresCorrigees>false</mesuresCorrigees>
            <accordClient>true</accordClient>
        </demande>
    </v2:consulterMesuresDetaillees>
</soapenv:Body>
```

### Known Issues

#### Contract deletion and creation on same day

If you stop a contract on a day, (for exemple 8/08/22), you cannot start a new contract for this date with [start contract route](./enedis-sge.md#user_contract_start). You have to wait for the next day. This might cause some production issues

#### User data collect opposition

Users can remove consent from enedis account on data collecting. This will return the following when checking contracts.

```xml
<serviceSouscritMesures>
    <serviceSouscritId>74472322</serviceSouscritId>
    <pointId>19176410771132</pointId>
    <serviceSouscritType code="OPPENR"/>
    <serviceSouscritLibelle>Opposition à l'enregistrement de la courbe de charge</serviceSouscritLibelle>
    <injection>false</injection>
    <soutirage>true</soutirage>
    <etatCode>ACTIF</etatCode>
    <dateDebut>2022-06-24+02:00</dateDebut>
    <dateFin>2022-08-10+02:00</dateFin>
    <motifFinLibelle>Arrêt par le client</motifFinLibelle>
</serviceSouscritMesures>
```

We cannot override that, the only solution is to tell the user to activate data collect on [enedis](https://mon-compte-particulier.enedis.fr/donnees/).