diff --git a/app/routes.py b/app/routes.py index 49e440e..3de8bf9 100644 --- a/app/routes.py +++ b/app/routes.py @@ -1,7 +1,9 @@ -from flask import Blueprint, render_template, request, redirect, url_for, session, flash +from flask import Blueprint, render_template, request, redirect, url_for, session, flash, Response, session import time import requests import mysql.connector +import csv +import io from werkzeug.security import check_password_hash, generate_password_hash from sqlalchemy import text from app import db @@ -296,3 +298,115 @@ def gestion_societes(): return render_template('gestion_societes.html', societes=societes) +# Routes pour la gestion des imports exports des actions csv +@main.route('/gestion-import-export-actions-csv', methods=['GET']) +def gestion_import_export_actions_csv(): + if 'user_id' not in session: + return redirect(url_for('main.index')) + return render_template('gestion_import_export_actions_csv.html') + +@main.route('/export-actions-csv', methods=['GET']) +def export_actions_csv(): + if 'user_id' not in session: + return redirect(url_for('main.index')) + + try: + # Récupération de toutes les données de la table actions + query = text("SELECT id, isin, ticker, company_name, exchange, pays, currency, updated_at FROM actions") + result = db.session.execute(query) + + # Création du fichier CSV en mémoire + output = io.StringIO() + writer = csv.writer(output, delimiter=';', quoting=csv.QUOTE_MINIMAL) + + # Écriture de l'en-tête du CSV + writer.writerow(['id', 'isin', 'ticker', 'company_name', 'exchange', 'pays', 'currency', 'updated_at']) + + # Écriture des lignes + for row in result: + writer.writerow([ + row.id, + row.isin or '', + row.ticker or '', + row.company_name or '', + row.exchange or '', + row.pays or '', + row.currency or '', + row.updated_at.strftime('%Y-%m-%d %H:%M:%S') if row.updated_at else '' + ]) + + output.seek(0) + + # Envoi du fichier en téléchargement + return Response( + output.getvalue(), + mimetype="text/csv", + headers={"Content-Disposition": "attachment;filename=actions_export.csv"} + ) + except Exception as e: + flash("Erreur lors de l'exportation du fichier CSV.", "danger") + return redirect(url_for('main.gestion_import_export_actions_csv')) + +@main.route('/import-actions-csv', methods=['POST']) +def import_actions_csv(): + if 'user_id' not in session: + return redirect(url_for('main.index')) + + if 'file' not in request.files: + flash("Aucun fichier sélectionné.", "danger") + return redirect(url_for('main.gestion_import_export_actions_csv')) + + file = request.files['file'] + + if file.filename == '': + flash("Aucun fichier sélectionné.", "danger") + return redirect(url_for('main.gestion_import_export_actions_csv')) + + if file and file.filename.endswith('.csv'): + try: + stream = io.TextIOWrapper(file.stream, encoding="utf-8") + csv_reader = csv.reader(stream, delimiter=';') + + header = next(csv_reader, None) + if not header: + flash("Le fichier CSV est vide.", "danger") + return redirect(url_for('main.gestion_import_export_actions_csv')) + + count = 0 + for row in csv_reader: + # Vérifie qu'on a au moins les 6 colonnes de base + if len(row) >= 6: + isin = row[0].strip() if row[0] != '' else None + ticker = row[1].strip() if row[1] != '' else None + company_name = row[2].strip() if row[2] != '' else None + exchange = row[3].strip() if row[3] != '' else '' + pays = row[4].strip() if row[4] != '' else '' + currency = row[5].strip() if row[5] != '' else '' + + if not isin or not ticker: + continue # Ignore les lignes mal formatées + + # Insertion ou mise à jour si le code ISIN existe déjà + query = text(""" + INSERT INTO actions (isin, ticker, company_name, exchange, pays, currency, updated_at) + VALUES (:isin, :ticker, :company_name, :exchange, :pays, :currency, NOW()) + ON DUPLICATE KEY UPDATE + ticker = :ticker, company_name = :company_name, + exchange = :exchange, pays = :pays, currency = :currency, updated_at = NOW() + """) + db.session.execute(query, { + "isin": isin, "ticker": ticker, "company_name": company_name, + "exchange": exchange, "pays": pays, "currency": currency + }) + count += 1 + + db.session.commit() + flash(f"Importation réussie : {count} actions traitées.", "success") + except Exception as e: + db.session.rollback() + flash(f"Erreur lors de l'importation du fichier : {str(e)}", "danger") + + return redirect(url_for('main.gestion_import_export_actions_csv')) + else: + flash("Veuillez fournir un fichier au format .csv valide.", "warning") + return redirect(url_for('main.gestion_import_export_actions_csv')) \ No newline at end of file diff --git a/app/templates/gestion_import_export_actions_csv.html b/app/templates/gestion_import_export_actions_csv.html new file mode 100644 index 0000000..a837fe0 --- /dev/null +++ b/app/templates/gestion_import_export_actions_csv.html @@ -0,0 +1,192 @@ +{% extends "base.html" %} {% block title %}Import / Export Actions - Bolsa{% +endblock %} {% block header_title %}Gestion CSV{% endblock %} {% block content +%} +
+ +
+ {% set messages = get_flashed_messages(with_categories=true) %} {% if + messages %} {% for category, message in messages %} +
+ {{ message }} +
+ {% endfor %} {% endif %} +
+ + +
+ +
+
+

+ Import & Export - Table Actions +

+

+ Gestion des transferts de données au format CSV. +

+
+ + Retour au menu + +
+ + +
+
+

+ Procédure d'utilisation +

+ +
+
+ 1. Exportation des données : +

+ Cliquez sur le bouton Exporter en CSV pour + télécharger une copie de sauvegarde de la table + actions + sur votre poste. Le fichier contiendra l'ensemble des colonnes + actuelles (isin, ticker, company_name, exchange, pays, currency). +

+
+ +
+ 2. Importation des données : +

+ Préparez votre fichier au format CSV en respectant scrupuleusement + l'ordre et le nom des en-têtes de colonnes (les champs + id + et + updated_at + sont facultatifs et gérés automatiquement) : + isin;ticker;company_name;exchange;pays;currency. Les données d'une même ligne doivent être séparées par un + point-virgule (;) et chaque enregistrement doit + simplement se trouver sur une nouvelle ligne. Cliquez sur + Importer un CSV pour sélectionner et téléverser + votre fichier vers la base de données. +

+
+ +
+ + + + Attention : Assurez-vous de l'intégrité de vos + données avant de procéder à un import massif pour éviter toute + incohérence dans le référentiel boursier. +
+
+
+ + +
+ + + + + + Exporter + + + +
+ + +
+
+
+ + +
+ Module de maintenance sécurisé — Giraud Finance - 2026 +
+
+
+ + +{% endblock %} diff --git a/app/templates/menu.html b/app/templates/menu.html index 6b0cea8..4d3937c 100644 --- a/app/templates/menu.html +++ b/app/templates/menu.html @@ -63,7 +63,7 @@ header_title %}Tableau de bord{% endblock %} {% block content %} 7. Import/Export Actions CSV diff --git a/isin.csv b/isin.csv deleted file mode 100644 index dc14d53..0000000 --- a/isin.csv +++ /dev/null @@ -1,141 +0,0 @@ -ISIN;nom;ticker -BE0003470755g;Solvay;SOLB -BE0003853703g;Montea C.V.A.;MONT -BE0974338700g;Titan Cement;TITC -FI0009000681p;Nokia Corporation;1NOKIA -FR0000031577p;Virbac;VIRP -FR0000031775p;Vicat;VCT -FR0000033219p;Altarea;ALTA -FR0000035081p;Icade;ICAD -FR0000039091p;Robertet;RBT -FR0000039299p;Bollore;BOL -FR0000044448p;Nexans;NEX -FR0000044471p;Ramsay Generale De Sante;GDS -FR0000045072p;Credit Agricole;ACA -FR0000045601p;Robertet Ci;CBE -FR0000045619p;Robertet CDV 87;CBR -FR0000050353p;Lisi;FII -FR0000050809p;Sopra Steria Group;SOP -FR0000051070p;Maurel Et Prom;MAU -FR0000051807p;Teleperformance;TEP -FR0000052292p;Hermes;RMS -FR0000053225p;Metropole Tv;MMT -FR0000054470p;Ubisoft Entertainment;UBI -FR0000054900p;TF1;TFI -FR0000060303p;Covivio Hotels;COVH -FR0000062234p;Compagnie Odet;ODET -FR0000064271p;STEF;STF -FR0000064578p;Covivio;COV -FR0000064784p;Peugeot Invest;PEUG -FR0000065484p;Lectra;LSS -FR0000071946p;Alten;ATE -FR0000073272p;Safran;SAF -FR0000073298p;Ipsos;IPS -FR0000076952p;Artois Nom.;ARTO -FR0000077919p;JC Decaux SE;DEC -FR0000120073p;Air Liquide;AI -FR0000120172p;Carrefour;CA -FR0000120271p;TotalEnergies;TTE -FR0000120321p;L'oreal;OR -FR0000120404p;Accor Hotels;AC -FR0000120503p;Bouygues;EN -FR0000120578p;Sanofi;SAN -FR0000120628p;Axa;CS -FR0000120644p;Danone;BN -FR0000120669p;North Atlantic Energies;NAE -FR0000120693p;Pernod Ricard;RI -FR0000120859p;Imerys;NK -FR0000120966p;Bic;BB -FR0000121014p;Lvmh;MC -FR0000121121p;Eurazeo;RF -FR0000121147p;Forvia;FRVIA -FR0000121204p;Wendel Invest.;MF -FR0000121220p;Sodexo;SW -FR0000121329p;Thales;HO -FR0000121485p;Kering;KER -FR0000121667p;EssilorLuxottica;EL -FR0000121709p;Seb;SK -FR0000121964p;Klepierre;LI -FR0000121972p;Schneider Electric;SU -FR0000124141p;Veolia;VIE -FR0000124570p;OPmobility;OPM -FR0000125007p;Saint Gobain;SGO -FR0000125338p;CapGemini;CAP -FR0000125486p;Vinci;DG -FR0000127771p;Vivendi;VIV -FR0000130213p;Lagardere;MMB -FR0000130395p;Remy Cointreau;RCO -FR0000130403p;Christian Dior;CDI -FR0000130452p;Eiffage;FGR -FR0000130577p;Publicis Groupe;PUB -FR0000130809p;Societe Generale;GLE -FR0000131104p;Bnp Paribas;BNP -FR0000131757p;Eramet;ERA -FR0000131906p;Renault;RNO -FR0000133308p;Orange;ORA -FR0004024222p;Interparfums;ITP -FR0004050250p;Neurones;NRO -FR0004125920p;Amundi;AMUN -FR0005691656p;Trigano;TRI -FR0006174348p;Bureau Veritas;BVI -FR0010040865p;Gecina Nom.;GFC -FR0010208488p;Engie;ENGI -FR0010220475p;Alstom;ALO -FR0010221234p;Eutelsat;ETL -FR0010241638p;Mercialys;MERY -FR0010259150p;Ipsen;IPN -FR0010282822p;Vusion;VU -FR0010307819p;Legrand SA;LR -FR0010313833p;Arkema;AKE -FR0010340141p;Adp;ADP -FR0010411983p;Scor;SCR -FR0010451203p;Rexel;RXL -FR0010481960p;Argan;ARG -FR0010533075p;Getlink;GET -FR0010667147p;Coface;COFA -FR0010828137p;Carmila;CARM -FR0010908533p;Edenred;EDEN -FR0010929125p;ID Logistics;IDL -FR0011726835p;GTT;GTT -FR0011995588p;Voltalia;VLTSA -FR0012435121p;Elis;ELIS -FR0012757854p;Spie;SPIE -FR0013154002p;Sartorius Stedim Biotech;DIM -FR0013176526p;Valeo;FR -FR0013227113p;Soitec Silicon;SOI -FR0013230612p;Tikehau Capital;TKO -FR0013258662p;Ayvens;AYV -FR0013269123p;Rubis;RUI -FR0013280286p;Biomerieux;BIM -FR0013326246p;Unibail Rodamco Westfield;URW -FR0013357621p;Wavestone;WAVE -FR0013447729p;Verallia;VRLA -FR0013451333p;FDJ United;FDJU -FR0013506730p;Vallourec;VK -FR0014000MR3p;Eurofins Scient.;ERF -FR0014003TT8p;Dassault Systemes;DSY -FR0014004L86p;Dassault Aviation;AM -FR0014005AL0p;Antin infra Partn;ANTIN -FR0014005HJ9p;OVHCLOUD;OVH -FR001400AJ45p;Michelin;ML -FR001400J770p;Air France - KLM;AF -FR001400PFU4p;Planisware;PLNW -FR001400Q9V2p;Exosens;EXENS -FR001400SF56p;Ldc;LOUP -FR001400SU99p;Moncey Fin. Nom.;FMONC -FR001400SUB7p;Cambodge Nom.;CBDG -FR001400X2S4p;Atos;ATO -FR00140182K6p;Worldline;WLN -GB00B5ZN1N88p;Segro PLC;SGRO -LU0088087324p;SES Sa;SESG -LU0569974404n;Aperam;APAM -LU1598757687n;Arcelor Mittal;MT -MA0000011488p;Maroc Telecom;IAM -MC0000031187p;Bains Mer Monaco;BAIN -NL0000226223p;Stmicroelectronics;STMPA -NL0000235190p;Airbus;AIR -NL0006294274p;Euronext;ENX -NL0014559478p;Technip Energies;TE -NL00150001Q9p;Stellantis;STLAP -NL0015001W49p;Pluxee;PLX -US2220702037p;Coty Inc.;COTY