25/09/2016

Google Polymer Openfisca Etalab

Un petit tutoriel pour apprendre à utiliser Openfisca de la DGFIP et d'Etalab, à partir de Polymer de Google.

OpenFisca propose une Web Api permettant de calculer prestations sociales, niveau de vie, impôts...
Polymer quand à lui permet de créer de jolies interfaces mobiles ou web à partir de webcomponents.


Prérequis

Nodejs et npm (installé avec nodejs)

Installation de Polymer-cli

npm install -g polymer-cli

Création d'un dossier de travail 

mkdir my-app cd my-app

Création de l'application

polymer init

- choisissez la ligne starter-kit
- l'application polymer doit maintenant être installé, pour vérifier, vous pouvez la lancer en utilisant la commande "polyserve" et elle devrait être accessible à l'adresse http://localhost:8080

Deux dossier nous intéressent maintenant :
- "src", c'est le dossier principal de l'application
- "bower_components", c'est le dossier des éléments de Polymer (webcomponents)

Création de l'élément "openfisca-calcul"

on va se placer dans le dossier "bower_components", créer le dossier de l'élément et créer l'élément encore une fois avec "polymer init".

cd bower_components
mkdir openfisca-calcul
polymer init

et cette fois, on va choisir de créer un élément (a blank template element)

Insertion de l'élément "openfisca-calcul"

Maintenant que notre élément est créé, on peut l'insérer dans notre application.
Allez dans le dossier "src" et ouvrez le fichier "my-view1.html" avec votre éditeur préféré.

Deux étapes sont nécessaire pour insérer un élément : l'import et le positionnement.

L'import :
<link rel="import" href="../bower_components/openfisca-calcul/openfisca-calcul.html">

Le positionnement :
Ajoutez simplement une balise ouvrante fermante représentant l'élément :

<openfisca-calcul></openfisca-calcul>

Profitons en aussi pour supprimer le "<div class="card"> ... </div>" ... on le déplacera dans notre élément

Votre fichier my-view1.html devrait maintenant ressembler à ceci :


 <!--  
 @license  
 Copyright (c) 2016 The Polymer Project Authors. All rights reserved.  
 This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt  
 The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt  
 The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt  
 Code distributed by Google as part of the polymer project is also  
 subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt  
 -->  
 <link rel="import" href="../bower_components/polymer/polymer.html">  
 <link rel="import" href="shared-styles.html">  
 <link rel="import" href="../bower_components/openfisca-calcul/openfisca-calcul.html">  
 <dom-module id="my-view1">  
  <template>  
   <style include="shared-styles">  
    :host {  
     display: block;  
     padding: 10px;  
    }  
   </style>  
      <openfisca-calcul></openfisca-calcul>  
  </template>  
  <script>  
   Polymer({  
    is: 'my-view1'  
   });  
  </script>  
 </dom-module>  


Construction de l'élément "openfisca-calcul"

Avec Polymer, on favorise la réutilisation d'éléments déjà existants.
On va ici avoir besoin de trois éléments différents : 
- un "paper-button" : un bouton pour lancer le calcul,
- un "iron-ajax" qui se chargera d'effectuer la requête vers l'adresse web de l'API d'Openfisca (https://api.openfisca.fr/api/1/calculate)
- un petit "paper-spinner" pour nous indiquer que l'application est en train de traiter la requete.

L'installation de ces trois éléments se fait tout simplement : commencer par vous positionner à la racine de votre application, là où se trouve le fichier "bower.json"

bower install --save paper-button iron-ajax paper-spinner

Maintenant que ces trois éléments sont disponibles pour notre application, il ne nous reste plus qu'à les intégrer... et leur tour est joué... enfin faudra aussi taper un peu de code, on est là pour ça, quand-même...

Pour l'intégration, on opère comme avec le fichier my-view1.html.
Editez le fichier "openfisca-calcul.html" situé dans "my-app/bower_components/openfisca-calcul", et ajoutez au début les lignes suivantes :

<link rel="import" href="../iron-ajax/iron-ajax.html"> <link rel="import" href="../paper-button/paper-button.html"> <link rel="import" href="../paper-spinner/paper-spinner.html">

Ajoutez par la même occasion la ligne suivante qui nous permettra de gérer les styles : 
<link rel="import" href="../../src/shared-styles.html">


Tant qu'on est sur les styles, intégrons les en modifiant la balise <style>...< /style>  ( dans le fichier "my-app/bower_components/openfisca-calcul/openfisca-calcul.html") et en la remplaçant par :

           <style include="shared-styles">  
                :host {  
                display: block;  
                padding: 10px;  
                }  
           </style>  

Après la balise <style> ainsi modifiée, insérée l'élément concernant la requête ajax en utilisant le code suivant :

           <iron-ajax  
           id="ajaxcalculate"  
           url="https://api.openfisca.fr/api/1/calculate"  
           body="{{data2send}}"  
           method="POST"  
           handle-as="json"  
           content-type="application/json"  
           on-response="handleResponse">  
           </iron-ajax>   

Quelques explications s'imposent :

  • <iron-ajax>...</iron-ajax> : nous permet d'insérer l'élément iron-ajax qui s'occupe d'effctuer la requête.
  • id="ajaxcalculate" : un id qui nous permettra d'identifier la requete lors de l'appui sur le bouton "Calcul"
  •  url="https://api.openfisca.fr/api/1/calculate" : l'adresse url vers laquelle la requête va être envoyée
  • body="{{data2send}}" : représente les données qui vont être envoyées à l'adresse url
  • method="POST" : l'API openfisca n'accepte que le requêtes de type "POST"
  • handle-as="json" : le format dans lequel on souhaite récupérer les données
  • content-type="application/json" : le format dans lequel les données sont envoyées à l'API
  • on-response="handleResponse" : la fonction "callback" exécutée lors les résultats arrivent de l'API
Et bien voilà... on a fait le principal, ne reste plus qu'à formater les données à envoyer et traiter les données reçues...

Tant qu'on y est, profitez-en pour insérer deux <div> : un pour le bouton "calcul" et un pour le résultat :

           <div class="card">  
                <div class="circle">0</div>                 
                <paper-button raised on-tap="calcul" value="CALCUL">CALCUL <paper-spinner id="spinner" alt="Calcul en cours"></paper-spinner></paper-button>  
           </div>  
           <div class="card">  
                <div class="circle">10</div>  
                <h1>Résultat</h1>  
                <p>Revenu disponible 2015 : {{revenuDisponible}} </p>  
           </div>  


Données à envoyer et résultat

Pour les données à insérer, il faut avouer que c'est un peu compliqué de communiquer avec l'API Openfisca, mais on y arrive :
Un objet JSON (JSONObject) avec un tableau (JSONArray) nommé "scenarios" et les "variables" que l'on souhaite obtenir en sortie.
Dans le scenario, on trouve un objet "testcase" et un/des "périodes".
Dans le testcase, on défini : "familles", "foyers_fiscaux", "menages" et "individus"...
Pour simplifier ici, on va prendre l'exemple fourni par la documentation d'Openfisca.
On défini les données que l'on va envoyer : "data2send" et les données que l'on aura en résultat : "revenuDisponible"

                     data2send : {  
                          type : Object,  
                          value : {  
                               "scenarios": [  
                               {  
                                    "test_case": {  
                                         "familles": [  
                                         {  
                                              "parents": ["individu0"]  
                                         }  
                                         ],  
                                         "foyers_fiscaux": [  
                                         {  
                                              "declarants": ["individu0"]  
                                         }  
                                         ],  
                                         "individus": [  
                                         {  
                                              "date_naissance": "1980-01-01",  
                                              "id": "individu0"  
                                         }  
                                         ],  
                                         "menages": [  
                                         {  
                                              "personne_de_reference": "individu0"  
                                         }  
                                         ]  
                                    },  
                                    "period": "2015"  
                               }  
                               ],  
                               "variables": ["revdisp","nivvie_net"]  
                          }  
                     },  
                     revenuDisponible : {  
                          type : String,  
                          value : ""  
                     }       


C'est presque terminé : il reste la fonction callback lorsque l'application reçoit le résultat et le bouton pour lancer la requête :

                /**  
                     * recupere et parse la reponse du serveur  
                     */  
                     handleResponse: function(data,error){  
                          var result=data.detail.response.value;  
                          console.log("RESULTATS");  
                          console.log(result);                 
                          this.$.spinner.active=false;  
                          for (var key in result) {  
                               if (result.hasOwnProperty(key)) {  
                                    var valeur=result[key];  
                                    console.log(key+" :");  
                                    console.log(valeur);  
                               }  
                          }                 
                          // entrer ensuite dans result pour avoir les details :   
                          //     console.log(result[0].menages[0].revdisp[2015]);  
                          for (var i in result){  
                               var resultat = result[i];  
                               console.log("Revenu disponible 2015 : "+resultat.menages[0].revdisp[2015]);  
                               console.log("Niveau de vie net 2015 : "+resultat.menages[0].nivvie_net[2015]);  
                               this.revenuDisponible=resultat.menages[0].revdisp[2015];  
                          }  
                     },  


                          calcul : function(){  
                               console.log(this.data2send);  
                               this.$.spinner.active=true;  
                               this.$.ajaxcalculate.generateRequest();       
                          }  


Et voilà... le tour est joué... y'a plus qu'à cliquer sur le bouton "CALCUL"....
Allez ... si j'étais pas très clair, je vous donne le code du fichier "openfisca-calcul"... A vous d'en faire bon usage... comme par exemple un comparateur de prestations en fonction de votre situation ...



 <link rel="import" href="../polymer/polymer.html">  
 <link rel="import" href="../../src/shared-styles.html">  
 <link rel="import" href="../iron-ajax/iron-ajax.html">  
 <link rel="import" href="../paper-button/paper-button.html">  
 <link rel="import" href="../paper-spinner/paper-spinner.html">  
 <!--  
      `openfisca-calcul`  
      @demo demo/index.html   
 -->  
 <dom-module id="openfisca-calcul">  
      <template>  
           <style include="shared-styles">  
                :host {  
                display: block;  
                padding: 10px;  
                }  
           </style>  
           <iron-ajax  
           id="ajaxcalculate"  
           url="https://api.openfisca.fr/api/1/calculate"  
           body="{{data2send}}"  
           method="POST"  
           handle-as="json"  
           content-type="application/json"  
           on-response="handleResponse">  
           </iron-ajax>   
           <div class="card">  
                <div class="circle">0</div>                 
                <paper-button raised on-tap="calcul" value="CALCUL">CALCUL <paper-spinner id="spinner" alt="Calcul en cours"></paper-spinner></paper-button>  
           </div>  
           <div class="card">  
                <div class="circle">10</div>  
                <h1>Résultat</h1>  
                <p>Revenu disponible 2015 : {{revenuDisponible}} </p>  
           </div>  
      </template>  
      <script>  
           Polymer({  
                is: 'openfisca-calcul',  
                properties: {  
                     data2send : {  
                          type : Object,  
                          value : {  
                               "scenarios": [  
                               {  
                                    "test_case": {  
                                         "familles": [  
                                         {  
                                              "parents": ["individu0"]  
                                         }  
                                         ],  
                                         "foyers_fiscaux": [  
                                         {  
                                              "declarants": ["individu0"]  
                                         }  
                                         ],  
                                         "individus": [  
                                         {  
                                              "date_naissance": "1980-01-01",  
                                              "id": "individu0"  
                                         }  
                                         ],  
                                         "menages": [  
                                         {  
                                              "personne_de_reference": "individu0"  
                                         }  
                                         ]  
                                    },  
                                    "period": "2015"  
                               }  
                               ],  
                               "variables": ["revdisp","nivvie_net"]  
                          }  
                     },  
                     revenuDisponible : {  
                          type : String,  
                          value : ""  
                     }       
                },  
                /**  
                     * recupere et parse la reponse du serveur  
                     */  
                     handleResponse: function(data,error){  
                          var result=data.detail.response.value;  
                          console.log("RESULTATS");  
                          console.log(result);                 
                          this.$.spinner.active=false;  
                          for (var key in result) {  
                               if (result.hasOwnProperty(key)) {  
                                    var valeur=result[key];  
                                    console.log(key+" :");  
                                    console.log(valeur);  
                               }  
                          }                 
                          // entrer ensuite dans result pour avoir les details :   
                          //     console.log(result[0].menages[0].revdisp[2015]);  
                          for (var i in result){  
                               var resultat = result[i];  
                               console.log("Revenu disponible 2015 : "+resultat.menages[0].revdisp[2015]);  
                               console.log("Niveau de vie net 2015 : "+resultat.menages[0].nivvie_net[2015]);  
                               this.revenuDisponible=resultat.menages[0].revdisp[2015];  
                          }  
                     },  
                     /**  
                          *  
                          */  
                          calcul : function(){  
                               console.log(this.data2send);  
                               this.$.spinner.active=true;  
                               this.$.ajaxcalculate.generateRequest();       
                          }  
                     });  
                </script>  
           </dom-module>  


Le code source est téléchargeable ici https://github.com/scenaristeur

Des questions ? des erreurs ? utilisez les commentaires ci-dessous ou le forum de l'article