Tenir une comptabilité avec Access

1re partie : L'encodage des faits et la génération des mouvements

Claude Leloup

Dans cette série d'articles, je voudrais partager mon expérience de comptable qui s'est aidé d'Access pour organiser son travail.
J'y explique ma démarche et présente une solution informatique utilisant Access.
Il ne s'agit pas de vous livrer un logiciel comptable universel « clé en main » ni à vous donner un cours de comptabilité.
Ceci s'adresse au lecteur qui veut organiser la comptabilité d'une petite entreprise et qui dispose déjà d'une connaissance de base en Access.
Pour illustrer mes propos, je prendrai un exemple concret : la comptabilité d'un restaurant.

Commentez

- Titre : Tenir une comptabilité avec Access

- Auteur : Claude Leloup

- Parution : 24 mai 2013

- Public visé :

- Licence : Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright ® 2013 Claude Leloup. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.

Sommaire

- I. Introduction

- I-A. La comptabilité évolue

- I-B. Quelques principes auxquels nous serons attentifs

- I-B-1. La saisie des faits est systématique

- I-B-2. On se base sur des pièces justificatives

- I-B-3. Division en exercices limités dans le temps

- I-C. Les étapes du processus proposé

- II. Survol de l'application

- II-A. Le modèle de données

- II-B. Le plan comptable : tPlanCompta

- II-C. Un formulaire d'encodage pour chaque famille de faits comptables

- II-C-1. Chaque formulaire est conçu suivant un même gabarit

- II-C-2. Conventions de nommage des formulaires « pères »

- II-C-3. Un exemple concret

- III. Le formulaire « fils » sfImputa

- IV. Une routine pour dimensionner le sous-formulaire d'après le nombre de ses enregistrements

- IV-A. Quelques explications sur le code

- V. L'encodage des opérations de caisse : fEcrCai

- V-A. Contexte opérationnel

- V-B. Comment cela fonctionne

- V-B-1. La démarche pour généraliser

- V-C. Les particularités de fEcrCai

- VI. Fonctionnement des boutons pour la création d'un schéma de comptabilisation

- VII. L'encodage des opérations de banque : fEcrBan

- VII-A. Contexte opérationnel

- VII-B. L'extrait de compte reçu de la banque constitue la pièce justificative, mais…

- VII-C. Un exemple concret pour expliquer l'utilisation du formulaire

- VII-D. Les particularités de fEncoBan

- VIII. L'encodage des factures d'achats : fEcrAch

- VIII-A. Contexte opérationnel

- VIII-B. Les particularités de fEncoAch

- VIII-B-1. Événement « Après mise à jour » du choix d'un fournisseur

- IX. L'encodage des factures aux clients : fEcrFac

- IX-A. Contexte opérationnel

- IX-B. Les particularités de fEcrFac

- X. L'encodage des opérations diverses : fEcrDiv

- X-A. Contexte opérationnel

- X-B. Les particularités de fEncoDiv

- XI. La création des mouvements comptables proprement dits

- XI-A. L'idée : une routine polyvalente…

- XI-B. … sollicitée en permanence

- XI-C. Le code

- XII. Conclusion de cette première partie

- XIII. Recommandations si vous voulez adapter ceci à votre environnement

- XIV. Remerciements

I - Introduction

J'essaierai d'être clair, mais soyez indulgent :

Auguste DETŒUF, Propos de O .L. Barenton Confiseur, Éditions du Tambourinaire, 1971.

Il y a trois sortes d'êtres au langage mystérieux.
Les plus aisés à comprendre sont les fous.
Puis viennent les polytechniciens.
Et enfin les comptables.

La comptabilité n'est pas une fin en soi !

Son objectif est de gérer de l'information chiffrée… pour ensuite l'utiliser.

C'est une technique qui permet d'enregistrer les faits qui influencent le patrimoine d'un agent économique, de les classer, de les regrouper, pour interpréter les résultats auxquels ces faits ont donné lieu.

Ce n'est pas une science exacte, mais plutôt un art : celui de traduire en chiffres un fait qui influence le patrimoine de l'entreprise.

I-A - La comptabilité évolue

Luca Pacioli (v.1445 - 1517)

1494 : Luca Pacioli publie à Venise la SUMMA DI ARITHMETICA, GEOMETRICA, PROPORTIONI ET PROPORTIONNALITA dont le Tractatus XI est considéré comme le premier ouvrage imprimé décrivant la comptabilité de manière cohérente et utile…

Vulgus homo numeris (1945-20??)

2013 : je vous propose une manière de faire sans vous expliquer les progrès depuis l'époque de Christophe Colomb. Retenez que les bases ont été fixées au Moyen Âge, mais que la technique et les normes progressent encore…

I-B - Quelques principes auxquels nous serons attentifs

I-B-1 - La saisie des faits est systématique

Il faut organiser la saisie systématique de tous les faits qui ont une incidence sur le patrimoine et le résultat.

Les comptes doivent indiquer systématiquement la nature et le montant :

- des avoirs et des droits ;

- des dettes, obligations et engagements ;

- des moyens propres ;

- des charges et produits.

I-B-2 - On se base sur des pièces justificatives

Toute écriture comptable s'appuie sur une pièce justificative datée et porte un indice de référence à celle-ci.

I-B-3 - Division en exercices limités dans le temps

Pour rester simple, disons que la comptabilité se tient par année. On parle d'exercice comptable suivi d'un millésime pour les distinguer.

I-C - Les étapes du processus proposé

La saisie des faits à comptabiliser.

L'interprétation des faits en écritures comptables.

L'agrégation des mouvements pour construire les états comptables classiques.

Dans cette 1re partie, nous traiterons les deux premiers points : constater un fait et le traduire en débits et crédits dans un système de comptes.

II - Survol de l'application

II-A - Le modèle de données

II-B - Le plan comptable : tPlanCompta

C'est l'ensemble des comptes qui fonctionnent dans une comptabilité.

Combien de comptes y a-t-il dans une comptabilité ?

Cela varie d'une entreprise à l'autre.

Cela varie d'une organisation comptable à l'autre.

En fait, cela dépend des ambitions que l'on a, lorsqu'on « tient » la comptabilité.

Veut-on un détail fin en permanence ou bien se contente-t-on d'un compte global que l'on ventilera, si le besoin s'en fait un jour sentir, en dehors de la comptabilité, « en extra-comptable » ?

D'une manière générale, plus une comptabilité est détaillée, plus il faut de moyens (humains et infrastructure) pour l'entretenir.

La bonne question est : « a-t-on les moyens de ses ambitions ? », si la réponse est non, il faut se résoudre à « avoir les ambitions de ses moyens ! ».

Le législateur a toutefois fixé des limites en imposant un plan comptable minimum normalisé aux entreprises pour la publication(1) de leurs comptes.

En attendant une uniformisation européenne, la numérotation varie selon le pays.

Exemples :

Libellé

Belgique

France

Clients

40xxxx

41xxxx

Fournisseurs

44xxxx

40xxxx

Banque

55xxxx

51xxxx

Caisse

57xxxx

53xxxx

Pour notre exemple, les comptes sont articulés sur le schéma belge. Nous attirerons l'attention du lecteur chaque fois que cette particularité a une incidence dans l'application.

Les comptes doivent être suffisamment détaillés pour permettre l'enregistrement de toutes les opérations de l'entreprise.

Le plan comptable doit être conçu de telle sorte que les comptes publiés «  procèdent de » la balance des comptes (2) . En d'autres termes, chaque article des comptes publiés doit être construit en additionnant le solde des comptes détaillés.

Pour l'exemple, j'ai choisi d'articuler le plan comptable sur celui de la Belgique, décimalisé en six positions.

II-C - Un formulaire d'encodage pour chaque famille de faits comptables

Dans notre cas :

- les recettes du restaurant et les diverses opérations de caisse : fEcrCai ;

- les opérations de banque : fEcrBan ;

- les factures des fournisseurs : fEcrAch ;

- les factures aux clients : fEcrFac ;

- les opérations diverses : fEcrDiv.

Cette division correspond à la pratique comptable qui consiste à classer les opérations par journaux spécialisés :

- des journaux de type « compte de trésorerie » : journal de caisse et journal de banque ;

- des journaux de type « facturier » : pour les factures d'achats et pour les factures des ventes ;

- un journal des opérations diverses pour tout le reste.

II-C-1 - Chaque formulaire est conçu suivant un même gabarit

Chacun est en deux parties :

- un formulaire « père » pour enregistrer les données propres à l'écriture comptable : la référence, la date, des champs calculés en relation avec le type d'écriture (par ex. l'ancien et le nouveau solde des comptes Caisse et Banque). Chaque « père » a aussi une série de boutons spécifiques pour afficher ses schémas de comptabilisation les plus courants ;

- un sous-formulaire « fils », pour saisir les imputations comptables proprement dites.

Dans le schéma proposé, chaque « père » a le même « fils » (sfImputa).

La table tEcritures constitue la source commune de tous les formulaires « pères ».
La table tImputa constitue la source commune de tous les formulaires « fils ».

Si la notion de formulaires « père » et « fils » ne vous est pas familière, voyez ce tutoriel : Comment classer les données dans des tables liées et construire un formulaire père/fils.

II-C-2 - Conventions de nommage des formulaires « pères »

Vous pouvez facilement adapter de cette application à votre contexte.

Par exemple si l'entreprise est en compte chez plusieurs banquiers et qu'il s'avère donc qu'on ne peut se satisfaire d'un seul « journal de banque », il suffit de dupliquer fEcrBan en : fEcrBNP, fEcrDEX, fEcrCAg, fEcrCCP… sans toucher au reste.

Peu importe le nom du formulaire, pour autant qu'il n'y ait pas de doublon de la chaine des trois dernières lettres.

II-C-3 - Un exemple concret

III - Le formulaire « fils » sfImputa

Ce formulaire est le « fils » inclus dans chaque formulaire d'encodage.

Sa source est l'ensemble des enregistrements de la table tImputa classés par ordre de création.

Il s'affiche en continu.

Ce contrôle est non visible, sa valeur est soit « D », « C » ou Null. Il sert au formatage conditionnel des contrôles « txtImdebit » et « txtImCredit ». L'idée est de bloquer le champ montant non adéquat :

- si la valeur est « D », le compte doit être débité, le champ txtImCredit sera désactivé ;

- si la valeur est « C », le compte doit être crédité, le champ txtImDebit sera désactivé.

Le choix peut se faire selon le N° ou l'intitulé du compte, les deux zones de liste sont liées à la même colonne de la table source. La mise à jour de l'une entraine automatiquement la mise à jour de l'autre.

Cette technique est décrite dans le tutoriel de Pierre Fauconnier : Sélection d'une donnée par l'une ou l'autre de ses propriétés.

Remarquez que dans la requête de la propriété « Contenu » on a exclu une série de comptes :

Comme on le verra plus loin, les imputations dans les comptes de trésorerie (« Caisse » et « Banque ») sont générées automatiquement (en tant que contreparties des imputations dans le journal ad hoc). Quant aux comptes « Clients » et « Fournisseurs », il s'agit de comptes globaux qui, dans le schéma que nous proposons, ne sont pas utilisés pour enregistrer des mouvements.

C'est pour éviter d'encoder des N° de comptes « en dur » que nous utilisons la fonction « Cpte ». En d'autres mots, si vous adoptez l'application telle quelle, vous pouvez modifier le numéro de ces comptes pour autant que ceux-là gardent leur intitulé actuel.

Les deux contrôles ont un fonctionnement analogue :

- leur propriété « Valide si » impose qu'ils soient positifs ou nuls ; voici le code associé aux événements :

si on clique, tout le montant est sélectionné :

Private Sub txtImDebit_Click()
Me.ActiveControl.SelStart = 0
Me.ActiveControl.SelLength = Len(Me.ActiveControl.Text)
End Sub

empêcher à la fois débit et crédit :

Private Sub txtImDebit_BeforeUpdate(Cancel As Integer)
If Me.txtImCredit <> 0 Then
MsgBox "Déjà un montant au crédit !"
Cancel = True
Me.txtImDebit.Undo
End If
End Sub

et aménager txtSens pour la mise en forme conditionnelle :

Private Sub txtImDebit_AfterUpdate()
On Error GoTo GestionErreur
'Aménager le sens
If Me.txtImDebit <> 0 Then
Me.txtImSens = "D"
Else
Me.txtImSens = Null
End If
Me.Refresh
Exit Sub
GestionErreur:
Select Case Err.Number
Case 3314
MsgBox "Vous devez choisir un compte"
Case Else
MsgBox "Erreur inattendue : " & Err.Number & " " & Err.Description
End Select
End Sub

Chaque fois que le nombre d'enregistrements à afficher varie, on adapte la dimension de sfImputa de sorte que les totaux logés dans le pied du formulaire s'affichent juste en dessous du dernier enregistrement.

Private Sub Form_AfterDelConfirm(Status As Integer)
Call AmenagerTailleSF(Me.Parent.Name, "ctnr" & Me.Name)
End Sub

Private Sub Form_AfterInsert()
Call AmenagerTailleSF(Me.Parent.Name, "ctnr" & Me.Name)
End Sub

IV - Une routine pour dimensionner le sous-formulaire d'après le nombre de ses enregistrements

Conventions :

- le contrôle qui contient le sous-formulaire s'appelle : ctnrNomDuSousFormulaire ;

- pour fixer la limite inférieure, on place dans le principal un contrôle « Trait » (propriété Visible = non) que l'on nomme : basctnrNomDuSousFormulaire, comme ceci :

- dans un module, on place cette routine :

Public Sub AmenagerTailleSF(NomDuForm As String, NomDuSF As String)
Dim EspaceNecessaire As Long, EspaceLibre As Long, iAffichables As Integer
On Error GoTo GestionErreurs
'Calculer l'espace nécessaire pour afficher tous les enregistrements
Forms(NomDuForm)(NomDuSF).Form.Recordset.movelast 'pour pouvoir ensuite compter le nbre d'enregistrements
EspaceNecessaire = Forms(NomDuForm)(NomDuSF).Form.Section(acHeader).Height _
+ Forms(NomDuForm)(NomDuSF).Form.Section(acFooter).Height _
+ Forms(NomDuForm)(NomDuSF).Form.Section(acDetail).Height _
* (Forms(NomDuForm)(NomDuSF).Form.Recordset.RecordCount - Forms(NomDuForm)(NomDuSF).Form.AllowAdditions)
'Ceci revient à ajouter 1 si ajout autorisé

'Calculer l'espace disponible et le nbre d'enregistrements affichables
EspaceLibre = Forms(NomDuForm)("Bas" & NomDuSF).Top - Forms(NomDuForm)(NomDuSF).Top
iAffichables = ((EspaceLibre - Forms(NomDuForm)(NomDuSF).Form.Section(acHeader).Height - Forms(NomDuForm)(NomDuSF).Form.Section(acFooter).Height) / _
Forms(NomDuForm)(NomDuSF).Form.Section(acDetail).Height) - 0.5
' N.B. On retire 0.5 pour éviter le forçage à l'unité supérieure lors de la conversion en entier
'Limitation au maximum possible
If EspaceNecessaire > EspaceLibre Then  'trop pour tout afficher tout
Forms(NomDuForm)(NomDuSF).Height = EspaceLibre
Forms(NomDuForm)(NomDuSF).Form.InsideHeight = EspaceLibre
Forms(NomDuForm)(NomDuSF).Form.ScrollBars = 2 'pour afficher une barre de défilement verticale
'Afficher les derniers enregistrements de la liste
Forms(NomDuForm)(NomDuSF).SetFocus
DoCmd.GoToRecord , , acNewRec 'afficher l'emplacement de l'ajout si permis, sinon erreur 2105 et instruction suivante
DoCmd.GoToRecord , , acLast
DoCmd.GoToRecord , , acPrevious, iAffichables - 1 + Forms(NomDuForm)(NomDuSF).Form.AllowAdditions
'se positionner sur le dernier
DoCmd.GoToRecord , , acLast
Else
Forms(NomDuForm)(NomDuSF).Height = EspaceNecessaire
Forms(NomDuForm)(NomDuSF).Form.InsideHeight = EspaceNecessaire
Forms(NomDuForm)(NomDuSF).Form.ScrollBars = 0  ' pas de barre de défilement verticale
'Afficher tous les enregistrements et se positionner sur le dernier
Forms(NomDuForm)(NomDuSF).SetFocus
DoCmd.GoToRecord , , acFirst
DoCmd.GoToRecord , , acLast
End If
Fin:
Exit Sub
GestionErreurs:
Select Case Err.Number
Case 3021 'Pas d'enregistrement dans le sous-formulaire
Resume Next
Case 2105 'Pas d'ajout permis dans le sous-formulaire
Resume Next
Case Else
MsgBox "Erreur dans AmenagerTailleSF : " & vbLf & "N° erreur : " & Err.Number & " " & Err.Description, vbCritical
End Select
End Sub

- dans l'événement « Sur activation » du principal, on appelle la routine :

Private Sub Form_Current()
Call AmenagerTailleSF(Me.Name, "ctnrNomDuSousFormulaire")
End Sub

- et dans les événements « Après suppression » et « Après insertion » du sous-formulaire :

Private Sub Form_AfterDelConfirm(Status As Integer)
Call AmenagerTailleSF(Me.Parent.Name, "ctnr" & Me.Name)
End Sub

Private Sub Form_AfterInsert()
Call AmenagerTailleSF(Me.Parent.Name, "ctnr" & Me.Name)
End Sub

IV-A - Quelques explications sur le code

On se positionne à la fin du recordset pour pouvoir ensuite compter le nombre d'enregistrements. Une erreur 3021 sera levée s'il n'y a pas d'enregistrement. Cette erreur éventuelle est trappée et on passe à l'instruction suivante.

Espace occupé par l'en-tête du sous-formulaire.

Espace occupé par le pied du sous-formulaire.

Espace occupé par une ligne de détail du sous-formulaire. Cet espace sera multiplié par le nombre de lignes affichées ( + ).

Nombre d'enregistrements à afficher = nombre de lignes avec des données.

La propriété « Ajout autorisé » vaut -1 si elle est positionnée à Oui et 0 si positionnée à Non. Soustraire cette valeur revient à ajouter un espace détail vierge pour l'ajout éventuel.

De l'espace total disponible,

On soustrait celui réservé à l'en-tête et au pied pour connaître celui disponible pour les lignes de détail…

… que l'on divise par l'espace nécessaire à une ligne de détail.

Le résultat du calcul est transféré dans une variable de type « integer », elle serait donc éventuellement forcée à l'unité supérieure si la partie décimale du quotient dépasse 0,50. L'astuce pour ne conserver que la partie entière consiste à retrancher d'abord 0,50.

Exemple :

Quotient

- 0,50

Arrondi

9,72

9,22

9

9,13

8,63

9

9,00

8,50

9

8,99

8,49

8

L'espace est insuffisant pour tout afficher.

On peut tout afficher.

Selon le cas, on affiche une barre de défilement verticale.

On fait voyager le sélecteur pour afficher toutes les dernières lignes. Y compris la ligne vierge pour l'ajout éventuel. Une erreur 2105 sera levée si la propriété « Ajout autorisé » est à Non. Cette erreur éventuelle est trappée et on passe à l'instruction suivante.

On se situe sur le dernier enregistrement et on remonte autant de fois que possible, c'est-à-dire iAffichables - 1 (pour le dernier déjà affiché) - 1 pour la ligne vierge éventuelle (rappelons que Forms(NomDuForm)(NomDuSF).Form.AllowAdditions vaut -1 ou 0 selon le cas).

V - L'encodage des opérations de caisse : fEcrCai

V-A - Contexte opérationnel

La recette doit être ventilée en trois catégories selon leur sort fiscal :

- la partie « nourriture » subit 12 % de TVA ;

- la partie « boissons » subit 21 % de TVA ;

- les services traiteur subissent 6 % de TVA.

Chaque note de restaurant fait l'objet d'une souche TVA en double exemplaire dont l'original est remis au client.

Les doubles des fiches TVA vont constituer la pièce justificative de l'écriture comptable.

Si tous les clients payaient leur note en espèces, nous comptabiliserions un C.A. de 3210 € par exemple comme ceci (ventilé nourriture/boissons suivant le détail des bons de prise de commande) :

Les recettes sont comptabilisées dans des comptes transitoires selon leur taux de TVA. En fin de période on soldera ces comptes pour créditer les comptes de Produits « C.A. traiteur », « C.A. Boissons »… pour la partie hors TVA et « TVA à payer » pour la partie qui revient à l'État.

Mais certains clients ont payé avec une carte, disons 2789 €, l'écriture serait alors :

Après quelque temps, la banque nous créditera des 2789 €… enfin moins une commission et probablement en plusieurs fois… pas toujours facile pour contrôler ! Dans un article à venir, nous expliquerons comment s'organiser pour émarger les opérations en suspens.

Pour compléter notre cas d'école, imaginons que ce jour-là nous ayons reçu un acompte de 300 € pour la préparation d'un buffet froid pour l'amicale des Anciens qui en a profité pour nous vendre une carte de soutien à 20 €. Et enfin, nous avons versé 500 € à la banque.

À supposer qu'il nous restait 125 € hier, il doit maintenant y avoir 326 € dans la caisse.

En utilisant le formulaire fEncoCai, voici le résultat.

En cliquant successivement les boutons « Versement banque » et « Recette journalière », le schéma de comptabilisation s'affiche :

Les débits s'affichent en jaune, les crédits en bleu. Pour éviter les erreurs d'imputation, le côté inutile est désactivé.

L'utilisateur complète les données, il vient ceci :

Pour acter la carte de soutien et l'acompte reçu, l'utilisateur choisit « manuellement » les comptes à mouvementer :

Le formulaire affiche que d'après la comptabilité, il devrait y avoir 326,00 € en caisse.

Il faut vérifier la caisse tous les jours ! C'est-à-dire comparer le solde du compte « Caisse » (ce qu'il devrait y avoir) avec les espèces (ce qu'il y a effectivement). En cas de différence, ceci permet de s'assurer :

- au mieux, qu'on n'a pas oublié d'encoder un fait ou qu'on s'est trompé dans les montants ;

- au pire, qu'il faut resserrer quelques boulons pour éviter les fuites…

Soyons réaliste, c'est rarement juste au cent près, mais prenez l'habitude de remettre les pendules à l'heure chaque jour en ajustant… la comptabilité et non pas la réalité !

Dans la caisse, il y a effectivement 325,20 € : on a probablement bien tout comptabilisé, mais on acte la différence : un clic sur « Différence trop peu » et finalement :

… la pendule compta est à l'heure !

Et voici les mouvements qui seront générés par la routine « Sub CreMvts » qui sera présentée plus loin dans l'article

N.B. Les débits sont signés « - », les crédits sont positifs.

V-B - Comment cela fonctionne

V-B-1 - La démarche pour généraliser

L'idée c'est :

- un formulaire « père » basé sur les enregistrements de tEcritures qui concernent les opérations de caisse ;

- un formulaire « fils » avec les enregistrements correspondants de tImputa.

Dans une première approche, nous aurions donc :

- la source de fEcrCai :

SELECT * FROM tEcritures WHERE EcOrigine="Cai" ORDER BY EcNumExtrait, EcDate;

N.B. Trié par numéro d'extrait (ici sans effet puisqu'égal à zéro) et par date pour la commodité d'utilisation.

- la source de fImputa :

SELECT * FROM tImputa;

et pour assurer la coordination des deux :

- la propriété « Champs fils » du conteneur : ImOrigine;EcFk ;

- la propriété « Champs pères » du conteneur : EcOrigine;EcPK.

Dans la requête source de fEcrCai, on sélectionne sur la base de « WHERE EcOrigine = "Cai" ». S'il s'était agi de fEcrBan, nous aurions eu « WHERE EcOrigine = "Ban" » et de même pour les autres fEcrXXX.

Puisque nous avons « normé » le nom des formulaires, nous pourrions généraliser en nous référant aux trois derniers caractères de leur nom soit quelque chose comme :

SELECT * FROM tEcritures WHERE EcOrigine= Right([Name],3)   ORDER BY EcNumExtrait, EcDate;

qui provoque ceci :

En fait, dans ce contexte, Access ne reconnaît pas [Name] comme représentant le nom du formulaire.

Rusons pour arriver à nos fins : nous allons construire la source du formulaire dans son événement « Sur chargement », comme ceci :

Private Sub Form_Load()
Dim sSql As String
sSql = "SELECT * FROM tEcritures WHERE EcOrigine='" & Right(Me.Name, 3) & "' ORDER BY EcNumFac, EcDate;"
Me.RecordSource = sSql
End Sub

Cette fois, Access ne réclame plus [Name], mais successivement :

C'est-à-dire ce que renseigne la propriété « Champs pères » du conteneur.

Qu'à cela ne tienne, ne définissons pas cette propriété a priori dans le formulaire et construisons-la aussi dans l'événement « Sur chargement » qui devient :

Private Sub Form_Load()
Dim sSql As String
sSql = "SELECT * FROM tEcritures WHERE EcOrigine='" & Right(Me.Name, 3) & "' ORDER BY EcNumFac, EcDate;"
Me.RecordSource = sSql
Me.ctnrsfImputa.LinkMasterFields = "EcOrigine;EcPK"
End Sub

Et cette fois, ça marche !

Donc, en résumé :

V-C - Les particularités de fEcrCai

La valeur par défaut est « Droite([Nom];3) ». Les nouveaux enregistrements seront créés avec « Cai » comme valeur de EcOrigine.

N.B. Ce contrôle est non visible, car sans intérêt pour l'utilisateur.

La valeur par défaut est « Droite([Nom];3) ». Elle sert dans la routine AjoutImputa exposée plus loin dans cet article.

Dans ce formulaire de type « trésorerie » (fEcrCai et FEcrBan), nous voulons empêcher que l'utilisateur introduise plusieurs fois la même date de comptabilisation. Comme ce ne sera pas le cas dans les formulaires des autres types (facturiers et opérations diverses), nous ne pouvons pas imposer l'unicité de « EcDate » au niveau de la définition de la table tEcritures.

Nous allons donc imposer cette contrainte au niveau du formulaire fEcrCai (et fEcrBan), dans l'événement « Avant mise à jour » du contrôle txtEcDate.

Voici le code et son explication :

Deux blocs :

si l'utilisateur essaie de modifier la date d'un enregistrement existant et que cette modification entraîne une date en doublon ;

si lors d'un nouvel enregistrement, l'utilisateur tente d'introduire une date déjà présente ;

dans les deux cas, si la nouvelle date est déjà présente, on affiche un message ;

on rétablit la valeur initiale ;

on supprime l'enregistrement en cours de création et on positionne la variable globale bRejetDate pour court-circuiter le processus de l'événement « Sur activation ».

On calcule ici le solde de la veille, c'est-à-dire le solde de départ de la journée en cours d'enregistrement.

=nz(SomDom("MvtMt";"tMvts";"MvtCpte = Cpte(""Caisse"")   and MvtDate<#" & Format([txtEcDate];"mm/dd/yy") & "#");0)

Ce n'est autre que la somme des mouvements au compte « Caisse » qui ont une date antérieure à celle du jour considéré.

Remarquez la transformation du formatage à l'anglo-saxonne de la date.

Si vous n'êtes pas à l'aise avec les fonctions de domaine voyez ce tutoriel de Philippe Jochmans :

Les Fonctions de Domaine dans Access.

La fonction nz() sert à remplacer par zéro la valeur nulle qui survient pour le 1er jour (il n'y a alors pas de veille !).

Cette manière de faire repose sur l'hypothèse que la table des mouvements (tMvts) est en permanence actualisée.

Voyez l'événement « Sur activation » du formulaire : la routine CreMvts est lancée à chaque lecture.

Le calcul du solde du jour est lui, construit par addition algébrique du solde de la veille et la contrepartie des mouvements dans le formulaire « fils ».

=[txtSoldeveille]+[ctnrsfImputa]!txtTotalDebit-[ctnrsfImputa]!txtTotalCredit

Un clic sur l'un de ces boutons déclenche la création d'un schéma d'imputations. Voyez la description du fonctionnement au titre suivant.

VI - Fonctionnement des boutons pour la création d'un schéma de comptabilisation

En un clic, ajouter le squelette de tous les mouvements pour les comptes concernés par un tel fait comptable :

L'idée est d'ajouter dans la table tImputa autant de lignes que de comptes concernés, c'est-à-dire que nous devons habiller les champs suivants :

Colonne de tImputa

Valeur

ImOrigine

Celle de l'enregistrement en cours (txtEcOrigine)

ImCpte

Voir plus bas

ImDebit

L'utilisateur complétera

ImCredit

L'utilisateur complétera

ImLibelle

Voir plus bas

ImSens

Voir plus bas

EcFk

Celle de l'enregistrement en cours (txtEcFk)

Comment communiquer « simplement » les trois données manquantes : le libellé, le numéro du compte et le sens ?

On va utiliser deux propriétés du bouton : « Légende » et « Remarque ».

On récupérera le texte de la légende du bouton en tant que ImLibelle.

On logera dans Remarque autant de paires numéro de compte/sens - séparées par des points-virgules - que de comptes inclus dans le schéma (attention : pas de point-virgule final !).
Cette propriété est rarement utilisée et pourtant bien pratique ! C'est un pense-bête, vous pouvez y inscrire ce que vous voulez avec un maximum de 2048 caractères. Contrairement aux autres propriétés, le paramétrage de celle-ci n'affecte pas les attributs d'un objet.

Et voici le code lié au clic d'un de ces boutons :

La propriété CodeContextObject permet de déterminer l'objet pour lequel du code Visual Basic est en cours d'exécution.

Quand la routine AjoutImputa() s'exécute : CodeContextObject représente l'objet qui a déclenché l'exécution. Il hérite alors de toutes les propriétés de ce dernier.

Par exemple, si dans le formulaire fEcrCai, un clic du bouton BtRecette appelle AjoutImputa(), nous aurons :

CodeContextObject.name égal à « fEcrCai » ;
CodeContextObject.ActiveControl.Tag égal au contenu de la propriété « Remarque » du bouton BtRecette.
CodeContextObject.ActiveControl.Caption égal à la légende du bouton.

L'instruction :

tabTag() = Split(Forms(CodeContextObject.Name).ActiveControl.Tag, ";")

aura donc comme résultat, un tableau d'une ligne (tabTag) et autant de colonnes qu'il y a de chaînes séparées par un point-virgule dans la propriété « Remarque » du bouton qui a appelé AjoutImputa().

Dans notre exemple :

tabTag(0) vaudra 497006C

tabTag(1) vaudra 497012C

tabTag(2) vaudra 497021C

tabTag(3) vaudra 580010D

Dans cette partie du code, pour chaque valeur du tableau tabTag, on exécute une requête ajout dont voici la représentation de la première :

On actualise le conteneur du sous-formulaire.

On déclenche l'événement « Sur Activation » pour provoquer l'ajustement de la taille de sfImputa.

VII - L'encodage des opérations de banque : fEcrBan

VII-A - Contexte opérationnel

Les faits qui concernent notre relation avec la banque ont cette particularité d'être enregistrés à deux endroits :

- dans la comptabilité de la banque ;

- dans notre comptabilité.

Si nous déposons 1000 € pour notre compte au guichet de la banque, celle-ci comptabilisera dans ses livres :

Elle traduit ainsi que ses actifs ont augmenté de 1000 (il y a plus dans sa caisse) et ses passifs ont aussi augmenté (elle doit plus à ses clients).

Par contre, dans notre comptabilité, nous passerons cette écriture :

Notre compte « Banque » augmente et en contrepartie notre compte « Caisse » diminue.

Le compte « Banque » dans nos livres est le miroir de notre compte dans les livres de la banque : « créditeur » chez la banque implique « débiteur » chez nous.

VII-B - L'extrait de compte reçu de la banque constitue la pièce justificative, mais…

Cependant, on ne peut pas se permettre d'attendre d'avoir en main l'extrait de la banque pour comptabiliser les faits. D'autant plus que depuis la banque en ligne, on ne demande plus à disposer d'un extrait papier journalier.

D'un autre côté, comptabiliser des montants rigoureusement symétriques à ceux de la banque n'est pas toujours pratique non plus.
Quand la banque nous débite d'un montant global couvrant le paiement de plusieurs factures à un fournisseur, c'est bien plus commode d'avoir dans notre comptabilité le détail des paiements facture par facture pour faciliter la justification du solde du compte de chaque fournisseur. Même raisonnement quand nos clients nous règlent plusieurs factures d'un coup.
Encore plus corsé : les montants que la banque nous bonifie pour les notes payées par cartes. La banque nous crédite d'un montant net de commissions d'encaissement et en regroupant parfois des journées différentes (les opérations du week-end par exemple). Cela complique la vérification avec les montants comptabilisés dans fEncoCai.
Dans ces trois cas, pour des raisons de visibilité dans notre comptabilité, nous nous organiserons pour comptabiliser dans notre formulaire fEncoBan des montants qui peuvent être facilement réconciliés avec ceux enregistrés dans les autres formulaires d'encodages (fEncoCai, fEncoAch…).

Dans un article à venir, nous expliquerons comment on peut organiser la justification des comptes « Virements internes » et « Paiements par cartes ».

Donc si l'extrait de la banque est la pièce justificative, les montants figurant à l'extrait et ceux apparaissant dans notre comptabilité seront de niveaux de détail différents. Par contre le solde du compte « Banque » dans nos livres sera le reflet exact du solde à l'extrait.

VII-C - Un exemple concret pour expliquer l'utilisation du formulaire

Le dernier extrait imprimé portait le N° 2 (daté par exemple du 10/1) :

Le solde précédent à la banque (14/1) était de 520,95 créditeur :

Nous sommes le 16/1 et nous consultons l'état de notre compte bancaire via Internet :

Et voici comment encoder ces opérations dans fEncoBan :

Le solde d'après notre formulaire correspond (au sens près) à celui de la banque : c'est un indice que nous avons reporté tous les montants.

VII-D - Les particularités de fEncoBan

Fort peu de différences entre fEcrCai et fEcrBan.

Dans notre exemple, c'est le seul cas où la colonne EcNumExtrait est exploitée. Ce N° constitue la référence à la pièce justificative (l'extrait délivré par la banque) et est utile en cas de recherche.
Sa valeur par défaut est :

=MaxDom("EcNumExtrait";"tEcritures";"EcOrigine='" & [txtEcOrigine] & "'")

Si nous comptabilisons au jour le jour sur la base de la consultation par Internet (l'extrait numéroté n'est donc pas encore en notre possession), nous aurons plusieurs enregistrements dans tEcritures avec le même N° d'extrait.
Pour prouver a posteriori que le solde de l'extrait correspond à notre comptabilité, il suffira d'afficher l'enregistrement avec la dernière date portant ce N° extrait.

Le calcul du solde de la veille :

=nz(SomDom("MvtMt";"tMvts";"MvtCpte = Cpte(""Banque"")   and MvtDate<#" & Format([txtEcDate];"mm/dd/yy") & "#");0)

VIII - L'encodage des factures d'achats : fEcrAch

VIII-A - Contexte opérationnel

Les factures reçues des fournisseurs sont numérotées dès leur réception. La numérotation doit être continue.

Dans l'exemple qui suit, on a choisi cette structure de numérotation :

AAAA-xxxx

où AAAA représente l'année comptable en cours et xxxx une suite qui commence à 0001.

Concrètement, lors de l'encodage le formulaire fEcrAch va attribuer le numéro (le dernier encodé + 1), on reproduit ce numéro sur la facture et on la classe… de manière à la retrouver facilement. Aucune règle n'est imposée pour ce classement (dans l'ordre des N°, par ordre alphabétique…).

La facture du fournisseur constitue la pièce justificative des données encodées dans fEcrAch.

Pour comptabiliser une facture d'achat, il faut :

- créditer le compte du fournisseur pour le montant total de la facture ;

- débiter le compte « TVA A RECUPERER » pour le montant de la TVA ;

- débiter une série de comptes souvent les mêmes pour ce fournisseur, par exemple : « MATIERES 1res » pour l'un, « TELEPHONE » pour tel autre…

Pour faciliter le travail d'encodage, nous proposons que, pour les fournisseurs habituels, on complète la colonne « PCImputa » de la table tPlanComptable avec une chaîne de caractères qui respecte la même syntaxe que celle décrite plus haut pour les boutons de création de schéma de comptabilisation.

VIII-B - Les particularités de fEncoAch

Ici, pas de restriction sur la date, contrairement au mécanisme décrit pour les formulaires d'encodage de type « Compte de trésorerie » (fEcrCai et fEcrBan).
tEcritures contiendra donc, pour l'origine « Ach » plusieurs enregistrements portant la même date.

Le numéro de séquence de la facture est attribué lors de la création de l'enregistrement voyez la valeur par défaut de ce contrôle :

Remarquez que ce N° de facture est systématiquement reporté comme valeur par défaut du contrôle « txtImLibelle » du sous-formulaire lors de l'événement « Sur activation » :

'Libelle par défaut = N° de facture
Me.ctnrsfImputa!txtImLibelle.DefaultValue = Me.txtEcNumFac

Ce qui entraine que tous les mouvements concernant l'enregistrement de cette facture auront son N° comme libellé.

Seuls les comptes de la plage réservée aux fournisseurs peuvent être choisis.

Voici la requête de la propriété « Contenu » du choix par nom de fournisseur :

SELECT PCIntitule, PCCpte FROM tPlanCompta WHERE PCCpte Between Cpte("Fournisseurs")+1 And Cpte("Fournisseurs")+999 ORDER BY PCIntitule;

Le choix du fournisseur déclenche le formatage du bouton btImputa (voir la description quelques lignes plus bas).

La date inscrite sur la facture du fournisseur n'est pas un élément obligatoire pour notre comptabilité. Cette donnée est utile si la facture n'a pas été payée au comptant : elle nous servira pour déterminer l'urgence du paiement (deuxième partie - à venir - de cet article).

Bouton btImputa.

VIII-B-1 - Événement « Après mise à jour » du choix d'un fournisseur

On affecte le N° de facture à la propriété « Légende » du bouton.

Dans la propriété « Remarque », on inscrit :

- Me.ActiveControl c'est-à-dire le N° du compte fournisseur, suivi d'un C (pour crédit) et le point-virgule séparateur ;

- pour ajouter le N° du compte TVA à débiter, on appelle « Cpte("TVA A RECUPERER") » ceci pour éviter de coder le N° « en dur » ;

Si l'utilisateur a prévu pour ce fournisseur une chaîne d'imputation : on l'ajoute, précédée du point-virgule.

On rend le bouton btImputa visible.

On affecte le N° de facture au libellé de l'écriture.

Si la date n'a pas encore été saisie, on rappelle qu'elle est obligatoire.

IX - L'encodage des factures aux clients : fEcrFac

IX-A - Contexte opérationnel

Le restaurant qui nous sert d'exemple émet peu de factures. En général pour des firmes qui organisent un repas d'affaires ou pour fêter un événement avec des membres de leur personnel (fêtes patronales, départ à la retraite…).

On établit aussi une facture pour des services traiteur qui ne sont pas payés directement au comptoir.

Les factures émises sont numérotées de manière continue.

Dans l'exemple qui suit, on a choisi cette structure de numérotation :

AAAA-xxxx

où AAAA représente l'année comptable en cours et xxxx une suite qui commence à 0001.

Concrètement, lors de l'encodage le formulaire fEcrFac va attribuer le numéro suivant.

On pourrait greffer sur ce formulaire des fonctions permettant d'établir la facture, de l'imprimer et même de l'envoyer annexée à un e-mail. Ce n'est pas envisagé dans le cadre de cet article.

IX-B - Les particularités de fEcrFac

Ce formulaire n'appelle pas de commentaires dans la mesure où sa composition et son fonctionnement sont semblables à ceux de fEcrAch.

X - L'encodage des opérations diverses : fEcrDiv

X-A - Contexte opérationnel

On enregistre ici toutes les opérations qui ne concernent ni un compte de trésorerie ni les factures.

Par exemple des écritures de régularisation : comme solder les comptes transitoires des recettes pour dégager les chiffres d'affaires hors TVA, comptabiliser les amortissements, les salaires à payer…

X-B - Les particularités de fEncoDiv

En fait, rien de particulier dans la mesure où tous les mécanismes mis en œuvre ont été décrits plus haut.

XI - La création des mouvements comptables proprement dits

XI-A - L'idée : une routine polyvalente…

C'est la même routine, quel que soit le formulaire d'encodage qui l'appelle.

XI-B - … sollicitée en permanence

À chaque lecture d'un enregistrement et à sa fermeture, le formulaire appelle la routine et tous les mouvements qui concernent ce formulaire sont systématiquement recréés depuis le début de l'exercice comptable.

Ainsi, si a posteriori on constate une erreur d'encodage, il suffit de la corriger et une nouvelle génération des mouvements viendra remplacer celle qui était erronée.

Du point de vue de l'orthodoxie comptable, cette pratique est en conflit avec le principe de l'irréversibilité des écritures.

Celle-ci implique :

- qu'une écriture ne peut être modifiée ultérieurement autrement que de manière visible, c'est-à-dire laissant apparaître, d'une part l'écriture initiale et, d'autre part, la correction apportée ;

- qu'une écriture ne peut être omise ultérieurement, sans que l'écriture initiale et son annulation ultérieure n'apparaissent clairement ;

- qu'une écriture additionnelle ne peut être insérée après coup, sans que cela n'apparaisse clairement.

Dans la pratique, ces corrections ne sont possibles que si elles restent sans conséquence pour la concordance avec les pièces officielles : factures des fournisseurs, extraits bancaires, carnets de souches TVA, déclarations officielles fiscales et sociales…

XI-C - Le code

On détermine le code « Origine » : les trois dernières positions du nom du formulaire qui appelle la routine.

On supprime tous les mouvements dont l'origine correspond.

Exemple pour fEcrCai :

On recrée tous les débits pour ce formulaire.

Exemple pour fEcrCai :

De même pour les crédits :

On crée les contreparties au compte « Caisse » des imputations dans fEcrCai :

De même pour le compte « Banque » :

XII - Conclusion de cette première partie

À ce stade, on se retrouve dans un environnement comptable classique : la table tMvts contient tous les débits et crédits qui traduisent les faits qui ont été saisis dans les différents formulaires d'encodage.

Il « suffit » de les agréger pour construire les différentes situations comptables classiques.

Cela fera l'objet d'un article à venir dans lequel nous présenterons aussi quelques outils de confort pour faciliter le travail du comptable.

XIII - Recommandations si vous voulez adapter ceci à votre environnement

Adoptez un plan comptable numéroté à six chiffres et/ou lettres. Certains automatismes tablent sur le nombre de caractères du N° de compte (pour les boutons de génération de schéma de comptabilisation par exemple).

Veillez au respect de l'intitulé de certains comptes qui interviennent dans le code : ceux appelés par la fonction Cpte() pour éviter de coder « en dur » des N° :

- CLIENTS ;

- FOURNISSEURS ;

- TVA A PAYER ;

- TVA A RECUPERER ;

- BANQUE ;

- CAISSE.

Vous pouvez avoir autant de formulaires que vous jugez nécessaires. Peu importe leur nom, pour autant que les trois dernières positions du nom constituent une chaîne sans doublon.

Quoi qu'il en soit, la db qui m'a servi d'exemple se trouve ici.

XIV - Remerciements

Merci à Pierre Fauconnier, Arkham46 pour leurs conseils techniques et à zoom61 pour la relecture orthographique.

(1)Donc, rien vous oblige à utiliser cette numérotation dans votre système comptable usuel, pour autant que vous soyez capable de publier vos données comptables dans le gabarit légal.

(2)« Procéder de » signifie « découler ».