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.
Bild 1: Tabelle zum Speichern der UmsätzeAuf 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).
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.