Rechnungsverwaltung: Kundendetails

Eine Rechnungsverwaltung, mit der Rechnungen an verschiedene Kunden geschickt werden sollen, benötigt eine Tabelle zum Speichern diese Kunden. Logisch, dass wir dieser Tabelle auch ein Formular zum komfortablen Bearbeiten der Kunden an die Seite stellen. Dieses enthält allerdings nicht nur die reinen Kundendaten, sondern wir wollen damit auch noch die Bestellungen des jeweiligen Kunden in einem Unterformular anzeigen – und darüber die Anzeige der Bestelldetails zu ermöglichen.

Unterformular sfmKundeDetails für die Bestellungen

Wir beginnen direkt mit dem Entwurf des Unterformulars zur Anzeige der Bestellungen des Kunden. Dieses wollen wir sfmKundeDetails nennen. Diesem fügen wir über die Eigenschaft Datensatzquelle gleich die Tabelle tblBestellungen hinzu.

Im Gegensatz zum Unterformular aus dem Beitrag Rechnungsverwaltung: Bestellübersicht (www.access-im-unternehmen.de/****), wo wir alle Bestellungen inklusive der Angabe des jeweiligen Kunden in einem Unterformular darstellen, benötigen wir hier nicht mehr die Anzeige des Kunden – dieser wird ja schon im Hauptformular angezeigt, das wir gleich noch erstellen werden. Also fügen wir nun die Felder Bestellnummer, RechnungAm, Zahlungsziel, BezahltAm und StorniertAm zum Detailbereich des Formularentwurfs hinzu.

Dieser sieht anschließend wie in Bild 1 aus. Damit die Daten in der Datenblattansicht angezeigt werden, legen wir die Eigenschaft Standardansicht dort auf den Wert Datenblatt fest. Außerdem wollen wir, dass der Kunde die Daten in diesem Unterformular nicht direkt bearbeiten kann. Daher legen wir die Eigenschaften Anfügen zulassen, Löschen zulassen und Bearbeitungen zulassen jeweils auf den Wert Nein ein. Damit können wir die Arbeiten an diesem Formular vorerst beenden und dieses schließen.

Entwurf des Unterformulars sfmKundeDetails

Bild 1: Entwurf des Unterformulars sfmKundeDetails

Hauptformular frmKundeDetails anlegen

Danach legen wir ein weiteres Formular namens frmKundeDetails an. Bevor wir diesem das Unterformular sfmKundeDetails hinzufügen, müssen wir die Datensatzquelle für das Hauptformular festlegen. So kann Access direkt erkennen, dass es zwischen den Datensatzquellen von Haupt- und Unterformular eine Beziehung gibt und dies entsprechend in den Eigenschaften Verknüpfen von und Verknüpfen nach des Unterformular-Steuerelements vermerken.

Wenn wir schon die Datensatzquelle definiert haben, können wir auch direkt die gewünschten Felder aus der Feldliste in den Detailbereich des Formulars ziehen. Dabei berücksichtigen wir alle Felder mit Ausnahme des Feldes ID, das nur zu Verknüpfungszwecken gepflegt wird und für den Benutzer unsichtbar bleiben soll (siehe Bild 2).

Entwurf des Hauptformulars frmKundeDetails

Bild 2: Entwurf des Hauptformulars frmKundeDetails

Falls Sie sich wundern, dass in unserem Formular beispielsweise für das Feld AnredeID ein Beschriftungsfeld mit dem Text Anrede angelegt wurde: Wir haben direkt im Tabellenentwurf die für die Bezeichnungsfelder gewünschten Texte für die Eigenschaft Beschriftung der jeweiligen Felder hinterlegt. Mehr dazu erfahren Sie im Beitrag Bezeichnungsfelder im Griff (www.access-im-unternehmen.de/****).

Unterformular zum Hauptformular hinzufügen

Danach teilen wir die Felder auf zwei Spalten auf, sodass wir unten das Unterformular sfmKundeDetails platzieren können. Dieses ziehen wir aus dem Navigationsbereich in den Formularentwurf und erhalten nach wenigen Anpassungen das Ergebnis aus Bild 3. Zu diesen Anpassungen gehört neben der Ausrichtung und der Einstellung der Größe das Festlegen der Eigenschaften Horizontaler Anker und Vertikaler Anker jeweils auf den Wert Beide. Damit wird das Unterformular mit dem Hauptformular vergrößert.

Das Hauptformular frmKundeDetails mit dem Unterformular

Bild 3: Das Hauptformular frmKundeDetails mit dem Unterformular

Gegebenenfalls können Sie sich nun noch davon überzeugen, dass Access automatisch das Primärschlüsselfeld ID der Tabelle tblKunden für die Eigenschaft Verknüpfen nach und das Fremdschlüsselfeld KundeID der Tabelle tblBestellungen für die Eigenschaft Verknüpfen von eingetragen hat. Dies stellt sicher, dass das Unterformular immer nur die Datensätze der Tabelle tblBestellungen anzeigt, die mit dem Datensatz der Tabelle tblKunden aus dem Hauptformlar verknüpft sind.

Da wir bereits einige Beispieldatensätze angelegt haben, wie im Beitrag Rechnungsverwaltung: Beispieldaten (www.access-im-unternehmen.de/****) beschrieben, finden wir beim Wechsel in die Formularansicht bereits einige Beispieldaten vor (siehe Bild 4).

Ein Kunde und seine Bestellungen

Bild 4: Ein Kunde und seine Bestellungen

Validierung im Hauptformular

Damit können wir uns nun um die Validierung der Eingabefelder im Hauptformular kümmern. Hier sind Einschränkungen bei folgenden Feldern nötig:

  • Anrede: Pflichtfeld
  • Vorname, Nachname, Straße, Ort, Land: Pflichtfelder
  • PLZ: Ausgehend von der vereinfachenden Annahme, wir hätten es mit Adressen aus dem Bereich Deutschland, Österreich und der Schweiz zu tun, muss diese fünf Stellen (für Deutschland) oder vier Stellen (für Österreich und Schweiz) aufweisen.
  • E-Mail: Diese soll grob validiert werden, also auf ein enthaltenes @-Zeichen und einen Punkt.
  • Ust-IDNr.: Soll für Deutschland und Österreich geprüft werden auf DE plus neun Ziffern beziehungsweise auf ATU plus acht Ziffern, für Schweiz muss das Feld leer sein.

Da Pflichtfelder nur beim Speichern des kompletten Datensatzes geprüft werden können und dies für die abhängigen Felder ohnehin der Fall ist, können wir uns hier auf das Ereignis Vor Aktualisierung des Formulars konzentrieren.

Für dieses hinterlegen wir die Prozedur aus Listing 1. Das Ereignis wird nur beim Versuch ausgelöst, den Datensatz nach vorherigen Änderungen zu speichern – also etwa beim Wechsel zu einem anderen Datensatz oder beim Speichern mit der Tastenkombination Strg + S.

Private Sub Form_BeforeUpdate(Cancel As Integer)
     If Len(Nz(Me!txtKundennummer, "")) = 0 Then
         MsgBox "Bitte geben Sie eine Kundennummer ein.", vbOKOnly + vbExclamation, "Kundennummer fehlt"
         Me!txtKundennummer.SetFocus
         Cancel = True
         Exit Sub
     End If
     If Nz(Me!cboAnredeID, 0) = 0 Then
         MsgBox "Bitte wählen Sie eine Anrede aus.", vbOKOnly + vbExclamation, "Anredefehlt"
         Me!cboAnredeID.SetFocus
         Cancel = True
         Exit Sub
     End If
     If Len(Nz(Me!txtVorname, "")) = 0 Then
         MsgBox "Bitte geben Sie einen Vornamen ein.", vbOKOnly + vbExclamation, "Vorname fehlt"
         Me!txtVorname.SetFocus
         Cancel = True
         Exit Sub
     End If
     If Len(Nz(Me!txtStrasse, "")) = 0 Then
         MsgBox "Bitte geben Sie eine Straße ein.", vbOKOnly + vbExclamation, "Straße fehlt"
         Me!txtStrasse.SetFocus
         Cancel = True
         Exit Sub
     End If
     If Len(Nz(Me!txtPLZ, "")) = 0 Then
         MsgBox "Bitte geben Sie eine PLZ ein.", vbOKOnly + vbExclamation, "PLZ fehlt"
         Me!txtPLZ.SetFocus
         Cancel = True
         Exit Sub
     End If
     If Len(Nz(Me!txtOrt, "")) = 0 Then
         MsgBox "Bitte geben Sie einen Ort ein.", vbOKOnly + vbExclamation, "Ort fehlt"
         Me!txtOrt.SetFocus
         Cancel = True
         Exit Sub
     End If
     If Len(Nz(Me!cboLand, 0)) = 0 Then
         MsgBox "WählenSie ein Land aus.", vbOKOnly + vbExclamation, "Land fehlt"
         Me!cboLand.SetFocus
         Cancel = True
         Exit Sub
     End If
     If Len(Nz(Me!txtEMail, "")) = 0 Then
         MsgBox "Bitte geben Sie eine E-Mail-Adresse ein.", vbOKOnly + vbExclamation, "E-Mail-Adresse fehlt"
         Me!txtEMail.SetFocus
         Cancel = True
         Exit Sub
     End If
End Sub

Listing 1: Validieren beim Speichern des Datensatzes

Vorab die Information, dass wir alle gebundenen Steuerelemente mit Präfixen versehen haben, in diesem Fall die Textfelder mit txt und die Kombinationsfelder mit cbo. Auf diese Weise kann man sauber zwischen den Feldnamen der Datensatzquelle und den daran gebundenen Steuerelementen unterscheiden.

Diese Prozedur enthält einige If…Then-Bedingungen, die jeweils eine Überprüfung für ein Feld vornehmen. Die erste untersucht beispielsweise, ob das Feld txtFirma leer ist. Ist das der Fall, erscheint eine entsprechende Meldung, der Fokus wird auf das Textfeld eingestellt und der Rückgabeparameter Cancel auf den Wert True.

Außerdem verlassen wir an dieser Stelle mit Exit Sub die Prozedur. Das Einstellen des Parameters Cancel auf True sorgt dafür, dass der Speichern-Vorgang, der das Ereignis Vor Aktualisierung ausgelöst hat, abgebrochen wird.

Validieren der E-Mail-Adresse

Die E-Mail-Adresse können wir direkt nach der Eingabe validieren und den Benutzer darauf hinweisen, falls die E-Mail-Adresse nicht gültig ist. Deshalb reicht es auch aus, dass wir in der Prozedur Form_BeforeUpdate nur auf eine leere Zeichenkette prüfen. Sobald der Benutzer einmal ein Zeichen für die E-Mail eingegeben hat, kann er dieses nur nach Eingabe einer gültigen E-Mail-Adresse verlassen.

Wie Sie die Gültigkeit einer E-Mail-Adresse überprüfen, haben wir im Beitrag E-Mail-Adressen validieren per VBA (www.access-im-unternehmen.de/****) beschrieben. Die dortige Funktion CheckEMailSyntax verwenden wir auch in diesem Formular, um die E-Mails nach der Eingabe zu prüfen. Dazu hinterlegen wir für das Ereignis Vor Aktualisierung des Textfelds txtEMail die Prozedur aus Listing 2.

Private Sub txtEMail_BeforeUpdate(Cancel As Integer)
     Dim strEMail As String
     strEMail = Nz(Me!txtEMail, "")
     If Not CheckEMailSyntax(strEMail) Then
         MsgBox "Die E-Mail-Adresse ''" & strEMail & "'' ist nicht gültig.", vbOKOnly + vbExclamation, "Ungültige E-Mail"
         Cancel = True
     End If
End Sub

Listing 2: Prozedur zum Prüfen von E-Mails direkt nach der Eingabe

Die Prozedur liest den Inhalt des Textfeldes txtEMail in die Variable strEMail ein. Falls das Feld den Inhalt Null hat, landet eine leere Zeichenkette in strEMail. Danach ruft die Prozedur die Funktion CheckEMailSyntax auf und übergibt dieser die E-Mail-Adresse zur Prüfung. Ist das Ergebnis nicht True, zeigt die Prozedur eine Meldung an. Außerdem sorgt das Einstellen des Parameters Cancel auf den Wert True dafür, dass das Feld nicht verlassen werden kann. Das Ergebnis sieht beispielsweise wie in Bild 5 aus.

Die E-Mail-Adresse konnte nicht validiert werden.

Bild 5: Die E-Mail-Adresse konnte nicht validiert werden.

Postleitzahl validieren

Das Feld PLZ ist ohnehin schon im Datenmodell auf fünf Zeichen begrenzt. Das reicht aus, wenn der Benutzer – wie vorgegeben – nur die Postleitzahl eingibt und nicht, wie hier und da noch zu sehen, die Postleitzahl mit führendem Länderkennzeichen, also beispielsweise D-47137. Es sollen also nur Zahlen eingegeben werden. Das Feld PLZ ist allerdings mit dem Felddatentyp Kurzer Text versehen. Warum das, wenn doch nur Zahlen eingegeben werden können sollen? Weil es auch Postleitzahlen mit führender Null gibt (01234) und diese gern wegfällt, wenn man das Text als Zahlenfeld definiert. Um dennoch dafür zu sorgen, dass nur Zahlen eingegeben werden können, haben wir zwei Möglichkeiten. Die erste ist, nach der Eingabe zu prüfen, ob der Benutzer nur Zahlen eingegeben hat. Das erledigen wir mit der Ereignisprozedur Vor Aktualisierung für das Feld txtPLZ:

Private Sub txtPLZ_BeforeUpdate(Cancel As Integer)
     If Not IsNumeric(Me!txtPLZ) Then
         MsgBox "Die PLZ darf nur aus Zahlen bestehen.",  vbOKCancel + vbExclamation,  "Ungültige Postleitzahl"
         Cancel = True
     End If
End Sub

Dadurch erscheint eine Meldung, wenn der Benutzer andere Zeichen als Zahlen eingibt.

Die Alternative ist, direkt die Eingabe von Zahlen zu unterbinden. Wie das gelingt, zeigen wir im Beitrag Textfeld nur mit bestimmten Zeichen füllen (www.access-im-unternehmen.de/****).

Wir könnten hier noch einen Schritt weitergehen und die Validierung der Postleitzahl vom angegebenen Land abhängig machen. Darauf verzichten wir an dieser Stelle jedoch.

Das Feld Kundennummer

Das Feld Kundennummer nimmt eine besondere Stellung ein. Es soll in unserem Beispiel eine Kundennummer angeben, die mit 99 beginnt und danach sechs Ziffern, bestehend aus Nullen und dem Wert des Primärschlüsselfeldes besteht. Für den Primärschlüsselwert 123 also beispielsweise 99000123. Dieser Wert soll möglichst automatisch erzeugt werden, wenn der Benutzer die ersten Daten in den Kundendatensatz einträgt. Wie man dies realisieren kann, lernen Sie im Beitrag Nummern für Bestellungen et cetera generieren (www.access-im-unternehmen.de/****).

Dort entnehmen wir die folgenden beiden Prozeduren, von denen die erste ausgelöst wird, wenn der Benutzer irgendein Feld bearbeitet. Dieses prüft, ob es sich um einen neuen, leeren Datensatz handelt und stellt die Eigenschaft TimerInterval auf 100 ein:

Private Sub Form_Dirty(Cancel As Integer)
     If Me.NewRecord Then
         Me.TimerInterval = 100
     End If
End Sub

Dadurch wird das Ereignis Bei Zeitgeber 100 Millisekunden später ausgelöst. Dieses stellt die Kundennummer auf einen Wert ein, welche aus 99000000 und dem Primärschlüsselwert zusammengesetzt ist. Danach stellt sie die Eigenschaft TimerInterval wieder auf 0 ein, was dazu führt, dass die Prozedur Form_Timer vorerst nicht erneut ausgelöst wird:

Private Sub Form_Timer()
     Me!txtKundennummer = Format(Me!ID, "99000000")
     Me.TimerInterval = 0
End Sub

Der Hintergrund ist, dass der Autowert für das Primärschlüsselfeld erst einen Augenblick nach dem Auslösen von Bei Geändert gesetzt wird und wir erst dann auf diesen zugreifen können, um ihn als Grundlage für die Kundennummer zu verwenden.

Kundennummer vor Zugriff schützen

Wenn wir die Kundennummer wie in diesem Fall beim Anlegen eines neuen Kunden per Code festlegen, sollten wir das irgendwie für den Benutzer kenntlich machen. Anderenfalls denkt er vielleicht, er müsse die Kundennummer selbst anlegen.

Die einfachste Möglichkeit ist, das Feld einfach zu deaktivieren und vor seinem Zugriff zu schützen. Dazu stellen wir die Eigenschaft Aktiviert des Textfeldes txtKundennummer auf Nein ein. Wir können das Feld auch so formatieren, dass der Kunde es gar nicht als editierbar wahrnimmt. Dazu stellen Sie auch noch die Eigenschaft Gesperrt auf Ja ein.

Damit der Rahmen verschwindet, legen Sie für die Eigenschaft Rahmenart den Wert Transparent fest. Und schließlich richten wir den Inhalt über den Wert Linksbündig für die Eigenschaft Textausrichtung noch links aus.

Die Kundennummer wird nun automatisch angelegt, sobald der Benutzer irgendein Feld bearbeitet, und erscheint wie in Bild 6.

Automatisches Anlegen der Kundennummer

Ende des frei verfügbaren Teil. Wenn Du mehr lesen möchtest, hole Dir ...

den kompletten Artikel im PDF-Format mit Beispieldatenbank

diesen und alle anderen Artikel mit dem Jahresabo

Schreibe einen Kommentar