Onlinebanking per Webservice III

Wenn Sie ein Abonnement des Magazins 'Access im Unternehmen' besitzen, können Sie sich anmelden und den kompletten Artikel lesen.
Anderenfalls können Sie das Abonnement hier im Shop erwerben.

Onlinebanking per Webservice III

In den ersten beiden Teilen dieser Beitragsreihe haben wir uns die Funktionen für das Einlesen von Informationen und das Konvertieren von Kontonummern in IBAN sowie das Ermitteln des Kontostandes angesehen. Im abschließenden, letzten Teil wird es spannend: Wir fügen Funktionen hinzu, mit denen Sie die Kontoumsätze abrufen und Überweisungen tätigen können. Damit ist auch der aktuelle Leistungsumfang des hier abgebildeten Webservice der Firma B+S Banksysteme AG beschrieben. Die Nutzung ist weiterhin für private Zwecke kostenlos!

Umsätze abrufen

Diese Funktion ist natürlich etwas umfangreicher als das Einlesen des Kontostandes, da wir ja nicht nur einen einzelnen Wert einlesen, sondern gleich eine ganze Reihe von Werten. Dazu benötigen wir natürlich eine eigene Tabelle, die wir tblUmsaetze nennen, und welche im Entwurf wie in Bild 1 aussieht.

Tabelle zum Speichern der Umsätze

Bild 1: Tabelle zum Speichern der Umsätze

Auf die einzelnen Felder gehen wir gleich bei der Beschreibung des Zugriffs auf den Webservice ein. Wichtig ist an dieser Stelle, dass die Tabelle nicht mit der Tabelle tblKonten verknüpft ist. Stattdessen enthält sie die beiden Felder BankCode und Accountnumber, welche die Bank und das Konto, über das die Transaktionen ausgeführt wurden, eindeutig identifiziert.

Banken fusionieren ja heutzutage gern mal oder ändern ihre Bankleitzahl aus anderen Gründen. Bei der hier durchgeführten Methode behalten Sie auf jeden Fall die Originalbankdaten bei. Es steht Ihnen natürlich frei, die Datensätze der Tabelle tblUmsaetze über ein Fremdschlüsselfeld mit der Tabelle tblKonten zu verknüpfen.

Weiterhin ist hier zu beachten, dass wir für das Feld HashValue einen eindeutigen Index definiert haben. Damit stellen wir sicher, dass ein bereits eingelesener Umsatz nicht nochmals eingelesen wird.

Formularelemente zum Abruf der Umsätze

Nun benötigen wir noch ein Element in der Benutzeroberfläche, um die Umsätze abzurufen und auch anzuzeigen. Dazu erweitern wir einfach das Formular frmKonten, und zwar um eine Schaltfläche namens cmdUmsaetzeEinlesen, zwei Textfelder namens txtStartdatum und txtEnddatum, mit denen Sie den Zeitraum für die einzulesenden Umsätze einstellen können, sowie ein Unterformular zur Anzeige der Umsätze (s. Bild 2).

Anpassungen des Formulars frmKonten

Bild 2: Anpassungen des Formulars frmKonten

Das Unterformular verwendet die Tabelle tblUmsaetze als Datenherkunft und zeigt davon die Felder Amount, Valuta, Purpose, RecBankID, RecAccountNr und RecName an.

Umsätze abrufen

Das Abrufen der Umsätze startet der Benutzer mit einem Klick auf die Schaltfläche cmdUmsaetzeEinlesen. Diese Prozedur sieht wie in Listing 1 aus und prüft zunächst, ob der Benutzer für das Kombinationsfeld cboKontakte überhaupt einen Wert ausgewählt hat.

Private Sub cmdUmsaetzeEinlesen_Click()
     Dim strContactData As String
     Dim strAccountId As String
     Dim strAccountnumber As String
     Dim strErrorCode As String
     Dim strErrorText As String
     Dim strXML As String
     If IsNull(Me!cboKontakte) Then
         MsgBox "Wählen Sie einen Kontakt aus."
         Me!cboKontakte.SetFocus
         Exit Sub
     End If
     strContactData = DLookup("ContactData", "tblKontakte", "KontaktID = " _
         & Me!cboKontakte) 'wegen Längenbeschränkung auf 255 Zeichen
     strAccountId = Me!cboKonten.Column(5)
     strAccountnumber = Me!cboKonten.Column(2)
     strXML = StatementRequest(strContactData, strAccountId, strErrorCode, strErrorText, Nz(Me!txtStartdatum, 0), _
         Nz(Me!txtEnddatum, 0))
     If Len(GetXMLElement(strXML, "//SuccessText")) > 0 Then
         UmsaetzeVerarbeiten strXML, strAccountnumber
         Me!sfmUmsaetze.Form.Requery
     Else
         MsgBox "Fehler:" & vbCrLf & strErrorCode & vbCrLf & strErrorText
     End If
End Sub?

Listing 1: Start des Einlesevorgangs der Umsätze

Anderenfalls erscheint eine entsprechende Meldung und die Prozedur wird beendet.

Danach ermittelt die Prozedur den Wert des Feldes ContactData für den aktuellen Kontakt. Während die folgenden Werte direkt aus den weiteren Spalten des Kombinationsfeldes cboKontakte ausgelesen werden, entnehmen wir diesen Wert per DLookup-Funktion aus der Tabelle tblKontakte. Der Grund ist einfach: Jede Spalte des Kombinationsfeldes kann nur 255 Zeichen aufnehmen, ContactData ist aber länger.

Danach liest die Prozedur die Werte der Felder AccountID und Accountnumber der Tabelle tblKontakte ein, die wir aber bereits in den folgenden Spalten des aktuellen Eintrags des Kombinationsfeldes cboKonten gespeichert haben.

Dann setzt die Prozedur einen Aufruf der Funktion StatementRequest ab, welche ein XML-Dokument mit den angefragten Umsatz-Informationen zurückliefert. Die Funktion erwartet die Werte der Felder ContactData und AccountID, zwei Parameter, mit denen eventuelle Fehlerinformationen zurückgeliefert werden können, sowie das Start- und das Enddatum, wenn nur die Umsätze eines begrenzten Zeitraums eingelesen werden sollen.

Das zurückgelieferte XML-Dokument wertet die Prozedur dann gleich aus – zunächst, indem sie prüft, ob das Ergebnisdokument ein Element namens SuccessText enthält. Ist dies der Fall, war der Aufruf des Webservice erfolgreich und wir können uns an die Auswertung begeben. Das bedeutet in diesem Fall, dass wir den Inhalt des XML-Dokuments zusammen mit dem Wert von strAccountnumber an die Routine UmsaetzeVerarbeiten übergeben. Danach brauchen wir nur noch das Unterformular sfmUmsaetze zu aktualisieren, damit die neu eingelesenen Umsatzpositionen dort angezeigt werden.

Umsätze vom Webservice holen

Die Funktion StatementRequest aus Listing 2 erwartet die bereits erwähnten Parameter. Sie fragt als Erstes per InputBox den PIN für den Zugriff auf das Konto ab und speichert diesen in der Variablen strPIN.

Public Function StatementRequest(strContactData As String, strAccountId As String, strErrorCode As String, _
         strErrorText As String, Optional datStart As Date, Optional datEnde As Date) As String
     Dim objXMLResponse As MSXML2.DOMDocument
     Dim strRequest As String, strResponse As String, strPIN As String
     Dim strStartdate As String, strEnddate As String, strFunction As String
     strFunction = "StatementRequest"
     strPIN = InputBox("PIN:")
     strRequest = "                <ser:StatementRequestData>" & vbCrLf
     strRequest = strRequest & "                    <ser:ContactData>" & strContactData & "</ser:ContactData>" & vbCrLf
     strRequest = strRequest & "                    <ser:AccountId>" & strAccountId & "</ser:AccountId>" & vbCrLf
     If datStart > 0 Then
         strStartdate = Format(datStart, "yyyy-mm-dd")
         strRequest = strRequest & "                <ser:StartDate>" & strStartdate & "</ser:StartDate>" & vbCrLf
     End If
     If datEnde > 0 Then
         strEnddate = Format(datEnde, "yyyy-mm-dd")
         strRequest = strRequest & "                <ser:EndDate>" & strEnddate & "</ser:EndDate>" & vbCrLf
     End If
     strRequest = strRequest & "                </ser:StatementRequestData>" & vbCrLf
     strRequest = strRequest & "                <ser:Pin>" & strPIN & "</ser:Pin>"
     strRequest = CreateSoapRequest(strRequest, strFunction)
     Request strRequest, objXMLResponse
     strResponse = objXMLResponse.XML
     strErrorCode = GetXMLElement(strResponse, "//" & strFunction & "Result/Error/ErrorCode")
     strErrorText = GetXMLElement(strResponse, "//" & strFunction & "Result/Error/ErrorText")
     StatementRequest = FormatXML(objXMLResponse.XML)
End Function

Listing 2: Zusammensetzen des Requests und Zurückgeben des Ergebnisses

Dann beginnt sie, den Request zusammenzusetzen. Dieses sieht anschließend beispielsweise wie folgt aus:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ser="http://service.ddbac.de/">
     <soapenv:Body>
         <ser:StatementRequest>
                 <ser:StatementRequestData>
                     <ser:ContactData>GgxGb1115NitZ...
                         </ser:ContactData>
                     <ser:AccountId>5E3A4E4882B730A...
                         </ser:AccountId>
                 </ser:StatementRequestData>
                 <ser:Pin>12345</ser:Pin>
         </ser:StatementRequest>
     </soapenv:Body>
</soapenv:Envelope>

Wenn der Benutzer ein Start- oder Enddatum angegeben hat, wird die Anfrage noch entsprechend erweitert:

...
<ser:StartDate>2015-01-01</ser:StartDate>
<ser:EndDate>2015-05-31</ser:EndDate>
...

Danach ruft die Funktion die Routine Request auf und übergibt ihr den Request als ersten und ein leeres DOMDocument-Objekt als zweiten Parameter. Letzterer soll die Antwort des Webservice auf den Request aufnehmen.

Das Ergebnis dieses Aufrufs (die Routine Request haben wir bereits im ersten Teil der Beitragsreihe beschrieben) speichert die Prozedur dann in der String-Variablen strResponse. Die im Modul mdlWebservice befindliche Funktion GetXMLElement ermittelt aus dieser Antwort den Inhalt der Elemente Result/Error/ErrorCode und Result/Error/ErrorText und speichert diese, soweit gefüllt, in den beiden Variablen strErrorCode und strErrorText. Ein Response-Dokument mit diesen Fehlerinformationen sieht beispielsweise wie in Listing 3 aus. Sie können diesen Fehler beispielsweise hervorrufen, indem Sie im Testsystem als PIN einen Wert eingeben, der mit 0 beginnt (also etwa 01111). Die Prozedur gibt neben eventuell vorhandenen Fehlerinformationen das zurückgelieferte XML-Dokument als Funktionswert an die aufrufende Prozedur zurück.

<soap:Envelope ...>
     <soap:Body>
         <StatementRequestResponse xmlns="http://service.ddbac.de/">
             <StatementRequestResult>
                 <Error>
                     <ErrorType>BUSINESS</ErrorType>
                     <ErrorCode>9800</ErrorCode>
                     <ErrorText>Der Dialog wurde abgebrochen. Bitte melden Sie sich erneut an. (9800);...</ErrorText>
                     <ErrorCustomerText>Der Dialog wurde abgebrochen. Bitte melden Sie sich erneut an. (9800); 
                         Ungültige Dialogkennung. Bitte melden Sie sich erneut an. (9010)...</ErrorCustomerText>
                     <NoFurtherRequestsPreferred>false</NoFurtherRequestsPreferred>
                 </Error>
             </StatementRequestResult>
         </StatementRequestResponse>
     </soap:Body>
</soap:Envelope>

Listing 3: Rückgabe für eine fehlerhafte Anfrage

Umsätze verarbeiten

Die Prozedur UmsaetzeVerarbeiten aus Listing 4 erwartet das XML-Dokument, das die Funktion StatementRequest geliefert hat, sowie die Kontonummer als Parameter.

Public Sub UmsaetzeVerarbeiten(strXML As String, strAccountnumber As String)
     Dim objXML As MSXML2.DOMDocument
     Dim db As DAO.Database
     Dim rst As DAO.Recordset
     Dim objBACStatementLine As MSXML2.IXMLDOMNode
     Dim strBankCode As String
     Dim strCustomerID As String
     Set objXML = New MSXML2.DOMDocument
     objXML.loadXML strXML
     strBankCode = objXML.selectSingleNode("//CustomerData/BankCode").nodeTypedValue
     strCustomerID = objXML.selectSingleNode("//CustomerData/CustomerId").nodeTypedValue
     Set db = CurrentDb
     Set rst = db.OpenRecordset("SELECT * FROM tblUmsaetze", dbOpenDynaset)
     For Each objBACStatementLine In objXML.selectNodes("//BACStatementLine")
         rst.AddNew
         rst!BankCode = strBankCode
         rst!AccountNumber = strAccountnumber
         rst!BusinessTransactionCode = objBACStatementLine.selectSingleNode("BusinessTransactionCode").nodeTypedValue
         rst!HashValue = objBACStatementLine.selectSingleNode("HashValue").nodeTypedValue
         rst!Amount = Eval(objBACStatementLine.selectSingleNode("Amount").nodeTypedValue)
         rst!StatementNr = objBACStatementLine.selectSingleNode("StatementNr").nodeTypedValue
         rst!BookingDate = DatumAusXML(objBACStatementLine.selectSingleNode("BookingDate").nodeTypedValue)
         rst!Currency = objBACStatementLine.selectSingleNode("Currency").nodeTypedValue
         rst!Valuta = DatumAusXML(objBACStatementLine.selectSingleNode("Valuta").nodeTypedValue)
         rst!BookingRef = objBACStatementLine.selectSingleNode("BookingRef").nodeTypedValue
         On Error Resume Next
         rst!Purpose = objBACStatementLine.selectSingleNode("Purpose").nodeTypedValue
         rst!RecBankId = objBACStatementLine.selectSingleNode("RecBankId").nodeTypedValue
         rst!RecAccountNr = objBACStatementLine.selectSingleNode("RecAccountNr").nodeTypedValue

Dies war die Leseprobe dieses Artikels.
Melden Sie sich an, um auf den vollständigen Artikel zuzugreifen.

Bitte geben Sie die Zahlenfolge in das nachfolgende Textfeld ein

Die mit einem * markierten Felder sind Pflichtfelder.

Aktuell im Blog
Onlinebanking mit Access

Es ist geschafft: Endlich ist das Buch Onlinebanking mit Access fertiggeschrieben. Das war... [mehr]

Direktzugriff auf Tabellen und Felder

Die IntelliSense-Erweiterung für Tabellen und Felder hat mir soviel Spaß gemacht, dass ich gleich... [mehr]

IntelliSense für Tabellen und Felder

Wenn Sie mit dem VBA-Editor arbeiten und dort gelegentlich SQL-Anweisungen eingeben, müssen Sie... [mehr]

Download Access und SQL Server

Erfahren Sie, welche Schritte zum Download des aktuellen Stands des Buchs "Access und SQL Server"... [mehr]

Bilder in Access 2013

Wer die Bibliothek mdlOGL0710 von Sascha Trowitzsch oder ein ähnliches Modul aus meinen... [mehr]

Dynamische Ribbons

Immer wieder fragen Leser, wie man Ribbon-Elemente wie etwa Schaltflächen in Abhängigkeit... [mehr]

Die Blogmaschine

Einen kleinen Blog zusätzlich zum Shop zu betreiben ist eine tolle Sache. Hier lassen sich... [mehr]

Wegwerfadressen für die Newsletteranmeldung

Die Verwendung von Wegwerf-Adressen für die Nutzung aller möglichen Online-Dienste nimmt... [mehr]

Access und Facebook

Facebook und Access - das ist eine der wenigen Kombinationen, die ich noch nicht in die Mangel... [mehr]

Access und SQL Server - das Projekt

Mein neues Buch Access und SQL Server (gemeinsam mit Bernd Jungbluth) geht in die Endphase. Wer... [mehr]