Contenu | Rechercher | Menus

Annonce

Si vous avez des soucis pour rester connecté, déconnectez-vous puis reconnectez-vous depuis ce lien en cochant la case
Me connecter automatiquement lors de mes prochaines visites.

À propos de l'équipe du forum.

#1 Le 02/01/2019, à 23:52

toitoinebzh

Csv2Qif - Convertir les fichiers .csv de Boursorama/N26 en .qif

Bonjour à tous,

Je vous présente un programme que je compte utilisé régulièrement.

Logo
Csv2Qif

Voilà j'ai constaté que les fichiers .qif de Boursorama étaient moins riches en information que les fichiers .csv.

J'ai donc créer ce logiciel qui convertir les .csv de Bourso en ".qif améliorés" exploitables par des logiciels tels que Kmymoney, Homebank, Skrooge, Gnucash, ...

https://framagit.org/toitoinebzh/csv2qif_bsr

Le qif créé contient alors une description plus précise des transactions (catégories et sous catégories notamment)

pour lancer le logiciel, il suffit de taper la commande suivante

python3 gui.py

vous avez alors l'interface suivante

demo

Cet outil à été codé à l'aide de PyQt5 et utilie le package csv pour lire les fichiers csv.

Dernière modification par toitoinebzh (Le 20/01/2019, à 22:12)

Hors ligne

#2 Le 04/01/2019, à 16:47

miraks

Re : Csv2Qif - Convertir les fichiers .csv de Boursorama/N26 en .qif

Bonjour,

Je suis le développeur de Skrooge et je trouve le format QIF assez pauvre de façon générale.
Par exemple: en QIF il n'est pas possible de précisé l'unité ($ ou €) d'un montant.

C'est pour cela que, dans Skrooge, je recommande plutôt d'importer du CSV (avec le bon mapping) que du QIF (c'est certes plus simple car il n'y a pas de mapping à faire).

Cordialement.


Skrooge, a personal finances manager powered by KDE
Donate

Hors ligne

#3 Le 04/01/2019, à 21:17

toitoinebzh

Re : Csv2Qif - Convertir les fichiers .csv de Boursorama/N26 en .qif

Salut miraks,

Merci pour ton commentaire.
Les csv de boursorama ne donnent pas l'unité monétaire non plus sad

J'utilise ce type de script depuis pas mal d'année maintenant (un de mes premier scripts en 2011 ...) et je le diffuse ici car ça peut toujours rendre service à quelqu'un d'autre.

Les Qif ou Ofx présentent l'avantage d'être assez simple à importer, malheureusement les banques ne respectent pas toujours ces formats et ça bug, j'en ai fait l'amère expérience à plusieurs reprises.

Le mapping c'est bien (mais pas dispo dans tous les logiciels). Et comme tu le dis ça demande un peu de temps et personnellement je trouve ça un peu rebutant pour un débutant en informatique.

De manière générale, je trouve que les logiciels de finances personnelles sont assez difficiles à prendre en main. J'ai beaucoup galéré et mis plusieurs mois pour être autonome et automatisé le tout. Je pense qu'il y a plusieurs raisons à cela

  • pas d'éducation financière (et je pense que c'est le cas la majorité des français) : les notions et surtout le vocabulaire de revenus/dépenses, actif/passif, amortissement, patrimoine brut/net, bilan/compte de résultat, opération compensée/rapprochée, date de valeur/opérations, actions/obligations ne sont pas évidents

  • je ne vais pas dire que les logiciels ne sont pas bons mais ils ont, à mes yeux, plutôt tendance à s'adresser à des personnes qui connaissent déjà le vocabulaire de la ligne précédente. Si un utilisateur lambda décide de faire sa compta, il installera le logiciel, cliquera à droite et à gauche et se pommera, il laissera tomber et au mieux utilisera libreoffice calc

Bon, je suis un peu hors sujet là mais c'est juste un retour d'expériences. Voilà dix ans que je suis mes finances perso de manière informatique et pour infos mon parcours a été le suivant libreoffice calc (et oui ...) > homebank > grisbi > kmymoney

J'ai un peu joué entre temps avec gnucah et skrooge lors de ses débuts.

Hors ligne

#4 Le 05/01/2019, à 10:31

kholo

Re : Csv2Qif - Convertir les fichiers .csv de Boursorama/N26 en .qif

salut les gens et bonne année !
je passe juste pour un petit com...

d'abord, merci de partager votre boulot !

je "m'amuse" avec des csv de Société Générale en ce moment et cela me sert à apprendre python...
depuis pas mal d'années, je récupère régulièrement ces csv (et les xls équivalent par sureté) dont beaucoup de lignes sont en doublon car les dates de téléchargement sont fluctuantes (la faute à moi). je fais tout cela avec 3 comptes...
en règle générale, je fais ça avec libreoffice calc :
j'importe les csv, regroupe, en supprimant les doublons, éventuellement j'ajoute les lignes que j'aurais zappé car trop attendu (à faire tous les 3 mois max, mais des fois je zappe), puis j'ajoute des colonnes pour faire mes ventilations, j'utilise les filtres pour faire le point et le copier / coller pour aller plus vite à la saisie,... puis enfin, je fais un tableau croisé dynamique pour chaque compte voire, depuis quelques années, pour les 3 comptes en même temps...
sous calc tout cela me prend l’équivalent de 3 jours répartis sur une à deux semaines en fonction de ma flemme; c'est le temps que cela me prends pour faire notre "bilan" personnel.
NB : certaines années le compte principal comprenait jusqu'à 800 lignes ; aujourd'hui c'est tout au plus la moitié...

j'ai rêvé que je pourrais faire tout cela en python cette année mais j'ai peur de ne pas avoir assez de temps ou de patience pour aller jusqu'au bout...
peut importe, la première partie est déjà réglée à grand coup de list et de set wink ; j'ai mes 3 csv utilisable et ce qui me prend les autres années 2 à 3 heures est digéré par le script en moins d'une seconde ! cool

voilà c'était pour vous faire part de mon retour d'expérience... et surtout la raison de ce choix des csv : c'est lisible, compréhensible (dans les 2 sens du terme lol ) et ça le restera des années encore là où tous les logiciels de compta et leur format proprio que j'ai vu passé depuis ma scolarité (88) ont rejoint les fossiles des dinosaures...

... ah oui, un peu de technique : les csv  :
XXXXXX.csv: ISO-8859 text, with CRLF line terminators

l'entête des fichiers originaux anonymisée:

="XXXXXXXXXX";02/01/2018;;XX;09/03/2018;0000,00 EUR

Date de l'opération;Libellé;Détail de l'écriture;Montant de l'opération;Devise

2 lignes d'exemple : (des frais bancaires lol )

17/02/2018;COTISATION JAZZ;COTISATION JAZZ    ;-8,50;EUR
17/02/2018;OPTION TRANQUILLIT;OPTION TRANQUILLITE    ;-0,65;EUR

NB : entre autre joyeusetés, que je corrige dans la foulée :
les doubles espaces,
les dates que je met dans mes scripts au format AAAA-MM-JJ pour faciliter le classement
et les montants dont je remplace les virgules par des points pour en faire des float

et, si cela vous intéresse, voilà où j'en suis (la partie 2 :  bilan):

#!/usr/bin/env python3
# -*- coding: UTF8 -*-

# ***************************************************************
# ***************************************************************
# ***************************************************************
# FONCTIONS

def virer_doubles_espaces(ligne):
    # >>>' '.join("   je      fais du       python".split())
    # je fais du python
    return ' '.join(ligne.split())

# la_ligne = "    Monty Python    "
def virer_espaces_debut_et_fin(ligne):
    return ligne.strip()
# un_test = ">" + virer_espaces_debut_et_fin(la_ligne) + "<"
# print(un_test)

def mef(montant): # montant_en_float
    """ permet de convertir  à la volée 
    les montants (strings) en float 
    avec un point à la place de la virgule """
    return float(montant.replace(',', '.'))

# ***************************************************************
# ***************************************************************
# ***************************************************************
# OBJETS

class FichierCsvBq:
    def __init__(self, fichier):
        self.fichier = fichier
        self.lignes = []
        self.nbre_lignes = 0
        self.champs = []
        self.nbre_champs = 0

        self.charger(fichier)

    def __str__(self):
        out = 30*'-' + '\n' + \
        "Champs :" + '\n' + str(self.champs) + '\n' + \
        str(self.nbre_lignes) + ' lignes' + '\n' + \
        str(self.lignes)
        30*'-' 
        return out

    def charger(self, un_fichier):
        with open(un_fichier,'r') as f:
            donnees = f.read()
        lignes = [ virer_doubles_espaces(l) for l in donnees.split('\n') if l != "" ]
        """ je passe les noms de champs depuis la première ligne en liste et j'ajoute un élément nommé tags"""
        self.champs = lignes[0].split(';') + ['tags']
        """ je compte les champs et met la valeur dans une variable accessible """
        self.nbre_champs = len(self.champs) # utile ??? ATTENTION mise à jour si ajout de ligne
        """ je supprime l'entete qui contient les champs """
        lignes.pop(0)
        """ chaque ligne est éclatée en une liste dont je vire les espaces de début et de fin
         puis j'ajoute un élément set pour mettre les tags """
        self.lignes = [ [x.strip() for x in l.split(';')] + [set()] for l in lignes ]
        """ je met le nombre de lignes dans une variable """
        self.nbre_lignes = len(self.lignes) # utile ??? ATTENTION mise à jour si ajout de ligne

    def ligne(self,num_ligne):
        """ affiche une ligne """
        return self.lignes[num_ligne]
    def champ(self,ligne, num_champ):
        """ affiche un des champs de 0 à len(champs)-1 d'une ligne """
        return self.lignes[num_ligne].split(';')[num_champ]
    def ligne_champ(self,num_ligne, num_champ):
        """ affiche un des champs de 0 à len(champs)-1 d'une ligne par indice """
        return self.lignes[num_ligne][num_champ]

    def afficher_un_champ_de_toutes_les_lignes(self, num_champ):
        return [ x[num_champ] for x in self.lignes ]

    def taguer_une_ligne(self, num_ligne, un_tag):
        self.lignes[num_ligne][self.nbre_champs - 1].add(un_tag)
    def supprimer_un_tag_d_une_ligne(self, num_ligne, un_tag):
        self.lignes[num_ligne][self.nbre_champs - 1].remove(un_tag)
    def afficher_tags_d_une_ligne(self, num_ligne):
        return self.lignes[num_ligne][self.nbre_champs - 1]
    def afficher_tags_vides(self):
        return [ x for x in self.lignes if len(x[self.nbre_champs - 1]) == 0 ]
        # return [ x for x in self.lignes if len(x[self.nbre_champs - 1]) < 2 ]

et mon if main du moment :

if __name__ == '__main__':
    compteMrMme = "XXXXXXXX"
    un_fichier = compteMrMme + ".csv"
    f = FichierCsvBq(un_fichier)
    '''
    # print(f)
    # print(30*'-')
    # print(repr(f))

    # print(30*'-')
    # """ affiche toutes les lignes """
    # print(f.lignes)

    # """ affiche une ligne """
    # print(f.lignes[0])
    # print(f.ligne(0))
    # """ affiche un champ d'une ligne """
    # print(f.ligne_champ(0, 2))
    '''
    """ affiche un champ d'une ligne """
    print("original" , f.ligne_champ(0, 3), "vers", mef(f.ligne_champ(0, 3)), type(mef(f.ligne_champ(0, 3))))

    '''
    # """ ajout de tags """
    # f.taguer_une_ligne(0, "coucou")
    # f.taguer_une_ligne(0, "encore")
    # print(f.ligne(0))
    # """ ajout d'un tag existant impossible car dans un set """
    # f.taguer_une_ligne(0, "coucou")
    # print(f.ligne(0))
    # """ afficher les tags d'une ligne """
    # print("tags de la ligne 0", f.afficher_tags_d_une_ligne(0), type(f.afficher_tags_d_une_ligne(0)))
    # """ supprimmer un tag """
    # f.supprimer_un_tag_d_une_ligne(0, "coucou")
    # print(f.ligne(0))
    '''
    
    """ afficher_un_champ_de_toutes_les_lignes(num_champ) """
    # print(f.afficher_un_champ_de_toutes_les_lignes(1)) # Lib1
    # print(f.afficher_un_champ_de_toutes_les_lignes(2)) # Lib2
    # print(f.afficher_un_champ_de_toutes_les_lignes(3)) # montants
    
    def tag_les(le_num_champ, le_modele, le_tag):
        """ tag une ligne en fonction d'un modèle qui peut être contenu dans un champ """
        for num_ligne in range(len(f.lignes)):
            if le_modele in f.lignes[num_ligne][le_num_champ]:
                f.taguer_une_ligne(num_ligne, le_tag)
                # print(f.lignes[num_ligne])
                
    # TAGS DU CHAMP 1
    # tag_les(1, "CHEQUE", "CHEQUE")
    # tag_les(1, "CARTE", "CARTE")
    # tag_les(1, "PRELEVEMENT", "PRELEVEMENT")

    # tag_les(1, "ARRETE", "BANQUE")
    # tag_les(1, "COTISATION JAZZ", "BANQUE")
    # tag_les(1, "OPTION TRANQUILLIT", "BANQUE")
    # ...

    # TAGS DU CHAMP 2
    # tag_les(2, "ARRETE", "BANQUE")
    # tag_les(2, "COTISATION JAZZ", "BANQUE")
    # tag_les(2, "OPTION TRANQUILLIT", "BANQUE")

    # tag_les(2, "Regie Eau", "EAU")
    # tag_les(2, "ELECTRICITE", "EDF")
    # tag_les(2, "ENGIE", "EDF")

    # tag_les(2, "D.G.F.I.P.", "IMPOTS")
    # tag_les(2, "CHEQUE", "CHEQUE")
    # tag_les(2, "ARRETE", "BANQUE")
    # ...

    # print(f.afficher_tags_vides())

ce matin, je me suis rendu compte que ce serais bien de mettre un index à mes lignes (quelle tache je fais !!!)
bon c'est le WE !
have fun !!!

Hors ligne

#5 Le 05/01/2019, à 20:58

toitoinebzh

Re : Csv2Qif - Convertir les fichiers .csv de Boursorama/N26 en .qif

salut kholo

3 jours sous calc !!!
j'y passe rarement plus de 30 minutes par mois

c'est vrai que ton approche permet d'être vraiment indépendant avec un format de fichier que tu maîtrises

as tu tenter l'expérience des logiciels dédiés à la gestion des finances personnelles, tu pourrais au moins t'en servir comme un simple viewer pour analyser tes dépenses

saches également que la plupart des logiciels existants permettent l'export en csv ou autre format ouvert, ce qui t'assure une certaine pérennité

concernant ton code, je pense que tu devrais créer une autre class pour représenter chacune de "tes lignes", tu gagnerais en visibilité
si tu regarde un bout de mon code, tu verras que j'ai créé deux class, l'une comme toi représente le Fichier csv (FichierCsvBq, Transactions chez moi) et l'autre représente chacune des "lignes" (Transaction chez moi)

si j'ai compris ton code, je vois aussi que ta stratégie est de ne pas toucher au csv de la société générale et de le lire tel quel

tu peux avoir une autre stratégie qui consiste en deux étapes;
Script 1 > lecture du csv société générale et création d'un nouveau csv "plus cool" à lire et à traiter avec calc ou autre logiciel
Script 2 > reprendre ton script du message précédent qui est pour moi un outil de lecture et le simplifier

enfin tu peux t'intéresser à la bibliothèque csv de python qui est là pour faciliter la lecture de csv, celà simplifie pas mal la vie (plus besoin de split et compagnie)
http://www.chicoree.fr/w/Fichiers_CSV_en_Python

dans tous les cas, merci pour ton partage smile

Dernière modification par toitoinebzh (Le 05/01/2019, à 21:04)

Hors ligne

#6 Le 06/01/2019, à 19:06

kholo

Re : Csv2Qif - Convertir les fichiers .csv de Boursorama/N26 en .qif

salut toitoinebzh
merci pour ta lecture et tes infos
je vais regarder ton code cette semaine à tête reposée et voir comment l'exploiter
cela va pas mal m'aider !!!

edit 2018 01 07
re,...
bon, j'ai pigé ton code (très simple et très lisible !)
chaque ligne est une transaction et tu as créé une class pour cela
puis la seconde est une liste pour importer le fichier ligne par ligne
je n'ai pas encore assez de bouteille mais, intuitivement, j'ai la sensation d'une étape de trop...
merci , encore une fois, c'est super propre !

Dernière modification par kholo (Le 07/01/2019, à 08:09)

Hors ligne

#7 Le 19/01/2019, à 18:09

toitoinebzh

Re : Csv2Qif - Convertir les fichiers .csv de Boursorama/N26 en .qif

up !

Mise à jour du logiciel
il prend maintenant en compte les fichiers .csv de N26 (qui ne fournit que tu csv d'ailleurs)

Hors ligne

#8 Le 20/01/2019, à 11:05

kholo

Re : Csv2Qif - Convertir les fichiers .csv de Boursorama/N26 en .qif

hello,
bon, je commence à mieux lire le code...
je vais tenter d'être constructif à mon humble niveau...
ce sont les try enchâssés de gui.py qui m'ont fait tiquer... puis, je me suis dit qu'une class pour la conversion serait peut être la bien venue...
ta class MainWindow resterait pour l'affichage de ta fenêtre principale puis tu aurais une class pour une fenêtre de type progressbar avec le défilement de la lecture et de la conversion (du texte, les progressbar non verbeuse sont juste esthétique) et cela serait plus pro que les print...

la gestion du combo peut être plus propre et évolutive...

        if self.comboBox.currentText() == "N26" :
            bank = "N26"
        else :
            bank = "BSR"
        print("Bank : ", bank)

un truc comme ça :

les_banques = ["N26", "BSR"]
mon_choix = self.comboBox.currentText()
for une_banque in les_banques:
    if une_banque == mon_choix:
        bank = une_banque
        break

ensuite, donc idem pour l'ajout des banques dans le combo... pour le moment c'est light mais pas super :

        self.comboBox.addItem(QIcon(icon_path_BSR), "Boursorama")
        self.comboBox.addItem(QIcon(icon_path_N26), "N26")

si tu te crées une liste avec les paramètres des banques, tu pourras la parser avec un for et facilement en ajouter d'autres

ah oui, je viens de comprendre, tu gères l'annulation de ton choix de fichier par un des try... c'est ça qui est pas glop !
et tu as un with pour ouvrir ton fichier dans le reader mais tu as laissé un open / close le gui...

pythoneusement...

Hors ligne

#9 Le 20/01/2019, à 12:56

toitoinebzh

Re : Csv2Qif - Convertir les fichiers .csv de Boursorama/N26 en .qif

Salut kholo,

merci pour tes commentaires,
effectivement, j'ai plus bricolé le code qu'autre chose pour l'ajout d'une seconde banque
je pense qu'une réécriture des classes sera nécessaire si j'envisage d'agrandir la liste de banque

pour la progressbar, je n'ai jamais utilisé ce widget, mais je n'en vois pas trop l'intérêt pour l'instant, la conversion est instantanée

le open/close dans la partie gui concerne uniquement le fichier de sortie, pas le fichier en entrée
il faudrait en effet que je rentre cette partie du code plutôt dans la classe Transactions pour être plus cohérent

la classe Mainwindow est là principalement pour l'affichage
j'ai crée le module csv_reader pour gérer la lecture et la conversion des fichiers (je ne sais pas si tu l'as vu ?)

d'accord avec toi pour les try, c'est plus une écriture faite pour avoir quelques choses de fonctionnelle rapidement mais pas propre, on est d"accord

merci pour tes suggestions pour y mettre une liste de banques, j' n'avais pas encore pris le temps d'y réfléchir, je vais sûrement reprendre ton code (si ça ne te gène pas) quand je remettrai le nez dans le logiciel

Hors ligne

#10 Le 20/01/2019, à 15:31

kholo

Re : Csv2Qif - Convertir les fichiers .csv de Boursorama/N26 en .qif

pas de soucis pour reprendre le code que je met ici... c'est fait pour
mais je pense qu'une liste de liste et des compréhensions voire un dico serait plus simple à maintenir

pour la progress bar, ce serait plutôt une class voire un module complet dédié à la conversion et donc à sa progression car, pour le moment, tu as laissé traîné les print() qui doivent te servir à justement suivre la progression de la conversion...

de mon coté, je me restreins à tkinter mais je te mettrai le code que je suis en train d'écrire pour cet exercice...

à suivre...

Hors ligne

#11 Le 20/01/2019, à 20:59

toitoinebzh

Re : Csv2Qif - Convertir les fichiers .csv de Boursorama/N26 en .qif

nouvelles corrections,
j'ai pris en compte tes suggestions pour la généralisation du code pour plusieurs banques (utilisations de dictionnaire,, écriture des boucles, ...)
légère réorganisation du code pour améliorer la lisibilité,
par contre, je n'ai pas touché au try/except et à la porgressbar

Hors ligne

#12 Le 06/12/2019, à 19:08

toitoinebzh

Re : Csv2Qif - Convertir les fichiers .csv de Boursorama/N26 en .qif

petite update ces derniers jours, je viens de constater que Boursorama a changé le format de ces fichiers .csv

Hors ligne

#13 Le 10/01/2020, à 20:57

toitoinebzh

Re : Csv2Qif - Convertir les fichiers .csv de Boursorama/N26 en .qif

Mise à jour du 10/01/2020

Ajout du support des banques

  • Crédit Mutuel de Bretagne

  • Crédit Agricole du Morbihan

Hors ligne