Bureautique & Productivité

Excel VBA : script de facturation avec numérotation auto

11 دقائق للقراءة

Automatiser la facturation sans investir dans un logiciel

Une TPE qui émet 20 à 100 factures par mois peut gagner un temps considérable avec une macro VBA qui génère automatiquement chaque facture, attribue un numéro séquentiel, l’archive et l’envoie par email. Cette solution remplace des outils à 30 euros par mois pendant plusieurs années.

Architecture du classeur

Quatre feuilles : Clients (base clients), Produits (catalogue), Facture (modèle vierge), Historique (journal des factures émises).

Feuille Facture : modèle

En-tête : nom entreprise, NINEA, adresse, téléphone, email. Encart Facturé à avec formules RECHERCHEV sur Clients. Cellule J5 : numéro de facture. Tableau de lignes : Référence, Désignation, Quantité, Prix unitaire, Total. Totaux : HT, TVA 18 pour cent, TTC.

Vue d’ensemble 1 : VBA de numérotation

Sub NouvelleFacture()
 Dim derniere As Long
 derniere = Application.WorksheetFunction.Max(Sheets("Historique").Range("A:A"))
 Sheets("Facture").Range("J5").Value = derniere + 1
 Sheets("Facture").Range("J7").Value = Date
 MsgBox "Nouvelle facture : " & derniere + 1
End Sub

Vue d’ensemble 2 : saisie client via formulaire

Insérer un bouton qui ouvre un UserForm avec liste déroulante Clients. À la sélection, les coordonnées remplissent automatiquement la facture :

Private Sub cmbClient_Change()
 Dim c As Range
 Set c = Sheets("Clients").Columns("A").Find(cmbClient.Value)
 If Not c Is Nothing Then
 Sheets("Facture").Range("B10").Value = c.Offset(0,1).Value 'Nom
 Sheets("Facture").Range("B11").Value = c.Offset(0,2).Value 'Adresse
 Sheets("Facture").Range("B12").Value = c.Offset(0,3).Value 'Ville
 Sheets("Facture").Range("B13").Value = c.Offset(0,4).Value 'NINEA
 End If
End Sub

Vue d’ensemble 3 : archivage automatique

Sub ArchiverFacture()
 Dim lig As Long
 lig = Sheets("Historique").Cells(Rows.Count, 1).End(xlUp).Row + 1
 Sheets("Historique").Cells(lig, 1).Value = Sheets("Facture").Range("J5").Value
 Sheets("Historique").Cells(lig, 2).Value = Sheets("Facture").Range("J7").Value
 Sheets("Historique").Cells(lig, 3).Value = Sheets("Facture").Range("B10").Value
 Sheets("Historique").Cells(lig, 4).Value = Sheets("Facture").Range("TotalTTC").Value
 Sheets("Historique").Cells(lig, 5).Value = "Émise"
End Sub

Vue d’ensemble 4 : export PDF

Sub ExporterPDF()
 Dim nom As String
 nom = "FA" & Sheets("Facture").Range("J5").Value & "_" & _
 Replace(Sheets("Facture").Range("B10").Value," ","_") & ".pdf"
 Sheets("Facture").ExportAsFixedFormat xlTypePDF, _
 "C:\Factures\" & nom, Quality:=xlQualityStandard
 MsgBox "Facture exportée : " & nom
End Sub

Vue d’ensemble 5 : envoi par email via Outlook

Sub EnvoyerFacture()
 Dim ol As Object, mail As Object
 Set ol = CreateObject("Outlook.Application")
 Set mail = ol.CreateItem(0)
 mail.To = Sheets("Facture").Range("EmailClient").Value
 mail.Subject = "Facture " & Sheets("Facture").Range("J5").Value
 mail.Body = "Bonjour, veuillez trouver ci-joint votre facture. Cordialement."
 mail.Attachments.Add "C:\Factures\FA" & Sheets("Facture").Range("J5").Value & ".pdf"
 mail.Send
End Sub

Vue d’ensemble 6 : suivi des paiements

Sur Historique, colonne Statut avec liste déroulante (Émise, Payée, Relancée, Contentieux). Colonne DateEcheance. Mise en forme conditionnelle : rouge si DateEcheance dépassée et Statut différent de Payée.

Vue d’ensemble 7 : rapport mensuel

TCD sur Historique : CA émis par mois, taux d’impayés, délai moyen de paiement. Exportable en PDF pour l’expert-comptable.

Considérations légales

Au, les factures doivent être émises en numérotation continue (pas de saut), conservées 10 ans, mentionner NINEA et TVA séparément. Le code VBA ci-dessus respecte ces exigences.

Conclusion

Une journée d’investissement VBA peut remplacer des années d’abonnement SaaS. Solution idéale pour freelances, artisans et petites PME. Pour évoluer : un passage à QuickBooks ou Odoo devient pertinent dès 300 factures par mois.

Voir aussi

Pourquoi un script VBA pour la facturation

Dans une PME basee a Sandaga ou au Plateau d’Abidjan, la facturation manuelle finit toujours par produire deux factures avec le meme numero. Avec une procedure VBA et une cellule compteur, vous garantissez une numerotation continue, sans trou ni doublon, conforme aux exigences fiscales locales.

L’objectif de ce tutoriel : un classeur Excel avec un onglet Facture, un onglet Compteur et un onglet Journal. Un bouton declenche la generation, incremente le numero, archive la facture en PDF et journalise l’operation.

Etape 1 : preparer la structure du classeur

Creez un nouveau classeur facturation.xlsm (format avec macros). Ajoutez trois feuilles renommees Facture, Compteur, Journal. Sur Compteur en A1 ecrivez le label NumeroSuivant et en B1 entrez 2026000001 (annee + 6 chiffres). Cette cellule pilote toute la numerotation.

Sur Facture, reservez B2 pour le numero, B3 pour la date, B5 pour le client, et la plage A10:E25 pour les lignes. En E26 placez la formule =SOMME(E10:E25) qui totalise hors taxes.

Etape 2 : ouvrir l’editeur VBA

Depuis Excel, faites Alt+F11. Vous arrivez dans Visual Basic for Applications. Clic droit sur VBAProject puis Insertion, Module. Vous obtenez Module1. C’est la qu’on ecrit le code, pas dans une feuille.

Sub GenererFacture()
    Dim wsF As Worksheet, wsC As Worksheet, wsJ As Worksheet
    Set wsF = ThisWorkbook.Sheets("Facture")
    Set wsC = ThisWorkbook.Sheets("Compteur")
    Set wsJ = ThisWorkbook.Sheets("Journal")
End Sub

Ces trois variables typees Worksheet evitent les erreurs de reference. Si une feuille est mal nommee, l’execution echoue immediatement avec un message clair plutot que de corrompre les donnees.

Etape 3 : lire et incrementer le compteur

Le coeur de la procedure lit B1 sur Compteur, ecrit le numero sur la facture, puis sauvegarde le compteur incremente. On encadre l’operation pour que meme une coupure de courant ne casse pas la sequence.

Dim numActuel As Long
numActuel = wsC.Range("B1").Value
wsF.Range("B2").Value = "FAC-" & numActuel
wsF.Range("B3").Value = Date
wsC.Range("B1").Value = numActuel + 1
ThisWorkbook.Save

Apres execution, B2 affichera FAC-2026000001 et le compteur basculera a 2026000002. La sauvegarde immediate verrouille la sequence avant tout export PDF.

Etape 4 : exporter en PDF horodate

L’export PDF utilise ExportAsFixedFormat avec un nom de fichier qui combine le numero et l’horodatage. Ainsi deux generations le meme jour ne s’ecrasent jamais.

Dim chemin As String
chemin = ThisWorkbook.Path & "\factures\"
If Dir(chemin, vbDirectory) = "" Then MkDir chemin
Dim nomFichier As String
nomFichier = chemin & wsF.Range("B2").Value & "_" & Format(Now, "yyyymmdd_hhnnss") & ".pdf"
wsF.ExportAsFixedFormat Type:=xlTypePDF, Filename:=nomFichier, Quality:=xlQualityStandard

Le sous-dossier factures est cree au premier appel. Vous obtenez un fichier comme FAC-2026000001_20260505_143022.pdf, immediatement archivable ou envoyable par email.

Etape 5 : journaliser dans l’onglet Journal

Pour la tracabilite, chaque facture est inscrite dans Journal avec numero, date, client, montant et chemin du PDF. Cela vous donne un registre des ventes prêt pour l’expert-comptable.

Dim ligne As Long
ligne = wsJ.Cells(wsJ.Rows.Count, 1).End(xlUp).Row + 1
wsJ.Cells(ligne, 1).Value = wsF.Range("B2").Value
wsJ.Cells(ligne, 2).Value = wsF.Range("B3").Value
wsJ.Cells(ligne, 3).Value = wsF.Range("B5").Value
wsJ.Cells(ligne, 4).Value = wsF.Range("E26").Value
wsJ.Cells(ligne, 5).Value = nomFichier

La technique End(xlUp) trouve la derniere ligne remplie en colonne A et y ajoute 1. Aucun risque d’ecraser des donnees existantes.

Etape 6 : ajouter le bouton declencheur

Retournez sur Excel. Onglet Developpeur (a activer dans Options si invisible), Inserer, Bouton de formulaire. Tracez le bouton, attribuez-lui la macro GenererFacture. Renommez le bouton Generer la facture.

Au clic, l’utilisateur final n’a plus besoin de toucher au VBA. Il remplit client, lignes, et clique. Les comptables qui formez a Yopougon ou Cocody seront operationnels en 10 minutes.

Etape 7 : prevenir les erreurs de saisie

Avant l’incrementation, validez que le client en B5 et au moins une ligne en A10 sont remplis. Sinon vous brulez un numero pour rien. Ajoutez ce bloc en debut de procedure.

If Trim(wsF.Range("B5").Value) = "" Then
    MsgBox "Renseignez le client avant de generer.", vbExclamation
    Exit Sub
End If
If Trim(wsF.Range("A10").Value) = "" Then
    MsgBox "Au moins une ligne de facturation requise.", vbExclamation
    Exit Sub
End If

Ces gardes-fous economisent des numeros de facture et evitent les sequences trouees qui inquietent l’administration fiscale en cas de controle.

Etape 8 : preparer le passage en production

Avant de distribuer le fichier, signez le projet VBA (Outils, Signature electronique dans VBA) ou abaissez la regle d’execution dans le centre de gestion de la confidentialite Excel. Sans cela, les macros sont bloquees a l’ouverture sur les postes utilisateurs.

Pour explorer plus loin, voyez nos tableaux de bord KPI Excel et le planning Gantt dynamique pour completer votre suite de gestion.

Etape 9 : gerer la TVA et la mention legale

Au Senegal la TVA standard est de 18 pourcent, en Cote d’Ivoire 18 pourcent egalement, au Burkina Faso 18 pourcent. Ajoutez en E27 la formule =E26*0,18 et en E28 =E26+E27 pour le total TTC. Sur la facture, mentionnez en bas de page votre numero NINEA (Senegal), CC (Cote d’Ivoire) ou IFU (Burkina, Benin, Togo). Sans ce numero, la facture est non opposable a l’administration fiscale.

wsF.Range("D27").Value = "TVA 18%"
wsF.Range("E27").Formula = "=E26*0.18"
wsF.Range("D28").Value = "Total TTC"
wsF.Range("E28").Formula = "=E26+E27"

Ces lignes peuvent etre injectees dynamiquement si certains clients sont exoneres (zone franche industrielle, ONG agreees) avec un If sur une cellule TauxTVA dediee.

Etape 10 : envoyer la facture par email automatiquement

VBA peut piloter Outlook pour expedier la facture des sa generation. Ajoutez une reference a Microsoft Outlook Object Library dans Outils, References. Puis le code suivant attache le PDF cree a l’etape 4.

Dim olApp As Object, olMail As Object
Set olApp = CreateObject("Outlook.Application")
Set olMail = olApp.CreateItem(0)
With olMail
    .To = wsF.Range("B6").Value
    .Subject = "Votre facture " & wsF.Range("B2").Value
    .Body = "Bonjour, veuillez trouver ci-joint votre facture. Cordialement."
    .Attachments.Add nomFichier
    .Display
End With

Display ouvre l’email pour relecture avant envoi. Remplacez par Send pour expedier directement. Mettez l’adresse client en B6 sur l’onglet Facture.

Etape 11 : sauvegarder le compteur dans un fichier externe

Si plusieurs postes utilisent le meme classeur facturation, le compteur en cellule B1 finit par diverger. La parade : centraliser le compteur dans un fichier texte sur un dossier reseau partage. Un verrou simple empeche les collisions.

Dim fso As Object, ts As Object, num As Long
Set fso = CreateObject("Scripting.FileSystemObject")
Set ts = fso.OpenTextFile("\\serveur\partage\compteur.txt", 1)
num = CLng(ts.ReadLine)
ts.Close
Set ts = fso.OpenTextFile("\\serveur\partage\compteur.txt", 2)
ts.WriteLine num + 1
ts.Close

Cette technique fonctionne sur un partage Windows ou un dossier OneDrive synchronise. Pour 5 a 10 utilisateurs concurrents, c’est suffisant. Au-dela, migrez vers Access ou SQL Server.

Etape 12 : recapituler et tester

Generez 5 factures de test consecutives. Verifiez que le Journal contient bien 5 lignes incrementales, que le sous-dossier factures contient 5 PDF distincts, et que B1 sur Compteur affiche bien le numero suivant. Si vous obtenez 2026000006, tout est conforme.

Sauvegardez le classeur sur un emplacement protege par mot de passe et formez un utilisateur principal et un suppleant. Une procedure VBA n’est utile que si elle survit a la rotation des equipes.

Etape 13 : verrouiller les cellules sensibles

Pour eviter qu’un utilisateur modifie accidentellement le compteur ou les formules de totaux, protegez la feuille Compteur et les cellules de totaux sur Facture. Selectionnez les plages a deverrouiller (B5, B6, A10:E25), faites Format de cellule, Protection, decochez Verrouillee. Puis Revision, Proteger la feuille avec un mot de passe robuste.

wsC.Protect Password:="motdepasse_fort", UserInterfaceOnly:=True
wsF.Protect Password:="motdepasse_fort", UserInterfaceOnly:=True

L’option UserInterfaceOnly autorise les macros a ecrire dans les cellules verrouillees tout en bloquant la saisie manuelle. Indispensable quand le compteur est protege mais doit etre incremente par VBA.

Etape 14 : conserver une archive annuelle

En fin d’exercice fiscal, exportez le Journal vers un fichier journal_2026.xlsx separe et reinitialisez le compteur en 2027000001. Cette procedure annuelle facilite les controles et reduit la taille du fichier de production.

Sub ArchiverJournal()
    Dim wsJ As Worksheet
    Set wsJ = ThisWorkbook.Sheets("Journal")
    wsJ.Copy
    ActiveWorkbook.SaveAs ThisWorkbook.Path & "\journal_" & Year(Date) & ".xlsx", xlOpenXMLWorkbook
    ActiveWorkbook.Close
    wsJ.Range("A2:E10000").ClearContents
    ThisWorkbook.Sheets("Compteur").Range("B1").Value = (Year(Date) + 1) * 1000000 + 1
End Sub

Lancez ArchiverJournal le 31 decembre. Le 1er janvier, le premier numero emis sera 2027000001 et l’historique 2026 reste accessible en lecture dans le fichier archive.

Etape 15 : preparer la conversion vers une vraie application

Quand le volume depasse 200 factures par mois ou 3 utilisateurs simultanes, Excel atteint ses limites. Migrez vers Access ou un ERP comme Dolibarr ou Odoo. La logique VBA developpee ici sert de specification fonctionnelle pour le futur cahier des charges.

Documentez chaque procedure, exportez les modules VBA via Fichier, Exporter sur chaque module (.bas), et versionnez-les sur un depot Git prive. Vous garantissez ainsi la perennite du savoir-faire au-dela des departs collaborateurs.

Etape 16 : auditer la qualite du code VBA

Activez Outils, Options, Editeur, Declaration des variables obligatoire. Cela ajoute Option Explicit en tete de chaque module et oblige a typer chaque variable. Vos macros gagnent immediatement en robustesse car les fautes de frappe sur les noms de variables provoquent une erreur de compilation au lieu d’un comportement silencieux et imprevisible.

Lancez Debogage, Compiler le projet VBA. Si la compilation reussit sans message, vous avez la garantie qu’aucune ligne morte ou reference cassee ne se cache dans vos modules. Cette etape devrait preceder tout deploiement vers les utilisateurs finaux a Bamako, Lome ou Cotonou.

مشاركة