# ------------------------------------------------------------------------------------------- # Création de FEC augmenté # v1.0 12/2023 # Plus d'infos : https://www.auditsi.eu/?p=12196 # ------------------------------------------------------------------------------------------- # Importation des bibliothèques externes import os import sys import easygui import pandas as pd # Identification du séparateur de champs (tabulation ou pipe) def recherche_separateur(fichier_FEC): separateur="" # Vérification si le fichier est un FEC if os.path.isfile(fichier_FEC) and fichier_FEC.lower().endswith('.txt'): try: # Lecture de la première ligne du fichier pour obtenir le séparateur with open(fichier_FEC, 'r') as f: premiere_ligne = f.readline().strip() # Séparateur tabulation (\t) if premiere_ligne.startswith("JournalCode\tJournalLib"): separateur="\t" # Séparateur pipe (|) elif premiere_ligne.startswith("JournalCode|JournalLib"): separateur="|" # Sinon Erreur (E) else: separateur="E" return separateur except Exception: return "E" # Création du champ MtTVA def calcul_champ_mttva(row): if row['CompteNum'].startswith(('44562', '44566', '4457', '44586', '44587')): return row['Solde'] return 0 # Création du champ BaseTVA def calcul_champ_basetva(row): if row['CompteNum'].startswith(('6', '7', '20', '21', '23')): if not row['CompteNum'].startswith(('603', '68', '78')): return row['Solde'] return 0 # Message d'introduction print("-" * 85) print("Création de FEC augmenté v1.0 (12/2023)") print("Plus d'infos : https://www.auditsi.eu/?p=12196") print() print("Ce programme ajoute les champs suivants au FEC sélectionné :") print(f"\t- Solde (débit-crédit)") print(f"\t- MtTVA : compte identifié comme un compte de TVA") print(f"\t- BaseTVA : compte identifié comme une base TVA") print(f"\t- EcritureTxTVA : taux de TVA de l'écriture comptable (reporté sur chaque ligne de l'écriture)") print(f"\t- AAAAMM : champ date type 2023/12") print(f"\t- Cpte1, Cpte2, Cpte3, Cpte4, Cpte5, Cpte6 : racines de compte") print("-" * 85) print() # Chemin d'accès par défaut chemin_Appli = os.getcwd() chemin_FEC = chemin_Appli # Boîte de dialogue de sélection d'un fichier FEC fichier_FEC = easygui.fileopenbox(title="Sélectionner le fichier FEC à traiter", default=chemin_FEC, filetypes=["*.txt"]) # Aucun FEC sélectionné (Echap ou Annuler) if not fichier_FEC: print("Aucun FEC sélectionné.") sys.exit() # Identification du séparateur de champs de données separateur=recherche_separateur(fichier_FEC) if separateur=="E": print("FEC non reconnu.") sys.exit() # Chargement du FEC fec = pd.read_csv(fichier_FEC, delimiter=separateur, encoding='ISO-8859-1', dtype=str) # Conversion des champs Debit et Credit en numérique (remplacement de la décimale , par un .) fec['Debit'] = pd.to_numeric(fec['Debit'].str.replace(',', '.'), errors='coerce') fec['Credit'] = pd.to_numeric(fec['Credit'].str.replace(',', '.'), errors='coerce') # Création du champ Solde = Debit - Credit fec['Solde'] = fec['Debit'] - fec['Credit'] # Conversion des champs EcritureDate, ValidDate et DateLet au format JJ/MM/AAAA fec['EcritureDate'] = pd.to_datetime(fec['EcritureDate'], format='%Y%m%d').dt.strftime('%d/%m/%Y') fec['ValidDate'] = pd.to_datetime(fec['ValidDate'], format='%Y%m%d').dt.strftime('%d/%m/%Y') fec['DateLet'] = pd.to_datetime(fec['DateLet'], format='%Y%m%d').dt.strftime('%d/%m/%Y') # Création du champ AAAAMM (AAAA/MM) fec['AAAAMM'] = pd.to_datetime(fec['EcritureDate'], format='%d/%m/%Y').dt.strftime('%Y/%m') # Création des champs MtTVA et BaseTVA à l'aide des fonctions ad hoc fec['MtTVA'] = fec.apply(calcul_champ_mttva, axis=1) fec['BaseTVA'] = fec.apply(calcul_champ_basetva, axis=1) # Création des champs EcritureTxTVA (taux de TVA) # --- Regroupement par EcritureNum et calcul de la somme de BaseTVA et MtTVA regroupement_donnees = fec.groupby('EcritureNum')[['BaseTVA', 'MtTVA']].sum().reset_index() # --- Pour chaque EcritureNum, calcul du Taux de TVA (si BaseTVA nulle, le résultat renvoyé est 'nan') regroupement_donnees['EcritureTxTVA'] = regroupement_donnees['MtTVA'] / regroupement_donnees['BaseTVA'] # --- Fusion des résultats du regroupement dans le FEC d'origine en fonction de EcritureNum fec = pd.merge(fec, regroupement_donnees[['EcritureNum', 'EcritureTxTVA']], on='EcritureNum', how='left') # --- Champ EcritureTxTVA arrondi à quatre décimales fec['EcritureTxTVA'] = fec['EcritureTxTVA'].round(4) # Création des champs racine de compte Cpte1..Cpte6 fec['Cpte6'] = fec['CompteNum'].str[:6].astype(int) fec['Cpte5'] = fec['CompteNum'].str[:5].astype(int) fec['Cpte4'] = fec['CompteNum'].str[:4].astype(int) fec['Cpte3'] = fec['CompteNum'].str[:3].astype(int) fec['Cpte2'] = fec['CompteNum'].str[:2].astype(int) fec['Cpte1'] = fec['CompteNum'].str[0].astype(int) # Remplacement des points par des virgules dans les champs de montant (Debit, Credit, Solde, BaseTVA, MtTVA, TxTVA...) fec[['Debit', 'Credit', 'Solde', 'MtTVA', 'BaseTVA', 'EcritureTxTVA']] = fec[['Debit', 'Credit', 'Solde', 'MtTVA', 'BaseTVA', 'EcritureTxTVA']].apply(lambda x: x.astype(str).str.replace('.', ',')) # Renommage des champs CompAuxNum et CompAuxLib en CompteAuxNum et CompteAuxLib fec.rename(columns={'CompAuxNum': 'CompteAuxNum', 'CompAuxLib': 'CompteAuxLib', 'Debit': 'Débit', 'Credit': 'Crédit', 'PieceRef': 'PièceRéf', 'PieceDate': 'PièceDate'}, inplace=True) # Modification de l'ordre des champs de données columns_order = ['EcritureNum', 'JournalCode', 'JournalLib', 'EcritureDate', 'CompteNum', 'CompteLib', 'CompteAuxNum', 'CompteAuxLib', 'EcritureLib', 'Débit', 'Crédit', 'Solde', 'PièceRéf', 'PièceDate', 'ValidDate', 'EcritureLet', 'DateLet', 'MtTVA', 'BaseTVA', 'EcritureTxTVA', 'AAAAMM', 'Cpte6', 'Cpte5', 'Cpte4', 'Cpte3', 'Cpte2', 'Cpte1'] # --- Si le champ CodeEtabt existe, le mettre en dernier if 'CodeEtabt' in fec.columns: columns_order.remove('CodeEtabt') columns_order.append('CodeEtabt') # --- Mise en oeuvre de l'ordre indiqué fec = fec[columns_order] # Récupération du nom du FEC sans l'arborescence nom_FEC = os.path.basename(fichier_FEC) # Création du nom de FEC augmenté fichier_FEC_augmente = chemin_Appli + '\\' + "FEC augmenté " + nom_FEC # Si le FEC existe déjà -> arrêt du programme if os.path.isfile(fichier_FEC_augmente): print(f"Le fichier {fichier_FEC_augmente} existe déjà. Traitement annulé") sys.exit() # Sinon : enregistrement du FEC modifié dans un nouveau fichier texte else: print(f"Le fichier {fichier_FEC_augmente} a été généré avec succès.") fec.to_csv(fichier_FEC_augmente, sep=separateur, index=False, encoding='ISO-8859-1') # Message final print() print("Traitement terminé.")