Excel - Power Query - Power Pivot - VBA

VBA18 | Gérer le catalogue avec une collection d'objets

Énoncé

  • Thème : classes, Collection et Dictionary | Durée : 45 min | Niveau : avancé.
  • Classeur de départ : VBA18_catalogue.xlsm (feuilles Catalogue et Synthèse), avec les fichiers clsArticle.cls et clsArticles.cls dans le même dossier (à télécharger sur la page parente).
  • Contexte : le catalogue de Brévalis Industries compte douze articles. Vous importez la classe clsArticle, rangez ses objets dans une Collection, puis dans une classe collection typée, clsArticles, qui accepte For Each et l'écriture courte catalogue("PS-12"). Vous combinez enfin la collection et un Dictionary pour valoriser le stock par famille.

Travail demandé

  • Ouvrir le classeur, puis l'éditeur Visual Basic (Alt+F11) et le module Module1.
  • Importer la classe clsArticle.
  • Ranger des objets dans une Collection : macro TesterCollection.
  • Importer la classe collection clsArticles.
  • Charger le catalogue dans clsArticles : macro ListerAlertes.
  • Cocher la référence Microsoft Scripting Runtime.
  • Valoriser le stock par famille : macro ValoriserParFamille.
  • Répondre au questionnaire de fin de lab (5 questions, 80 % pour valider).

Importer la classe clsArticle

  • Dans l'éditeur Visual Basic : Fichier > Importer un fichier (Ctrl+M), puis choisissez clsArticle.cls. Le module clsArticle rejoint le dossier Modules de classe.
  • Une classe se réutilise d'un classeur à l'autre : Fichier > Exporter un fichier la sauve en .cls, Fichier > Importer un fichier l'ajoute à un autre projet. clsArticle est la classe du lab VBA16, complétée d'un champ public Famille.

Ranger des objets dans une Collection

Sub TesterCollection()
Dim colArticles As Collection
Dim art As clsArticle
Dim ws As Worksheet
Dim ligne As Long

    Set colArticles = New Collection
    Set ws = Worksheets("Catalogue")
    For ligne = 2 To ws.Cells(ws.Rows.Count, 1).End(xlUp).Row
        Set art = New clsArticle
        art.Ref = ws.Cells(ligne, 1).Value
        art.Designation = ws.Cells(ligne, 2).Value
        colArticles.Add art, art.Ref
    Next ligne
    Debug.Print colArticles.Count; "articles | 3e : "; colArticles(3).Ref; " | PS-20 : "; colArticles("PS-20").Designation
    For Each art In colArticles
        If art.Ref Like "CN-*" Then Debug.Print "  "; art.Designation
    Next art
End Sub
  • Une Collection range des éléments de n'importe quel type, avec une clé facultative (ici la référence). On lit un élément par son indice (à partir de 1) ou par sa clé, et For Each parcourt les éléments. Mais rien n'empêche d'y ranger autre chose qu'un article : la Collection n'est pas typée.
  • Résultat attendu :
    • La fenêtre Exécution affiche 12 articles, PS-12 en 3e position et la désignation de PS-20
    • Les deux carénages nautiques (CN-40 et CN-60) sont listés par For Each

Importer la classe collection clsArticles

  • Dans l'éditeur Visual Basic : Fichier > Importer un fichier (Ctrl+M), puis choisissez clsArticles.cls. Le module clsArticles rejoint le dossier Modules de classe.
  • clsArticles enveloppe une Collection privée et n'accepte que des clsArticle : Add crée l'article et refuse une référence en double, Exists teste une clé sans parcourir la collection, Item, Count et Remove complètent l'ensemble. Deux attributs, invisibles dans l'éditeur, font d'Item le membre par défaut et de NewEnum l'énumérateur qui autorise For Each. Ils ne se saisissent pas : ils sont lus à l'importation du fichier .cls.
  • Après l'importation, ouvrez le code de clsArticles : les lignes Attribute du fichier n'y apparaissent pas.
  • Résultat attendu :
    • clsArticles a bien un membre par défaut (Item) et un énumérateur (NewEnum)

Charger le catalogue dans clsArticles

Function ChargerCatalogue() As clsArticles
Dim cat As clsArticles
Dim art As clsArticle
Dim ws As Worksheet
Dim ligne As Long

    Set cat = New clsArticles
    Set ws = Worksheets("Catalogue")
    For ligne = 2 To ws.Cells(ws.Rows.Count, 1).End(xlUp).Row
        Set art = cat.Add(ws.Cells(ligne, 1).Value)
        art.Designation = ws.Cells(ligne, 2).Value
        art.Famille = ws.Cells(ligne, 3).Value
        art.Prix = ws.Cells(ligne, 4).Value
        art.Stock = ws.Cells(ligne, 5).Value
        art.Seuil = ws.Cells(ligne, 6).Value
    Next ligne
    Set ChargerCatalogue = cat
End Function

Sub ListerAlertes()
Dim cat As clsArticles
Dim art As clsArticle
Dim ws As Worksheet
Dim ligne As Long

    Set cat = ChargerCatalogue()
    Debug.Print cat.Count; "articles | PS-12 existe : "; cat.Exists("PS-12"); " | prix de PS-12 : "; cat("PS-12").Prix
    Set ws = Worksheets("Synthèse")
    ws.Range("A1:C20").ClearContents
    ws.Range("A1").Value = "Article à commander"
    ws.Range("B1").Value = "Stock"
    ws.Range("C1").Value = "Seuil"
    ligne = 2
    For Each art In cat
        If art.EstSousSeuil Then
            ws.Cells(ligne, 1).Value = art.Ref
            ws.Cells(ligne, 2).Value = art.Stock
            ws.Cells(ligne, 3).Value = art.Seuil
            ligne = ligne + 1
        End If
    Next art
End Sub
  • cat.Add crée et renvoie l'article : on le complète aussitôt. cat("PS-12") équivaut à cat.Item("PS-12") grâce au membre par défaut, et For Each art In cat fonctionne grâce à NewEnum. Le code appelant ne voit plus la Collection : il manipule un catalogue.
  • Résultat attendu :
    • La fenêtre Exécution affiche 12 articles, PS-12 existe : Vrai et son prix 564
    • La feuille Synthèse liste les 4 articles à commander avec leur stock et leur seuil

Cocher la référence Microsoft Scripting Runtime

  • Dans l'éditeur Visual Basic : Outils > Références, cochez Microsoft Scripting Runtime, puis OK.
  • La dernière macro regroupe les valeurs par famille dans un Dictionary, en liaison anticipée : la référence Microsoft Scripting Runtime doit être cochée dans ce classeur.

Valoriser le stock par famille

Sub ValoriserParFamille()
Dim cat As clsArticles
Dim art As clsArticle
Dim dFamilles As Scripting.Dictionary
Dim ws As Worksheet
Dim cle As Variant
Dim ligne As Long

    Set cat = ChargerCatalogue()
    Set dFamilles = New Scripting.Dictionary
    For Each art In cat
        dFamilles(art.Famille) = dFamilles(art.Famille) + art.Valeur
    Next art
    Set ws = Worksheets("Synthèse")
    ws.Range("E1").Value = "Famille"
    ws.Range("F1").Value = "Valeur du stock"
    ligne = 2
    For Each cle In dFamilles.Keys
        ws.Cells(ligne, 5).Value = cle
        ws.Cells(ligne, 6).Value = Round(dFamilles(cle), 2)
        ligne = ligne + 1
    Next cle
End Sub
  • La classe collection fournit les objets, le Dictionary les regroupe : la clé est la famille, l'élément cumule art.Valeur. Chaque outil fait ce qu'il sait faire, et la macro reste courte et lisible.
  • Résultat attendu :
    • La feuille Synthèse donne la valeur du stock des 5 familles (colonnes E et F)

Pour aller plus loin