MoneyMoney Export API

Einführung

MoneyMoney kann mit Extensions erweitert werden, um Umsätze zur Weiterverarbeitung in anderen Anwendungen zu exportieren. Diese Extensions sind kurze Lua-Skripte, die einfach zu erstellen, zu modifizieren und auszuwechseln sind.

Das Skript des CSV-Exports steht für eigene Anpassungen als Open-Source zur Verfügung. So lässt sich der CSV-Export durch Modifikation dieses Skripts bis ins Detail konfigurieren. (Download)

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.

Fehlermeldungen werden im Protokoll-Fenster von MoneyMoney angezeigt. Das Protokoll-Fenster lässt sich mit der Menüfunktion »Fenster« → »Protokollfenster« erreichen.

Die eigene Extension wird beim Aufruf der Menüfunktion »Konto« → »Umsätze exportieren« in der Formatauswahl mit der im Parameter format festgelegten Bezeichnung (siehe nächster Abschnitt) angezeigt und kann dort ausgewählt werden.

Registrierung einer Extension

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

Exporter{
  version = 1.00,
  format = "Custom CSV file",
  fileExtension = "csv",
  description = "Export transactions as custom CSV file"
}

enthält. Bei den benannten Parametern der Funktion Exporter handelt es sich um:

ParameterTypOptionalBeschreibung
versionNumberneinVersionsnummer der Extension
formatStringjaBezeichnung des Dateiformats, wie sie in der Formatauswahl des Datei-Speichern-Dialogs angezeigt wird
fileExtensionStringjaDateinamenserweiterung
bundleIdentifierStringjaWenn dieser Parameter mit dem Bundle-Identifier einer installierten App belegt ist, wird die App im Menü »Sende Umsätze an« gelistet.
hiddenBooleanjaWenn dieser Parameter mit true belegt ist, wird diese Extension nicht im Auswahldialog für den manuellen Umsatzexport angezeigt. Standardmäßig wird die Extension angezeigt.
reverseOrderBooleanjaWenn dieser Parameter mit true belegt ist, werden die Umsätze in umgekehrter Reihenfolge an das Skript übergeben. Standardmäßig werden die Umsätze in der gleichen Reihenfolge übergeben, wie sie in MoneyMoney angezeigt werden, d.h. neueste Umsätze zuerst.
descriptionStringjaBeschreibung der Extension

Lua-Laufzeitumgebung

Die Parameter der Funktion Exporter sind später im Skript als globale Variablen version, format, fileExtension, bundleIdentifier, reverseOrder 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.

Ablauf

MoneyMoney treibt die Ausführung des Skripts, was bedeutet, dass jedes Skript bestimmte Funktionen als Einsprungspunkte zur Verfügung stellen muss. MoneyMoney ruft zum Umsatzexport folgende Funktionen des Skripts auf:

  1. WriteHeader (Dateianfang)
  2. für jeden Buchungstag: WriteTransactions (Umsätze schreiben)
  3. WriteTail (Dateiende)

Es wird das einfache I/O-Modell von Lua verwendet: Das Skript braucht die Daten bloß mit assert(io.write(...)) zur Standardausgabe (stdout) zu schreiben. Das Öffnen und Schließen der Ausgabedatei übernimmt MoneyMoney.

Vorlage

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

Exporter{
  version = 1.00,
  format = "Custom CSV file",
  fileExtension = "csv",
  description = "Export transactions as custom CSV file"
}

local function csvField (str)
  -- Helper function for quoting separator character and escaping double quotes.
  if str == nil then
    return ""
  elseif string.find(str, ";") then
    return '"' .. string.gsub(str, '"', '""') .. '"'
  else
    return str
  end
end

function WriteHeader (account, startDate, endDate, transactionCount)
  -- Write CSV header.
  assert(io.write("Date;Value date;Category;Name;Purpose;Account;Bank;Amount;Currency\n"))
end

function WriteTransactions (account, transactions)
  -- Write one line per transaction.
  for _,transaction in ipairs(transactions) do
    assert(io.write(
      csvField(MM.localizeDate(transaction.bookingDate)) .. ";" ..
      csvField(MM.localizeDate(transaction.valueDate)) .. ";" ..
      csvField(string.gsub(transaction.category, [[\]], " - ")) .. ";" ..
      csvField(transaction.name) .. ";" ..
      csvField(transaction.purpose) .. ";" ..
      csvField(transaction.accountNumber) .. ";" ..
      csvField(transaction.bankCode) .. ";" ..
      csvField(MM.localizeNumber("0.00;-0.00", transaction.amount)) .. ";" ..
      csvField(transaction.currency) .. "\n"
    ))
  end
end

function WriteTail (account)
  -- Nothing to do.
end

Einsprungspunkte

WriteHeader

function WriteHeader (account, startDate, endDate, transactionCount)

Schreibt den Dateianfang.

ParameterTypOptionalBeschreibung
accountTableneinDas Konto, von dem die Umsätze exportiert werden. Die Struktur ist im Abschnitt »Datenstruktur eines Kontos« beschrieben.
startDateNumberneinDas Buchungsdatum des ältesten Umsatzes; Die Angabe erfolgt in Form eines POSIX-Zeitstempels.
endDateNumberneinDas Buchungsdatum des neuesten Umsatzes; Die Angabe erfolgt in Form eines POSIX-Zeitstempels.
transactionCountNumberneinAnzahl der zu exportierenden Umsätze
RückgabeTypBeschreibung
nilNichts oder nil, wenn die Funktion erfolgreich war.
StringEine Fehlermeldung.

WriteTransactions

function WriteTransactions (account, transactions)

Schreibt die Umsätze eines Buchungstags in die Datei.

ParameterTypOptionalBeschreibung
accountTableneinDas Konto, von dem die Umsätze exportiert werden. Die Struktur ist im Abschnitt »Datenstruktur eines Kontos« beschrieben.
transactionsArrayneinDie Umsätze eines Buchungstags. Die Struktur der Array-Elemente ist im Abschnitt »Datenstruktur eines Umsatzes« beschrieben.
RückgabeTypBeschreibung
nilNichts oder nil, wenn die Funktion erfolgreich war.
StringEine Fehlermeldung.

WriteTail

function WriteTail (account)

Schreibt das Dateiende.

ParameterTypOptionalBeschreibung
accountTableneinDas Konto, von dem die Umsätze exportiert werden. Die Struktur ist im Abschnitt »Datenstruktur eines Kontos« beschrieben.
RückgabeTypBeschreibung
nilNichts oder nil, wenn die Funktion erfolgreich war.
StringEine Fehlermeldung.

Datenstrukturen

Datenstruktur eines Kontos

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

FeldTypBeschreibung
nameStringBezeichnung des Kontos
ownerStringName des Kontoinhabers
accountNumberStringKontonummer
subAccountStringUnterkontomerkmal
bankCodeStringBankleitzahl
currencyStringKontowährung
ibanStringIBAN
bicStringBIC
typeKonstanteKontoart, siehe unten
attributesTableBenutzerdefinierte Felder
commentStringNotiz
balanceNumberKontostand
balanceDateNumberDatum des Kontostands; Die Angabe erfolgt in Form eines POSIX-Zeitstempels.

Mögliche Werte für die Kontoart type. Die Konstanten sind mit dem englischen Beschreibungstext belegt; der in Klammern angegebene deutsche Beschreibungstext kann mit der Funktion MM.localizeText erzeugt werden:

KonstanteBedeutung
AccountTypeGiroGirokonto
AccountTypeSavingsSparkonto
AccountTypeFixedTermDepositFestgeldanlage
AccountTypeLoanDarlehenskonto
AccountTypeCreditCardKreditkarte
AccountTypeCashBargeld
AccountTypeOtherSonstige

Datenstruktur eines Umsatzes

Die Daten eines Umsatzes werden in einer Lua-Tabelle gespeichert:

FeldTypBeschreibung
nameStringName des Auftraggebers/Zahlungsempfängers
accountNumberStringKontonummer oder IBAN des Auftraggebers/Zahlungsempfängers
bankCodeStringBankleitzahl oder BIC des Auftraggebers/Zahlungsempfängers
amountNumberBetrag
currencyStringWährung
bookingDateNumberBuchungstag; Die Angabe erfolgt in Form eines POSIX-Zeitstempels.
valueDateNumberWertstellungsdatum; Die Angabe erfolgt in Form eines POSIX-Zeitstempels.
purposeStringVerwendungszweck; Mehrere Zeilen können durch Zeilenumbrüche (\n) getrennt werden.
transactionCodeNumberGeschäftsvorfallcode
textKeyExtensionNumberTextschlüsselergänzung
purposeCodeStringSEPA-Verwendungsschlüssel
bookingKeyStringSWIFT-Buchungsschlüssel
bookingTextStringUmsatzart
primanotaNumberStringPrimanota-Nummer
batchReferenceStringSammlerreferenz
endToEndReferenceStringSEPA-Ende-zu-Ende-Referenz
mandateReferenceStringSEPA-Mandatsreferenz
creditorIdStringSEPA-Gläubiger-ID
returnReasonStringRückgabegrund
bookedBooleanGebuchter oder vorgemerkter Umsatz
checkmarkBooleanAls erledigt oder unerledigt markierter Umsatz
categoryStringKategorienname
commentStringNotiz
idNumberInterner Primärschlüssel dieses Umsatzes in der MoneyMoney-Datenbank

MM-Funktionen

Lokalisierung

MM.localizeText

str = MM.localizeText(str)

Übersetzt einen Text. 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.

ParameterTypOptionalBeschreibung
strStringneinEnglischer Text
RückgabeTypBeschreibung
strStringÜbersetzter Text

MM.localizeDate

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.

ParameterTypOptionalBeschreibung
formatStringjaAusgabeformat; Die Angabe erfolgt wie bei der Cocoa-Klasse NSDateFormatter nach dem Unicode Technical Standard #35.
dateNumberneinDatum; Die Angabe erfolgt in Form eines POSIX-Zeitstempels.
RückgabeTypBeschreibung
strStringDatum im lokalisierten Format

MM.localizeNumber

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.

ParameterTypOptionalBeschreibung
formatStringjaAusgabeformat; Die Angabe erfolgt wie bei der Cocoa-Klasse NSNumberFormatter nach dem Unicode Technical Standard #35.
numNumberneinZahl
RückgabeTypBeschreibung
strStringZahl im lokalisierten Format

MM.localizeAmount

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

Lokalisiert einen Währungsbetrag.

ParameterTypOptionalBeschreibung
formatStringjaAusgabeformat; Die Angabe erfolgt wie bei der Cocoa-Klasse NSNumberFormatter nach dem Unicode Technical Standard #35.
amountNumberneinBetrag
currencyStringjaWährung; Ohne diesen Parameter wird nur der Betrag ohne Währungsangabe zurückgegeben.
RückgabeTypBeschreibung
strStringWährungsbetrag im lokalisierten Format

Zeichenketten und Kodierung

MM.toEncoding

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

Konvertiert einen Text von UTF-8 zu einem anderen Zeichensatz — z. B. um CSV-Dateien für Programme zu erzeugen, die kein UTF-8 verstehen.

ParameterTypOptionalBeschreibung
charsetStringneinZeichensatz; Die Angabe erfolgt wie bei HTTP nach IANA.
strStringneinText in UTF-8
bomBooleanjaWenn dieser Parameter mit true belegt ist, wird der Rückgabewert um eine Byte Order Mark (BOM) ergänzt, sofern sie für den angegebenen Zeichensatz existiert.
RückgabeTypBeschreibung
dataBinaryText im angegebenen Zeichensatz

Siehe auch: MM.fromEncoding

MM.fromEncoding

str = MM.fromEncoding(charset, data)

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

ParameterTypOptionalBeschreibung
charsetStringneinZeichensatz; Die Angabe erfolgt wie bei HTTP nach IANA.
dataBinaryneinText im angegebenen Zeichensatz
RückgabeTypBeschreibung
strStringText in UTF-8

Siehe auch: MM.toEncoding