Lokaler Webshop, Teil II

Nach dem Anzeigen der Artikel unseres in Access nachgebildeten Webshops der vorletzten Ausgabe geht es nun an das Bestellen der Produkte bei der ABasics Computer GmbH. Für den hier benötigten Warenkorb, die Kasse und die Bestellvorgänge kommen ganz neue Formulare ins Spiel. Deren Design, Aufbau und Programmierung widmet sich dieser Beitrag, wobei allerlei Tricks und Kniffe nicht zu kurz kommen.

Beispieldatenbank

Die Beispiele dieses Artikels finden Sie in der Datenbank 1610_Web-shopII.zip.

Bestellen im Webshop

Sie möchten im Hauptformular frmShop der Anwendung einen Drucker bestellen. Nach Auswahl der Produktkategorie Drucker im Kombinationsfeld links oben, und nach Markierung der Unterkategorie Tintenstrahler ab A3 im Listenfeld links, füllt sich die Produktliste lstArtikel in der Mitte mit den verfügbaren Produkten. Da Ihnen der Hersteller Hewlett-Packard am vertrauenswürdigsten erscheint, filtern Sie diese Liste über das Kombinationsfeld rechts oben (siehe Bild 1). In dieser Combobox finden sich ausschließlich jene Hersteller, die auch in der Produktliste aufgeführt sind. Ihre Datenherkunft verhält sich also dynamisch in Abhängigkeit von der gewählten Unterkategorie.

So präsentiert sich der Webshop nach dem Start des Formulars frmShop mit eingestellten Kategorien und einem Produkt

Bild 1: So präsentiert sich der Webshop nach dem Start des Formulars frmShop mit eingestellten Kategorien und einem Produkt

Listing 1 zeigt, wie sie bei Auslösen des Ereignisses Nach Aktualisierung des Listenfelds lstKategorien über einen neuen SQL-Select-Ausdruck festgelegt wird. Die RowSource des Steuerelements ist im Prinzip an die Tabelle tblHersteller gebunden. Damit aus dieser aber nur jene Datensätze ausgewählt werden, die in ihrem Feld ID den gleichen Wert aufweisen, der auch in der Kategorienliste markiert ist (lstKategorien.Value), benötigen wir eine Zwischenabfrage, denn die Herstellertabelle kennt selbst keine Kategorien. Das ist ein schönes Beispiel für den Einsatz der IN-Klausel. Aus tblArtikel ermittelt die Select-Abfrage innerhalb der Klammer alle Datensätze, deren Kategorien (IDKategorie) mit dem markierten Eintrag des Listenfelds übereinstimmen und gibt aus ihren nur jeweils die IDHersteller zurück. Befindet sich wiederum eine ID der Herstellertabelle IN diesem Pool, so ist die Bedingung positiv und der Datensatz mitsamt der Herstellerbezeichnung wird ausgegeben, so dass er im Kombinationsfeld erscheinen kann.

Private Sub lstKategorien_AfterUpdate()
     ...
     Me!cbHerstellerFilter.RowSource = "SELECT * FROM tblHersteller " & _
         "WHERE ID IN(SELECT IDHersteller FROM tblArtikel WHERE IDKategorie=" & _
         Me!lstKategorien.Value & ")"
     ...
End Sub

Listing 1: Setzen der Datenherkunft der Hersteller-Combobox cbHersteller

Sie interessieren sich für den Deskjet T730 und haben ihn in der Produktliste markiert. Seine Details gibt nun das Unterformular rechts im Bild wieder. Den Preis finden Sie OK und Sie klicken auf den Button In den Warenkorb. Damit erscheint sogleich in einer Msgbox die Info aus Bild 2. Klicken Sie erneut auf den Button, so zeigt sich eine abweichende Meldung (Bild 3).

Info zum Warenkorb

Bild 2: Info zum Warenkorb

Info zum Warenkorb bei wiederholtem Hinzufügen

Bild 3: Info zum Warenkorb bei wiederholtem Hinzufügen

Die beim Klicken auf den Button cmdAdd ausgelöste Prozedur finden Sie in Listing 2.

Private Sub cmdAdd_Click()
     Dim n As Long
     Dim ID As Long
     
     n = Nz(DLookup("Anzahl", "tblBestellDetails", "ArtikelID=" & Me!ID.Value & _
            " AND BestellID=" & BestellID))
     If n = 0 Then
         CurDB.Execute "INSERT INTO tblBestellDetails" & _
                       " (BestellID,ArtikelID,Anzahl,Netto,Ust)" & _
                       " VALUES (" & BestellID & "," & Me!ID.Value & ",1," & _
                       Str(Me!Netto.Value) & "," & Str(Me!USt.Value) & ")"
         MsgBox "Sie haben '" & Me!Produkt & "' in den Warenkorb gelegt.", vbInformation
     Else
         ID = DLookup("ID", "tblBestellDetails", "ArtikelID=" & Me!ID.Value & _
              " AND BestellID=" & BestellID)
         CurDB.Execute "UPDATE tblBestellDetails SET Anzahl=" & (n + 1) & _
                       " WHERE ID=" & ID
         MsgBox "Sie haben die Anzahl von '" & Me!Produkt & "' im Warenkorb erhöht."
     End If
     Me!cbWarenkorb.Requery
End Sub

Listing 2: Das Legen eines Produkts in den Warenkorb über den Button cmdAdd

In der ersten Zeile ermittelt eine DLookup-Funktion zunächst die Anzahl jener Artikel, die sich bereits in der Bestellung befinden, wobei nach dem aktuell ausgewählten Produkt (ArtikelID = Me!ID) und nach der momentanen Bestellung (BestellID) gefiltert wird. Im ersten Betrag wurde erläutert, dass schon beim öffnen des Shop-Formulars ein temporärer Bestelldatensatz in der Tabelle tblBestellDetails angelegt und ein Verweis auf dessen ID in der globalen Variablen BestellID abgespeichert wird. Hier nun kommt diese ID zum Tragen. Ist der Artikel bereits in der Bestellung vorhanden, so gibt DLookup einen von 0 abweichenden Wert zurück und weist diesen der Variablen n zu. Die Prozedur verzweigt jetzt in Abhängigkeit von diesem Wert.

Ist der Artikel neu, was den einfacheren Fall darstellt so findet das Einfügen eines Datensatzes über die INSERT INTO-Anweisung statt. Ihr werden als Feldparameter die aktuelle BestellID, der Preis (Me!Netto) und der Umsatzsteuersatz (Me!Ust) verabreicht. Diese letzten beiden Werte können nicht aus der Artikeltabelle entnommen werden! Denn bald könnte sich der Preis ja ändern, was bei Bearbeitung der Bestellung zu einer erhöhten Summe führen würde.

Hier muss der aktuelle Preis gelten, weshalb er fest in den Bestelldatensatz gespeichert werden muss. Die anschließende MsgBox zeigt nun lediglich das Produkt (Me!Produkt) in einem entsprechenden Text an.

Ist der Artikel in der Bestellung bereits vorhanden, also der Wert von n ungleich 0, so führt sich der nächste Zweig der Prozedur aus. Hier muss erst ermittelt werden, welche ID der betreffende Bestelldatensatz hat, wobei abermals eine DLookup-Funktion verwendet wird. Anschließend erhöht eine SQL-UPDATE-Anweisung den Wert des Felds Anzahl im gefundenen Datensatz. Die Meldung sieht nun geringfügig anders aus.

Auf die Bedeutung der letzten Zeile, die ein Requery auf das Kombinationsfeld cbWarenkorb auslöst, kommen wir gleich zu sprechen.

Die SQL-Anweisungen geschehen übrigens über die Objektvariable CurDB. Das ist tatsächlich eine Funktion, die nur die Access-Eigenschaft CurrentDb ersetzt. Sie befindet sich im Modul mdlShop der Datenbank (Listing 3). Die im Kopf des Moduls deklarierte Objektvariable thisdb bekommt beim ersten Aufruf der Funktion den Inhalt von CurrentDb verpasst. Forthin gibt sie deren Wert zurück. Der Vorteil der Funktion ist, neben kürzerer Schreibweise, eine bessere Performance.

Private thisdb As Database 
Function CurDB() As Database
     If thisdb Is Nothing Then Set thisdb = CurrentDb
     Set CurDB = thisdb
End Function

Listing 3: CurDB gibt die aus CurrentDb erhaltene Objektvariable thisdb zurück

Artikel im Warenkorb

Für den Warenkorb ist dieselbe Tabelle verantwortlich, wie für die Bestellungen: tblBestelldetails. Ohne das Formular für den Warenkorb zu öffnen können bereits im Shop-Formular die hinzugefügten Artikel inspiziert werden. Dazu klicken Sie mit der Maus auf den Button Warenkorb rechts. Sogleich klappt eine Combobox mit der Liste der bestellten Produkte auf (Bild 4). Der Vorgang mag ungewöhnlich sein. In Webshops passiert dies häufig beim überfahren der Maus auf ein Warenkorbsymbol. Dies nachzustellen wäre hier des Aufwands etwas zu viel gewesen. Die Combobox soll genügen. Ihre Datenherkunft ist an eine Abfrage gebunden, die folgenden Text hat:

Der Inhalt des Warenkorbs kann über eine Combobox eingesehen werden, die sich hinter dem Button befindet

Bild 4: Der Inhalt des Warenkorbs kann über eine Combobox eingesehen werden, die sich hinter dem Button befindet

SELECT 
   "- " & [tblArtikel].[Produkt] AS P,
   tblArtikel.ID,
   tblArtikel.IDKategorie,
   tblBestellDetails.BestellID
FROM tblArtikel
INNER JOIN
tblBestellDetails ON tblArtikel.ID =
    tblBestellDetails.ArtikelID
WHERE tblBestellDetails.BestellID = 
   [Forms]![frmShop]![txtBestellID]

Die Datensätze bilden sich über den JOIN aus der Verknüpfung zwischen tblBestellDetails mit tblArtikel. Da nur die aktuelle Bestellung berücksichtigt werden soll, filtert die WHERE-Bedingung nach der BestellID. Und die kommt direkt aus dem Formular frmShop, in dem das unsichtbare Textfeld txtBestellID vorhanden ist. Superelegant ist derlei nicht, aber als Datenherkunft für ein Kombinationsfeld innerhalb des Formulars ist so ein fester Bezug durchaus akzeptabel. Die Requery-Anweisung auf cbWarenkorb führt zur Neuauswertung der SQL-Abfrage, so dass ihr Datenbestand immer aktuell ist.

Das Ausklappen der Combobox erledigt die Routine in Listing 4. Bei Rechtsklick auf die Schaltfläche Warenkorb (cmdWarenkorb) ereignet sich das MouseDown-Event. Steht der Parameter Button auf 2, so handelt es sich um die rechte Maustaste. Dann stellt die Prozedur den Fokus auf die Combobox cbWarenkorb und bewirkt über die Methode Dropdown deren Ausklappen. Sie gerät dadurch in den Vordergrund, obwohl sie im Formularentwurf in den Hintergrund verfrachtet wurde. Bei Verlassen des Steuerelements wird automatisch wieder der Ausgangszustand hergestellt.

Private Sub cmdWarenkorb_MouseDown(Button As Integer, Shift As Integer, _
                                    X As Single, Y As Single)
     If Button = 2 Then
         Me!cbWarenkorb.SetFocus
         Me!cbWarenkorb.Dropdown
     End If
End SUb

Listing 4: Ausklappen der Combobox beim Maustaste Ab-Ereignis des Buttons

Beim normalen Linksklick auf den Button Warenkorb ruft dieser die Click-Prozedur auf und öffnet das Formular frmWarenkorb (Bild 5).

Allerdings auch nur dann, wenn sich im Warenkorb Artikel befinden. Ansonsten erfolgt eine Meldung, dass der Warenkorb leer sei. Die erste Zeile in Listing 5 wertet über COUNT(*) aus, wie viele Datensätze die Tabelle tblBestellDetails zur aktuellen BestellID aufweist. Ist die Anzahl 0, so kommt es zur Meldung und andernfalls zum öffnen des Formulars.

Private Sub cmdWarenkorb_Click()
     Dim n As Long
     
     n = CurDB.OpenRecordset("SELECT COUNT(*) FROM tblBestellDetails" & _
                             " WHERE BestellID=" & BestellID)(0)
     If n = 0 Then
         MsgBox "Ihr Warenkorb ist leer!", vbExclamation, sLogo
     Else
         DoCmd.OpenForm "frmWarenkorb", , , , , , BestellID
     End If
End SUb

Listing 5: Das Starten des Warenkorbformulars hängt von der Anzahl der aktuell bestellten Artikel in tblBestellDetails ab

Warenkorbformular

Das gestartete Warenkorbformular frmWarenkorb (Bild 5) weist die folgenden Grundeinstellungen auf. Die Eigenschaft Popup steht auf Ja und die Eigenschaft Gebunden ebenfalls. Dadurch steht es im Vordergrund vor dem Shop-Formular, auf welches nun kein Zugriff mehr möglich ist. Als Ansichtsmodus ist Endlosformular vorgesehen. Im Detailbereich finden sich die Felder für die Bestelldetails, also die Produkte mit deren Artikelnummer, der Bezeichnung, der gewünschten Anzahl, dem Preis und der Verfügbarkeit. Bis auf das Steuerelement für die Anzahl sind alle weiteren gesperrt (Eigenschaftenblatt für das Steuerelement | Daten | Gesperrt = Ja). Die Anzahl kann der Kunde im Warenkorb noch ändern.

So etwa zeigt sich das Formular frmWarenkorb mit zwei bestellten Produkten

Bild 5: So etwa zeigt sich das Formular frmWarenkorb mit zwei bestellten Produkten

Möchten Sie weiterlesen? Dann lösen Sie Ihr Ticket!
Hier geht es zur Bestellung des Jahresabonnements des Magazins Access [basics]:
Zur Bestellung ...
Danach greifen Sie sofort auf alle rund 400 Artikel unseres Angebots zu - auch auf diesen hier!
Oder haben Sie bereits Zugangsdaten? Dann loggen Sie sich gleich hier ein:

Schreibe einen Kommentar