2026-03-18 16:20:09 +01:00
|
|
|
"""
|
|
|
|
|
DragonBank - Backend API
|
|
|
|
|
========================
|
2026-03-27 17:52:41 +01:00
|
|
|
Point d'entree de l'API REST DragonBank.
|
|
|
|
|
|
|
|
|
|
Ce fichier ne contient que les routes Flask.
|
|
|
|
|
Toute la logique est deleguee aux classes metier (Services) :
|
|
|
|
|
|
|
|
|
|
config.py — Constantes et parametres
|
|
|
|
|
database.py — Connexion et serialisation
|
|
|
|
|
auth.py — JWT et protection des routes
|
|
|
|
|
validators.py — Validation des donnees entrantes
|
|
|
|
|
services/
|
|
|
|
|
auth_service.py - Inscription et connexion
|
|
|
|
|
utilisateur_service.py - Profil utilisateur
|
|
|
|
|
compte_service.py - Gestion des comptes
|
|
|
|
|
beneficiaire_service.py- Gestion des beneficiaires
|
|
|
|
|
transaction_service.py - Virements et historique
|
|
|
|
|
stats_service.py - Statistiques tableau de bord
|
|
|
|
|
models/
|
|
|
|
|
simulateur.py — Logique calcul interets composes
|
|
|
|
|
|
|
|
|
|
Version : 3.0 (Refactoring Service Layer)
|
2026-03-18 16:20:09 +01:00
|
|
|
"""
|
|
|
|
|
|
2026-03-27 17:52:41 +01:00
|
|
|
import logging
|
|
|
|
|
from datetime import datetime, timezone
|
2026-03-18 16:20:09 +01:00
|
|
|
|
|
|
|
|
from flask import Flask, request, jsonify
|
|
|
|
|
from flask_cors import CORS
|
|
|
|
|
|
2026-03-27 17:52:41 +01:00
|
|
|
from config import CLE_SECRETE
|
|
|
|
|
from database import creer_connexion
|
|
|
|
|
from auth import token_requis
|
|
|
|
|
from validators import valider_parametres_simulateur
|
|
|
|
|
|
|
|
|
|
from services.auth_service import AuthService
|
|
|
|
|
from services.utilisateur_service import UtilisateurService
|
|
|
|
|
from services.compte_service import CompteService
|
|
|
|
|
from services.beneficiaire_service import BeneficiaireService
|
|
|
|
|
from services.transaction_service import TransactionService
|
|
|
|
|
from services.stats_service import StatsService
|
|
|
|
|
from models.simulateur import Simulateur
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# ============================================================
|
|
|
|
|
# INITIALISATION
|
|
|
|
|
# ============================================================
|
|
|
|
|
|
2026-03-18 16:20:09 +01:00
|
|
|
app = Flask(__name__)
|
|
|
|
|
CORS(app)
|
2026-03-27 17:52:41 +01:00
|
|
|
app.config['SECRET_KEY'] = CLE_SECRETE
|
2026-03-18 16:20:09 +01:00
|
|
|
|
2026-03-27 17:52:41 +01:00
|
|
|
logging.basicConfig(
|
|
|
|
|
level=logging.INFO,
|
|
|
|
|
format='%(asctime)s [%(levelname)s] %(name)s - %(message)s',
|
|
|
|
|
datefmt='%Y-%m-%d %H:%M:%S'
|
|
|
|
|
)
|
|
|
|
|
journaliseur = logging.getLogger('dragonbank')
|
2026-03-18 16:20:09 +01:00
|
|
|
|
2026-03-27 17:52:41 +01:00
|
|
|
# Instances des services (sans etat, reutilisables)
|
|
|
|
|
auth_service = AuthService()
|
|
|
|
|
utilisateur_service = UtilisateurService()
|
|
|
|
|
compte_service = CompteService()
|
|
|
|
|
beneficiaire_service = BeneficiaireService()
|
|
|
|
|
transaction_service = TransactionService()
|
|
|
|
|
stats_service = StatsService()
|
|
|
|
|
simulateur = Simulateur()
|
2026-03-18 16:20:09 +01:00
|
|
|
|
|
|
|
|
|
2026-03-27 17:52:41 +01:00
|
|
|
# ============================================================
|
|
|
|
|
# SANTE
|
|
|
|
|
# ============================================================
|
2026-03-18 16:20:09 +01:00
|
|
|
|
|
|
|
|
@app.route('/api/health', methods=['GET'])
|
2026-03-27 17:52:41 +01:00
|
|
|
def verification_sante():
|
|
|
|
|
"""Healthcheck pour Docker et load balancers."""
|
2026-03-18 16:20:09 +01:00
|
|
|
try:
|
2026-03-27 17:52:41 +01:00
|
|
|
conn = creer_connexion()
|
|
|
|
|
conn.cursor().execute('SELECT 1')
|
2026-03-18 16:20:09 +01:00
|
|
|
conn.close()
|
|
|
|
|
return jsonify({
|
2026-03-27 17:52:41 +01:00
|
|
|
'status': 'healthy',
|
|
|
|
|
'service': 'DragonBank Backend API',
|
|
|
|
|
'version': '3.0',
|
|
|
|
|
'database': 'connected',
|
2026-03-18 16:20:09 +01:00
|
|
|
'timestamp': datetime.now(timezone.utc).isoformat()
|
|
|
|
|
}), 200
|
|
|
|
|
except Exception as e:
|
2026-03-27 17:52:41 +01:00
|
|
|
journaliseur.error("Health check echoue : %s", str(e))
|
|
|
|
|
return jsonify({'status': 'unhealthy', 'error': str(e)}), 500
|
2026-03-18 16:20:09 +01:00
|
|
|
|
|
|
|
|
|
2026-03-27 17:52:41 +01:00
|
|
|
# ============================================================
|
|
|
|
|
# AUTHENTIFICATION
|
|
|
|
|
# ============================================================
|
|
|
|
|
|
2026-03-18 16:20:09 +01:00
|
|
|
@app.route('/api/auth/register', methods=['POST'])
|
2026-03-27 17:52:41 +01:00
|
|
|
def inscription():
|
|
|
|
|
"""Cree un nouveau compte utilisateur avec un compte courant de bienvenue."""
|
|
|
|
|
donnees = request.get_json(silent=True)
|
2026-03-18 16:20:09 +01:00
|
|
|
try:
|
2026-03-27 17:52:41 +01:00
|
|
|
resultat = auth_service.inscrire(donnees)
|
|
|
|
|
return jsonify(resultat), 201
|
|
|
|
|
except ValueError as e:
|
|
|
|
|
return jsonify({'error': str(e)}), 400
|
2026-03-18 16:20:09 +01:00
|
|
|
except Exception as e:
|
2026-03-27 17:52:41 +01:00
|
|
|
journaliseur.error("Erreur inscription : %s", str(e))
|
|
|
|
|
return jsonify({'error': "Erreur interne lors de l'inscription"}), 500
|
2026-03-18 16:20:09 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
@app.route('/api/auth/login', methods=['POST'])
|
2026-03-27 17:52:41 +01:00
|
|
|
def connexion_utilisateur():
|
|
|
|
|
"""Authentifie un utilisateur et retourne un token JWT."""
|
|
|
|
|
donnees = request.get_json(silent=True)
|
2026-03-18 16:20:09 +01:00
|
|
|
try:
|
2026-03-27 17:52:41 +01:00
|
|
|
resultat = auth_service.connecter(donnees)
|
|
|
|
|
return jsonify(resultat), 200
|
|
|
|
|
except ValueError as e:
|
|
|
|
|
return jsonify({'error': str(e)}), 400
|
|
|
|
|
except PermissionError as e:
|
|
|
|
|
return jsonify({'error': str(e)}), 403
|
2026-03-18 16:20:09 +01:00
|
|
|
except Exception as e:
|
2026-03-27 17:52:41 +01:00
|
|
|
journaliseur.error("Erreur connexion : %s", str(e))
|
|
|
|
|
return jsonify({'error': 'Erreur interne lors de la connexion'}), 500
|
2026-03-18 16:20:09 +01:00
|
|
|
|
|
|
|
|
|
2026-03-27 17:52:41 +01:00
|
|
|
# ============================================================
|
|
|
|
|
# PROFIL UTILISATEUR
|
|
|
|
|
# ============================================================
|
|
|
|
|
|
2026-03-18 16:20:09 +01:00
|
|
|
@app.route('/api/user/profile', methods=['GET'])
|
2026-03-27 17:52:41 +01:00
|
|
|
@token_requis
|
|
|
|
|
def obtenir_profil(id_utilisateur_courant):
|
|
|
|
|
"""Retourne le profil de l'utilisateur connecte."""
|
2026-03-18 16:20:09 +01:00
|
|
|
try:
|
2026-03-27 17:52:41 +01:00
|
|
|
utilisateur = utilisateur_service.obtenir_profil(id_utilisateur_courant)
|
|
|
|
|
return jsonify({'user': utilisateur}), 200
|
|
|
|
|
except ValueError as e:
|
|
|
|
|
return jsonify({'error': str(e)}), 404
|
|
|
|
|
except Exception as e:
|
|
|
|
|
return jsonify({'error': 'Erreur interne lors de la recuperation du profil'}), 500
|
2026-03-18 16:20:09 +01:00
|
|
|
|
|
|
|
|
|
2026-03-27 17:52:41 +01:00
|
|
|
@app.route('/api/user/profile', methods=['PUT'])
|
|
|
|
|
@token_requis
|
|
|
|
|
def modifier_profil(id_utilisateur_courant):
|
|
|
|
|
"""Met a jour les champs non sensibles du profil."""
|
|
|
|
|
donnees = request.get_json(silent=True)
|
|
|
|
|
try:
|
|
|
|
|
mis_a_jour = utilisateur_service.modifier_profil(id_utilisateur_courant, donnees)
|
|
|
|
|
return jsonify({'message': 'Profil mis a jour', 'user': mis_a_jour}), 200
|
|
|
|
|
except ValueError as e:
|
|
|
|
|
return jsonify({'error': str(e)}), 400
|
|
|
|
|
except Exception as e:
|
|
|
|
|
return jsonify({'error': 'Erreur lors de la mise a jour'}), 500
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@app.route('/api/user/security/password', methods=['PUT'])
|
|
|
|
|
@token_requis
|
|
|
|
|
def modifier_mot_de_passe(id_utilisateur_courant):
|
|
|
|
|
"""Met a jour le mot de passe utilisateur (necessite le mot de passe actuel)."""
|
|
|
|
|
donnees = request.get_json(silent=True)
|
|
|
|
|
try:
|
|
|
|
|
utilisateur_service.changer_mot_de_passe(id_utilisateur_courant, donnees)
|
|
|
|
|
return jsonify({'message': 'Mot de passe mis a jour avec succes'}), 200
|
|
|
|
|
except ValueError as e:
|
|
|
|
|
return jsonify({'error': str(e)}), 400
|
|
|
|
|
except PermissionError as e:
|
|
|
|
|
return jsonify({'error': str(e)}), 403
|
|
|
|
|
except Exception as e:
|
|
|
|
|
journaliseur.error("Erreur modification mot de passe : %s", str(e))
|
|
|
|
|
return jsonify({'error': 'Erreur interne'}), 500
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@app.route('/api/user/security/email', methods=['PUT'])
|
|
|
|
|
@token_requis
|
|
|
|
|
def modifier_email(id_utilisateur_courant):
|
|
|
|
|
"""Met a jour l'adresse email (necessite le mot de passe actuel)."""
|
|
|
|
|
donnees = request.get_json(silent=True)
|
|
|
|
|
try:
|
|
|
|
|
utilisateur_service.changer_email(id_utilisateur_courant, donnees)
|
|
|
|
|
return jsonify({'message': 'Email mis a jour avec succes. Veuillez vous reconnecter avec votre nouvel email.'}), 200
|
|
|
|
|
except ValueError as e:
|
|
|
|
|
return jsonify({'error': str(e)}), 400
|
|
|
|
|
except PermissionError as e:
|
|
|
|
|
return jsonify({'error': str(e)}), 403
|
|
|
|
|
except Exception as e:
|
|
|
|
|
journaliseur.error("Erreur modification email : %s", str(e))
|
|
|
|
|
return jsonify({'error': 'Erreur interne'}), 500
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# ============================================================
|
|
|
|
|
# COMPTES BANCAIRES
|
|
|
|
|
# ============================================================
|
|
|
|
|
|
2026-03-18 16:20:09 +01:00
|
|
|
@app.route('/api/accounts', methods=['GET'])
|
2026-03-27 17:52:41 +01:00
|
|
|
@token_requis
|
|
|
|
|
def obtenir_comptes(id_utilisateur_courant):
|
|
|
|
|
"""Retourne la liste des comptes actifs."""
|
2026-03-18 16:20:09 +01:00
|
|
|
try:
|
2026-03-27 17:52:41 +01:00
|
|
|
comptes = compte_service.obtenir_comptes(id_utilisateur_courant)
|
|
|
|
|
return jsonify({'accounts': comptes}), 200
|
|
|
|
|
except Exception:
|
|
|
|
|
return jsonify({'error': 'Erreur lors de la recuperation des comptes'}), 500
|
2026-03-18 16:20:09 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
@app.route('/api/accounts', methods=['POST'])
|
2026-03-27 17:52:41 +01:00
|
|
|
@token_requis
|
|
|
|
|
def ouvrir_compte(id_utilisateur_courant):
|
|
|
|
|
"""Ouvre un nouveau compte bancaire."""
|
|
|
|
|
donnees = request.get_json(silent=True)
|
2026-03-18 16:20:09 +01:00
|
|
|
try:
|
2026-03-27 17:52:41 +01:00
|
|
|
compte = compte_service.ouvrir_compte(id_utilisateur_courant, donnees)
|
|
|
|
|
return jsonify({'message': 'Compte ouvert avec succes', 'account': compte}), 201
|
|
|
|
|
except ValueError as e:
|
|
|
|
|
return jsonify({'error': str(e)}), 400 if 'invalide' in str(e) else 409
|
2026-03-18 16:20:09 +01:00
|
|
|
except Exception as e:
|
2026-03-27 17:52:41 +01:00
|
|
|
journaliseur.error("Erreur ouverture compte : %s", str(e))
|
|
|
|
|
return jsonify({'error': "Erreur lors de l'ouverture du compte"}), 500
|
2026-03-18 16:20:09 +01:00
|
|
|
|
|
|
|
|
|
2026-03-27 17:52:41 +01:00
|
|
|
@app.route('/api/accounts/<id_compte>', methods=['GET'])
|
|
|
|
|
@token_requis
|
|
|
|
|
def obtenir_detail_compte(id_utilisateur_courant, id_compte):
|
|
|
|
|
"""Retourne les details d'un compte specifique."""
|
2026-03-18 16:20:09 +01:00
|
|
|
try:
|
2026-03-27 17:52:41 +01:00
|
|
|
compte = compte_service.obtenir_detail_compte(id_utilisateur_courant, id_compte)
|
|
|
|
|
return jsonify({'account': compte}), 200
|
|
|
|
|
except ValueError as e:
|
|
|
|
|
return jsonify({'error': str(e)}), 404
|
|
|
|
|
except Exception:
|
|
|
|
|
return jsonify({'error': 'Erreur serveur'}), 500
|
2026-03-18 16:20:09 +01:00
|
|
|
|
|
|
|
|
|
2026-03-27 17:52:41 +01:00
|
|
|
@app.route('/api/accounts/<id_compte>/history', methods=['GET'])
|
|
|
|
|
@token_requis
|
|
|
|
|
def historique_solde(id_utilisateur_courant, id_compte):
|
|
|
|
|
"""Retourne l'evolution du solde pour le graphique."""
|
|
|
|
|
try:
|
|
|
|
|
historique = compte_service.historique_solde(id_utilisateur_courant, id_compte)
|
|
|
|
|
return jsonify(historique), 200
|
|
|
|
|
except ValueError as e:
|
|
|
|
|
return jsonify({'error': str(e)}), 404
|
|
|
|
|
except Exception:
|
|
|
|
|
return jsonify({'error': 'Erreur serveur'}), 500
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# ============================================================
|
|
|
|
|
# BENEFICIAIRES
|
|
|
|
|
# ============================================================
|
|
|
|
|
|
2026-03-18 16:20:09 +01:00
|
|
|
@app.route('/api/beneficiaries', methods=['GET'])
|
2026-03-27 17:52:41 +01:00
|
|
|
@token_requis
|
|
|
|
|
def obtenir_beneficiaires(id_utilisateur_courant):
|
|
|
|
|
"""Retourne la liste des beneficiaires."""
|
2026-03-18 16:20:09 +01:00
|
|
|
try:
|
2026-03-27 17:52:41 +01:00
|
|
|
beneficiaires = beneficiaire_service.obtenir_beneficiaires(id_utilisateur_courant)
|
|
|
|
|
return jsonify({'beneficiaries': beneficiaires}), 200
|
|
|
|
|
except Exception:
|
|
|
|
|
return jsonify({'error': 'Erreur serveur'}), 500
|
2026-03-18 16:20:09 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
@app.route('/api/beneficiaries', methods=['POST'])
|
2026-03-27 17:52:41 +01:00
|
|
|
@token_requis
|
|
|
|
|
def ajouter_beneficiaire(id_utilisateur_courant):
|
|
|
|
|
"""Ajoute un nouveau beneficiaire."""
|
|
|
|
|
donnees = request.get_json(silent=True)
|
2026-03-18 16:20:09 +01:00
|
|
|
try:
|
2026-03-27 17:52:41 +01:00
|
|
|
beneficiaire = beneficiaire_service.ajouter_beneficiaire(id_utilisateur_courant, donnees)
|
|
|
|
|
return jsonify({'message': 'Beneficiaire ajoute', 'beneficiary': beneficiaire}), 201
|
|
|
|
|
except ValueError as e:
|
|
|
|
|
return jsonify({'error': str(e)}), 400 if 'vous-meme' in str(e) else 409
|
2026-03-18 16:20:09 +01:00
|
|
|
except Exception as e:
|
2026-03-27 17:52:41 +01:00
|
|
|
return jsonify({'error': "Erreur lors de l'ajout"}), 500
|
2026-03-18 16:20:09 +01:00
|
|
|
|
|
|
|
|
|
2026-03-27 17:52:41 +01:00
|
|
|
@app.route('/api/beneficiaries/<id_beneficiaire>', methods=['DELETE'])
|
|
|
|
|
@token_requis
|
|
|
|
|
def supprimer_beneficiaire(id_utilisateur_courant, id_beneficiaire):
|
|
|
|
|
"""Supprime un beneficiaire."""
|
2026-03-18 16:20:09 +01:00
|
|
|
try:
|
2026-03-27 17:52:41 +01:00
|
|
|
beneficiaire_service.supprimer_beneficiaire(id_utilisateur_courant, id_beneficiaire)
|
|
|
|
|
return jsonify({'message': 'Beneficiaire supprime'}), 200
|
|
|
|
|
except ValueError as e:
|
|
|
|
|
return jsonify({'error': str(e)}), 404
|
2026-03-18 16:20:09 +01:00
|
|
|
except Exception as e:
|
2026-03-27 17:52:41 +01:00
|
|
|
return jsonify({'error': 'Erreur lors de la suppression'}), 500
|
2026-03-18 16:20:09 +01:00
|
|
|
|
|
|
|
|
|
2026-03-27 17:52:41 +01:00
|
|
|
# ============================================================
|
|
|
|
|
# VIREMENTS
|
|
|
|
|
# ============================================================
|
|
|
|
|
|
2026-03-18 16:20:09 +01:00
|
|
|
@app.route('/api/transfers/internal', methods=['POST'])
|
2026-03-27 17:52:41 +01:00
|
|
|
@token_requis
|
|
|
|
|
def virement_interne(id_utilisateur_courant):
|
|
|
|
|
"""Virement entre les propres comptes de l'utilisateur."""
|
|
|
|
|
donnees = request.get_json(silent=True)
|
2026-03-18 16:20:09 +01:00
|
|
|
try:
|
2026-03-27 17:52:41 +01:00
|
|
|
transaction = transaction_service.virement_interne(id_utilisateur_courant, donnees)
|
|
|
|
|
return jsonify({'message': 'Virement effectue', 'transaction': transaction}), 200
|
|
|
|
|
except ValueError as e:
|
|
|
|
|
return jsonify({'error': str(e)}), 400 if 'introuvable' not in str(e) else 404
|
2026-03-18 16:20:09 +01:00
|
|
|
except Exception as e:
|
2026-03-27 17:52:41 +01:00
|
|
|
journaliseur.error("Erreur virement interne : %s", str(e))
|
|
|
|
|
return jsonify({'error': 'Erreur lors du virement'}), 500
|
2026-03-18 16:20:09 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
@app.route('/api/transfers/person', methods=['POST'])
|
2026-03-27 17:52:41 +01:00
|
|
|
@token_requis
|
|
|
|
|
def virement_beneficiaire(id_utilisateur_courant):
|
|
|
|
|
"""Virement vers un beneficiaire enregistre."""
|
|
|
|
|
donnees = request.get_json(silent=True)
|
2026-03-18 16:20:09 +01:00
|
|
|
try:
|
2026-03-27 17:52:41 +01:00
|
|
|
transaction = transaction_service.virement_beneficiaire(id_utilisateur_courant, donnees)
|
|
|
|
|
return jsonify({'message': 'Virement effectue', 'transaction': transaction}), 200
|
|
|
|
|
except ValueError as e:
|
|
|
|
|
return jsonify({'error': str(e)}), 400 if 'introuvable' not in str(e) else 404
|
2026-03-18 16:20:09 +01:00
|
|
|
except Exception as e:
|
2026-03-27 17:52:41 +01:00
|
|
|
return jsonify({'error': 'Erreur lors du virement'}), 500
|
2026-03-18 16:20:09 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
@app.route('/api/transfers/external', methods=['POST'])
|
2026-03-27 17:52:41 +01:00
|
|
|
@token_requis
|
|
|
|
|
def virement_externe(id_utilisateur_courant):
|
|
|
|
|
"""Virement simule depuis/vers une banque externe."""
|
|
|
|
|
donnees = request.get_json(silent=True)
|
2026-03-18 16:20:09 +01:00
|
|
|
try:
|
2026-03-27 17:52:41 +01:00
|
|
|
transaction, direction = transaction_service.virement_externe(id_utilisateur_courant, donnees)
|
|
|
|
|
sens = 'sortant' if direction == 'outgoing' else 'entrant'
|
2026-03-18 16:20:09 +01:00
|
|
|
return jsonify({
|
2026-03-27 17:52:41 +01:00
|
|
|
'message': 'Virement externe ' + sens + ' effectue',
|
|
|
|
|
'transaction': transaction
|
2026-03-18 16:20:09 +01:00
|
|
|
}), 200
|
2026-03-27 17:52:41 +01:00
|
|
|
except ValueError as e:
|
|
|
|
|
return jsonify({'error': str(e)}), 400 if 'introuvable' not in str(e) else 404
|
2026-03-18 16:20:09 +01:00
|
|
|
except Exception as e:
|
2026-03-27 17:52:41 +01:00
|
|
|
return jsonify({'error': 'Erreur lors du virement externe'}), 500
|
2026-03-18 16:20:09 +01:00
|
|
|
|
|
|
|
|
|
2026-03-27 17:52:41 +01:00
|
|
|
# ============================================================
|
|
|
|
|
# TRANSACTIONS
|
|
|
|
|
# ============================================================
|
|
|
|
|
|
2026-03-18 16:20:09 +01:00
|
|
|
@app.route('/api/transactions', methods=['GET'])
|
2026-03-27 17:52:41 +01:00
|
|
|
@token_requis
|
|
|
|
|
def obtenir_transactions(id_utilisateur_courant):
|
|
|
|
|
"""Historique des transactions avec filtres optionnels."""
|
|
|
|
|
id_compte = request.args.get('account_id')
|
|
|
|
|
type_transaction = request.args.get('type')
|
|
|
|
|
limite = request.args.get('limit', 50, type=int)
|
|
|
|
|
|
2026-03-18 16:20:09 +01:00
|
|
|
try:
|
2026-03-27 17:52:41 +01:00
|
|
|
transactions = transaction_service.obtenir_transactions(
|
|
|
|
|
id_utilisateur_courant, id_compte, type_transaction, limite
|
|
|
|
|
)
|
|
|
|
|
return jsonify({'transactions': transactions, 'count': len(transactions)}), 200
|
|
|
|
|
except ValueError as e:
|
|
|
|
|
return jsonify({'error': str(e)}), 404
|
|
|
|
|
except Exception:
|
|
|
|
|
return jsonify({'error': 'Erreur serveur'}), 500
|
2026-03-18 16:20:09 +01:00
|
|
|
|
|
|
|
|
|
2026-03-27 17:52:41 +01:00
|
|
|
@app.route('/api/transactions/export', methods=['GET'])
|
|
|
|
|
@token_requis
|
|
|
|
|
def exporter_csv(id_utilisateur_courant):
|
|
|
|
|
"""Export CSV de l'historique des transactions."""
|
|
|
|
|
id_compte = request.args.get('account_id')
|
|
|
|
|
try:
|
|
|
|
|
csv_response = transaction_service.exporter_csv(id_utilisateur_courant, id_compte)
|
|
|
|
|
return csv_response
|
|
|
|
|
except ValueError as e:
|
|
|
|
|
return jsonify({'error': str(e)}), 404
|
|
|
|
|
except Exception:
|
|
|
|
|
return jsonify({'error': 'Erreur serveur'}), 500
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# ============================================================
|
|
|
|
|
# STATISTIQUES
|
|
|
|
|
# ============================================================
|
|
|
|
|
|
2026-03-18 16:20:09 +01:00
|
|
|
@app.route('/api/stats', methods=['GET'])
|
2026-03-27 17:52:41 +01:00
|
|
|
@token_requis
|
|
|
|
|
def obtenir_statistiques(id_utilisateur_courant):
|
|
|
|
|
"""Tableau de bord statistique de l'utilisateur."""
|
2026-03-18 16:20:09 +01:00
|
|
|
try:
|
2026-03-27 17:52:41 +01:00
|
|
|
stats = stats_service.obtenir_statistiques(id_utilisateur_courant)
|
|
|
|
|
return jsonify({'stats': stats}), 200
|
|
|
|
|
except Exception:
|
|
|
|
|
return jsonify({'error': 'Erreur serveur'}), 500
|
2026-03-18 16:20:09 +01:00
|
|
|
|
|
|
|
|
|
2026-03-27 17:52:41 +01:00
|
|
|
# ============================================================
|
|
|
|
|
# SIMULATEUR D'EPARGNE
|
|
|
|
|
# ============================================================
|
|
|
|
|
|
|
|
|
|
@app.route('/api/simulator', methods=['POST'])
|
|
|
|
|
@token_requis
|
|
|
|
|
def simuler_epargne(id_utilisateur_courant):
|
|
|
|
|
"""Simulation de croissance d'epargne par interets composes."""
|
|
|
|
|
donnees = request.get_json(silent=True)
|
|
|
|
|
try:
|
|
|
|
|
if not donnees:
|
|
|
|
|
raise ValueError("Donnees JSON manquantes")
|
|
|
|
|
|
|
|
|
|
capital = float(donnees.get('capital_initial', 0))
|
|
|
|
|
taux = float(donnees.get('taux_annuel', 0))
|
|
|
|
|
duree = int(donnees.get('duree_annees', 1))
|
|
|
|
|
versement = float(donnees.get('versement_mensuel', 0))
|
|
|
|
|
|
|
|
|
|
valider_parametres_simulateur(capital, taux, duree, versement)
|
|
|
|
|
|
|
|
|
|
resultat = simulateur.simuler(capital, taux, duree, versement)
|
|
|
|
|
return jsonify(resultat), 200
|
|
|
|
|
|
|
|
|
|
except (TypeError, ValueError) as e:
|
|
|
|
|
return jsonify({'error': str(e)}), 400
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# ============================================================
|
|
|
|
|
# GESTION DES ERREURS HTTP
|
|
|
|
|
# ============================================================
|
|
|
|
|
|
|
|
|
|
@app.errorhandler(404)
|
|
|
|
|
def erreur_404(e):
|
|
|
|
|
return jsonify({'error': 'Route introuvable'}), 404
|
|
|
|
|
|
|
|
|
|
@app.errorhandler(405)
|
|
|
|
|
def erreur_405(e):
|
|
|
|
|
return jsonify({'error': 'Methode HTTP non autorisee'}), 405
|
|
|
|
|
|
|
|
|
|
@app.errorhandler(500)
|
|
|
|
|
def erreur_500(e):
|
|
|
|
|
journaliseur.error("Erreur interne : %s", str(e))
|
|
|
|
|
return jsonify({'error': 'Erreur interne du serveur'}), 500
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# ============================================================
|
|
|
|
|
# POINT D'ENTREE
|
|
|
|
|
# ============================================================
|
|
|
|
|
|
2026-03-18 16:20:09 +01:00
|
|
|
if __name__ == '__main__':
|
2026-03-27 17:52:41 +01:00
|
|
|
from config import URL_BASE_DE_DONNEES
|
|
|
|
|
print("DragonBank Backend API v3.0 - demarrage...")
|
|
|
|
|
print("Base : " + (URL_BASE_DE_DONNEES.split('@')[1] if '@' in URL_BASE_DE_DONNEES else 'configuree'))
|
|
|
|
|
app.run(host='0.0.0.0', port=5000, debug=False)
|