Projet d’automatisation de rapports avec Excel & VBA & Oracle
Réalisation:Haral Valcourt
Objectif
L'objectif de ce projet est de mettre en place une solution automatisée de reporting permettant de générer, mettre en forme et présenter dynamiquement des rapports et tableaux de bord basés sur des données issues d’une base de données Oracle 19C. L’objectif principal est de démontrer une maîtrise avancée du langage VBA, ainsi qu’une capacité à automatiser un processus de reporting de bout en bout.
Technologies et langages utilisés
- Microsoft Excel.
- VBA (Visual Basic for Applications) pour l’automatisation.
- SQL pour la récupération de données Oracle.
- SQL Developer pour tester certaines requêtes SQL
- Oracle Database (via OraOLEDB.Oracle).
- ADO pour la gestion des connexions et des recordsets.
Fonctionnalités
- Connexion directe à la base Oracle via ADO
- Exécution dynamique de requêtes SQL avec paramètres, regroupements et pivot SQL.
- Création automatique de graphiques
- Personnalisation graphique poussée
- Structuration des dashboards modulaires, avec séparation entre graphiques simples et graphiques avancés
- Interface visuelle entièrement générée par VBA
- Génération de rapports automatisés
- Mise en place de filtre au niveau des rapports
- Conception UI/UX dans Excel
- Export automatique des rapports en PDF
- Envoi automatique des rapports par e-mail
- Protection de l’interface
Résultats
- Diminution drastique du temps de production des rapports (de plusieurs heures à quelques secondes).
- Homogénéité des visuels.
- Démonstration concrète d’une maîtrise professionnelle du VBA, de l’intégration SQL-Oracle, et de la conception UI/UX dans Excel.
Etapes clés
- Connexion à la base de données
- Présentation du jeu de données
- Création des utilisateurs
- Création des tableaux de bord et des rapports
- Exportation des rapports au format pdf
- Diffusion des rapports par email
- Securisation du projet
Connexion à la base de données
Dans ce projet, l’accès aux données de la base Oracle est réalisé grâce à ADO (ActiveX Data Objects), une technologie Microsoft permettant d’interagir avec des bases de données relationnelles depuis VBA. Cette méthode permet de se connecter directement depuis un fichier Excel à une base Oracle distante, sans avoir à passer par un export manuel des données.
L’objet principal utilisé est ADODB.Connection, qui sert à ouvrir une session entre Excel et Oracle. Il est configuré avec une chaîne de connexion (Connection String) qui contient les paramètres essentiels : le nom du fournisseur (Provider), l’adresse du serveur, le SID ou le nom de service, ainsi que les identifiants d’accès (utilisateur et mot de passe).
Script VBA de connexion à la base de données
```vba
Public Function GetConnexionOracle() As ADODB.Connection
Dim wb As Workbook
Dim CONN_STRING, PasswordStocke As String
Set wb = ThisWorkbook
PasswordStocke = wb.Sheets("FeuilParam").Range("A4").Value
CONN_STRING = "Provider=OraOLEDB.Oracle;Data Source=ORCLPDB;User ID=system;Password=" & PasswordStocke & ";"
On Error GoTo ErreurConnexion
' Vérifier si la connexion existe déjà et est active
If Not connOracle Is Nothing Then
If connOracle.State = adStateOpen Then
Set GetConnexionOracle = connOracle
Exit Function
End If
End If
' Créer une nouvelle connexion
Set connOracle = New ADODB.Connection
connOracle.ConnectionString = CONN_STRING
connOracle.Open
Set GetConnexionOracle = connOracle
Exit Function
ErreurConnexion:
MsgBox "Erreur de connexion Oracle : " & Err.Description, vbCritical
Set GetConnexionOracle = Nothing
If Not connOracle Is Nothing Then
Set connOracle = Nothing
End If
End Function
```
Présentation du jeu de données
Script VBA de récupération de la structure de la table Compte
```vba
Sub ListerColonnes()
Dim conn As Object
Dim rs As Object
Dim ws As Worksheet
Dim i As Long
' Connexion Oracle
Set conn = GetConnexionOracle()
If conn Is Nothing Then
MsgBox "Impossible d'établir la connexion à Oracle.", vbCritical
Exit Sub
End If
Set rs = CreateObject("ADODB.Recordset")
' Requête SQL
Dim sql As String
sql = "SELECT COLUMN_NAME, DATA_TYPE, DATA_LENGTH FROM ALL_TAB_COLUMNS WHERE TABLE_NAME = 'COMPTE' AND OWNER = 'SYSTEM' ORDER BY COLUMN_ID"
rs.Open sql, conn, 1, 1
' Préparation de la feuille Excel
Set ws = ThisWorkbook.Sheets.Add
ws.Name = "StructureCompte"
ws.Cells.ClearContents
' En-têtes
ws.Cells(1, 1).Value = "Nom de Colonne"
ws.Cells(1, 2).Value = "Type de Donnée"
ws.Cells(1, 3).Value = "Taille"
' Remplissage
i = 2
Do While Not rs.EOF
ws.Cells(i, 1).Value = rs.Fields("COLUMN_NAME").Value
ws.Cells(i, 2).Value = rs.Fields("DATA_TYPE").Value
ws.Cells(i, 3).Value = rs.Fields("DATA_LENGTH").Value
i = i + 1
rs.MoveNext
Loop
' Mise en forme simple
ws.Columns("A:C").AutoFit
With Range("A1:C1")
.Interior.Color = RGB(142, 154, 175)
End With
' Nettoyage
rs.Close
conn.Close
Set rs = Nothing
Set conn = Nothing
MsgBox "Structure de la table COMPTE importée avec succès.", vbInformation
End Sub
```

Création des utilisateurs
Résumé du processus de création des utilisateurs
Le processus de création d'un utilisateur de l'application est le suivant:
- Inscription dans la table applicative (utilisateur)
- Création de l’utilisateur Oracle
- Attribution des privilèges Oracle
- Encodage et stockage du mot de passe
Interface de création des utilisateurs
Script VBA de création des utilisateurs
```vba
Private Sub btnAjouterUtilisateur_Click()
Call ConnexionOraclePDB
If conn Is Nothing Then
MsgBox "Connexion échouée à la base de données.", vbCritical
Exit Sub
End If
Dim nomUtilisateur As String
Dim motDePasse As String
Dim motDePasseChiffre As String
Dim profil As String
nomUtilisateur = Trim(Me.txtNomUtilisateur.Text)
motDePasse = Trim(Me.txtMotDePasse.Text)
profil = Me.cmbProfil.Value
If nomUtilisateur = "" Or motDePasse = "" Or profil = "" Then
MsgBox "Veuillez remplir tous les champs.", vbExclamation
Exit Sub
End If
' Chiffrement simple (base64)
motDePasseChiffre = EncodeBase64(motDePasse)
' Insertion dans la table utilisateur
Dim cmd As ADODB.Command
Set cmd = New ADODB.Command
With cmd
.ActiveConnection = conn
.CommandText = "INSERT INTO utilisateur (id_utilisateur, nom_utilisateur, mot_de_passe, profil) " & _
"VALUES (seq_utilisateur.NEXTVAL, :nom, :pwd, :profil)"
.CommandType = adCmdText
.Parameters.Append .CreateParameter(":nom", adVarChar, adParamInput, 50, nomUtilisateur)
.Parameters.Append .CreateParameter(":pwd", adVarChar, adParamInput, 50, motDePasseChiffre)
.Parameters.Append .CreateParameter(":profil", adVarChar, adParamInput, 20, profil)
.Execute
End With
' Création de l'utilisateur Oracle
Dim sqlCreateUser As String
sqlCreateUser = "CREATE USER " & nomUtilisateur & " IDENTIFIED BY " & motDePasse
conn.Execute sqlCreateUser
' Attribution de privileges
conn.Execute "GRANT CONNECT TO " & nomUtilisateur
conn.Execute "GRANT CREATE SESSION TO " & nomUtilisateur
MsgBox "Utilisateur ajouté avec succès.", vbInformation
Unload Me
End Sub
```
Vérification de la création de l'utilisateur à travers Oracle SQL Developer
Connexion de l'utilisateur
Script VBA de connexion des utilisateurs
```vba
Private Sub btnConnexion_Click()
Dim cmd As ADODB.Command
Dim rs As ADODB.Recordset
Dim login As String, mdp As String, profil As String
Dim sql As String
' Récupérer les identifiants depuis les champs du formulaire
login = Trim(Me.txtUser.Text)
mdp = Trim(Me.txtPass.Text)
mdp = EncodeBase64(mdp)
' Appel à la procédure de connexion dans Module1
ConnexionOraclePDB
If conn Is Nothing Or conn.State <> adStateOpen Then
MsgBox "Connexion échouée. Vérifiez vos paramètres.", vbCritical
Exit Sub
End If
' Requête sécurisée
sql = "SELECT PROFIL FROM UTILISATEUR WHERE NOM_UTILISATEUR = ? AND MOT_DE_PASSE = ?"
Set cmd = New ADODB.Command
With cmd
.ActiveConnection = conn
.CommandText = sql
.CommandType = adCmdText
.Parameters.Append .CreateParameter("login", adVarChar, adParamInput, 50, login)
.Parameters.Append .CreateParameter("mdp", adVarChar, adParamInput, 50, mdp)
End With
Set rs = cmd.Execute
If Not rs.EOF Then
profil = LCase(Trim(rs.Fields("PROFIL").Value))
MsgBox "Bienvenue " & login & " (" & profil & ")", vbInformation
AfficherFeuillesSelonProfil profil
Me.Hide
Else
MsgBox "Login ou mot de passe incorrect.", vbExclamation
End If
' Nettoyage
If Not rs Is Nothing Then rs.Close
If Not conn Is Nothing Then conn.Close
Set rs = Nothing
Set cmd = Nothing
Set conn = Nothing
End Sub
```
Présentation de l'application
L'application est composée des pages suivantes:
- La page d'accueil
- La page d'administration
- La page DashboardSimple
- La page DashboardAvance
- Les pages de certains rapports
- Les rapports générés sauvegardés.
La page d'accueil
Elle est constituée principlament du formulaire de connexion à l'application en fonction du profil de l'utilisateur
La page d'administration
Cette page, accessible uniquement à l'administrateur, permet la réalisation des tâches suivantes
- Création ou rafraîchissement automatique du Dashboard avec visuels simples
- Création ou rafraîchissement automatique du Dashboard avec visuels avancés
- Activation de la protection des rapports et des dashboards
- Désactivation de la protection des rapports et des dashboards
- Création des utilisateurs de l'application
La page DashboardSimple
Accessible aux utilisateurs de profil "Opérateur", elle est constituée
- D'un bloc de KPIs: Solde total, Nombre de comptes, % Compte Courant, % Compte épargne, % Dépôt à terme, % Prêt à terme
- D'un bloc de visuels simples
- Répartition des comptes par statut
- Répartition du montant total par type
- Répartition des comptes par succursale
- Répartition des comptes par sexe
- Pourcentage du montant total par zone
- Répartition des comptes par tranche d'âge
- D'une zone réservée aux rapports regroupés par:
- Activité mensuelle
- Segmentation client
- Répartition géographique
- Typologie des comptes
La page DashboardAvance
Accessible aux utilisateurs de profil "Manager", elle est constituée
- D'un bloc de visuels avancés
- Répartition du solde et des comptes par zone
- Répartition du montant moyen par zone et sexe
- Montant et nombre de comptes par succursale
- Nombre de comptes actifs par statut et tranche d'âge
- Evolution du solde par année et type de compte
- Top 5 grands clients par type de compte
- D'une zone réservée
- A d'autres rapports
- A l'exportation en PDF
- A la transmission par email
Rapports crées dans le workbook
Analyse des performances par succursale et produit
Analyse des succursale avec filtre
Rapport d'analyse filtré pour une succursale
Les rapports générés sauvegardés hors du workbook
Comptes ouverts par trimestre
Scripte VBA du rapport des comptes ouverts par trimestre
```vba
Sub Rapport_OuvertsParTrimestre()
Dim conn As Object, rs As Object
Dim wbTemp As Workbook, ws As Worksheet
Dim chartObj1 As ChartObject, chartObj2 As ChartObject
Dim i As Long, lastRow As Long
Dim tblRange As Range
Dim paletteColors As Variant
Dim dossierBase As String, dossierRapport As String, nomFichier As String, cheminComplet As String
' Palette personnalisée (hexadécimale convertie en RGB)
paletteColors = Array(HexToRGBColor("8e9aaf"), HexToRGBColor("cbc0d3"), HexToRGBColor("efd3d7"), _
HexToRGBColor("feeafa"), HexToRGBColor("dee2ff"), HexToRGBColor("b8bedd"))
' Connexion Oracle
Set conn = GetConnexionOracle()
If conn Is Nothing Then
MsgBox "Impossible d'établir la connexion à Oracle.", vbCritical
Exit Sub
End If
Set rs = CreateObject("ADODB.Recordset")
rs.Open "SELECT TO_CHAR(DATEOPEN, 'YYYY') || ' T' || TO_CHAR(DATEOPEN, 'Q') AS TRIMESTRE, COUNT(*) AS NOMBRE " & _
"FROM compte GROUP BY TO_CHAR(DATEOPEN, 'YYYY'), TO_CHAR(DATEOPEN, 'Q') ORDER BY 1", conn
' Créer un nouveau classeur temporaire
Set wbTemp = Workbooks.Add(xlWBATWorksheet) ' classeur avec 1 feuille
' Renommer la feuille active
Set ws = wbTemp.Sheets(1)
ws.Name = "Rapport Trimestriel"
' --- REMPLISSAGE DES DONNÉES ---
' Titre
With ws.Range("A1:W1")
.Merge
.Value = "Rapport des Comptes Ouverts par Trimestre"
.Font.Size = 16
.Font.Bold = True
.HorizontalAlignment = xlCenter
.Interior.Color = paletteColors(0)
End With
' En-têtes
ws.Range("A3").Value = "Trimestre"
ws.Range("B3").Value = "Nombre"
ws.Range("A3:B3").Font.Bold = True
ws.Range("A3:B3").Interior.Color = paletteColors(1)
' Données
i = 4
Do While Not rs.EOF
ws.Cells(i, 1).Value = rs.Fields(0).Value
ws.Cells(i, 2).Value = rs.Fields(1).Value
rs.MoveNext
i = i + 1
Loop
lastRow = i - 1
' Format tableau et couleurs
Set tblRange = ws.Range("A3:B" & lastRow)
tblRange.Borders.LineStyle = xlContinuous
For i = 4 To lastRow
ws.Range("A" & i & ":B" & i).Interior.Color = paletteColors((i - 4) Mod UBound(paletteColors) + 1)
Next i
' Graphique en barres verticales
Set chartObj1 = ws.ChartObjects.Add(Left:=ws.Range("C3").Left, Width:=500, Top:=ws.Range("C3").Top, Height:=300)
With chartObj1.Chart
.SetSourceData Source:=tblRange
.ChartType = xlColumnClustered
.HasLegend = False
.HasTitle = True
.ChartTitle.Text = "Comptes Ouverts par Trimestre"
.ChartTitle.Font.Size = 12
.ChartTitle.Font.Bold = True
.Axes(xlCategory).HasTitle = False
.Axes(xlValue).HasTitle = False
On Error Resume Next
.Axes(xlCategory).MajorGridlines.Delete
.Axes(xlValue).MajorGridlines.Delete
On Error GoTo 0
.Axes(xlCategory).TickLabels.Orientation = xlUpward
On Error Resume Next
.Axes(xlValue).Delete
On Error GoTo 0
' Couleurs personnalisées
For i = 1 To .SeriesCollection(1).Points.Count
.SeriesCollection(1).Points(i).Format.Fill.ForeColor.RGB = paletteColors((i - 1) Mod UBound(paletteColors) + 1)
Next i
.SeriesCollection(1).ApplyDataLabels
End With
' Graphique en courbe
Set chartObj2 = ws.ChartObjects.Add(Left:=chartObj1.Left + chartObj1.Width + 5, Width:=500, Top:=chartObj1.Top, Height:=300)
With chartObj2.Chart
.SetSourceData Source:=tblRange
.ChartType = xlLine
.HasTitle = True
.ChartTitle.Text = "Comptes Ouverts par Trimestre"
.ChartTitle.Font.Size = 12
.ChartTitle.Font.Bold = True
.HasLegend = False
.Axes(xlCategory).HasTitle = False
.Axes(xlCategory).TickLabels.Font.Size = 10
On Error Resume Next
.Axes(xlValue).Delete
.Axes(xlCategory).MajorGridlines.Delete
.Axes(xlValue).MajorGridlines.Delete
On Error GoTo 0
.Axes(xlCategory).TickLabels.Orientation = xlUpward
With .SeriesCollection(1).Format.Line
.ForeColor.RGB = paletteColors(3)
.Weight = 3.5
End With
.SeriesCollection(1).ApplyDataLabels
End With
Call ProtegerToutesLesFeuillesDansClasseur(wbTemp, "tonMotDePasse")
' --- Sauvegarde dans dossier RapportExcel ---
dossierBase = ThisWorkbook.Path
If Right(dossierBase, 1) <> "\" Then dossierBase = dossierBase & "\"
dossierRapport = dossierBase & "RapportExcel\"
If Dir(dossierRapport, vbDirectory) = "" Then MkDir dossierRapport
nomFichier = "Rapport_Trimestriel_" & Format(Date, "yyyymmdd") & ".xlsx"
cheminComplet = dossierRapport & nomFichier
' Supprimer fichier existant si présent
If Dir(cheminComplet) <> "" Then Kill cheminComplet
' Sauvegarder le classeur temporaire
Application.DisplayAlerts = False
wbTemp.SaveAs Filename:=cheminComplet, FileFormat:=xlOpenXMLWorkbook
Application.DisplayAlerts = True
wbTemp.Close SaveChanges:=False
' Nettoyage
If Not rs Is Nothing Then
If rs.State = 1 Then rs.Close
Set rs = Nothing
End If
If Not conn Is Nothing Then
If conn.State = 1 Then conn.Close
Set conn = Nothing
End If
MsgBox "Rapport trimestriel généré et sauvegardé dans " & cheminComplet, vbInformation
End Sub
```
Répartition du solde par année

Script VBA du rapport de répartition du solde par année
```vba
Sub RapportVolumeAnnuel()
Dim conn As Object, rs As Object
Dim wsTemp As Worksheet
Dim sql As String
Dim i As Integer
Dim tblStartCell As Range
Dim chartObj As ChartObject, chartObjPie As ChartObject
Dim lastRow As Long
Dim couleurs As Variant
Dim wbTemp As Workbook
Dim cheminTemp As String
Dim dossierBase As String, dossierRapport As String, nomFichier As String, cheminComplet As String
' Connexion Oracle
Set conn = GetConnexionOracle()
If conn Is Nothing Then
MsgBox "Impossible d'établir la connexion à Oracle.", vbCritical
Exit Sub
End If
Set rs = CreateObject("ADODB.Recordset")
' Requête SQL : Volume annuel
sql = "SELECT TO_CHAR(DATEOPEN, 'YYYY') AS ANNEE, TRUNC(SUM(BALANCE)/1000000, 2) AS VOLUME " & _
"FROM compte WHERE DATEOPEN IS NOT NULL GROUP BY TO_CHAR(DATEOPEN, 'YYYY') ORDER BY 1"
' Exécuter la requête
Set rs = CreateObject("ADODB.Recordset")
rs.Open sql, conn, 1, 1 ' adOpenKeyset, adLockReadOnly
' Créer un nouveau classeur temporaire
Set wbTemp = Workbooks.Add(xlWBATWorksheet)
Set wsTemp = wbTemp.Sheets(1)
wsTemp.Name = "VolumeAnnuel"
' Point d’insertion du tableau
Set tblStartCell = wsTemp.Range("E3")
' Entêtes
For i = 1 To rs.Fields.Count
tblStartCell.Cells(1, i).Value = rs.Fields(i - 1).Name
Next i
' Données
tblStartCell.Offset(1, 0).CopyFromRecordset rs
' AutoFit colonnes
lastRow = wsTemp.Cells(wsTemp.Rows.Count, tblStartCell.Column).End(xlUp).Row
wsTemp.Range(tblStartCell, wsTemp.Cells(lastRow, tblStartCell.Column + 1)).Columns.AutoFit
' Palette de couleurs personnalisée
couleurs = Array("8e9aaf", "cbc0d3", "efd3d7", "feeafa", "dee2ff")
' Créer le graphique en barres
Set chartObj = wsTemp.ChartObjects.Add( _
Left:=wsTemp.Range("A1").Left, _
Width:=455, _
Top:=wsTemp.Cells(lastRow + 2, 1).Top, Height:=250)
With chartObj.Chart
.ChartType = xlColumnClustered
.SetSourceData Source:=wsTemp.Range(tblStartCell, wsTemp.Cells(lastRow, tblStartCell.Column + 1))
.HasTitle = True
.ChartTitle.Text = "Volume annuel (en M)"
.ChartTitle.Font.Size = 12
.ChartTitle.Font.Bold = True
' Afficher les valeurs sur les barres
.SeriesCollection(1).ApplyDataLabels
' Supprimer la grille principale
On Error Resume Next
.Axes(xlValue).MajorGridlines.Delete
.Axes(xlValue).Delete ' supprime axe Y
On Error GoTo 0
' Supprimer titre axe catégories et légende
.Axes(xlCategory).HasTitle = False
.Legend.Delete
' Appliquer les couleurs personnalisées
Dim idx As Integer
For i = 1 To .SeriesCollection(1).Points.Count
idx = ((i - 1) Mod UBound(couleurs) + 1)
With .SeriesCollection(1).Points(i).Format.Fill.ForeColor
.RGB = RGB( _
CLng("&H" & mid(couleurs(idx - 1), 1, 2)), _
CLng("&H" & mid(couleurs(idx - 1), 3, 2)), _
CLng("&H" & mid(couleurs(idx - 1), 5, 2)) _
)
End With
Next i
End With
' Créer le graphique en secteurs
Set chartObjPie = wsTemp.ChartObjects.Add( _
Left:=chartObj.Left, _
Width:=chartObj.Width, _
Top:=chartObj.Top + chartObj.Height + 10, _
Height:=chartObj.Height)
With chartObjPie.Chart
.ChartType = xlPie
.SetSourceData Source:=wsTemp.Range(tblStartCell.Offset(1, 0), wsTemp.Cells(lastRow, tblStartCell.Column + 1))
.HasTitle = True
.ChartTitle.Text = "Répartition du volume par année"
.ChartTitle.Font.Size = 12
.ChartTitle.Font.Bold = True
.HasLegend = True
' Afficher valeurs et pourcentages
.ApplyDataLabels
Dim pt As Point
For Each pt In .SeriesCollection(1).Points
pt.DataLabel.ShowPercentage = True
pt.DataLabel.ShowValue = False
Next pt
' Appliquer couleurs personnalisées
For i = 1 To .SeriesCollection(1).Points.Count
.SeriesCollection(1).Points(i).Format.Fill.ForeColor.RGB = RGB( _
CLng("&H" & mid(couleurs(i - 1), 1, 2)), _
CLng("&H" & mid(couleurs(i - 1), 3, 2)), _
CLng("&H" & mid(couleurs(i - 1), 5, 2)) _
)
Next i
End With
' Formatage du tableau de données
With wsTemp.Range("E3:F3")
.Font.Name = "Calibri"
.Font.Size = 11
.Borders.LineStyle = xlContinuous
.Interior.Color = RGB(225, 225, 240)
.HorizontalAlignment = xlCenter
End With
With wsTemp.Range("E4:F" & lastRow)
.Font.Name = "Calibri"
.Font.Size = 11
.Borders.LineStyle = xlContinuous
.Interior.Color = RGB(242, 242, 242)
.HorizontalAlignment = xlCenter
End With
' Formatage du titre
With wsTemp.Range("A1:J1")
.Merge
.Value = "Répartition du solde par année"
.Font.Bold = True
.Font.Size = 16
.Font.Name = "Calibri"
.Font.Color = RGB(0, 0, 0)
.Interior.Color = RGB(225, 225, 240)
.HorizontalAlignment = xlCenter
.VerticalAlignment = xlCenter
.Borders.LineStyle = xlNone
.RowHeight = 20
End With
With wsTemp
.Rows("2:8").RowHeight = 12
End With
'Protéger les feuilles du classeur principal
Call ProtegerToutesLesFeuillesDansClasseur(wbTemp, "tonMotDePasse")
' --- Sauvegarde dans dossier RapportExcel ---
dossierBase = ThisWorkbook.Path
If Right(dossierBase, 1) <> "\" Then dossierBase = dossierBase & "\"
dossierRapport = dossierBase & "RapportExcel\"
If Dir(dossierRapport, vbDirectory) = "" Then MkDir dossierRapport
nomFichier = "Rapport_VolumeAnnuel_" & Format(Date, "yyyymmdd") & ".xlsx"
cheminComplet = dossierRapport & nomFichier
' Supprimer fichier existant si présent
If Dir(cheminComplet) <> "" Then Kill cheminComplet
' Sauvegarder le classeur temporaire
Application.DisplayAlerts = False
wbTemp.SaveAs Filename:=cheminComplet, FileFormat:=xlOpenXMLWorkbook
Application.DisplayAlerts = True
wbTemp.Close SaveChanges:=False
' Nettoyage objets
rs.Close
conn.Close
Set rs = Nothing
Set conn = Nothing
MsgBox "Rapport généré avec succès", vbInformation
End Sub
```
Répartition des comptes et du solde moyen par statut

Script VBA du rapport de répartition des comptes et du solde moyen par statut
```vba
Sub RapportCompteStatut()
Dim conn As Object, rs As Object
Dim ws As Worksheet
Dim chartObj, chartObj1, chartObj2 As ChartObject, s As Series
Dim startRow As Long, startCol As Long, lastRow As Long
Dim dataRange As Range, i As Long
Dim req1 As String, req2 As String
Dim rs1 As Object, rs2 As Object
Dim couleurs As Variant
Dim dossierBase As String
Dim dossierRapport As String
Dim nomFichier As String
Dim cheminComplet As String
Dim wbTemp As Workbook
' Nouveau classeur
Set wbTemp = Workbooks.Add(xlWBATWorksheet)
Set ws = wbTemp.Worksheets(1)
ws.Name = "CompteStatut"
With Worksheets("CompteStatut").PageSetup
.Orientation = xlLandscape
.LeftMargin = Application.InchesToPoints(0.5)
.RightMargin = Application.InchesToPoints(0.5)
.TopMargin = Application.InchesToPoints(0.75)
.BottomMargin = Application.InchesToPoints(0.75)
.HeaderMargin = Application.InchesToPoints(0.3)
.FooterMargin = Application.InchesToPoints(0.3)
End With
' Connexion Oracle
Set conn = GetConnexionOracle()
If conn Is Nothing Then
MsgBox "Impossible d'établir la connexion à Oracle.", vbCritical
Exit Sub
End If
'Requête 1 - STATUT ET SOLDE MOYEN
req1 = "SELECT STATUT_COMPTE, ROUND(AVG(BALANCE), 2) AS SOLDE_MOYEN FROM COMPTE GROUP BY STATUT_COMPTE ORDER BY SOLDE_MOYEN DESC"
Set rs1 = CreateObject("ADODB.Recordset")
rs1.Open req1, conn, 3, 1
' Requête 2 - STATUT_COMPTE ET NOMBRE DE COMPTE
req2 = "SELECT STATUT_COMPTE, COUNT(NOCOMPTE) AS NOMBRE_COMPTE FROM COMPTE GROUP BY STATUT_COMPTE ORDER BY NOMBRE_COMPTE DESC"
Set rs2 = CreateObject("ADODB.Recordset")
rs2.Open req2, conn, 3, 1
' Création du graphique 1
startRow = 3
startCol = 3
For i = 0 To rs1.Fields.Count - 1
ws.Cells(startRow, startCol + i).Value = rs1.Fields(i).Name
Next i
ws.Cells(startRow + 1, startCol).CopyFromRecordset rs1
lastRow = ws.Cells(ws.Rows.Count, startCol).End(xlUp).Row
Set dataRange = ws.Range(ws.Cells(startRow, startCol), ws.Cells(lastRow, startCol + 1))
' Créer le graphique
Set chartObj1 = ws.ChartObjects.Add(Left:=5, Top:=110, Width:=300, Height:=300)
With chartObj1.Chart
.ChartType = xlColumnClustered
.SetSourceData dataRange
.HasTitle = True
.ChartTitle.Text = "Solde moyen par statut"
.HasLegend = False
.ChartGroups(1).GapWidth = 30
End With
With chartObj1.Chart
.HasTitle = True
.ChartTitle.Font.Size = 12
.ChartTitle.Font.Bold = True
.ChartTitle.Font.Color = RGB(0, 0, 128)
End With
chartObj1.Chart.Axes(xlValue).Delete
chartObj1.Chart.Axes(xlValue).MajorGridlines.Format.Line.Visible = msoFalse
chartObj1.Chart.Axes(xlCategory).MajorGridlines.Delete '
' Ajouter les labels
With chartObj1.Chart.SeriesCollection(1)
.ApplyDataLabels
With .DataLabels
.ShowValue = True
.Position = xlLabelPositionInsideEnd
End With
End With
Set s = chartObj1.Chart.SeriesCollection(1)
For i = 1 To s.Points.Count
Select Case LCase(Trim(s.XValues(i)))
Case "ouvert": s.Points(i).Format.Fill.ForeColor.RGB = RGB(142, 154, 175)
Case "dormant": s.Points(i).Format.Fill.ForeColor.RGB = RGB(203, 192, 211)
Case "no débit": s.Points(i).Format.Fill.ForeColor.RGB = RGB(239, 211, 215)
Case "fermé": s.Points(i).Format.Fill.ForeColor.RGB = RGB(254, 234, 250)
Case Else: s.Points(i).Format.Fill.ForeColor.RGB = RGB(222, 226, 255)
End Select
Next i
' Création du graphique 2
startRow = 3
startCol = 10
For i = 0 To rs2.Fields.Count - 1
ws.Cells(startRow, startCol + i).Value = rs2.Fields(i).Name
Next i
ws.Cells(startRow + 1, startCol).CopyFromRecordset rs2
lastRow = ws.Cells(ws.Rows.Count, startCol).End(xlUp).Row
Set dataRange = ws.Range(ws.Cells(startRow, startCol), ws.Cells(lastRow, startCol + 1))
' Créer le graphique2
Set chartObj2 = ws.ChartObjects.Add(Left:=350, Top:=110, Width:=300, Height:=300)
With chartObj2.Chart
.ChartType = xlColumnClustered
.SetSourceData dataRange
.HasTitle = True
.ChartTitle.Text = "Nombre de compte par statut"
.HasLegend = False
.ChartGroups(1).GapWidth = 30
End With
With chartObj2.Chart
.HasTitle = True
.ChartTitle.Font.Size = 12
.ChartTitle.Font.Bold = True
.ChartTitle.Font.Color = RGB(0, 0, 128)
End With
chartObj2.Chart.Axes(xlValue).Delete
chartObj2.Chart.Axes(xlValue).MajorGridlines.Format.Line.Visible = msoFalse
chartObj2.Chart.Axes(xlCategory).MajorGridlines.Delete '
' Ajouter les labels et couleurs
With chartObj2.Chart.SeriesCollection(1)
.ApplyDataLabels
With .DataLabels
.ShowValue = True
.Position = xlLabelPositionInsideEnd
End With
End With
Set s = chartObj2.Chart.SeriesCollection(1)
For i = 1 To s.Points.Count
Select Case LCase(Trim(s.XValues(i)))
Case "ouvert": s.Points(i).Format.Fill.ForeColor.RGB = RGB(142, 154, 175)
Case "dormant": s.Points(i).Format.Fill.ForeColor.RGB = RGB(203, 192, 211)
Case "no débit": s.Points(i).Format.Fill.ForeColor.RGB = RGB(239, 211, 215)
Case "fermé": s.Points(i).Format.Fill.ForeColor.RGB = RGB(254, 234, 250)
Case Else: s.Points(i).Format.Fill.ForeColor.RGB = RGB(222, 226, 255)
End Select
Next i
' Formatage du tableau de données
With Range("C3:D3")
.Font.Name = "Calibri"
.Font.Size = 11
.Borders.LineStyle = xlContinuous
.Interior.Color = MaPalette("lavande")
.HorizontalAlignment = xlCenter
.Columns.AutoFit
End With
With Range("C4:D7")
.Font.Name = "Calibri"
.Font.Size = 11
.Borders.LineStyle = xlContinuous
.Interior.Color = RGB(242, 242, 242)
.HorizontalAlignment = xlCenter
End With
With Range("J3:K3")
.Font.Name = "Calibri"
.Font.Size = 11
.Borders.LineStyle = xlContinuous
.Interior.Color = MaPalette("lavande")
.HorizontalAlignment = xlCenter
.Columns.AutoFit
End With
With Range("J4:K7")
.Font.Name = "Calibri"
.Font.Size = 11
.Borders.LineStyle = xlContinuous
.Interior.Color = RGB(242, 242, 242)
.HorizontalAlignment = xlCenter
End With
'Formatage du titre
With ws.Range("A1:N1")
.Merge
.Value = "Répartition des comptes et du solde moyen par statut"
.Font.Bold = True
.Font.Size = 16
.Font.Name = "Calibri"
.Font.Color = RGB(0, 0, 0)
.Interior.Color = MaPalette("lavande")
.HorizontalAlignment = xlCenter
.VerticalAlignment = xlCenter
.Borders.LineStyle = xlNone
.RowHeight = 20
End With
'Protéger les feuilles du classeur principal
Call ProtegerToutesLesFeuillesDansClasseur(wbTemp, "tonMotDePasse")
' --- Sauvegarde dans dossier RapportExcel ---
dossierBase = ThisWorkbook.Path
If Right(dossierBase, 1) <> "\" Then dossierBase = dossierBase & "\"
dossierRapport = dossierBase & "RapportExcel\"
If Dir(dossierRapport, vbDirectory) = "" Then MkDir dossierRapport
nomFichier = "Rapport_CompteStatut_" & Format(Date, "yyyymmdd") & ".xlsx"
cheminComplet = dossierRapport & nomFichier
' Supprimer fichier existant si présent
If Dir(cheminComplet) <> "" Then Kill cheminComplet
' Sauvegarder le classeur temporaire
Application.DisplayAlerts = False
wbTemp.SaveAs Filename:=cheminComplet, FileFormat:=xlOpenXMLWorkbook
Application.DisplayAlerts = True
wbTemp.Close SaveChanges:=False
' Nettoyage objets
conn.Close
Set rs = Nothing
Set conn = Nothing
MsgBox "Rapport généré avec succès", vbInformation
End Sub
```
Exportation des rapports au format PDF
L'utilisateur autorisé a la possibilité de
- Sélectionner le rapport de format excel à exporter
- Exporter le rapport au format pdf.
Sélection du rapport à exporter
Ouverture du rapport exporté
Script VBA d'exportation d'un rapport excel au format pdf
```vba
Sub ExporterFichierExcelEnPDF()
Dim fd As FileDialog
Dim cheminFichierExcel As String
Dim nomFichierSansExt As String
Dim dossierPDF As String
Dim cheminFichierPDF As String
Dim wbSource As Workbook
Dim fichierOuvert As Boolean
' Boîte de dialogue pour choisir un fichier Excel
Set fd = Application.FileDialog(msoFileDialogFilePicker)
With fd
.Title = "Sélectionner le fichier Excel à exporter"
.InitialFileName = ThisWorkbook.Path & "\RapportExcel\"
.Filters.Clear
.Filters.Add "Fichiers Excel", "*.xls; *.xlsx; *.xlsm"
.AllowMultiSelect = False
If .Show <> -1 Then Exit Sub
cheminFichierExcel = .SelectedItems(1)
End With
' Extraire le nom sans extension
nomFichierSansExt = mid(Dir(cheminFichierExcel), 1, InStrRev(Dir(cheminFichierExcel), ".") - 1)
' Créer dossier RapportPDF si inexistant
dossierPDF = ThisWorkbook.Path & "\RapportPDF"
If Dir(dossierPDF, vbDirectory) = "" Then MkDir dossierPDF
cheminFichierPDF = dossierPDF & "\" & nomFichierSansExt & ".pdf"
Application.ScreenUpdating = False
Set wbSource = Workbooks.Open(cheminFichierExcel)
' Vérifier si PDF est ouvert
fichierOuvert = False
If Dir(cheminFichierPDF) <> "" Then
On Error Resume Next
Open cheminFichierPDF For Binary Access Read Write Lock Read Write As #1
If Err.Number <> 0 Then fichierOuvert = True
Close #1
On Error GoTo 0
If fichierOuvert Then
MsgBox "Le fichier PDF est déjà ouvert. Fermez-le puis recommencez.", vbExclamation
wbSource.Close SaveChanges:=False
Application.ScreenUpdating = True
Exit Sub
Else
Kill cheminFichierPDF
End If
End If
' Mise en page avant export PDF
With wbSource.Sheets(1).PageSetup
.Zoom = False
.FitToPagesWide = 1
.FitToPagesTall = 1
.LeftMargin = Application.InchesToPoints(0.5)
.RightMargin = Application.InchesToPoints(0.5)
.TopMargin = Application.InchesToPoints(0.75)
.BottomMargin = Application.InchesToPoints(0.75)
.LeftFooter = "Créé le : &D"
.RightFooter = "Page &P sur &N"
.CenterFooter = ""
End With
' Exporter la première feuille en PDF
wbSource.Sheets(1).ExportAsFixedFormat Type:=xlTypePDF, Filename:=cheminFichierPDF, Quality:=xlQualityStandard
' Ouvrir l'explorateur et sélectionner le PDF
Shell "explorer.exe /select,""" & cheminFichierPDF & """", vbNormalFocus
wbSource.Close SaveChanges:=False
Application.ScreenUpdating = True
MsgBox "Exportation en PDF réussie." & vbCrLf & cheminFichierPDF, vbInformation
End Sub
```
Transmission des rapports au format PDF par email
L'utilisateur autorisé a la possibilité de
- Retrouver le rapport pdf souhaité à travers un répertoire
- Saisir l'email du destinataire
- Expedier le rapport en attachement.
Sélection du rapport pdf à transmettre
Saisie de l'adresse e-mail du destinataire

Vérification de la reception du message
Ouverture de rapport attaché
Script VBA de la transmission par e-mail
```vba
Sub EnvoyerPDFParGmail()
Dim fichierPDF As String
Dim destinataire As String
Dim sujet As String
Dim message As String
Dim username As String
Dim motDePasse As String
' Étape 1 : Choisir le fichier PDF
fichierPDF = Application.GetOpenFilename("Fichiers PDF (*.pdf), *.pdf", , "Sélectionnez un rapport PDF")
If fichierPDF = "Faux" Then
MsgBox "Aucun fichier sélectionné.", vbExclamation
Exit Sub
End If
' Étape 2 : Paramètres de l’e-mail
destinataire = InputBox("Adresse e-mail du destinataire :", "Envoyer PDF")
If destinataire = "" Then Exit Sub
sujet = "Rapport PDF"
message = "Veuillez trouver ci-joint le rapport demandé."
' Étape 3 : Configuration CDO pour Gmail
Dim CDOmsg As Object
Dim CDOconf As Object
Dim champsConfig As Object
Set CDOmsg = CreateObject("CDO.Message")
Set CDOconf = CreateObject("CDO.Configuration")
Set champsConfig = CDOconf.Fields
With champsConfig
.Item("http://schemas.microsoft.com/cdo/configuration/sendusing") = 2
.Item("http://schemas.microsoft.com/cdo/configuration/smtpserver") = "smtp.gmail.com"
.Item("http://schemas.microsoft.com/cdo/configuration/smtpserverport") = 465
.Item("http://schemas.microsoft.com/cdo/configuration/smtpauthenticate") = 1
.Item("http://schemas.microsoft.com/cdo/configuration/sendusername") = "valcourth@gmail.com"
.Item("http://schemas.microsoft.com/cdo/configuration/sendpassword") = "*************"
.Item("http://schemas.microsoft.com/cdo/configuration/smtpusessl") = True
.Update
End With
With CDOmsg
Set .Configuration = CDOconf
.To = destinataire
.From = username
.Subject = sujet
.TextBody = message
.AddAttachment fichierPDF
.Send
End With
MsgBox "E-mail envoyé avec succès à " & destinataire, vbInformation
End Sub
```
Sécurisation de l'application
Les dispositions de sécurité sont mises en place au niveau de la base de données et au niveau d'Excel.
- Contrôle d’accès Oracle ( création des utilisateurs dédiés,affectation des rôles et profils).
- Authentification et contrôle de profil dans l’application (création des utilisateurs avec mot de passe encodé et formulaires sécurisés).
- Acces aux Dasboards et rapports enfonction du profil utilisateur
- Connexion et requêtes sécurisées (pas d’injection SQL).
- Protection du workbook (script VBA permettant de protéger/déprotéger les rapports et dashboards).
- Protection des fichiers excel et pdf générés dans des dossiers dédiés(script VBA de protéger/déprotéger les dossiers par mots de passe).
Protection des feuilles et des dossiers
La protection des feuilles et des dossiers est réalisée l'administrateur. Les étapes sont les suivantes:
- Connexion à l'application
- Ouvrir le formulaire de protection des feuilles
- Saisir le mot de passe stocké pour protection
- Lancer la protection des rapports et dossiers
Scripts VBA de protection des dashboards et feuilles de rapport
```vba
Private Sub btnProteger_Click()
Dim mdp As String
Dim feuilleParam As Worksheet
mdp = Trim(Me.txtMotDePasse.Value)
If mdp = "" Then
MsgBox "Veuillez saisir un mot de passe.", vbExclamation
Exit Sub
End If
Set feuilleParam = ThisWorkbook.Worksheets("FeuilParam")
' Déprotéger FeuilParam si protégée (ajuste le mot de passe si nécessaire)
On Error Resume Next
feuilleParam.Unprotect Password:=feuilleParam.Range("A4").Value
On Error GoTo 0
' Enregistrer le mot de passe saisi
feuilleParam.Range("A4").Value = mdp
' Reprotéger FeuilParam avec le nouveau mot de passe
feuilleParam.Protect Password:=mdp, UserInterfaceOnly:=True
' Appeler la procédure qui protège toutes les feuilles avec ce mot de passe
Call ProtegerToutesLesFeuillesAvecMdp(mdp)
MsgBox "Mot de passe enregistré et feuilles protégées.", vbInformation
Me.Hide
End Sub
```
```vba
Sub ProtegerToutesLesFeuillesAvecMdp(mdp As String)
Dim ws As Worksheet
Dim feuilleParam As Worksheet
Dim etatVisible As XlSheetVisibility
On Error Resume Next
Set feuilleParam = ThisWorkbook.Worksheets("FeuilParam")
On Error GoTo 0
If feuilleParam Is Nothing Then
MsgBox "La feuille 'FeuilParam' est introuvable.", vbCritical
Exit Sub
End If
' Sauvegarde l'état de visibilité
etatVisible = feuilleParam.Visible
' Rendre la feuille visible et non protégée
With feuilleParam
.Visible = xlSheetVisible
.Unprotect Password:=mdp ' si elle est protégée avec ce mot de passe
.Range("A4").Value = mdp
.Protect Password:=mdp, UserInterfaceOnly:=True
.Visible = etatVisible ' remet l'état d'origine
End With
' Protéger toutes les feuilles sauf FeuilParam
For Each ws In ThisWorkbook.Worksheets
If ws.Name <> "FeuilParam" Then
ws.Protect Password:=mdp, UserInterfaceOnly:=True
End If
Next ws
MsgBox "Toutes les feuilles ont été protégées.", vbInformation
End Sub
```
```vba
Sub ProtegerFeuillesClasseur(wb As Workbook, motDePasse As String)
Dim ws As Worksheet
Application.ScreenUpdating = False
On Error Resume Next
For Each ws In wb.Worksheets
With ws
If .ProtectContents Then
.Unprotect Password:=motDePasse
End If
.Protect Password:=motDePasse, _
DrawingObjects:=True, _
Contents:=True, _
Scenarios:=True, _
AllowFiltering:=True, _
AllowSorting:=True, _
AllowUsingPivotTables:=True
End With
Next ws
On Error GoTo 0
Application.ScreenUpdating = True
End Sub
```