Script PowerShell : transformer un relevé bancaire en note de frais

Bonjour,
voici un tuto pour s'initier rapidement au PowerShell et l'utiliser pour traiter des fichiers csv. Le PowerShell est un langage qui est de plus en plus à la mode car il sert entre autre à manipuler les infrastructures informatiques dans le Cloud de Microsoft Azure. Donc bien connaître le PowerShell peut ouvrir pas mal de portes.
Ce tuto s'adresse aux grands débutants en informatique, donc désolé pour les initiés je vais enfoncer pas mal de portes ouvertes.
En fait, je connais pas mal de monde qui aurait envie de se reconvertir à l'informatique. J'ai cherché des tutos sur le Web qui leur permettraient de commencer de zéro, et aussi de tester si l'informatique est un métier qui pourrait leur plaire. Je n'ai rien trouvé qui me plaisait, un tuto simple rapide et qui serve vraiment à quelque chose de pratique. Donc j'ai créé celui-ci à partir d'un programme en PowerShell qui me sert tous les mois à consolider mes notes de frais avec mes relevés de CB.
C'est donc un vrai tuto pratique de PowerShell pour les nuls !

1-Le format csv
On va commencer par le format csv. C'est un format de tableur lisible par Excel où les colonnes sont indiquées par des points virgules (on peut aussi utiliser les virgules). Exemple :

date;fournisseur;montant
18/11/2021; café daguerre; 22.30
19/11/2021; un jour à Hanoï; 18.15

si vous copiez les trois lignes ci-dessus dans un fichier du bloc note (Notepad .txt) et que vous changez l'extension en .csv, le fichier s'ouvrira sous forme de tableau dans Excel.
Faites le test et enregistrez le fichier dans un dossier nommé "PowerShell" que vous aurez créé directement sur le disque C. En informatique on dit "à la racine du disque C"


Encodez en ANSI pour ne pas perdre l'accentuation en français



2- Format attendu d'une note de frais
Maintenant, le format attendu d'une note de frais doit comporter les différents types de TVA pour qu'on puisse la déduire et l'objet de la dépense. Donc notre fichier de départ deviendrait quelque chose comme ça :



3- Transformer un relevé bancaire en note de frais
L'objectif du tuto est de partir d'un relevé bancaire de vos dépenses au format csv et de le traiter en utilisant le PowerShell pour le formater en note de frais.
On part de ça :
et on veut obtenir ça:

4-Télécharger le relevé bancaire
Si vous êtes à la Société Générale en tant que particulier vous pouvez suivre les explications suivantes, sinon, vous pouvez télécharger le fichier sur un espace de stockage de mon compte Microsoft Azure :

télécharger le fichier avec ce lien

Pour obtenir un relevé au format csv à la Société Générale.
Dans le menu horizontal tout en haut cliquez sur "Autres"

Faire défiler l'écran vers le bas et cliquez sur la flêche de "télécharger mes relevés"

Sélectionner le compte dont vous voulez les relevés, sélectionner le format csv et saisir la date de départ souhaitée des relevés :

Si vous utilisez Chrome comme navigateur vous verrez le téléchargement du fichier dans la barre d'état et vous pourrez naviguer vers le fichier téléchargé.

A l'ouverture vous devriez obtenir quelque chose comme ça :


5- Environnement PowerShell
Maintenant, nous allons enfin commencer à faire du PowerShell. Dans la barre de recherche de Windows taper PowerShell afin de trouver l'app PowerShell.

Quand l'app PowerShell s'ouvre vous êtes situé dans un chemin du type c:\Users\votreNomDutilisateur
Pour remonter au niveau du disque C il faut taper deux fois
cd ..
suivi de la touche Entrée (Enter) de votre clavier

Si vous avez mis le relevé bancaire dans un répertoire nommé PowerShell à la racine de votre disque C,
il vous suffit ensuite de taper
cd
et le début du nom du dossier, comme "pow", et ensuite d'appuyer sur la touche Tab (tabulation) du clavier.


L'app PowerShell vous propose le répertoire dès que vous avez appuyé sur la touche tab.

Et si vous tapez sur la touche "Entrée" vous êtes calé sur votre répertoire de travail.
Si vous tapez dir suivi de la touche entrée, l'app PowerShell vous liste le contenu du répertoire:
6- Premier programme en PowerShell
Maintenant nous allons exécuter nos premières commandes en PowerShell.
Nous allons charger toutes les lignes du fichier de relevé bancaire dans une variable PowerShell et ensuite afficher les lignes dans la console PowerShell.
L'informatique, c'est un peu comme Harry Potter, il y a des formules magiques à invoquer et ensuite des choses surprenantes se mettent à arriver.
Donc première formule magique comment importer un fichier csv dans une variable. C'est très simple il faut utiliser la commande :

Import-csv

Mais la commande demande des précisions. Il faut lui dire où est le fichier à importer sur l'ordinateur et aussi parfois quel séparateur est utilisé dans le csv. On a vu tout à l'heure qu'on pouvait utiliser la virgule ou le point virgule. Vous allez voir que PowerShell va vous aider à trouver les compléments de la commande.
Il faut expliquer aussi ce qu'est une variable. Une variable, c'est comme un récipient qu'on va remplir avec des informations. Ensuite on va pouvoir réutiliser ce récipient quand on voudra car il contiendra les informations qu'on y a mis. Une variable en PowerShell commence toujours avec le signe $.
Bon, d'accord, c'est un des langages fétiches de Microsoft qui est une entreprise américaine, et oui, aussi, si on est très fort en PowerShell on peut gagner pas mal de $.

Donc sur la console on va saisir notre variable, mettons qu'on l'appelle mesLignes puisqu'on va y mettre toutes lignes de notre relevé bancaire, donc on commence par saisir la variable :
$mesLignes

ensuite, on va dire avec un signe "=" que la variable doit contenir le résultat de notre commande import-csv, donc on écrit après $mesLignes:
= Import-c
et là si vous appuyez sur la touche Tab, PowerShell devrait compléter le reste de la commande. Vous verrez qu'il va vous trouver 2 ou 3 autres commandes avant de trouver Import-csv. En informatique on appelle ça l'autocomplétion ou encore l'IntelliSense bien que le dernier mot soit très "microsoftien".



Maintenant il faut compléter la commande avec le chemin vers le fichier csv de relevé bancaire quant à la spécification du séparateur utilisé je me suis aperçu qu'elle n'était pas obligatoire.

En PowerShell tout complément de commande commence par le signe -.
Donc on va mettre un espace après $mesLignes = Import-Csv et saisir le signe -

Et là on va demander à PowerShell de nous aider encore avec la touche Tab et tous les compléments vont défiler et il suffira de choisir Path qui veut dire chemin en anglais.

Il ne nous reste plus qu'à sélectionner le nom de notre fichier de relevé bancaire en sélectionnant toutes les lettres avec la souris. Puis pour le copier il suffit juste de faire un clic droit ou de presser les touches ctrl et c.

Puis si on presse les touches ctrl et v on voit le nom de notre fichier se placer après le complément -Path de notre commande.

Voilà, on a fini d'écrire notre première formule magique. Pour l'exécuter, il suffit d'appuyer sur la touche "Entrée".
Et là, consternation, je vous avais promis de la magie et il ne s'est absolument rien passé, mais rassurez vous, c'est plutôt bon signe, si on avait fait une bêtise, l'écran serait couvert de signes cabalistiques de couleur rouge. En PowerShell souvent pas de nouvelles = bonnes nouvelles.
Et c'est maintenant que la magie va opérer.
on va rappeler la variable $mesLignes en utilisant l'autocomplétion. On va saisir $me et appuyer sur la touche Tab et PowerShell va compléter en écrivant $mesLignes.
et c'est en appuyant sur la touche Entrée que la magie va opérer car la variable va nous régurgiter tout ce qu'elle contient, c'est à dire toutes les lignes de notre fichier qui sont désormais dans la variable $mesLignes :
Bon à ce stade deux possibilités, soit ça vous plaît, vous êtes assez excité par ce que vous venez de réaliser, ça vous a semblé clair, fluide et vous pourriez envisager une reconversion à l'informatique, soit vous réalisez, que, non, en fait l'informatique n'est pas pour vous, vous ne vous voyez pas faire des trucs comme ça toute le journée pour gagner votre vie.
à suivre... dans la prochaine étape on va boucler sur chaque ligne et commencer à mettre en forme pour l'utilisation souhaitée de l'information...

Bonjour, 25 novembre 2021, suite du tuto.

Si vous avez regardé attentivement l'écran précédent ou le vôtre si vous avez réussi à faire les manips comme il faut, vous vous êtes aperçu que les montants de dépenses étaient tronqués (encore du jargon d'informaticien, ça veut dire qu'il manque un bout de l'information).
Et là, un informaticien se dit tout de suite : " Bon Dieu, PowerShell a arrêté le traitement à la virgule qui sert à faire les décimales des sommes dépensées, faut que je lui précise le délimiteur comme étant un point-virgule".
Bienvenus dans le métier, chaque jour apporte ses surprises, j'ai 15 ans de métier et je viens d'apprendre ça en même temps que vous. Donc, on est patient, on recommence en précisant cette fois-ci le délimiteur sans oublier de mettre des simple quotes ou des doubles quotes (guillemets en français) autour du point-virgule sans quoi ça plante. Je vous ai laissé le message d'erreur en rouge pour vous montrer comment ça fait quand PowerShell est pas content.


Donc si on refait tout bien on obtient ça :

Voilà, c'est beaucoup mieux, on a toute l'info maintenant avec les décimales et la devise. Mais vous me direz, ça ne ressemble plus à des lignes. Et vous aurez raison. Sans anticiper sur les concepts informatiques, chaque paragraphe correspondant à une ligne du fichier s'appelle en informatique un objet ! Un objet c'est un groupe d'information structurée. Un objet a des propriétés (ici, date d'effet, date de compensation, libelle, montant, etc.) et chaque propriété a des valeurs une date, un montant, un libellé, etc... Bon si vous avez du mal avec ça pas grave, on va voir en pratique à quoi ça sert dans la prochaine section.

7-première boucle
Si vous avez regardé les informations du fichier de relevé bancaire vous avez constaté que pour notre note de frais il y en a pas mal qui servent à rien et que celles qui servent sont mélangées.
La date de compensation je m'en fiche, je veux la date à laquelle l'achat a été effectué et cette date c'est la date d'effet mais elle est dupliquée dans le libellé et en plus elle est pas formatée comme une date et il manque l'année. Bravo la banque :-)
Donc une bonne petite séance de nettoyage de la donnée s'impose.
Alors comment donc qu'on fait ça en informatique. Ben on fait une boucle. On boucle sur toutes les lignes, enfin tous nos objets et à chaque boucle on nettoie.
On va commencer par faire une boucle. Il y en plusieurs en PowerShell. Quand on a la chance d'avoir une collection d'objets comme ici, la plus simple et la plus facile est la boucle Foreach (pour chaque en français). Donc on va dire à PowerShell "pour chaque" objet fais moi ci, fais moi ça.
et voilà comment ça s'écrit:
Foreach ($unObjetLigne in $mesLignes){ fais moi ci fais moi ça}

Vous avez noté ? le parcours de chaque objet de la liste (en informatique on appelle ça une itération) en PowerShell se met entre deux ().
Et l'instruction de ce que PowerShell doit faire pour chaque objet se met entre {}.
Et pour le "fais moi ci, fais moi ça", dans un premier temps, on va juste demander à PowerShell d'écrire un bout de l'information. Et ce qu'il y a de formidable avec les objets c'est qu'on peut accéder à une partie de cette information structurée en écrivant $monObjet.maPropriété.
Donc si on dit à PowerShell $monObjetLigne.Libelle il va comprendre qu'on lui demande la valeur de la colonne libelle d'une ligne.
Enfin, pour faire écrire un truc à PowerShell dans la console, la formule magique est write-output.
Donc on résume, pour faire écrire à PowerShell tous les libellés du fichier il faut écrire ceci :
Foreach($unObjetLigne in $mesLignes){ write-output $unObjetLigne.libelle}

Et effectivement, si vous copiez ça dans la console et que vous appuyez sur la touche Entrée, ça marche !
8- Concaténation
Bon maintenant, je veux écrire, la date d'effet, le libellé et le montant pour que ça commence à ressembler à ma note de frais.
Pour faire ça je dois concaténer (en informatique : assembler des bouts de textes) plusieurs propriétés de mes objets. Par chance c'est simple en PowerShell, ça se fait avec le signe "+".
Donc on recommence :
Foreach($unObjetLigne in $mesLignes){ write-output ($unObjetLigne."date d'effet" + " " + $unObjetLigne.libelle + " " + $unObjetLigne.Montant)}

Petites subtilités que vous aurez notées :
  • J'ai "concaténé" avec des espaces (" ") entre les valeurs pour rendre le résultat lisible
  • J'ai dû rajouter des parenthèses pour mon write-output pour y placer ma chaine d'instruction de concaténation
  • La propriété "date d'effet" contient un espace et une simple quote (apostrophe), donc j'ai dû l'entourer des double quotes (guillemets)
Et ça marche !

Seulement, en informatique, pour bien voir les parenthèses du write-output, les accolades de l'instruction donnée à PowerShell pour chaque itération, on préfère mettre ça sur plusieurs lignes :
Foreach($unObjetLigne in $mesLignes){ 
	write-output ($unObjetLigne."date d'effet" + " " + $unObjetLigne.libelle + " " + $unObjetLigne.Montant)
}


C'est beaucoup plus lisible comme ça, sur plusieurs lignes, et ça marche aussi dans la console et permet d'avoir des lignes moins longues donc des copies d'écran avec une meilleures définition. Donc on va se mettre à écrire sur plusieurs lignes maintenant.
9-Fonctions texte
Maintenant, on va commencer à nettoyer le texte. Le signe "-" sur les montant, je veux l'enlever car je sais que mes montants seront tous des débits vu que c'est une note de frais.
En PowerShell on a une fonction replace (remplacer) qui fait ça très bien. Donc je vais définir une nouvelle variable pour contenir mon montant sans le signe moins et je vais y stocker le résultat de ma fonction qui va enlever le signe moins.
ça s'écrit comme ça :
$monMontantSansSigneMoins = $unObjetLigne.montant.replace("-","")

Je dis à PowerShell de remplacer le signe moins par rien ("") et je stocke ce résultat dans ma variable $monMontantSansSigneMoins
Ensuite, je n'ai plus qu'à placer ça dans mon bloc de code:
Foreach($unObjetLigne in $mesLignes){ 
	$monMontantSansSigneMoins = $unObjetLigne.montant.replace("-","")
	write-output ($unObjetLigne."date d'effet" + " " + $unObjetLigne.libelle + " " + $monMontantSansSigneMoins)
}

10- Fichier .ps1 et éditeur de code
Bon, si vous en êtes arrivés à ce stade du tuto, c'est que vous êtes un vrai mordu d'informatique. On va passer à la vitesse supérieure.
On va complexifier notre bloc de code et même si on peut faire ça dans la console, ça n'est pas très propre, alors on va écrire notre code dans un fichier et utiliser un éditeur de code pour écrire notre PowerShell.
Donc vous allez télécharger Visual Studio Code qui est complètement gratuit. ici


Créez un fichier avec l'extension .ps1 dans votre dossier PowerShell à la racine du disque C et ouvrez le avec votre éditeur de code Visual Studio Code en faisant un clic droit sur le fichier.
Puis collez notre bloc de code dedans.
Il se peut que votre éditeur reconnaisse que c'est du PowerShell grâce à l'extension du fichier (.ps1). Dans ce cas il va :
  • coloriser le code qui sera encore plus lisible
  • Vous indiquer qu'il a reconnu que c'était du PowerShell
  • Vous aurez l'autocomplétion comme dans la console mais là comme c'est un logiciel Microsoft on parlera d'IntelliSense.
  • Si vous faites une erreur de code PowerShell, l'éditeur de code est censé vous prévenir.
  • Enfin, votre code est bien protégé sous la forme d'un fichier que vous pouvez exécuter à volonté contrairement à ce qui est écrit dans la console et que vous perdrez définitivement si vous fermez la console.
Et aussi, ça fera trop super méga pro quand vos potes et vos copines viendront vous voir et qu'ils verront ça sur votre écran d'ordi ;-)
ça fera trop hacker de série Netflix.
Maintenant il faut aussi remettre le code d'import du fichier csv parce que dans la console on peut utiliser la variable $mesLignes à volonté parce qu'elle est "chargée", mais dans le fichier, il faudra rejouer l'import à chaque exécution.

N'oubliez pas de cliquez sur "Manage" dans le message "restricted mode..." en haut de l'éditeur pour "Truster" le fichier comme étant un fichier sûr afin de bénéficier de l'IntelliSense:
donc voici notre code complet:
$mesLignes = Import-Csv -Path exemple-de-releve-bancaire.csv -Delimiter ";"

Foreach($unObjetLigne in $mesLignes){
	$monMontantSansSigneMoins = $unObjetLigne.montant.replace("-","")
	write-output ($unObjetLigne."date d'effet" + " " + $unObjetLigne.libelle + " " + $monMontantSansSigneMoins)
}

Ensuite il suffit d'enregistrer le fichier (le point blanc à côté du nom du fichier doit disparaître).
Puis dans la console PowerShell de l'éditeur, vous pouvez recommencer à vous caler sur le répertoire C:\PowerShell.
Enfin pour exécuter le code, il suffit de taper:
.\tran
Puis la touche Tab pour que la console intégrée à l'éditeur complète le nom du fichier.
Enfin si on appuie sur la touche entrée, le code s'exécute dans la console intégrée à l'éditeur.
11- Formatage avancé
Maintenant, nous allons nettoyer le libellé.
Nous allons enlever le mot "PARIS", le nombre "75", le nombre "14" des libellés, ainsi que le nombre "5339" qui est dans les libellés Franprix.
ça se fait comme ça :
$monLibellePropre = $monLibellePropre.replace("75","")
$monLibellePropre = $monLibellePropre.replace("14","")
$monLibellePropre = $monLibellePropre.replace("5339","")
write-output ($unObjetLigne."date d'effet" + " " + $monLibellePropre + " " + $monMontantSansSigneMoins)

Notez que je réécris la même varaible à chaque transformation.
Voudevriez obtenir ce résultat:
Mais là je m'aperçois que j'ai fait une mini-bêtise. J'ai enlevé le nombre "14" de deux dates dans deux libellés. C'est embêtant parce que j'allais enlever les dates tronquées dans les libellés en me servant d'une fonction qui permet de supprimer les 5 premiers caractères d'un texte. A cause de ma mini bêtise je ne peux pas généraliser le traitement car j'ai maintenant deux libellés qui commencent par une date avec seulement 3 caractères vu que j'ai enlevé le nombre "14" de ces deux dates.
Pas grave on va faire ce traitement, et on enlèvera les mots et nombre gênant ensuite. En programmation l'ordre des instructions est important, je n'ai qu'à placer mon prochain traitement avant celui que je viens de programmer.
voilà comment on supprime les 5 premiers caractères d'une chaîne de caractère en PowerShell :
$monLibellePropre = $unObjetLigne.libelle.substring(5, ($unObjetLigne.libelle.length - 5))

Substring, c'est pour obtenir une sous-chaîne de caractères à partie d'un texte de départ, je ne veux qu'une partie de mon texte.
La fonction fonctionne comme ça :
MaVariableAvecMonTexteComplet.substring(numéroDuCaractèreApartirDuquelJeVeuxCouper , NombreDeCaractèresQueJeVeuxRécupérerEnsuite)

Je dis à la fonction que je veux récupérer un partie du texte à partir du 5ème caractère et qu'ensuite je veux récupérer tout ce qui reste.
Et tout ce qu'il reste, c'est donc le nombre total de caractères moins les 5 premier que j'ai enlevés.
En PowerShell une longueur de chaine de caractère, c'est $monTexte.length
Donc le nombre de caractère que je veux récupérer ici c'est bien : $monTextedeDépart.Length-5
Voilà donc notre code maintenant :
$mesLignes = Import-Csv -Path exemple-de-releve-bancaire.csv -Delimiter ";"

Foreach($unObjetLigne in $mesLignes){
	$monMontantSansSigneMoins = $unObjetLigne.montant.replace("-","")
	$monLibellePropre = $unObjetLigne.libelle.substring(5, ($unObjetLigne.libelle.length - 5))	
	$monLibellePropre = $monLibellePropre.replace("PARIS","")
	$monLibellePropre = $monLibellePropre.replace("75","")
	$monLibellePropre = $monLibellePropre.replace("14","")
	$monLibellePropre = $monLibellePropre.replace("5339","")
	write-output ($unObjetLigne."date d'effet" + " " + $monLibellePropre + " " + $monMontantSansSigneMoins)
}

Et voici ce que vous devez récupérer à l'exécution:
Voilà, on a bien nettoyé, il ne nous reste vraiment plus que les noms de magasins.

12-Créer des objets et remplir un Tableau avec
Maintenant, nous allons préparer l'écriture du fichier de sortie. Il faut qu'on génère un fichier CSV avec les données nettoyées et pour faire ça on a besoin d'une collection d'objets. Chaque objet sera une ligne de notre fichier de sortie.
On peut dire grosso modo une collection ou un tableau, même si les puristes vont me détester s'ils lisent ça, ha ha ha.
Pour créer un tableau en PowerShell on fait comme ça :
$maCollection =@()
et là, on peut mettre des objets dedans.
et pour créer un objet on fait :
$monObjet=@{
	maPropriété1 = valeurDeLaPropriété1
	maPropriété2 = valeurDeLaPropriété2
	etc.
}

dans notre cas ça sera donc :
$maLigneDeNoteDeFrais = @{
    Date = $unObjetLigne."date d'effet"
    Fournisseur = $monLibellePropre 
    Montant = $monMontantSansSigneMoins
}

Enfin, pour ajouter un objet à une collection, on utilise +=
$maCollectionDobjets += $maLigneDeNoteDeFrais

Donc voilà notre code maintenant:
$maNoteDeFrais =@()
Foreach($unObjetLigne in $mesLignes){
	$monMontantSansSigneMoins = $unObjetLigne.montant.replace("-","")
	$monLibellePropre = $unObjetLigne.libelle.substring(5, ($unObjetLigne.libelle.length - 5))
	$monLibellePropre = $monLibellePropre.replace("PARIS","")
	$monLibellePropre = $monLibellePropre.replace("75","")
	$monLibellePropre = $monLibellePropre.replace("14","")
	$monLibellePropre = $monLibellePropre.replace("5339","")
	write-output ($unObjetLigne."date d'effet" + " " + $monLibellePropre + " " + $monMontantSansSigneMoins)
	$maLigneDeNoteDeFrais = @{
    		Date        = $unObjetLigne."date d'effet"
        	Fournisseur = $monLibellePropre 
        	Montant     = $monMontantSansSigneMoins
	}
	$maNoteDeFrais+=$maLigneDeNoteDeFrais
}

Maintenant, pour être sûr que la collection est bien remplie avec les bons objets tout bien remplis eux aussi, il faudrait faire une boucle sur notre collection pour voir si on peut écrire dans la console tout ce qu'on y a bien rangé. ça serait cool non ?
Ben c'est ce qu'on va faire. Et vous savez faire hein ?
C'est comme ça :
Foreach ($uneLigneDeNoteDeFrais in $maNoteDeFrais){
    write-output($uneLigneDeNoteDeFrais.Date + " " +$uneLigneDeNoteDeFrais.Fournisseur + " " + $uneLigneDeNoteDeFrais.Montant)
}

Mais si on fait ça, on va écrire deux fois les lignes. Une fois avec le fichier de départ et une autre fois avec la collection. On n'a plus besoin d'écrire les lignes de départ maintenant. Donc on va dire à l'instruction d'écriture des lignes de départ de ne plus s'exécuter, en programmation ça s'appelle commenter.
Pour commenter une ligne de code en PowerShell, il suffit de placer le caractère # devant la ligne.
Vous verrez, Visual Studio Code va mettre la ligne en vert? ça veut dire qu'elle ne sera pas exécutée par le programme. donc voici notre code à ce stade :
$mesLignes = Import-Csv -Path exemple-de-releve-bancaire.csv -Delimiter ";"
$maNoteDeFrais =@()
Foreach($unObjetLigne in $mesLignes){
	$monMontantSansSigneMoins = $unObjetLigne.montant.replace("-","")
	$monLibellePropre = $unObjetLigne.libelle.substring(5, ($unObjetLigne.libelle.length - 5))
	$monLibellePropre = $monLibellePropre.replace("PARIS","")
	$monLibellePropre = $monLibellePropre.replace("75","")
	$monLibellePropre = $monLibellePropre.replace("14","")
	$monLibellePropre = $monLibellePropre.replace("5339","")
	#write-output ($unObjetLigne."date d'effet" + " " + $monLibellePropre + " " + $monMontantSansSigneMoins)
	$maLigneDeNoteDeFrais = @{
    		Date = $unObjetLigne."date d'effet"
    		Fournisseur = $monLibellePropre 
    		Montant = $monMontantSansSigneMoins
	}
$maNoteDeFrais+=$maLigneDeNoteDeFrais
}

Foreach ($uneLigneDeNoteDeFrais in $maNoteDeFrais){
    write-output($uneLigneDeNoteDeFrais.Date + " " +$uneLigneDeNoteDeFrais.Fournisseur + " " + $uneLigneDeNoteDeFrais.Montant)
}

Et ce que ça donne à l'exécution :

13-Tri d'une collection d'objet sur une propriété en PowerShell
Vous avez remarqué, dans le relevé bancaire, ce n'est pas trié sur la date d'effet. On a 9 octobre, 8 octobre, 10 octobre.
On veut une note de frais triée par date d'achat alors il faut trier notre collection sur la date d'achat.
Voilà comment on fait ça en PowerShell:
$maNoteDeFraisTriee = $maNoteDeFrais | Sort-Object { $_.Date } -Descending

Le caractère "bar key" | s'appelle un pipe en PowerShell (prononcer païpe comme en anglais) et est déjà l'abréviation de pipeline. Ah les informaticiens et leur jargon !
Le pipeline permet de récupérer le résultat d'un traitement et de le refiler à un autre traitement dans la même ligne.
Les bons développeurs de PowerShell utilisent le pipe au maximum ce qui leur permet de faire plein de trucs en une seule ligne de code et d'avoir des lignes de code super courtes.
Là on a refilé à la fonction sort-Object le résultat de la collection des lignes de la notre de frais, et on a utilisé $_.Date pour lui dire d'utiliser la propriété Date pour faire le tri. On a aussi demandé "Descending" pour que les dates soient triées de la plus récente à plus ancienne.
Du coup ça donne ça :
On voit bien maintenant que les dates sont dans l'ordre, 8 octobre, 9 octobre, 10 octobre.
Voilà, le tutoriel est presque terminé, on va rajouter des colonnes vides pour le Hors Taxe et les TVA, et écrire le fichier.
Pour rajouter des colonnes, très simple, et on va en profiter pour remplacer la propriété Montant par TTC :
$maLigneDeNoteDeFrais = @{
    Date = $unObjetLigne."date d'effet"
    Fournisseur = $monLibellePropre 
    HT = ""
    TVA20 = ""
    TVA10=""
    TVA055 =""
    TTC = $monMontantSansSigneMoins
}

J'en profite d'ailleurs pour vous montrer la fonction de formatage du code de Visual Studio Code qui va bien ranger le code car, normalement, quand on programme, à chaque imbrication de code, on tabule ce qui est imbriqué. ça rend le code plus lisible, et dans le langage Python, c'est même obligatoire. On essaie d'aligner les signes = aussi
Donc avant le formatage. On fait un clic droit dans l'éditeur et on choisit "Format document" dans le menu contextuel :
Et après formatage :
Vous remarquez que tout ce qui est dans les accolades de la première boucle foreach a été avancé d'une tabulation, et que dans l'écriture de l'objet, tous les signes = sont maintenant alignés verticalement, beaucoup plus agréable à lire et élégant. Et oui, il y a un côté esthétique dans la programmation :-)

14-Ecriture d'un fichier csv à partir d'une collection d'objets : la note de frais
Pour finir en beauté, une syntaxe de PowerShell un peu complexe mais tellement pratique:
$(Foreach ($x in $maNoteDeFraisTriee) {
    New-object psobject -Property $x
}) | Select-Object "Date", "Fournisseur", "HT", "TVA20", "TVA10", "TVA055", "TTC" | Export-Csv ("note-de-frais.csv") -Delimiter ";" -NoTypeInformation 

A utiliser comme une pure formule d'Harry Potter, où il suffira de remplacer le nom de la collection, le nom du fichier de sortie, et la liste des colonnes que vous voulez afficher.
Et effectivement, ça marche (pas signes cabalistiques rouges):
fichier de sortie présent dans le répertoire de travail.
Et, fichier csv conforme aux attentes:
Code complet du tutoriel:
$mesLignes = Import-Csv -Path exemple-de-releve-bancaire.csv -Delimiter ";"
$maNoteDeFrais = @()
Foreach ($unObjetLigne in $mesLignes) {
    $monMontantSansSigneMoins = $unObjetLigne.montant.replace("-", "")
    $monLibellePropre = $unObjetLigne.libelle.substring(5, ($unObjetLigne.libelle.length - 5))
    $monLibellePropre = $monLibellePropre.replace("PARIS", "")
    $monLibellePropre = $monLibellePropre.replace("75", "")
    $monLibellePropre = $monLibellePropre.replace("14", "")
    $monLibellePropre = $monLibellePropre.replace("5339", "")
    #write-output ($unObjetLigne."date d'effet" + " " + $monLibellePropre + " " + $monMontantSansSigneMoins)
    $maLigneDeNoteDeFrais = @{
        Date        = $unObjetLigne."date d'effet"
        Fournisseur = $monLibellePropre 
        HT          = ""
        TVA20       = ""
        TVA10       = ""
        TVA055      = ""
        TTC         = $monMontantSansSigneMoins
    }
    $maNoteDeFrais += $maLigneDeNoteDeFrais
}

$maNoteDeFraisTriee = $maNoteDeFrais | Sort-Object { $_.Date } -Descending

Foreach ($uneLigneDeNoteDeFrais in $maNoteDeFraisTriee) {
    write-output($uneLigneDeNoteDeFrais.Date + " " + $uneLigneDeNoteDeFrais.Fournisseur + " " + $uneLigneDeNoteDeFrais.TTC)
}

$(Foreach ($x in $maNoteDeFraisTriee) {
        New-object psobject -Property $x
    }) | Select-Object "Date", "Fournisseur", "HT", "TVA20", "TVA10", "TVA055", "TTC" | Export-Csv ("note-de-frais.csv") -Delimiter ";" -NoTypeInformation 


15-Pour aller plus loin - Fonctions et paramètre de fichier PowerShell
Voilà, on peut arrêter le tutoriel ici si on veut, le programme fait la job comme on dit au Québec, mais on peut aussi l'améliorer.
Par exemple, on pourrait délocaliser dans une fonction le nettoyage du libellé. ça rendrait le programme principal plus lisible. en PowerShell on peut écrire une fonction comme ça :
function NettoyerLibelle($texteAnettoyer){

    $texteNettoye = $texteAnettoyer.substring(5, ($unObjetLigne.libelle.length - 5))
    $texteNettoye = $texteNettoye.replace("PARIS", "")
    $texteNettoye = $texteNettoye.replace("75", "")
    $texteNettoye = $texteNettoye.replace("14", "")
    $texteNettoye = $texteNettoye.replace("5339", "")
    return $texteNettoye
}

on dit à PowerShell qu'on crée un fonction avec le mot function, ensuite on met le nom de la fonction qui servira à l'appeler, puis entre parenthèses le ou les paramètres d'entrée (ici on n'en a qu'un), puis dans les accolades le morceau de programme que doit exécuter la fonction et enfin, après le mot clé return, la valeur qui doit être renvoyée par la fonction.
Pour appeler la fonction en PowerShell on met son nom suivi du paramètre tout simplement :
$monLibellePropre = NettoyerLibelle $unObjetLigne.libelle

Attention, le PowerShell reste un langage de script, donc "interprété", ça veut dire que le programme est lu ligne par ligne par le moteur d'éxécution et une ligne après l'autre, donc on ne peut pas écrire le code de la fonction après des morceaux de code qui appellent cette fonction. La fonction doit être écrite dans le fichier avant tous ses appels.
Notre programme devient donc :
$mesLignes = Import-Csv -Path exemple-de-releve-bancaire.csv -Delimiter ";"
$maNoteDeFrais = @()

function NettoyerLibelle($texteAnettoyer) {
    $texteNettoye = $texteAnettoyer.substring(5, ($unObjetLigne.libelle.length - 5))
    $texteNettoye = $texteNettoye.replace("PARIS", "")
    $texteNettoye = $texteNettoye.replace("75", "")
    $texteNettoye = $texteNettoye.replace("14", "")
    $texteNettoye = $texteNettoye.replace("5339", "")
    return $texteNettoye
}

Foreach ($unObjetLigne in $mesLignes) {
    $monMontantSansSigneMoins = $unObjetLigne.montant.replace("-", "")
    $monLibellePropre = NettoyerLibelle $unObjetLigne.libelle
    #write-output ($unObjetLigne."date d'effet" + " " + $monLibellePropre + " " + $monMontantSansSigneMoins)
    $maLigneDeNoteDeFrais = @{
        Date        = $unObjetLigne."date d'effet"
        Fournisseur = $monLibellePropre 
        HT          = ""
        TVA20       = ""
        TVA10       = ""
        TVA055      = ""
        TTC         = $monMontantSansSigneMoins
    }
    $maNoteDeFrais += $maLigneDeNoteDeFrais
}

$maNoteDeFraisTriee = $maNoteDeFrais | Sort-Object { $_.Date } -Descending

Foreach ($uneLigneDeNoteDeFrais in $maNoteDeFraisTriee) {
    write-output($uneLigneDeNoteDeFrais.Date + " " + $uneLigneDeNoteDeFrais.Fournisseur + " " + $uneLigneDeNoteDeFrais.TTC)
}

$(Foreach ($x in $maNoteDeFraisTriee) {
        New-object psobject -Property $x
    }) | Select-Object "Date", "Fournisseur", "HT", "TVA20", "TVA10", "TVA055", "TTC" | Export-Csv ("note-de-frais.csv") -Delimiter ";" -NoTypeInformation 

Comments

Popular posts from this blog

Delivery of eat-nearby.com