MoneyMoney

Einführung

MoneyMoney kann mit Extensions erweitert werden, um Umsätze aus anderen Anwendungen zu importieren. Diese Extensions sind kurze Lua-Skripte, die einfach zu erstellen, zu modifizieren und auszuwechseln sind. Bisher nicht unterstützte Dateiformate lassen sich durch neu geschriebene Skripte nachrüsten.

Die Lua-Skripte werden in einer virtuellen Maschine ausgeführt und kommunizieren über eine dokumentierte API mit MoneyMoney. Das vorliegende Dokument spezifiziert diese API. Die Wahl der Skriptsprache fiel auf Lua, da sie relativ leicht zu erlernen ist und sich gut mit C/C++/Objective-C kombinieren lässt. Für unsere Extensions reicht es vollkommen aus, die ersten fünf Kapitel von »Programming in Lua« gelesen zu haben. Die meisten innerhalb einer Extension aufgerufenen Funktionen sind nämlich gar nicht Bestandteil von Lua, sondern existieren ausschließlich in MoneyMoney.

Vom Skript zur Extension

Installation

Das Verzeichnis, in dem eigene Extensions abgelegt werden, kann über Menü Hilfe → Zeige Datenbank im Finder im Finder geöffnet werden:

~/Library/Containers/com.moneymoney-app.retail/Data/Library/Application Support/MoneyMoney/Extensions

Jede Änderung an Dateien in diesem Verzeichnis wirkt sich unmittelbar auf MoneyMoney aus, d.h. es ist nicht nötig, MoneyMoney neu zu starten.

Registrierung einer Extension

Ein Skript weist sich als Import-Extension aus, indem es am Beginn des Skripts einen Aufruf der Art

Importer{version          = 1.05,
         format           = "Comma-separated values",
         fileExtension    = "csv",
         description      = "Import transactions from CSV file"}

enthält. Bei den benannten Parameter der Funktion Importer handelt es sich um:

  1. Number version: Versionsnummer der Extension
  2. String format (optional): Bezeichnung des Dateiformats, wie sie in der Formatauswahl des Datei-Öffnen-Dialogs angezeigt wird
  3. String fileExtension (optional): Dateinamenserweiterung
  4. String description (optional): Beschreibung der Extension

Lua-Laufzeitumgebung

Die Parameter der Funktion Importer sind später im Skript als globale Variablen version, format, fileExtension, und description zugänglich. Zusätzlich ist auch noch die globale Variable extensionName mit dem Namen der Extension definiert.

Die Variablen MM.productName und MM.productVersion enthalten Informationen zur Anwendung, also MoneyMoney.

Die Ausgabe der Standard-Funktion print wird im Protokoll-Fenster von MoneyMoney angezeigt.

Die Standard-Funktion error bricht die Ausführung des Skripts ab.

Das Skript selbst muss UTF-8-kodiert sein und es werden auch alle Strings als UTF-8-Strings zwischen dem Skript und MoneyMoney übergeben, außer es steht in der API-Beschreibung, dass es sich um Binärdaten handelt.

Aufbau einer Import-Extension

Einsprungspunkte

MoneyMoney treibt die Ausführung des Skripts, was bedeutet, dass jedes Skript eine bestimmte Funktion als Einsprungspunkt zur Verfügung stellen muss. MoneyMoney ruft zum Umsatzimport folgende Funktion des Skripts auf:

  • ReadTransactions (Umsätze lesen)

Es wird das einfache I/O-Modell von Lua verwendet: Das Skript braucht die Daten bloß mit assert(io.read(...)) von der Standardeingabe (stdin) zu lesen. Das Öffnen und Schließen der Datei übernimmt MoneyMoney.

Umsätze lesen

Diese Funktion liest die Umsätze aus der Datei:

function ReadTransactions (account)

Parameter:

Table account: Das Konto, in das die Umsätze importiert werden; Die Strukur ist im Abschnitt »Datenstruktur eines Kontos« beschrieben.

Mögliche Rückgabewerte:

  • Ein Array mit den Umsätzen aus der Datei; Die Struktur der Array-Elemente ist im Abschnitt »Datenstruktur eines Umsatzes« beschrieben.
  • Ein String mit einer Fehlermeldung.

Vorlage

Folgende Vorlage kann als Ausgangspunkt für eigene Import-Extensions dienen.

Importer{version=1.00, format="Tab-separated values", fileExtension="tsv"}

local function strToDate (str)
  -- Helper function for converting localized date strings to timestamps.
  local d, m, y = string.match(str, "(%d%d).(%d%d).(%d%d%d%d)")
  return os.time{year=y, month=m, day=d}
end

function ReadTransactions (account)
  -- Read transactions from a file with the format "date<TAB>amount<TAB>purpose".
  local transactions = {}
  for line in assert(io.lines()) do
    local values = {}
    for value in string.gmatch(line, "[^\t]+") do
      table.insert(values, value)
    end
    if #values >= 3 then
      local transaction = {
        bookingDate = strToDate(values[1]),
        amount = tonumber(values[2]),
        purpose = values[3]
      }
      table.insert(transactions, transaction)
    end
  end
  return transactions
end

Die API von MoneyMoney

Datenstruktur eines Kontos

Die Informationen eines Konto werden in einer Lua-Tabelle gespeichert. Folgende Felder sind definiert:

  • String name: Bezeichnung des Kontos
  • String owner: Name des Kontoinhabers
  • String accountNumber: Kontonummer
  • String subAccount: Unterkontomerkmal
  • Boolean portfolio: true für Depots und false für alle anderen Konten
  • String bankCode: Bankleitzahl
  • String currency: Kontowährung
  • String iban: IBAN
  • String bic: BIC
  • Konstante type: Kontoart; Mögliche Werte sind AccountTypeGiro (Girokonto), AccountTypeSavings (Sparkonto), AccountTypeFixedTermDeposit (Festgeldanlage), AccountTypeLoan (Darlehenskonto), AccountTypeCreditCard (Kreditkarte), AccountTypePortfolio (Wertpapierdepot), AccountTypePayPal (PayPal), AccountTypeCash (Bargeld), AccountTypeOther (Sonstige).

Datenstruktur eines Umsatzes

Die Daten eines Umsatzes werden in einer Lua-Tabelle gespeichert. Die Felder orientieren sich an SWIFT MT-940/MT-942:

  • String name: Name des Auftraggebers/Zahlungsempfängers
  • String accountNumber: Kontonummer oder IBAN des Auftraggebers/Zahlungsempfängers
  • String bankCode: Bankzeitzahl oder BIC des Auftraggebers/Zahlungsempfängers
  • Number amount: Betrag
  • String currency: Währung
  • Number bookingDate: Buchungstag; Die Angabe erfolgt in Form eines POSIX-Zeitstempels.
  • Number valueDate: Wertstellungsdatum; Die Angabe erfolgt in Form eines POSIX-Zeitstempels.
  • String purpose: Verwendungszweck; Mehrere Zeilen können durch Zeilenumbrüche ("\n") getrennt werden.
  • Number transactionCode: Geschäftsvorfallcode
  • Number textKeyExtension: Textschlüsselergänzung
  • String purposeCode: SEPA-Verwendungsschlüssel
  • String bookingKey: SWIFT-Buchungsschlüssel
  • String bookingText: Umsatzart
  • String primanotaNumber: Primanota-Nummer
  • String customerReference: SEPA-Einreicherreferenz
  • String endToEndReference: SEPA-Ende-zu-Ende-Referenz
  • String mandateReference: SEPA-Mandatsreferenz
  • String creditorId: SEPA-Gläubiger-ID
  • String returnReason: Rückgabegrund
  • Boolean booked: Gebuchter oder vorgemerkter Umsatz
  • String category: Kategorienname
  • String comment: Notiz

Objekt für Bankinformationen

bankInfo = BankInfo(bankCode)

Erzeugt ein neues Objekt mit Informationen zu einer Bank. Um den richtigen Nummernkreis zu wählen, wird die globale Variable country herangezogen.

Parameter:

String bankCode: Bankleitzahl

Beispiel:

print(BankInfo("80007777").name)

Datenstruktur für Bankinformationen

Die Informationen zu einer Bank werden in einer Lua-Tabelle gespeichert. Derzeit gibt es nur ein einziges belegtes Feld:

  • String name: Name der Bank

Sonstige Funktionen

str = MM.localizeText(str)

Mit dieser Funktion kann ein Text übersetzt werden. Diese Funktion ist primär für die mit MoneyMoney ausgelieferten Extensions gedacht. Sie ist ein Wrapper für die Cocoa-Funktion NSLocalizedString und liefert natürlich nur dann eine Übersetzung, wenn der Text in MoneyMoney hinterlegt worden ist.

Parameter:

String str: Englischer Text

Rückgabewert:

String str: Übersetzter Text

str = MM.localizeDate([format, ]date)

Lokalisiert eine Zeitangabe. Da die von Lua unterstützten POSIX Locales innerhalb von macOS-Apps nicht zur Verfügung stehen, baut diese Funktion auf der Cocoa-Klasse NSDateFormatter auf.

Parameter:

  1. String format (optional): Ausgabeformat; Die Angabe erfolgt wie bei der Cocoa-Klasse NSDateFormatter nach dem Unicode Technical Standard #35.
  2. Number date: Datum; Die Angabe erfolgt in Form eines POSIX-Zeitstempels.

Rückgabewert:

String str: Datum im lokalisierten Format

str = MM.localizeNumber([format, ]num)

Lokalisiert eine Zahl. Da die von Lua unterstützten POSIX Locales innerhalb von macOS-Apps nicht zur Verfügung stehen, baut diese Funktion auf der Cocoa-Klasse NSNumberFormatter auf.

Parameter:

  1. String format (optional): Ausgabeformat; Die Angabe erfolgt wie bei der Cocoa-Klasse NSNumberFormatter nach dem Unicode Technical Standard #35.
  2. Number num: Zahl

Rückgabewert:

String str: Zahl im lokalisierten Format

str = MM.localizeAmount([format, ]amount[, currency])

Lokalisiert einen Währungsbetrag.

Parameter:

  1. String format (optional): Ausgabeformat; Die Angabe erfolgt wie bei der Cocoa-Klasse NSNumberFormatter nach dem Unicode Technical Standard #35.
  2. Number amount: Betrag
  3. String currency (optional): Währung; Ohne diesen Parameter wird nur der Betrag ohne Währungsangabe zurückgegeben.

Rückgabewert:

String str: Währungsbetrag im lokalisierten Format

data = MM.toEncoding(charset, str[, bom])

Konvertiert einen Text von UTF-8 zu einem anderen Zeichensatz.

Parameter:

  1. String charset: Zeichensatz; Die Angabe erfolgt wie bei HTTP nach IANA.
  2. String str: Text in UTF-8
  3. Boolean bom (optional): Wenn dieser Parameter mit true belegt ist, wird der Rückgabewert um eine Byte Order Mark (BOM) ergänzt, sofern sie für den angegeben Zeichensatz existiert.

Rückgabewert:

Binary data: Text im angegebenen Zeichensatz

str = MM.fromEncoding(charset, data)

Konvertiert einen Text von einem anderen Zeichensatz zu UTF-8.

Parameter:

  1. String charset: Zeichensatz; Die Angabe erfolgt wie bei HTTP nach IANA.
  2. Binary data: Text im angegebenen Zeichensatz

Rückgabewert:

String str: Text in UTF-8