-
Notifications
You must be signed in to change notification settings - Fork 44
Plugins in Pecunia (deutsch)
Plugins dienen in Pecunia dazu, auf Quellen von Zahlungsinformation zuzugreifen, die nicht über das, zumeist in Deutschland gebräuchliche, HBCI/FinTS Protokoll angesprochen werden können. Das können Kreditkarteninformation, Paypal oder andere Quellen sein - was immer man über das http(s) Protokoll erreichen kann.
Implementiert werden Plugins mittels Javascript, wobei jedes Plugin in einer eigenen Datei implementiert sein muss. Die js Dateien müssen im Datenordner von Pecunia, im Unterordner Plugins abgelegt werden. Dieser wird zu Beginn mit Standardplugins gefüllt, falls diese dort nicht existieren. Den Datenordner findet man über die Pecunia Einstellungen -> Speicherort -> Finder... Eine Ordnerhierarchie darüber befindet sich der gesuchte Datenordner, der u.a. auch Plugins und andere Resourcen beinhaltet. Plugins werden beim Start von Pecunia geladen. Für ein Update eines Plugins muss Pecunia deshalb neugestartet werden.
- Plugins werden über eine spezielle ID identifiziert, die zu einem Konto zugewiesen wird, was über dieses Plugin bedient werden soll.
- Ein Plugin kann auch von mehreren Konten verwendet werden. Jedoch kann ein Konto immer nur mit einem Plugin verknüpft sein.
- Plugins laufen grundsätzlich in einem eigenen JS Kontext und werden parallel ausgeführt. Pecunia trägt dafür Sorge, dass z.B. PIN Abfragen serialisiert werden.
- Der Arbeitskontext selbst enthält kein DOM und kann auch nicht für Webanfragen verwendet werden. Stattdessen wird von Pecunia eine WebView Instanz (names webClient) in den Arbeitskontext injiziert, der für sämtliche Anfragen, Manipulationen usw. Verwendung findet. Dabei steht dem Plugin Programmierer fast die gesamte Funktionalität von WebKit zur Verfügung.
- Es gibt eine Testumgebung, um Plugins einfacher entwickeln zu können, ohne dass dazu Pecunia laufen muss. Mehr dazu in einem eigenen Wiki Dokument.
- Zwar meldet der JS Parser viele Fehler, doch kann es vorkommen, dass ein Script wegen eines Syntaxfehlers nicht geladen werden kann, Pecunia davon aber nichts mitbekommt. Deshalb muss ein Plugin script mit einer Zeile "true;" beendet werden. Dieser Wert wird nur dann zurückgeliefert, wenn wirklich alles beim Laden in Ordnung war. So kann Pecunia das erfolgreiche Laden in jedem Fall bestimmen.
- Auch in der Zeit von IBAN + BIC wird vorerst noch die BLZ für die Plugins verwendet. Zumindest für Banken in DE.
Zur Erkennung eines Plugins muss dieses nicht nur im richtigen Ordner sein, sondern muss eine ID der Form: pecunia.plugin.xxxxx
in einer globalen Variable name
bereitstellen. Desweiteren ist eine Variable description
erforderlich, die eine Klartextbeschreibung für das Plugin enthält. Am besten eine sehr kurze Beschreibung des Kontotyps, dass damit realisiert wird und in einer Auswahlbox angezeigt werden kann. Eine Zahl optionaler Variablen können zusätzliche Informationen, wie Lizenz, Homepage und Authorname enthalten. Ein typisches Set sieht so aus:
var name = "pecunia.plugin.dkbvisa";
var author = "Mike Lischke";
var description = "DKB Kreditkartenkonto";
var homePage = "http://pecuniabanking.de";
var license = "CC BY-NC-ND 4.0 - http://creativecommons.org/licenses/by-nc-nd/4.0/deed.de";
var version = "1.0";
Webanfragen werden grundsätzlich asynchron behandelt. Navigiert wird durch setzen eines Wertes in webClient.URL.
Pecunia ruft beim erfolgreichen Laden der neuen Seite eine callback Funktion im JS Arbeitskontext auf, die vorher durch Zuweisung an webClient.callback
gesetzt werden muss. Es bietet sich an in diesem callback eine Art state machine zu implementieren, die die verschiedenen Navigationsschritte behandelt.
Das Plugin System integriert eine einfache Funktion, um für ein gegebenes Konto (Nummer + BLZ) ein geeignetes Plugin zu finden, sodass der Nutzer oft keine manuelle Zuordnung machen muss. Dazu muss ein Plugin die Funktion canHandle
implementieren, die true
oder false
zurückgibt, je nachdem, ob das Plugin das angegebene Konto unterstützt. Das erste Plugin was true zurückgibt "gewinnt". Beispiel:
function canHandle(account, bankCode) {
if (bankCode != "12030000")
return false;
// Credit cards are the only accounts with 16 digits.
if (account.length != 16)
return false;
return true;
}
Im Arbeitskontext sind verschiedene Mittel integriert, die eine Rückmeldung an Pecunia bzw. den Nutzer erlauben. Zum einen ist da die variable logger
mit seinen Funktionen logError
, logWarning
, logInfo
, logDebug
und logVerbose
, welche Informationen in das Pecunia Log schreiben. In der Testumgebung werden diese Ausgaben in ein Textfeld zur direkten Begutachtung ausgegeben. Außerdem gibt es noch eine Funktion reportError
, mit deren Hilfe man eine Fehlernachricht für den Nutzer anzeigen lassen kann (alert()
oder window.alert()
funktionieren nicht). Alle diese Funktionen akzeptieren nur einen String (die Meldung).
Derzeit ist der Ablauf im Plugin auf die Abfrage von Kontoumsätzen beschränkt. Dazu muss das Plugin eine Funktion mit dieser Signatur bereitstellen:
function getStatements(user, bankCode, password, from, to, numbers) {
...
}
Die Parameter sind in dieser Reihenfolge: die Nutzer ID zur Anmeldung, die BLZ, das Passwort, Start- und Endedatum, sowie ein array mit Kontonummern (oder Kreditkartennummern, wenn es sich um Kreditkartenkonten handelt). Der Rückgabecode muss true
sein, wenn der Prozess erfolgreich gestartet wurde. Anhand des arrays numbers
erkennt man, dass Pecunia Abfragen für mehrere Konten, die alle vom gleichen Plugin bedient werden zusammenfasst. Dadurch lässt sich oft viel Zeit sparen, da nicht jedesmal ein voller Loginprozess nötig wird.
Nachdem das Plugin alle Daten gesammelt hat müssen diese in ein binäres JSON Format gebracht und an die Funktion webClient.resultsArrived
"gesendet werden. Die textuelle Entsprechung der Ergebnisse sieht wie folgt aus:
[ { Ergebnisse erstes Konto }, { Ergebnisse zweites Konto }, ... ]
Ergebnis map:
{
"isCreditCard": true/false,
"account": "xxxx", (Kontonummer)
"bankCode": "xxxx", (BLZ)
"balance": "100,0 EUR", (Saldo als String, korrekte Konvertierung erfolgt in Pecunia)
"statements": [ Überweisung ],
"lastSettleDate": Date (Datum der letzten Aktualisierung)
}
Überweisung:
{
"final" = true/false, (false für vorgemerkte Umsätze)
"valutaDate" = Date, (Wertstellungsdatum)
"date" = Date, (Buchungsdatum)
"transactionText" = "...", (Verwendungszweck)
"value" = "123.456,00 EUR", (Umsatz als String, korrekte Konvertierung erfolgt in Pecunia)
"originalValue" = dito wie "value" (für Umsätze die von anderen Währungen stammen)
}
Wichtig hier zwei Dinge: Datumswerte werden als JS Datum übergeben (sowohl beim Aufruf von getStatements, als auch in den Ergebnissen). Geldwerte immer als String übergeben, da eine Umrechnung via doubles Rundungsfehler verursacht. Die Währung ist dabei optional (default is EUR).
Um zu verhindern, dass sich Rundungsfehler wegen der immanenten Beschränkung der Datentypen float + double einschleichen, erledgt Pecunia die Umrechnung aus den Strings. Dabei kann Pecunia nur mit Komma und Punkt als Dezimal- bzw. Gruppenseparator arbeiten. Da Zahlen selbst in einem Datensatz unterschiedlich sein können (mal Punkt als Dezimalseparator, mal das Komma) versucht das Pluginsystem über einen heuristischen Ansatz das korrekte Format zu erkennen. Es wird angenommen, dass Nachkommastellen immer höchstens zweistellig sind, was in den allermeisten Fällen so sein dürfte. Weiterhin wird angenommen, dass Zahlengruppen immer 3 Ziffern beinhalten, außer der linken äußersten (z.B. 1.234,56). Damit ist es möglich zu bestimmen, was für den Dezimal- und was für den Gruppenseparator verwendet wurde (wenn überhaupt). Das bedeutet von seiten der Plugins ist keine weitere Behandlung von Geldbeträgen notwendig.
Die derzeitige Plugin Implementation befindet sich noch in einem frühen Stadium und mag hier und da noch Probleme haben. Diese sollte am besten im Bug Tracker oder unserer Mailingliste gemeldet werden. Aufgrund der hervorragenden Integration von JS in Obj-C/Swift sind Erweiterungen in Zukunft kein Problem. Die gesamte Implementation ist sehr flexibel. Es wäre auch durchaus möglich komplexe Vorgänge/Berechnungen usw. nach Pecunia auszulagern. Indirekt kann praktisch alles verfügbar gemacht werden.