# Doc Transverse


## FLux 4 Gestion des statuts d'une offre

### route spécifique bailleurs

    POST     /api/dmo/housing_applications/update_status/
    
    {  
    "data":{     
      "attributes":{
                 "unique_number":"0690412654321G3U05",
                 "external_ref":"CVL-000014",
                 "status":"Visite proposée",
                 "last_status_update_date":"01/01/0001",
                 "lessor_event_informations ":"0"
        }
      }
    }
     

### Explication rapide du concept de "status"

Pour gérer au niveau du moteur le cycle de vie d'un objet, nous employons le concept de **"status"**.
Ceux-ci permettent de discriminer des objets entre eux en fonction de l'état "métier" dans lequel ils se trouvent.

Pour gérer ces statuts il y a deux méthodes accessibles :
- 1. Modifier un champ "status" sur une offre
- 2. Produire un "status" détaillé par la route : **POST api/dmo/statuses**

### Changement de "status" simple

Dans le cas des offres, les champs accessibles pour gérer ces changements non-détaillés de "status" sont les suivants :
- **lessor_status:** status fournit par le bailleur
- **offer_status:** status fournit par SOPRA ou produit par effet de bord
Changer la valeur d'un de ces champs vers la valeur adéquate, permet au moteur de produire les effets souhaités.

### Changement de "status" détaillé

uri :

     POST api/dmo/statuses

Il s'agit ensuite de fournir un corps de requête adéquat.
Pour le détail fonctionnel des champs présents dans notre swagger [https://als-hermes-scoring-rec.be-idys.com/api/swagger/index.html](https://als-hermes-scoring-rec.be-idys.com/api/swagger/index.html):
- **status_label:** complément de status indiquant à quel concept ce status est associé (ex: *lessor*, *offer*, *request*, *entity*, ...)
- **motive:** description du motif de passage à ce status
- **title:** intitulé du status. IMPORTANT : La validité parfaite de sa valeur est essentielle => ce champs détermine - pour le moteur, l'état métier actuel de l'objet associé.
- **object_id:** id de l'objet associé
- **performer_id:** dans le cas d'une possibilité de "status" concurrents, il est essentiel d'indiquer ici l'id du déclencheur de ce status. *(non utile dans le cas du bailleur)*

### Correspondance des évènements aux status

**NOUS AVONS BESOIN DE FAIRE UN POINT SUR CETTE CORRESPONDANCE.**

évènement|label de status|valeur PAW
---------|---------------|----------
||









## Flux 21 Envoi d'une candidature au back sopra (sortant sopra)
Ce flux se déclenche lors de la création d'une candidature pour une offre ( au create d'une
housing_application ). Il envoie une requête  vers Sopra indiquant l'offre concerné et la demande concernée ainsi que la date de positionnement.
      
      
## Flux 30 Envoi d'une demande (sortant sopra)
ce flux se déclanche a la création ou a l'update d'une housing_request et permet de renseigner le back sopra sur les modifications d'une demande de logement.




## Flux 32 Envoie d'un NUD au FRONT

Pour créer un Nud :

uri:

    POST /api/dmo/nuds

body :

    {
      "data": {
        "attributes": {
          "housing_request_id": ,// String, id PAW de la demande concernée (utilisez aussi l'als_id si vous preferez)
          "als_id":             ,// String, als_id de la demande concernée (connue sous le nom de ref_interne chez sopre
          "department":         ,// String, code du département rattaché au nud
          "creation_date":      ,// DateTime, date de création rattaché au nud
          "unique_number":      ,// String, numéro unique du nud
          "is_active":           // Boolean, true si toujours d'actualité, false pour désactiver la validité
        }
      }
    }

Cette méthode API gère aussi les doublons :
Si la paire **"unique_number"** <==> **"housing_request_id"**, est déjà réferencée, alors l'objet portant cette correspondance sera récupéré et mit à jour.

Vous pouvez vous référer au [swagger](https://als-hermes-scoring-rec.be-idys.com/api/swagger/index.html) pour connaitre le reste de ses fonctionnalités classiques.

## Flux 36 Validation d'une demande par une entreprise (sortant sopra)
ce flux se déclenche quand entity_validated est modifié

## Flux 37 Dès détection d'une modification de l'orientation sur une demande suite au traitement automatique de détermination

	GET api/dmo/housing_requests/clp_details?als_ids[]=${id1}&als_ids[]=${id2}…

Le paramètre **_« als_ids »_** est ici obligatoire. C’est l’équivalent du paramètre **_« ids »_** mais pour la correspondance avec le champ « als_id » porté par une demande.

Ce paramètre n’existe que pour cette action !!! Autrement il faut utiliser **« als_id[$in] »** pour reproduire son effet.

Mapping des champs :

 - Nombre de candidatures => **applicantions_nb** Date dernière
  - candidature => **last_application_date** Nombres d’offres éligibles
  - détaillé => **eligible_offers_nb_detailed** Objet qui contient les
  - clefs : Nombre non commercialisées => **non_commercialized** Nombre
	  - commercialisées et non publiées => **commercialized_non_pubicated**
		 -  Nombre commercialisées et publiées => **commercialized_publicated**















## Flux 50 à 56 Communication d'évènements candidature (sortant sopra)

Ce flux se déclenche lors de la modification du statut d'une candidature (champ "status" d'une housing_application).   
Il envoie une requête indiquant l'évènement vers Sopra avec un code évènement tel que décrit ci dessous.
      
### Statuts des candidatures
Cette liste peut être amenée à évoluer car certaines corrrespondances avec les précédents statuts ne sont pas encore bien établies.

A présent il est indispensable de séparer les statuts de commissions des statuts de visite, il existe donc deux champs sur le modèle HousingApplication qui sont `status` et `visit_status`

Actuellement la correspondance avec le code évènement fonctionne avec les anciens et les nouveaux statuts.   
Si un ancien statut est utilisé alors il sera converti suivant ce tableau.  
Le code évènement sera renvoyé avec les anciens et nouveaux statuts (si correspondance)

|status|visit_status|Ancienne correspondance|Code évènement renvoyé|
|---|---|---|---|
|EN ATTENTE||Waiting||
|PLO||PLO||
|TRANSMIS BAILLEUR||Inscription CAL|INSCAL|
|RETENUE EN CAL||Attribution lot avec rang|DESCAL|
|REFUSEE EN CAL||Refus attribution|DESCAL03|
|NON RETENUE||Refus lot demandeur|REFLOG|
|NON RETENUE EN CAL||Radiation attribution|RADATT|
|DESISTEMENT SALARIE AVANT CAL||||
|ANNULEE BAILLEUR||||
|DESISTEMENT||||
|ANNULEE||||
|A L’ETUDE ALS||||
|DESISTEMENT APRES CAL||||
|**RETENUE EN CAL**|VISITE PROPOSEE|Visite proposée|VISPRO|
|**RETENUE EN CAL**|VISITE EFFECTUEE|Visite effectuée|VISEFF|
||DESISTEMENT APRES VISITE|||
||ACCORD APRES VISITE|||
|**RETENUE EN CAL**||Attribution lot|DESCAL01|
|**RETENUE EN CAL**||Attribution sous condition|DESCAL02|

### Déclanchement des effets de bords

A la suite de certaines modifications sur les statuts d'une HousingApplication, cela peut déclencher une série d'évènements.

|status|visit_status|Effet|Impact|
|---|---|---|---|
|si inclut le mot 'DESISTEMENT'|VISITE EFFECTUEE|Re-calcul du scoring|- 35 points|
|RETENUE EN CAL|NA|Re-calcul du scoring|+ 35 points|

### Affichage de l'historique des statuts pour un candidat

Un candidat peut afficher la liste des statuts de ses candidatures via la requête suivante : 

    GET /api/dmo/statuses/applications_history

La notion d'historisation est liée au filtrage par 2 paramètres disponibles, `start_date` et `end_date`, que l'on peut ajouter à la requête soit l'un ou l'autre, soit les deux : 

    GET /api/dmo/statuses/applications_history?start_date=01/01/2020&end_date=31/12/2020

Le requête est alors filtrée sur les statuts dont la date de mise à jour (`updated_at`) est comprise entre les bornes datées.



    







## Envoi d'email

Pour demander à l'api  d'envoyer un email, on doit réaliser la requete 

    POST /api/d2/docs
    
avec dans le body json de la requête : 
 
    {
        "to": "String",
        "cc": "String",
        "bcc": "String",
        "from": "String"
        "data":{
            "attributes":{
                "type": "email",  //doit etre égal à "email" pour que l'envoi soit réalisé
                "title": "String", //objet du mail
                "body": "String"   //contenu du mail
            }
        }
    }








    
## Gestion Documents 

A la création d'une Demande (housing_request), ainsi qu'aux updates, un objet housing_request_folder representant le dossier demande est créé ou mis a jour.
Des objets de type "required_document" sont générés après un calcul sur les pieces a fournir pour un dossier donné.
le calcul est automatisé par notre API, et il n'y a plus qu'a afficher la liste des pieces a fournir.
Si les pieces existent déja pour un applicant donné, alors elles sont récupérés directement.
Si la demande évolue et entraine une modification des pieces à fournir, alors les required_documents sont mis a jours automatiquement

### Récupération de la liste des pieces à fournir pour une demande

    GET api/dmo/housing_requests/${id}/housing_request_folder
    
cette requete renvoie un JSON ressemlant à ceci :

    {
        "data" : {
                    "id" : "5de12f9b88cb11400c9dcdfe",
                  "type" : "housing_request_folders",
            "attributes" : {
                        "created_at" : "2019-11-29T15:47:55.045+01:00",
                        "updated_at" : "2019-11-29T15:47:55.045+01:00",
                            "nud_status" : "Dossier validé", //status du dossier de demande pour obtention d'un nud
                            "consultation_status" : "Dossier validé", //status du dossier de demande pour consulter les offre
                            "application_status" : "Dossier incomplet", //status du dossier de demande pour candidater aux offre
                        "completion" : 0, //pourcentage de completion du dossier
                "housing_request_id" : "5de12f9a88cb11400c9dcdf9",
                "required_documents" : [{
                                                "id" : "5de12f9b88cb11400c9dcdfa",
                                        "created_at" : "2019-11-29T15:47:55.048+01:00",
                                        "updated_at" : "2019-11-29T15:47:55.048+01:00",
                                            "nature" : "Pièce d'identité"
                                              "type" : "Carte nationale d’identité ou passeport",
                                             "label" : "Veuillez déposer une copie recto-verso de votre carte d'identité ou en cours de validité. 
                                                          Attention, ce document doit impérativement faire figurer 
                                                          Nom d’usage, Nom de naissance, Prénom (uniquement le premier),Date de naissance,Lieu de naissance,Pays de naissance, Date d’émission, Date d’expiration, Signature et photo. 
                                                          Ce document doit être lisible et complet.""validity_limit" : "2021-11-29T15:47:55.045+01:00", //limite de validité si la piece n'est valable qu'un certain temps
                                            "status" : "pièce non fournie", //status de la piece à fournir
                                          "category" : "SPI",  //code de catégorie du document
                      "is_required_for_nud" : false,  //true si requis pour obtenir un nud
                      "is_required_for_consultation" : false,  //true si requis pour consulter les offres
                       "is_required_for_application" : true,   //true si requis pour postuler aux offres
                             "is_for_main_applicant" : false,  //true si le document est requis pour le main applicant
                               "dependent_infos" : {           //n'est renseigné que si la piece doit etre au nom du dépendent
                                              "last_name" : "GOUBILLze",
                                             "first_name" : "CHRIS",
                                             "birth_date" : "2017-03-23T00:00:00.000Z",
                                               "rel_type" : "P",
                                                    "sex" : "M"
                                         },
                                         disability_index: nil //rensigné si la piece est liée au handicap
                                          //le document justificatif doit concerner cet applicant (demandeur)
                                         "applicant" : {             
                                                       "id" : "5de12f9a88cb11400c9dcdf7",
                                               "created_at" : "2019-11-29T15:47:54.930+01:00",
                                               "updated_at" : "2019-11-29T15:47:55.071+01:00",
                                                      "nud" : nil,
                                             "temporary_id" : nil,
                                "sne_profile_creation_date" : nil,
                                                    "ss_id" : nil,
                                               "first_name" : "Océane",
                                                "last_name" : "Vincent",
                                                "full_name" : "Océane Vincent",
                                                ...
                                                        }            
                                        },
                                        {...},
                                        {...}
                                    ]
                                      
            }
        }
    }
#### Statuts des dossiers de demande

pour la conception de l'UX il sera important de prendre en considération les deux status des housing_request_folders
nud_status, consultation_status et application_status

nud_status, consultation_status et application_status pourront prendre les valeurs suivantes : 
    
   - "Dossier incomplet"
   - "Dossier validé"

#### Statuts des pièces à fournir

à ce jour les required_documents.status pourront prendre les valeurs suivantes : 
    
   - "Pièce manquante" -> la piece n'a pas eté fournie
   - "Pièce validée" -> le traitement KYC ou un collaborateur offre logement a déclaré la piece valide 

#### Impact sur le status de la housing_request

par défaut : housing_request.request_status = "INCOMPLETE"

nud_status == "Dossier validé" => housing_request.request_status = "EN ATTENTE DE NUD" (puis "EN ATTENTE DE PIECES" lorsque le nud est arrivé)

consultation_status == "Dossier validé" => housing_request.request_status = "ELIGIBLE"
application_status == "Dossier validé" => housing_request.request_status = "COMPLETE"

***Lorsque `housing_request.request_status = "ELIGIBLE"` :***

housing_request.entity.auto_request_validation == `true` => housing_request.entity_status = "EN COURS"
housing_request.entity.auto_request_validation == `false` => housing_request.entity_status = "A VALIDER"

#### personne concernée par la piece a fournir

il faut pour cela aller regarder dans la partie "applicant" du json pour pouvoir recuperer cette information
   
### Page d'accès publique à la liste des documents à fournir
SWAGGER: **API_DMO_HOUSING_REQUEST_SHARES**

Requete GET

    GET /api/dmo/housing_request_shares/:id?code=xxxxxxx

Requete POST

    POST /api/dmo/housing_request_shares

    {
        "data":{
            "id":"5ec29dfdd195548c7d716cff",
            "type":"housing_request_shares",
            "attributes":{
                "responsible":{
                    "id":"5ec29dfcd195548c7d716cf2",
                    "first_name":"Thomas",
                    "last_name":"Clemént"
                },
                "readers":null,
                "writers":null,
                "read_level":"guest",
                "created_at":"2020-05-18T16:38:53.244+02:00",
                "updated_at":"2020-05-18T16:38:53.244+02:00",
                "housing_request_id":"5ec29dfcd195548c7d716cf6",
                "lessor_id":"5ec29dfdd195548c7d716cfe",
                "code":"okplrdytdqrd",
                "expire_at":"2020-06-01T00:00:00.000+02:00",
                "public_url":"/api/dmo/housing_request_shares/5ec29dfdd195548c7d716cff?code=okplrdytdqrd"
            }
        }
    }

Lorsqu'une demande passe en candidature appliqué, (status: 'COMPLETE' ||'EN ATTENTE DE PIECES' ||'EN ATTENTE DE NUD'). Un enregistrement de type HousingRequestShare sera créé et un code de validation sera généré.

Il est aussi possible pour un utilisateur authentifié de créer manuellement un HousingRequestShare en fournissant un `:housing_request_id` et un `:lessor_id`

Pour accèder à la page publique de la liste des documents, il faut renseigner un id de HousingRequestShare ainsi que le code de validation qui est associé. Si l'id et le code sont valide, alors un objet HousingRequest avec les required_documents nesté sera retourné.











## Securisation de la récupération des documents sur le SNE

### Demande d'envoi d'une clef d'authentification par mail :

    POST api/dmo/nuds/${numero_unique_departemental}/send_pin_code_on_mail
    
Lorsque une requete est envoyée sur ce point d'entré, une recherche d'existence du NUD est faite. si elle permet de remonter à un NUD existant, alors on evoie sur le mail qui lui est asscié un code à 6 caractères.

La récupération des demandes a partir du numéro unique etant débouchonnée, il faut désormais contacter Sopra (christophe.sebisch@soprasteria.com) pour obtenir des numéros uniques valides. 
Output :
-	200 – OK
-	400 – NUD non trouvé / incorrect
- 422 - voir le message d'erreur :

    - unique_number_not_covered_by_sne => le numéro unique n'est pas couvert dans la liste des départements
    - recuperation_of_housing_request_from_sne_already_done => le numéro unique a déja été utilisé pour créer une housing_request

note : provisoirement, l'email est 
- envoyé depuis l'adresse : securite@masolutionlogement.fr
- expédié sur l'adresse : recette.hermes@actionlogement.fr et comptetestals@gmail.com

### Envoi par l'utilisateur du code pin reçu sur son mail

    POST api/dmo/nuds/${numero_unique_departemental}/authentify_with_pin_code
    
    //avec en body de la requête : 
    {
      "pin_code": "A9i74M"
    }
    
Requete à envoyer lorsque l'utilisateur saisis le code qu'il vient de recevoir sur sa boite mail.
    
-	400 – aucune association trouvée ou association expirée
-	200 – OK, la réponse doit renvoyer une demande initialisée avec les infos issues du SNE si existantes sinon vide,
elle renvoie donc un objet du type "housing_request" dont le format est décrit plus haut dans cette documentation
- 422 - voir le message d'erreur :

    - unique_number_not_covered_by_sne => le numéro unique n'est pas couvert dans la liste des départements
    - recuperation_of_housing_request_from_sne_already_done => le numéro unique a déja été utilisé pour créer une housing_request
    - unable_to_send_mail_with_pin_code => un probleme est survenu lors de l'envoi
    





    
## récuperer la liste des départements valide pour le SNE

    GET /api/dmo/nuds/sne_department_list
    
retour :

    ["01", "02","04","05", ... ,  "971","972","973" ]


## récuperer la liste des départements valide pour le IMHOWEB

    GET /api/dmo/nuds/imhoweb_department_list
    
retour :

    ["01", "02","04","05", ... ,  "971","972","973" ]




## Modèles geolocalisables
|field|type|info|
|---|---|---|
|`:address`|`string`||
|`:postal_code`|`string`||
|`:district`|`string`||
|`:country`|`string`||
|`:latitude`|`float`||
|`:longitude`|`float`||

Pour utiliser le géocodage dans un modèle, il faut inclure le concern `include ::Concerns::Geolocalizable`

Les modèles concernés sont `Hermes::Entity`, `Hermes::Applicant` et `Hermes::HousingOffer`, ils utilisent la [gem geocoder](https://github.com/alexreisner/geocoder)
et peuvent donc utiliser toute les méthodes de recherche qu'elle fournit.

- A chaque création de l'un de ces modèles, le geocode ou reverse_geocode est appelé
- A chaque mise à jour de l'un de ces modèles, si l'un des champs ci-dessus est modifié alors le geocode ou reverse_geocode est appelé

**Attention** Afin de ne pas être blocant, l'appel api pour le geocodage est executé dans une tache paralèlle, les données ne seront donc pas retournées immédiatement après la création/modification d'un enregistrement geocodable, cela implique donc une seconde requete (GET) pour recevoir ces informations


  

 























## Centre de Notifications
- Endpoint notifications: `/api/dmo/{targetable_type}/{targetable_id}/notifications`
- Endpoint subscriptions: `/api/dmo/{targetable_type}/{targetable_id}/subscriptions`
- [Collection postman](https://www.getpostman.com/collections/2d165c413a89f7df87f9)

### Utilisation
Lors de de certaines actions une notification peut être créé. Cette notification est un
enregistrement en base de donnée qui relie une entité **notifiable** et une entité **targetable**. Par exemple, lorsqu'un
nouveau logement est disponible et est éligible pour un salarié donné, **HousingOffer** est le **notifiable** et Applicant le **targetable**.

Par défaut un **Applicant** sera notifié par email lorsqu'une nouvelle notification lui sera destiné mais il est possible
de créer un abonnement à un type de notification et de spécifier si oui ou non les emails doivent être envoyés lors de
la création d'une nouvelle notification.
Si l'email est envoyé, celui-ci contient un message informant d'une nouvelle notification, et d'un lien permettant de
redirigé vers l'entité notifiable en question.

L'api fournit une série de routes permettants la gestion des notifications et abonnements.

### Clés d'abonnement aux notifications disponible
|Modèle|Clé|Création|
|---|---|---|
|Hermes::HousingRequest|housing_request.status.change|Si le status d'une HousingRequest est modifié, alors on notifie le candidat|
|Hermes::HousingOffer|housing_offer.new.eligible|Si un candiat est éligible à un nouveau logement lors de la création d'un score, celui-ci est notifé|

### Exemple pour la gestion des notifications d'un Applicant

**Objet Notification**

    {
    "data": {
        "id": "5e848a63d19554699b8358d0",
        "type": "notifications",
        "attributes": {
            "responsible": {
                "id": "5dd39e0ca70bf2255538a2eb",
                "first_name": "Pierre",
                "last_name": "DUPONT"
            },
            "readers": null,
            "writers": null,
            "read_level": "guest",
            "created_at": "2020-04-01T14:34:45.221+02:00",
            "updated_at": "2020-04-01T15:01:42.704+02:00",
            "title": "Notification title",
            "body": "Notification body",
            "opened_at": "2020-04-01T15:01:42.703+02:00",
            "key": "housing_offer.new_eligible",
            "sender_type": "Hermes::Lessor",
            "sender_id": "5dd26f45a70bf26eeed14b3a",
            "notifiable_type": "Hermes::HousingOffer",
            "notifiable_id": "5dfa69c122ec79668b6c1077",
            "subscription_id": "5e848a5dd19554699b8358cf"
        }
    }
}

**Récupération de la liste de ses notifications**

    GET /api/dmo/applicants/5dcd4a32a70bf24770e869b2/notifications

    status: 200

**Marquer une notification comme lue**

    PUT /api/dmo/applicants/5dcd4a32a70bf24770e869b2/notifications/5e5d2534d195540cc306cec2/open

    status: 200

**Ouvrir toute les notifications**
Il est possible d'utiliser le query param `:limit` afin d'ouvrir (x) notifications

    PUT /api/dmo/applicants/5dcd4a32a70bf24770e869b2/notifications/open_all

    status: 200

**Supprimer une notification**

    DELETE /api/dmo/applicants/5dcd4a32a70bf24770e869b2/notifications/5e5d2534d195540cc306cec2

    status: 204
### Exemple pour la gestion des abonnements d'un Applicant

**Objet abonnement**

    {
        "data": {
            "id": "5e848a5dd19554699b8358cf",
            "type": "subscriptions",
            "attributes": {
                "responsible": {
                    "id": "5dd39e0ca70bf2255538a2eb",
                    "first_name": "Pierre",
                    "last_name": "DUPONT"
                },
                "readers": null,
                "writers": null,
                "read_level": "guest",
                "created_at": "2020-04-01T14:34:37.391+02:00",
                "updated_at": "2020-04-01T14:34:37.391+02:00",
                "keys": [
                    {
                        "name": "housing_request.status.change",
                        "email": true,
                        "slack": false
                    },
                    {
                        "name": "housing_offer.new.eligible",
                        "email": true,
                        "slack": false
                    },
                ],
                "subscriber_type": "Hermes::Applicant",
                "subscriber_id": "5dd39e0ca70bf2255538a2eb"
            }
        }
    }

**Récupération de la liste des abonnements**

    GET /api/dmo/applicants/5dcd4a32a70bf24770e869b2/subscriptions/5e848a5dd19554699b8358cf

    status: 200

**S'abonner**

    PUT /api/dmo/applicants/5dcd4a32a70bf24770e869b2/subscriptions/5e848a5dd19554699b8358cf/subscribe

body

    {
        "provider": "email",
        "key": "housing_offer.new.eligible"
    }

    status: 200
    

**Se désabonner**

    PUT api/dmo/applicants/5dcd4a32a70bf24770e869b2/subscriptions/5e848a5dd19554699b8358cf/unsubscribe

body

    {
        "provider": "email",
        "key": "housing_offer.new.eligible"
    }

    status: 200

### HousingRequest notifications personalisés
Il est possible d'envoyé une notification personnalisé au candidat principal d'une demande et de sélectionner
le cannal de diffusion parmis les cannaux disponibles (email, sms, slack).

    POST api/dmo/housing_requests/5ec8f699d195547125211a45/notify

Avec en body :

    {
      "data": {
        "attributes": {
          "title": "Titre de la notification",
          "body": "Corps de la notification",
          "channels"?: ["sms"]
        }
      }
    }

Réponse : 

    {
        "data": {
            "id": "5ec8f699d195547125211a4f",
            "type": "notifications",
            "attributes": {
            "responsible": {
                "id": "5ec8f699d195547125211a42",
                "first_name": "Kylian",
                "last_name": "Giraud"
            },
            "readers": null,
            "writers": null,
            "read_level": "guest",
            "created_at": "2020-05-23T12:10:33.956+02:00",
            "updated_at": "2020-05-23T12:10:33.956+02:00",
            "title": "Titre de la notification",
            "body": "Corps de la notification",
            "opened_at": null,
            "key": "housing_request.custom.notification",
            "channels": [
                "sms"
            ],
            "sender_type": "User",
            "sender_id": "5ec8f699d195547125211a43", // current_user
            "notifiable_type": "Hermes::HousingRequest",
            "notifiable_id": "5ec8f699d195547125211a45",
            "targetable_type": "Hermes::Applicant",
            "targetable_id": "5ec8f7aad195547356fef879", // main_applicant
            "subscription_id": "5ec8f699d195547125211a50"
            }
        }
    }





























## Fonctionnement REX

  Liens de parenté via le champs parent_id dans les entities/lessors
  id_rex et cristal_id qui donne les ids correspondant dans les différents services

  Tous les appels retourne les données en fonctionne de l'habillitation de l'utilisateur.
  Pour ses 2 appels, on peut spécifier le parmètre for_lessor=true pour n'avoir que les bailleurs

  Retourne l'id et le nom des élements à la racine des arborescence: 
    
    GET /api/dmo/rex/root_elements?for_lessor=true|false

    {
        "data"=>[
            {
                "id"=>"5ebe3c03a6f7e901dbbed1d4", 
                "type"=>"hermes-entities", 
                "attributes"=>{
                    "title"=>"etpA1"
                }
            }, {
                "id"=>"5ebe3c04a6f7e901dbbed1f0", 
                "type"=>"hermes-entities", 
                "attributes"=>{
                    "title"=>"etpB1"
                }
            }
        ]
    }

  Retourne l'arborescence compléte pour une entreprise/bailleur: 
    
    GET /api/dmo/rex/{entity_id/lessor_id}?for_lessor=true|false
  
    {
        data: {
            from_element: {
                id: entity_id,
                ... # information de l'entreprise/bailleur qui correspond à entity_id/lessor_id
            },
            tree: [
                {
                    ... # information de l'enfant 1 dans l'arbrorescence REX
                    children: [
                        {
                            ... # information de l'enfant de l'enfant 1 dans l'arbrorescence REX
                        }
                    ]
                },
                {
                    ... # information de l'enfant 2 dans l'arbrorescence REX
                }
            ]
        }
    }

  Retourne les filliales pour une liste de parents
    
    GET /api/dmo/rex/subsidiaries?parent_ids[id1]&parent_ids[id2]&for_lessor=true|false

















## Mailing form 

Faire une demande de code captcha :

    GET /api/dmo/public_forms/captcha

Réponse type :

    {status: "success", code: 200, message: {'captcha' => str', 'form_mailer_token' => "mailer_data_#{form_mailer_token}"}}

Le code captcha que vous recevez est une opération comme 1+2 ou 2-1

    POST /api/dmo/public_forms/confirm

Pour pouvoir envoyer un mail, confirmez le captcha sur l'endpoint ci-dessus avec en body de la requête :

        {
            res => resultat du captcha 
            form_id => id du form pour origine du mail 
            email => mail du destinataire
            content => contenu du mail 
            form_mailer_token => token reçu dans dans le GET du /captcha 

        }

Réponse type :

        {status: "success", code: 200, message: "mail delivered"}











## Zones détendues : untensed_area

Objectif :  Pouvoir definir des zones pour lesquelles le dossier de cadidature est allégé en termes de pieces justificatives a fournir.

Les administrateurs de l'application ont la possibilité de venir créer/modifier/supprimer/voir les zones détendues grace à un CRUD classique similaire aux autres objets de l'application :

Le modèle untensed_area est classique : 

    POST /api/dmo/untensed_areas  ->creation
    GET /api/dmo/untensed_areas  ->liste des zones détendues (on peut utiliser tout les modificateurs classiques de recherche)
    GET /api/dmo/untensed_areas/{id}  ->lecture d'une untensed_area
    PUT/PATCH /api/dmo/untensed_areas/{id}  ->modification
    DELETE /api/dmo/untensed_areas/{id}   ->supression

la donnée est affichée et modifiable sous ce format (l'idéal etant de renseigner ou le code comune ou le département, si le code commune et le département sont renseignés en meme temps, l'algorithme considerera que tout le département est en zone détendue) :

    data : {
        attributes : {
                           insee_code: 'String', // code insee de la commune à inclure dans les zones détendues
                           department: 'String', // departement à considerer comme zone détendue
                       }
     }
     
Lorsqu'une nouvelle zone détendue est ajoutée, modifiée, ou supprimée, l'ensemble des demandes concernées sont mises a jour et se voient attribuer le booleen "is_untensed_area" à true ou a false en fonction des communes choisies dans "seeked_localisation_list".

Le dossier de pieces justificatives des demandes avec le booléen "is_untensed_area" est automatiquement recalculé et seules les pieces liées a l'identitée du demandeur principal sont requises.

Ce recalcul est aussi effectué lorsque les "seeked_localisation_list" de la housing_request sont créées ou modifiées.















## Gestion des filières logements

Les filières logements sont gérées via 2 modèles : `HousingChannel` (filière logement) et `HousingChannelSetting` (filtrage des filières par département).
La lecture et l'écriture de ces 2 modèles sont uniquement accessibles au role **Administrator**.

### Pour administrateurs uniquement

1. **HousingChannel (filière logement)**

Requête pour créer une nouvelle filière logement : 

    POST api/dmo/housing_channels

Requête pour mettre à jour une filière logement : 

    PUT api/dmo/housing_channels/{id de l'housing_channel}

Avec en body pour les 2 requêtes : 

    {
      "data": {
        "attributes": {
          "key"(required): 'string', // e.g. 'public_priority'
          "label": 'string',         // e.g. 'Offre Public prioritaire'
          "request_name": 'string'   // e.g. 'Demande Publique prioritaire validés'
          "code_ikos": 'string'      // e.g. 'PUBPR'
        }
      }
    }

Pour supprimer une filière : 

    DELETE api/dmo/housing_channels/{id de l'housing_channel}

Pour afficher la liste des filières logement (utilitaires de tri disponibles $in, $nin, $ne, $eq, $all) : 

    GET api/dmo/housing_channels

Pour afficher une filière logement spécifique : 

    GET api/dmo/housing_channels/{id de l'housing_channel}

2. **HousingChannelSetting (filtrage des filières par département)**

Un utilisateur **Administrator** peut créer un filtrage de filière (`HousingChannelSetting`) pour un département donné. Il renseigne alors dans le tableau `housing_channel_keys`, les clés des filières logement qu'il souhaite associer à ce département.

**Attention, les clés ajoutées dans le tableau `housing_channel_keys` doivent correspondre au champ `key` de filières `HousingChannel` préalablement créées.**

Requête pour créer un nouveau filtrage : 

    POST api/dmo/housing_channel_settings

Requête pour mettre à jour un filtrage : 

    PUT api/dmo/housing_channel_settings/{id de l'housing_channel_setting'}

Avec en body pour les 2 requêtes : 

    {
      "data": {
        "attributes": {
          "department"(required): '34',
          "insee_code": '34001',
          "housing_channel_keys": ['priority_public', 'dalo'] 
        }
      }
    }

Pour supprimer un filtrage : 

    DELETE api/dmo/housing_channel_settings/{id de l'housing_channel_setting}

Pour afficher la liste des filtrages (utilitaires de tri disponibles $in, $nin, $ne, $eq, $all) : 

    GET api/dmo/housing_channel_settings

Pour afficher un filtrage spécifique : 

    GET api/dmo/housing_channel_settings/{id de l'housing_channel}

### Ajout et validation des filières logements pour une HousingRequest

Une `HousingRequest` porte dorénavant 3 nouveaux champs de type `array` : 

- • `housing_channel_pending_keys` : correspond aux clés des filières logement en attente de validation pour une demande de logement.
- • `housing_channel_keys` : correspond aux clés des filières logement validées pour une demande de logement.
- • `housing_channel_chosen_keys` : correspond aux mêmes clés des filières ajoutées dans le tableau "pending". Cependant ce tableau de clés "chosen" est immuable.

  --- 

  **Attention, la mise en attente de validation puis la validation des clés de filières est désactivée, cf. point 4 ci-dessous**

  --- 

1. **Ajout d'une filière logement en attente de validation**

Pour ajouter une clé de filière logement sur une HousingRequest :

    POST api/dmo/housing_requests/{id de l'housing_request}/add_housing_channel

Avec en body 

    {
      "key"(required): 'dalo'
    }

**Attention, la clé ajoutée doit correspondre à une filière `HousingChannel` existante.**

La clé est alors ajoutée dans le tableau `housing_channel_pending_keys` **et** dans le tableau `housing_channel_chosen_keys` d'une demande de logement.   
Si le nom de la clé correspond à un champ booléen d'`HousingRequest` (comme 'dalo' ou 'priority_public'), celui-ci passe à `false`.

    GET api/dmo/housing_request/{id de l'housing_request}

    {
      "data": {
        "id": "5dc27c71a70bf201ccee9d39",
        "type": "housing_requests",
        "attributes": {
          ...
          "housing_channel_chosen_keys": [
            'dalo'
          ],
          "housing_channel_pending_keys": [
            'dalo'
          ],
          "housing_channel_keys": [],
          "dalo": false
        }
      }
    }


2. **Validation d'une filière logement**

Pour valider une clé de filière logement sur une HousingRequest :

    POST api/dmo/housing_requests/{id de l'housing_request}/validate_housing_channel

Avec en body 

    {
      "key"(required): 'dalo'
    }

**Attention, la clé ajoutée doit correspondre à une filière `HousingChannel` existante.**   
**Elle doit également être présente au préalable dans le champ `housing_channel_pending_keys` de l'housing_request.**

La filière validée passe alors de `housing_channel_pending_keys` à `housing_channel_keys`. Le tableau `housing_channel_chosen_keys` reste inchangé.   
Si le nom de la clé correspond à un champ booléen d'`HousingRequest` (comme 'dalo' ou 'priority_public'), celui-ci passe à `true`.

    GET api/dmo/housing_request/{id de l'housing_request}

    {
      "data": {
        "id": "5dc27c71a70bf201ccee9d39",
        "type": "housing_requests",
        "attributes": {
          ...
          "housing_channel_chosen_keys": [
            'dalo'
          ],
          "housing_channel_pending_keys": [],
          "housing_channel_keys": [
            'dalo'
          ],
          "dalo": true
        }
      }
    }

3. **Filtrage par département**

S'il existe un filtrage de filières (`HousingChannelSetting`) pour un des départements recherchés (`truly_seeked_departments`), on ne peut ajouter à la demande de logement que des filières logement dont les clés sont incluses dans le filtrage.

Exemple : 

Soit le filtrage (`HousingChannelSetting`) suivant : 

    {
      "department": "34",
      "insee_code": null,
      "housing_channel_keys": [
        "dalo"
      ]
    }

Et la demande de logement suivante : 

    {
      "data": {
        "id": "5dc27c71a70bf201ccee9d39",
        "type": "housing_requests",
        "attributes": {
          ...
          "truly_seeked_departments": [
            '34'
          ],
          "housing_channel_chosen_keys": [],
          "housing_channel_pending_keys": [],
          "housing_channel_keys": []
        }
      }
    }

Je ne peux ajouter pour cette demande que la filière "dalo", car c'est la seule disponible pour le département '34'.

4. **Bypass de la validation**

Actuellement, seule la requête api suivante est disponible pour une HousingRequest : 

    POST api/dmo/housing_requests/{id de l'housing_request}/add_housing_channel

Avec en body 

    {
      "key"(required): 'dalo'
    }

Elle n'ajoute pas la clé dans le tableau `housing_channel_pending_keys` mais directement dans le tableau final `housing_channel_keys` sans passer par l'étape de validation.

- • les clés sont toujours dupliquées dans le tableau `housing_channel_chosen_keys`.
- • le filtrage par département est toujours actif et fonctionnel.



### Ajout et suppression de clés de filières logement pour une HousingOffer

Une `HousingOffer` porte dorénavant un nouveau champ `housing_channel_keys`.

**Les requêtes API sont disponibles uniquement pour :**

- • les utilisateurs 'bailleur' qui sont au moins lecteurs du `lessor_id` porté par l'offre.
- • les utilisateurs 'reservataire'/'collaborateur offre logement' dont le `reservation_holder_id` correspond au `reservation_holder_id` de l'offre.

Pour ajouter une clé de filière :  

    POST api/dmo/housing_offers/{id de l'housing_offer}/add_housing_channel

Avec en body 

    {
      "key"(required): 'cle_à_ajouter' // e.g. 'dalo'
    }

**Attention, la clé ajoutée doit correspondre à une filière `HousingChannel` existante.**

Pour supprimer une clé de filière :  

    POST api/dmo/housing_offers/{id de l'housing_offer}/remove_housing_channel

Avec en body 

    {
      "key"(required): 'cle_à_supprimer'
    }


















## Recupération des retours erreurs des appels asynchrones vers le SNE/Sopra par le frontend :

Il faut se connecter avec un client faye js(websocket) sur le channel 

    /logs/users 
et filtrer les messages par code et par user_id


Les messages renvoyé dans ce channel comportent les infos suivantes :

    { 
      "code" : (le code erreur), 
      "log_id" : (l'id du log), 
      "id" : (l'id du user)
    }

donc si on traite les messages dont l'id du user est bien celui de l'utilisateur connecté il reste à vérifier le code erreur, si celui çi doit être affiché avec plus d'information. Il faut ensuite aller chercher le log sur 
      
      GET /api/d2/logs/ID_DU_LOG 
      
 l'id du log etant log_id dans le message websocket/faye

Exemple de librairie websocket faye angular : https://github.com/monterail/angular-faye

### fonctionnement

Lorsqu'une erreur se produit lors de l'appel d'un flux sopra, un log emmetant un evenement websocket est produit. ce log contient l'url appelée ainsi que le retour erreur du webservice sopra .






## Charges eau et chauffage individualisé pour taux d'effort

  Si le `heating_type` est défini sur une offre à une des valeurs suivante : 'Individuel gaz', 'Individuel PAC Electrique', 'Collectif autre', 'Individuel autre', 'Individuel électrique'. On ajoute des charges correspondantes pour l'eau et le chauffage pour le calcul du taux d'effort.
    










  
## Indicateur vérifiant si l'offre a été vue par un collaborateur offre logement

il y a un booléen  viewed_by_colaborator_offre_logement sur l'objet housing request qui passe a false lorsque :
->le cerfa change.
->le status de la requete change.
->une piece justificative est déposée.

il peut etre repassé à true via une requete put/patch classique.
ce champs est recherchable

## Dashboard Administrateur

Il est possible gérer les resources suivantes sur le dashboard administrateur

|Resource|path|
|---|---|
|`Hermes::Threshold`|/admin/thresholds|
|`Hermes::UntensedArea`|/admin/areas|

## Recherche superadministrateur

Recherche sur les entreprises qui retrouve les utilisateurs liés à ces entreprises :

    GET /api/dmo/entities/admin_search
    # avec les paramètres suivant disponibles
    {
      entity_params: {
        id: 'id',
        id_cristal: 'id_cristal',
        siren: 'siren',
        siret: 'siret',
        title: 'title',
      },
      user_params: {
        id: 'id',
        first_name: 'first_name',
        last_name: 'last_name',
        email: 'email',
        auth_roles: 'auth_roles',
      }
    }
    #retour
    data: [
      {
        right: 'administrator',
        user_id: 'user_id',
        user_email: 'user_email',
        user_first_name: 'user_first_name',
        user_last_name: 'user_last_name',
        user_auth_roles: 'user_auth_roles',
        user_phone_number: 'user_phone_number',
        entity_id: 'entity_id',
        entity_als_id: 'entity_als_id',
        entity_title: 'entity_title',
        entity_siret: 'entity_siret',
        entity_siren: 'entity_siren',
        entity_id_cristal: 'entity_id_cristal',
      }
    ]

Recherche sur les bailleurs qui retrouve les utilisateurs liés à ces bailleurs :

    GET /api/dmo/lerrors/admin_search
    # avec les paramètres suivant disponibles
    {
      lessor_params: {
        id: 'id',
        id_cristal: 'id_cristal',
        siren: 'siren',
        siret: 'siret',
        title: 'title',
      },
      user_params: {
        id: 'id',
        first_name: 'first_name',
        last_name: 'last_name',
        email: 'email',
        auth_roles: 'auth_roles',
      }
    }
    #retour
    data: [
      {
        right: 'administrator',
        user_id: 'user_id',
        user_email: 'user_email',
        user_first_name: 'user_first_name',
        user_last_name: 'user_last_name',
        user_auth_roles: 'user_auth_roles',
        user_phone_number: 'user_phone_number',
        lessor_id: 'lessor_id',
        lessor_als_id: 'lessor_als_id',
        lessor_title: 'lessor_title',
        lessor_siret: 'lessor_siret',
        lessor_siren: 'lessor_siren',
        lessor_id_cristal: 'lessor_id_cristal',
      }
    ]

Recherche sur les demandes qui retourne les infos sur les demandeur et entreprises liés :

    GET /api/dmo/housing_request/admin_search
    # avec les paramètres suivant disponibles
    {
      entity_params: {
        id: 'id',
        id_cristal: 'id_cristal',
        siren: 'siren',
        siret: 'siret',
        title: 'title',
        als_id: 'als_id',
      },
      applicant_params: {
        id: 'id',
        requester_firstname: 'first_name',
        requester_lastname: 'last_name',
        requester_email: 'email',
      },
      unique_numbers: ['unique_number']
    }
    #retour
    data: [
      {
        id: 'id',
        unique_numbers: ['unique_number'],
        als_id: 'als_id',
        user_id: 'user_id',
        applicant_id: 'applicant_id',
        applicant_email: 'applicant_email',
        applicant_first_name: 'applicant_first_name',
        applicant_last_name: 'applicant_last_name',
        entity_id: 'entity_id',
        entity_als_id: 'entity_als_id',
        entity_title: 'entity_title',
        entity_siret: 'entity_siret',
        entity_siren: 'entity_siren',
        entity_id_cristal: 'entity_id_cristal',
      }
    ]

    Avec des inforamtions de paginations stockées dans meta pour les 3 types de recherche:

      meta: {
        pagination: {
          per_page: per_page,
          total_pages: total_pages,
          total_objects: count,
        }
      }
## Hermes config

il faut aller dans parametres -> hermes_config

apres edition, il faut cliquer sur "mettre a jour", puis lancer sur tout les serveurs de prod la commande

    sudo /opt/scripts/bin/restart_paw

modele du json : 

    {
      "google_street_view": {
        "key": "XXXXXXXXXXXXXXXXXXXXXXXX"
        "signature": "XXXXXXXXXXXXXXXXXXXXXXXX"
        },
    	"ged": {
    		"url": "https://ged-test.dev.hermes.openstack.local",
    		"X-Auth-User-Token": "XXXXXXXXXXXXXXXXXXXXXXXX"
    	},
    	"kyc": {
    		"url": "https://integration-api.preventgo.io/v2",
    		"login": "XXXXXXXXXXXXXXXXXXXXXXXX",
    		"password": "XXXXXXXXXXXXXXXXXXXXXXXX"
    	},
    	"identity_provider_key": "als_hermes_salarie",
    	"DEP_PROVIDERS":
    	 {  
    	 "IMHOWEB": [
               "240"
               ],
    	 "SNE" : [
            "01",
            "02",
            "04",
            "05",
            "06",
            "07",
            "08",
            "09",
            "10",
            "11",
            "12",
            "13",
            "18",
            "19",
            "20",
            "23",
            "24",
            "26",
            "27",
            "28",
            "2A",
            "2B",
            "30",
            "32",
            "33",
            "34",
            "36",
            "38",
            "39",
            "40",
            "41",
            "42",
            "45",
            "46",
            "47",
            "48",
            "51",
            "52",
            "54",
            "55",
            "57",
            "59",
            "60",
            "62",
            "64",
            "65",
            "66",
            "69",
            "70",
            "71",
            "73",
            "74",
            "75",
            "76",
            "77",
            "78",
            "80",
            "81",
            "82",
            "83",
            "84",
            "87",
            "89",
            "90",
            "91",
            "92",
            "93",
            "94",
            "95",
            "971",
            "972",
            "973",
            "974",
            "111"
          ]
    }

