Améliorations diverses

This commit is contained in:
2026-07-20 22:12:49 +02:00
parent 441da1975a
commit 41c464e6a3
24 changed files with 907 additions and 55 deletions
+112
View File
@@ -0,0 +1,112 @@
# Power Query — exemples de connexion à l'API v1
Exemples de requêtes [Power Query](https://learn.microsoft.com/fr-fr/power-query/) (Excel)
pour interroger le portefeuille crowdlending depuis un classeur Excel, en s'appuyant sur
la même API v1 (lecture seule) que le [serveur MCP](../mcp-server/README.md).
Aucune écriture : ces requêtes ne font que lire des données, comme le serveur MCP.
## Prérequis
- Une clé API générée dans l'app : **Mon compte → Clés API → Nouvelle clé**
- Le backend accessible (en local `http://localhost:4000`, ou l'URL de votre instance en
production, ex. `https://crowdlending.croguennec.net`)
- Excel avec Power Query (Excel 365 / 2016+ sous Windows ou Mac — Power Query est intégré
nativement, rien à installer)
## Option 1 — Classeur prêt à l'emploi (`crowdlending-powerquery-exemple.xlsb`)
Le plus rapide : ouvrez `crowdlending-powerquery-exemple.xlsb` directement dans Excel.
> **Pourquoi un `.xlsb` et pas un `.xlsx` ?** Le format binaire d'Excel (`.xlsb`) est celui
> à partir duquel ce classeur a pu être construit et vérifié de façon fiable en dehors
> d'Excel. Il s'ouvre et se comporte exactement comme un `.xlsx` — Power Query, tableaux,
> actualisation, tout fonctionne à l'identique. Si vous préférez un `.xlsx`, ouvrez le
> fichier puis **Fichier → Enregistrer sous** et changez le format ; les requêtes suivent.
Le classeur contient :
| Requête | Rôle |
|---|---|
| `ApiBaseUrl` | URL de l'API à interroger (à modifier) |
| `ApiKey` | Votre clé API (à modifier — voir ci-dessous) |
| `fnApiGet` | Fonction utilitaire partagée (appel HTTP + parsing JSON), utilisée par toutes les requêtes de données |
| `Investisseur` | Profil investisseur (ou liste des membres si clé « Famille et entreprises ») |
| `Dashboard` | KPIs du portefeuille (capital investi, capital en risque, intérêts, cash), au format « Indicateur / Valeur » |
| `Investissements` | Liste des investissements |
| `Remboursements` | Historique des remboursements |
| `DepotsRetraits` | Historique des mouvements de cash |
| `fnDetailInvestissement` | Fonction avancée : détail + remboursements d'un investissement par id |
| `Test` | Table d'instructions (« À lire avant de commencer ») — pas une donnée métier |
Étapes :
1. Ouvrez le classeur. La feuille affiche par défaut un exemple mis en cache (pas encore
vos données) — c'est normal, Excel n'a pas encore appelé l'API.
2. **Données → Requêtes et connexions**. Repérez `ApiKey` dans le volet à droite.
3. Clic droit sur `ApiKey`**Modifier**. Dans l'éditeur, remplacez
`"clk_live_VOTRE_CLE_API"` par votre vraie clé (entre guillemets), puis
**Fermer et charger**.
4. Vérifiez `ApiBaseUrl` de la même façon : `http://localhost:4000/api/v1` en local, ou
`https://crowdlending.croguennec.net/api/v1` en production (adaptez à votre domaine).
5. **Données → Actualiser tout** (ou Ctrl+Alt+F5). La table « Test » se met à jour avec les
instructions, signe que la connexion fonctionne.
6. Pour chaque requête de données qui vous intéresse (`Investissements`, `Remboursements`…) :
clic droit dans le volet **Requêtes et connexions****Charger dans…** → choisissez
Tableau (ou Tableau croisé dynamique) et la feuille de destination.
## Option 2 — Coller les requêtes manuellement (`queries/*.pq`)
Utile si vous préférez tout construire vous-même dans un classeur existant, ou si une
requête du classeur ne s'affiche pas correctement chez vous.
Pour chaque fichier, dans l'ordre ci-dessous : **Données → Obtenir des données → À partir
d'autres sources → Requête vide**, renommez la requête (volet de droite, ou après double-clic
sur son nom) avec **exactement** le nom du fichier (sans `.pq`), puis **Accueil → Éditeur
avancé**, effacez le contenu par défaut, collez le contenu du fichier, **Terminé**.
Ordre à respecter (chaque requête réutilise les précédentes par leur nom) :
1. `ApiBaseUrl.pq` — modifiez l'URL avant de coller si besoin
2. `ApiKey.pq` — remplacez `VOTRE_CLE_API` par votre clé avant de coller
3. `fnApiGet.pq`
4. `Investisseur.pq`, `Dashboard.pq`, `Investissements.pq`, `Remboursements.pq`,
`DepotsRetraits.pq` — dans l'ordre que vous voulez
5. `fnDetailInvestissement.pq` (optionnel, usage avancé — voir plus bas)
Une fois `fnApiGet` créée, **Fermer et charger** chaque requête de données individuellement
(clic droit → Charger dans…) pour l'ajouter comme tableau.
## Filtres
Les requêtes `Dashboard`, `Investissements` et `Remboursements` acceptent des filtres côté
API (année, statut, période). Par défaut elles ramènent tout (`null`). Pour filtrer,
ouvrez la requête dans l'éditeur avancé et remplacez `null` par le paramètre indiqué en
commentaire en tête du fichier `.pq` correspondant, par exemple :
```
Source = fnApiGet("/investissements", [statut = "rembourse"])
```
Statuts possibles : `en_cours`, `rembourse`, `en_retard`, `procedure`, `cloture`.
## Usage avancé — détail d'un investissement par ligne
`fnDetailInvestissement` permet de ramener, pour chaque ligne de la table `Investissements`,
le détail complet (dont les remboursements) sans requête séparée : sur la table
`Investissements`, **Ajout de colonne → Colonne personnalisée**, formule
`= fnDetailInvestissement([id])`. Attention : ceci déclenche un appel API par ligne — à
réserver à un nombre raisonnable d'investissements (quelques dizaines).
## Dépannage
- **`Impossible de se connecter au service distant`** — le backend n'est pas démarré, ou
`ApiBaseUrl` est incorrecte (vérifiez le port et le suffixe `/api/v1`).
- **`Erreur API (401)` / `Clé API invalide ou révoquée`** — régénérez une clé dans
Mon compte → Clés API et remplacez la valeur de `ApiKey`.
- **Une requête du classeur n'apparaît pas dans le volet, ou affiche une erreur au premier
chargement** — repartez de l'Option 2 pour cette requête précise : créez une requête
vide portant son nom et collez le contenu du `.pq` correspondant.
- **Avertissement de sécurité / niveau de confidentialité au premier chargement** — normal
pour toute nouvelle source Web dans Power Query ; choisissez « Organisationnel » ou
« Public » selon votre contexte, ce n'est pas spécifique à ce classeur.
Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

@@ -0,0 +1,3 @@
// URL de base de l'API v1. En local : http://localhost:4000/api/v1
// En production : https://votre-domaine/api/v1
"http://localhost:4000/api/v1"
@@ -0,0 +1,2 @@
// Clé API générée dans l'app : Mon compte > Clés API > Nouvelle clé
"clk_live_VOTRE_CLE_API"
@@ -0,0 +1,14 @@
let
// Pour filtrer sur une année, remplacez null par [annee = "2026"]
Source = fnApiGet("/dashboard", null),
VersLignes = (enregistrement as record, nomSection as text) =>
Table.AddColumn(Record.ToTable(enregistrement), "Section", each nomSection),
Combine = Table.Combine({
VersLignes(Source[investissements], "Investissements"),
VersLignes(Source[interets], "Interets"),
VersLignes(Source[cash], "Cash")
}),
Reordonne = Table.ReorderColumns(Combine, {"Section", "Name", "Value"}),
Resultat = Table.RenameColumns(Reordonne, {{"Name", "Indicateur"}, {"Value", "Valeur"}})
in
Resultat
@@ -0,0 +1,5 @@
let
Source = fnApiGet("/depots-retraits", null),
Resultat = Table.FromRecords(Source)
in
Resultat
@@ -0,0 +1,7 @@
let
// Pour filtrer par statut, remplacez null par [statut = "rembourse"]
// Statuts possibles : en_cours, rembourse, en_retard, procedure, cloture
Source = fnApiGet("/investissements", null),
Resultat = Table.FromRecords(Source)
in
Resultat
@@ -0,0 +1,6 @@
let
Source = fnApiGet("/investisseur", null),
// Clé "Famille et entreprises" -> liste ; clé mono-investisseur -> objet unique
Resultat = if Value.Is(Source, type list) then Table.FromRecords(Source) else Table.FromRecords({Source})
in
Resultat
@@ -0,0 +1,6 @@
let
// Pour filtrer par période, remplacez null par [date_debut = "2026-01-01", date_fin = "2026-12-31"]
Source = fnApiGet("/remboursements", null),
Resultat = Table.FromRecords(Source)
in
Resultat
@@ -0,0 +1,19 @@
(chemin as text, optional parametres as nullable record) as any =>
let
parametresBruts = if parametres = null then [] else parametres,
champsUtiles = List.Select(
Record.FieldNames(parametresBruts),
each Record.Field(parametresBruts, _) <> null and Record.Field(parametresBruts, _) <> ""
),
parametresNettoyes = Record.SelectFields(parametresBruts, champsUtiles),
reponse = Web.Contents(
ApiBaseUrl,
[
RelativePath = chemin,
Headers = [#"X-API-Key" = ApiKey, #"Accept" = "application/json"],
Query = parametresNettoyes
]
),
resultat = Json.Document(reponse)
in
resultat
@@ -0,0 +1,5 @@
// Astuce avancée : sur la table Investissements, colonne personnalisée
// "= fnDetailInvestissement([id])" pour ramener le détail + les remboursements
// de chaque prêt (Ajout de colonne > Colonne personnalisée).
(id as number) as record =>
fnApiGet("/investissements/" & Text.From(id), null)