Excel - Power Query - Power Pivot - VBA

VBA16 | Modéliser les articles du stock

Énoncé

  • Thème : modules de classe | Durée : 40 min | Niveau : avancé.
  • Classeur de départ : VBA16_stock.xlsm (feuille Stock).
  • Contexte : le magasin de Brévalis Industries veut contrôler son stock sans multiplier les Cells(ligne, 4) * Cells(ligne, 5) illisibles. Vous créez votre propre objet clsArticle dans un module de classe : champs privés, propriétés Property Get et Property Let avec contrôle de saisie, propriété en lecture seule, méthodes et événement Class_Initialize. Vous l'utilisez ensuite pour analyser la feuille Stock.

Travail demandé

  • Ouvrir le classeur, puis l'éditeur Visual Basic (Alt+F11) et le module Module1.
  • Insérer le module de classe clsArticle.
  • Déclarer les champs privés et les propriétés.
  • Créer un objet et l'utiliser : macro TesterArticle.
  • Ajouter des méthodes et l'événement Class_Initialize : macro TesterMethodes.
  • Analyser la feuille Stock avec l'objet : macro ControlerStock.
  • Répondre au questionnaire de fin de lab (5 questions, 80 % pour valider).

Insérer le module de classe clsArticle

  • Dans l'éditeur Visual Basic : Insertion > Module de classe. Le module Classe1 apparaît dans le dossier Modules de classe.
  • Dans la fenêtre Propriétés (F4), remplacez (Name) Classe1 par clsArticle.
  • Un module de classe décrit un type d'objet : ses données (propriétés) et ses actions (méthodes). Le nom du module devient le nom du type : Dim art As clsArticle. Le préfixe cls distingue les classes des modules standard.

Déclarer les champs privés et les propriétés

  • Code à ajouter dans clsArticle, sous Option Explicit :
Public Designation As String

Private mRef As String
Private mPrix As Double
Private mStock As Long

Public Property Get Ref() As String
    Ref = mRef
End Property

Public Property Let Ref(ByVal sRef As String)
    mRef = UCase(Trim(sRef))
End Property

Public Property Get Prix() As Double
    Prix = mPrix
End Property

Public Property Let Prix(ByVal dPrix As Double)
    If dPrix < 0 Then
        Err.Raise vbObjectError + 1, "clsArticle", "Le prix ne peut pas être négatif."
    End If
    mPrix = dPrix
End Property

Public Property Get Stock() As Long
    Stock = mStock
End Property

Public Property Let Stock(ByVal lStock As Long)
    If lStock < 0 Then
        Err.Raise vbObjectError + 2, "clsArticle", "Le stock ne peut pas être négatif."
    End If
    mStock = lStock
End Property

Public Property Get Valeur() As Double
    Valeur = Round(mPrix * mStock, 2)
End Property
  • Les champs Private (mRef, mPrix, mStock) ne sont visibles que dans la classe. Property Get les lit, Property Let les modifie et peut refuser une valeur (Err.Raise). Valeur n'a pas de Property Let : elle est en lecture seule. Designation, déclarée Public, est un champ public sans contrôle.

Créer un objet et l'utiliser

Sub TesterArticle()
Dim art As clsArticle

    Set art = New clsArticle
    art.Ref = " cx-200 "
    art.Designation = "Capot composite CX-200"
    art.Prix = 365.32
    art.Stock = 24
    Debug.Print art.Ref; " | "; art.Designation; " | valeur : "; art.Valeur
    Set art = Nothing
End Sub
  • New crée une instance de la classe, et Set range sa référence dans la variable. art.Ref = " cx-200 " appelle Property Let Ref, qui met la référence en majuscules sans espaces. art.Valeur appelle Property Get Valeur.
  • Tapez la macro dans Module1, puis lancez-la par F5. Le résultat s'affiche dans la fenêtre Exécution (Ctrl+G).
  • Résultat attendu :
    • La fenêtre Exécution affiche CX-200 | Capot composite CX-200 | valeur : 8767,68

Ajouter des méthodes et l'événement Class_Initialize

  • Dans clsArticle, sous Private mStock As Long :
Private mSeuil As Long
  • Dans clsArticle, à la fin du module :
Private Sub Class_Initialize()
    mSeuil = 5
End Sub

Public Property Get Seuil() As Long
    Seuil = mSeuil
End Property

Public Property Let Seuil(ByVal lSeuil As Long)
    mSeuil = lSeuil
End Property

Public Function EstSousSeuil() As Boolean
    EstSousSeuil = (mStock < mSeuil)
End Function

Public Sub Sortir(ByVal lQuantite As Long)
    If lQuantite > mStock Then
        Err.Raise vbObjectError + 3, "clsArticle", "Stock insuffisant pour " & mRef & "."
    End If
    mStock = mStock - lQuantite
End Sub
  • Dans Module1 :
Sub TesterMethodes()
Dim art As clsArticle

    Set art = New clsArticle
    art.Ref = "ps-12"
    art.Stock = 8
    Debug.Print art.Ref; " | seuil par défaut : "; art.Seuil
    art.Sortir 5
    Debug.Print "Après sortie : "; art.Stock; "| sous le seuil : "; art.EstSousSeuil
    On Error Resume Next
    art.Sortir 10
    Debug.Print "Sortie refusée : "; Err.Description
    Err.Clear
    art.Prix = -10
    Debug.Print "Prix refusé : "; Err.Description
End Sub
  • Une Function ou une Sub publique de la classe devient une méthode de l'objet : art.EstSousSeuil, art.Sortir 5. Class_Initialize s'exécute à chaque New : il pose ici le seuil par défaut. Sortir refuse une sortie supérieure au stock en levant une erreur, que la macro intercepte avec On Error Resume Next.
  • Ajoutez d'abord les deux blocs dans clsArticle, puis la macro dans Module1, et lancez TesterMethodes (F5).
  • Résultat attendu :
    • La fenêtre Exécution affiche le seuil par défaut 5, le stock 3 après la sortie et sous le seuil : Vrai
    • Les deux refus sont affichés : stock insuffisant pour PS-12 et prix négatif

Analyser la feuille Stock avec l'objet

Function LireArticle(ByVal ws As Worksheet, ByVal ligne As Long) As clsArticle
Dim art As clsArticle

    Set art = New clsArticle
    art.Ref = ws.Cells(ligne, 1).Value
    art.Designation = ws.Cells(ligne, 2).Value
    art.Prix = ws.Cells(ligne, 4).Value
    art.Stock = ws.Cells(ligne, 5).Value
    art.Seuil = ws.Cells(ligne, 6).Value
    Set LireArticle = art
End Function

Sub ControlerStock()
Dim ws As Worksheet
Dim art As clsArticle
Dim ligne As Long, nbAlertes As Long

    Set ws = Worksheets("Stock")
    ws.Range("G1").Value = "Valeur stock"
    ws.Range("H1").Value = "Alerte"
    For ligne = 2 To ws.Cells(ws.Rows.Count, 1).End(xlUp).Row
        Set art = LireArticle(ws, ligne)
        ws.Cells(ligne, 7).Value = art.Valeur
        If art.EstSousSeuil Then
            ws.Cells(ligne, 8).Value = "À commander"
            nbAlertes = nbAlertes + 1
        Else
            ws.Cells(ligne, 8).Value = ""
        End If
    Next ligne
    MsgBox nbAlertes & " article(s) à commander", vbInformation
End Sub
  • La fonction LireArticle renvoie un objet clsArticle rempli à partir d'une ligne (Set LireArticle = art). ControlerStock ne manipule plus de numéros de colonnes : art.Valeur et art.EstSousSeuil disent ce qu'ils calculent.
  • Résultat attendu :
    • La colonne G (Valeur stock) contient la valeur de chaque article
    • La colonne H signale « À commander » pour CX-350, CN-40 et PF-25 seulement

Pour aller plus loin