Abonnements verwalten, Teil 2

Im ersten Teil dieser Beitragsreihe haben Sie das Datenmodell der Abonnementverwaltung und einige Formulare zur Eingabe von Kunden, Produkten und Abonnements erstellt. Im zweiten Teil kümmern wir uns um weitere Funktionen – zum Beispiel das Ermitteln abgelaufener Abonnements und die Verlängerung, Kündigung und Stornierung von Abonnements.

Abonnements kündigen und stornieren

Kunden können Abonnements kündigen und stornieren. Dies sind zwei unterschiedliche Vorgänge. Bei einer Kündigung wird das laufende Abonnement noch durchgeführt, die automatische Verlängerung bleibt jedoch aus.

Bei einer Stornierung wird das aktuelle Abonnement storniert. Dies ist in der Regel nur innerhalb der ersten zwei bis vier Wochen nach der Bestellung möglich – je nach Kulanz des Anbieters.

Für beide Fälle enthält die Tabelle tblAbonnements je ein Datumsfeld. Das erste heißt GekuendigtAm, das zweite StorniertAm. Für den Bearbeiter des Abonnements ist es wohl am einfachsten, wenn er das Datum der Kündigung beziehungsweise der Stornierung manuell eingibt. Dies soll – neben dem Speichern des jeweiligen Datums – gleichzeitig noch eine weitere Aktion auslösen, nämlich den Versand einer E-Mail mit der Bestätigung der Kündigung oder Stornierung.

Wenn Sie nicht komplett digital arbeiten, können Sie natürlich auch einen Bericht mit den Kundendaten und den Daten der Kündigung oder Stornierung erzeugen, diesen ausdrucken und per Briefpost versenden.

Kündigung eintragen

Die Kündigung tragen Sie beispielsweise in das Textfeld txtGekuendigtAm des Unterformulars sfmAbonnements des Formulars frmKunden ein (s. Bild 1). Dies sorgt nach dem Bestätigen des eingetragenen Wertes für die Anzeige eines Meldungsfensters, mit dem der Benutzer festlegt, ob der Kunde eine E-Mail mit einer Kündigungsbestätigung erhalten soll.

pic003.png

Bild 1: Eintragen des Kündigungsdatums

Klickt der Benutzer anschließend auf Ja, erstellt die Anwendung eine E-Mail auf Basis der Benutzerdaten und öffnet diese (s. Bild 2).

pic002.png

Bild 3: Kündigungsbestätigung per Ereignisprozedur auslösen

Das Erstellen dieser E-Mail erfolgt mit Outlook. Der dazu benötigte Code ist überschaubar, da wir eine Klasse namens clsMail verwenden, die das Erstellen von E-Mails mit Outlook erheblich vereinfacht.

Diese Klasse und ihre Beschreibung finden Sie im Beitrag Outlook-Mails mit Klasse (www.access-im-unternehmen.de/859).

Um die Klasse clsMail in der Beispieldatenbank Abonnementverwaltung.mdb verfügbar zu machen, importieren Sie diese aus der Beispieldatenbank des Artikels Outlook-Mails mit Klasse. Dies gelingt am einfachsten, indem Sie die VBA-Projekte beider Datenbankanwendungen öffnen und die Klasse clsMails per Drag and Drop von einem Projekt-Explorer in den anderen ziehen.

Damit die Klasse funktioniert, fügen Sie außerdem noch einen Verweis auf die Bibliothek Microsoft Outlook x.0 Object Library zum VBA-Projekt hinzu (Menüeintrag Extras|Verweise im VBA-Editor).

Danach legen Sie die entsprechende Ereignisprozedur an. Öffnen Sie das Formular sfmAbonnements in der Entwurfsansicht und markieren Sie das Textfeld txtGekuendigtAm (die gebundenen Steuerelemente wurden mit entsprechenden Präfixen wie txt, cbo et cetera versehen).

Wählen Sie für die Eigenschaft Nach Aktualisierung den Eintrag [Ereignisprozedur] aus und klicken Sie auf die Schaltfläche mit den drei Punkten (s. Bild 3). Danach ergänzen Sie die im VBA-Editor erscheinende Ereignisprozedur wie in Listing 1.

Listing 1: Erstellen einer Kündigungsbestätigung per E-Mail

Private Sub txtGekuendigtAm_AfterUpdate()
    Dim objMail As clsMail
    If MsgBox("Bestätigung per E-Mail versenden", vbYesNo) = vbYes Then
        Set objMail = New clsMail
        With objMail
            .AnHinzufuegen Me.Parent!EMail
            .Betreff = "Kündigung ''" & Me!cboProduktID.Column(1) & "''"
            .Inhalt = "Hallo " & Me.Parent!cboAnredeID.Column(1) & " " & Me.Parent!txtNachname _
                & ", " & vbCrLf & vbCrLf _
                & "hiermit bestätigen wir Ihnen die Kündigung Ihres Abonnements von ''" _
                & Me!cboProduktID.Column(1) & "''" & vbCrLf & vbCrLf _
                & "Mit freundlichen Grüßen" & vbCrLf & vbCrLf _
                & "Ihr Abo-Service"
            .Anzeigen
        End With
    End If
End Sub

pic004.png

Bild 2: Kündigungsbestätigung per E-Mail

Die Prozedur deklariert ein Objekt des Typs clsMail mit dem Namen objMail. Danach fragt sie mit einer entsprechenden MsgBox-Anweisung, ob die Kündigung per E-Mail versendet werden soll. Falls ja, wird objMail mit einem neuen Objekt der Klasse clsMail instanziert. Mit der Funktion AnHinzufuegen wird der Empfänger hinzugefügt, der aus dem Feld EMail des übergeordneten Formulars (also frmKunden) gewonnen wird.

Den Betreff stellt die Prozedur aus dem Ausdruck Kündigung und dem in Hochkommata eingefassten Namen des Produkts zusammen, der aus der zweiten Spalte des Kombinationfeldes cboProduktID des aktuellen Datensatzes im Unterformular sfmAbonnements gewonnen wird.

Den Inhalt der E-Mail stellt die Prozedur ebenfalls aus einer Mischung aus Literalen und dynamischen Elementen zusammen. Dazu gehören die Anrede und der Nachname aus dem übergeordneten Formular und nochmals die Produktbezeichnung.

Weitere Kunden- und Abonnementdaten verwenden

Sie erkennen bereits, dass es relativ müßig ist, sich die Daten für die Kündigungsbestätigung aus dem Haupt- und dem Unterformular zusammenzuklauben. Noch aufwendiger und wartungsunfreundlicher wird es, wenn Sie noch andere Möglichkeiten zum Eintragen von Kündigungs- und Stornierungsdaten vorsehen möchten.

Sie werden gleich beispielsweise noch ein Formular kennenlernen, das einen Überblick über alle Abonnements gewährleistet und verschiedene Aktionen erlauben soll – auch hier soll das Eintragen von Kündigungs- und Stornierungsdaten möglich sein.

Normalerweise würde man dort zum Versenden der Kündigungs- und Stornierungsbestätigung gern den gleichen Code verwenden, den Sie soeben kennengelernt haben – entweder per Copy and Paste des Codes und kleinere Anpassungen oder durch Refaktorieren. Das bedeutet, dass Sie die Hauptelemente des Codes in eine eigene Funktion füllen und diese von den verschiedenen Stellen aus aufrufen.

Das Problem ist das Zusammenstellen der in der Bestätigung verwendeten Daten: Diese stammen teils aus dem Unterformular, in das Sie das Kündigungs- oder Stornierungsdatum eintragen, teils aus dem übergeordneten Hauptformular. Dieses ist aber vielleicht an anderer Stelle gar nicht vorhanden. Also müssen wir einen flexibleren Weg für den Zugriff auf die Daten des zu bearbeitenden Abonnements und des entsprechenden Kunden finden.

Dies wäre beispielsweise über eine Klasse möglich, die alle relevanten Daten des Kunden und des Abonnements enthält.

Diese wird vor einer Operation, welche auf die Daten des Abonnements zugreifen muss, erzeugt und mit den entsprechenden Stammdaten gefüllt und stellt diese dann über eine einfache Schnittstelle bereit.

Klasse für den einfachen Zugriff auf Abonnementdaten

Die Klasse soll einige der Daten der Tabellen des Datenmodells enthalten. Diese finden Sie in Bild 4 in einer Abfrage namens qryAbonnementsKlasse, die wir speziell für diesen Fall erstellt haben. Um diese Klasse zu erstellen – und zusätzlich eine kleine Prozedur, welche ein Objekt auf Basis dieser Klasse erstellt und diese mit den Daten eines angegebenen Datensatzes füllt -, verwenden wir das Add-In aiuKlassengenerator, das im Beitrag Klassengenerator (www.access-im-unternehmen.de/871) vorgestellt wird.

pic005.png

Bild 4: Felder, die in der Abonnement-Klasse abgebildet werden sollen

Starten Sie das Add-In mit dem Eintrag aiuKlassengenerator des Add-In-Menüs (s. Bild 5). Wählen Sie im Kombinationsfeld Tabelle oder Abfrage den Eintrag qryAbonnementsKlasse aus. Stellen Sie die Eigenschaften Klassenname auf clsAbonnement und Primärschlüsselfeld auf AbonnementID ein. Aktivieren Sie die Option Ladeprozedur hinzufügen und klicken Sie auf Erzeugen, um den Code zu erstellen.

pic006.png

Bild 5: Erstellen der Klasse für den einfachen Zugriff auf die Daten eines Abonnements

Kopieren Sie den oberen Teil des erstellten Codes (bis zur Prozedur ErzeugeAbonnement) in ein neues Klassenmodul namens clsAbonnement. Die Prozedur ErzeugeAbonnement kopieren Sie in das vorhandene Modul mdlAbonnements.

Das Klassenmodul enthält für jedes Feld der zugrunde liegenden Abfrage drei Elemente – eine Membervariable, eine Set/Let-Prozedur und eine Get-Prozedur:

Dim m_AbonnementID As Long
Public Property Get AbonnementID() As Long
    AbonnementID = m_AbonnementID
End Property
Public Property Let AbonnementID(lngAbonnementID As Long)
    m_AbonnementID = lngAbonnementID
End Property

Die Prozedur zum Erzeugen der Klasse auf Basis eines Datensatzes der Abfrage qryAbonnementsKlasse sieht wie in Listing 2 aus. Vereinzelt sind dort noch Anpassungen nötig – so kann es beispielsweise vorkommen, dass die Felder GekuendigtAm oder StorniertAm leer sind. Für diesen Fall fügen Sie dort noch die Nz-Funktion ein, die Nullwerte in diesem Fall durch 0 ersetzt:

objAbonnementsKlasse.StorniertAm = Nz(rst!StorniertAm, 0)

Listing 2: Erstellen eines Objekts auf Basis der Klasse clsAbonnements und Füllen der Eigenschaften der Klasse

Public Function ErzeugeAbonnementsKlasse(lngID As Long) As clsAbonnement
    Dim db As DAO.Database
    Dim rst As DAO.Recordset
    Dim objAbonnementsKlasse As clsAbonnement
    Set db = CurrentDb
    Set rst = db.OpenRecordset("SELECT * FROM qryAbonnementsKlasse WHERE AbonnementID = " _
        & lngID, dbOpenDynaset)
    Set objAbonnementsKlasse = New clsAbonnementsKlasse
    objAbonnementsKlasse.AbonnementID = rst!AbonnementID
    objAbonnementsKlasse.ProduktID = rst!ProduktID
    objAbonnementsKlasse.Produkt = rst!Produkt
    ''... weitere Zuweisungen
    Set ErzeugeAbonnementsKlasse = objAbonnementsKlasse
    Set db = Nothing
End Function

Alternativ können Sie auch den Datentyp für eine Eigenschaft in der Klasse clsAbonnement auf Variant einstellen – dieser nimmt auch Nullwerte entgegen. In diesem Fall ist dies die bessere Variante – hier umgesetzt für das Feld GekuendigtAm:

Dim m_GekuendigtAm As Variant
Public Property Get GekuendigtAm() As Variant
    GekuendigtAm = m_GekuendigtAm
End Property
Public Property Let GekuendigtAm(datGekuendigtAm As Variant)
    m_GekuendigtAm = datGekuendigtAm
End Property

Mit dieser Klasse können Sie etwa das Zusammenstellen der Kündigungsbestätigung viel einfacher gestalten – siehe Listing 3. Diese Prozedur können Sie flexibel aufrufen – also beispielsweise von der Ereignisprozedur txtGekuendigtAm_AfterUpdate aus, in der sich die Funktionalität zuvor befunden hat. Sie müssen nur die Nummer des Abonnements übergeben:

Private Sub txtGekuendigtAm_AfterUpdate()
    KuendigungSenden Me!AbonnementID
    End Sub

Listing 3: Erstellen der Kündigungsbestätigung, verbesserte Variante

Public Sub KuendigungSenden(lngAbonnementID As Long)
    Dim objMail As clsMail
    Dim objAbonnement As clsAbonnement
    If MsgBox("Bestätigung der Kündigung per E-Mail versenden", vbYesNo + vbExclamation, _
            "Kündigungsbestätigung") = vbYes Then
        Set objMail = New clsMail
        Set objAbonnement = ErzeugeAbonnementsKlasse(lngAbonnementID)
        With objMail
            .AnHinzufuegen objAbonnement.EMail
            .Betreff = "Kündigung ''" & objAbonnement.Produkt & "''"
            .Inhalt = "Hallo " & objAbonnement.Anrede & " " & objAbonnement.Nachname & ", " _
                & vbCrLf & vbCrLf _
                & "hiermit bestätigen wir Ihnen die Kündigung Ihres Abonnements von ''" _
                & objAbonnement.Produkt & "''." & vbCrLf & vbCrLf _
                & "Das Abonnement endet am " & Format(DateAdd("m", objAbonnement.Laufzeit, _
                objAbonnement.Startdatum), "dd.mm.yyyy") & "." & vbCrLf & vbCrLf _
                & "Mit freundlichen Grüßen" & vbCrLf & vbCrLf _
                & "Ihr Abo-Service"
            .Anzeigen
        End With
    End If
End Sub

Auf die gleiche Weise könnten Sie diese Prozedur nun von anderen Formularen aus aufrufen – dazu später mehr.

Die Prozedur KuendigungSenden zeigt auch, wie einfach Sie mit den Eigenschaften der Klasse etwa das Kündigungsdatum ermitteln können. Dazu greifen Sie direkt auf die Laufzeit und das Startdatum zu:

Format(DateAdd("m", objAbonnement.Laufzeit, _
objAbonnement.Startdatum), "dd.mm.yyyy")

Natürlich könnten Sie dies auch erledigen, wenn Sie statt des Objekts objAbonnement einfach ein Recordset auf Basis des betroffenen Datensatzes verwenden. Allerdings lässt es sich mit der Klasse viel einfacher programmieren, weil diese alle Felder beziehungsweise Eigenschaften per IntelliSense zur Verfügung stellt.

Sie haben das Ende des frei verfügbaren Textes erreicht. Möchten Sie ...

TestzugangOder bist Du bereits Abonnent? Dann logge Dich gleich hier ein. Die Zugangsdaten findest Du entweder in der aktuellen Print-Ausgabe auf Seite U2 oder beim Online-Abo in der E-Mail, die Du als Abonnent regelmäßig erhältst:

Schreibe einen Kommentar