Workaround für die, die keine DB-Konto haben:
Offlinekonto erstellen.
Daten von Miles&More-Seite als csv exportierern.
Mit ein Windows PowerShell Script Datei in StarMoney Format umwandeln.
Daten importieren.
Achtung Kontoausgleichszahlungen müssen manuell eingebucht werden.
Hier der .ps1 Code:
<#
.SYNOPSIS
Konvertiert eine Miles & More Kreditkarten-Abrechnung (CSV) in das
StarMoney-Importformat ("Saldo";"SdoWaehr";...).
.DESCRIPTION
Liest die Umsaetze (Belegdatum, Eingangstag, Verwendungszweck, Betraege)
aus der Abrechnungs-CSV und erzeugt eine Importdatei fuer StarMoney.
- Saldo wird als laufende Summe der Umsaetze berechnet.
- Umsaetze werden AUFSTEIGEND nach Datum sortiert (aeltester zuerst),
da StarMoney sonst nach der ersten Zeile abbricht.
- Verwendungszweck komplett in VWZ1 (wie beim StarMoney-Export).
- BuchDatum = Belegdatum, WertDatum = Eingangstag.
- Fremdwaehrungs-Betraege landen in OCMTBetr/OCMTWaehr.
- Lfd.Nr und ID bleiben leer (wird von StarMoney vergeben).
- Ausgabe: UTF-8, Semikolon-getrennt, Dateiname wie Quelldatei mit
Suffix "_starmoney.txt".
- Das Skript ist absichtlich reines ASCII (Umlaute im Importkopf werden
per Zeichencode erzeugt), damit die Kodierung der .ps1 egal ist.
.EXAMPLE
.\ConvertTo-StarMoney.ps1 (Datei wird per Dialog ausgewaehlt)
.\ConvertTo-StarMoney.ps1 -InputFile "C:\Temp\abrechnung.csv"
.\ConvertTo-StarMoney.ps1 -InputFile "abrechnung.csv" -OutputFile "import.txt"
#>
param(
[string]$InputFile = "",
[string]$OutputFile = "",
# Diagnose-Optionen:
[int]$FirstN = 0, # 0 = alle Umsaetze; >0 = nur die ersten N Umsaetze schreiben
[switch]$KeepOrder # Reihenfolge der CSV beibehalten (Standard: aufsteigend nach Datum sortieren,
# da StarMoney Umsatzdateien aeltester-zuerst erwartet)
)
# Umlaute per Zeichencode (0xE4=ae, 0xF6=oe, 0xFC=ue) - kodierungsunabhaengig
$CH_AE = [string][char]0xE4
$CH_OE = [string][char]0xF6
$CH_UE = [string][char]0xFC
# Falls keine Eingabedatei uebergeben wurde: Dateiauswahl-Dialog oeffnen
if ($InputFile -eq "") {
Add-Type -AssemblyName System.Windows.Forms | Out-Null
$dlg = New-Object System.Windows.Forms.OpenFileDialog
$dlg.Title = "Kreditkarten-Abrechnung (CSV) auswaehlen"
$dlg.Filter = "CSV-Dateien (*.csv)|*.csv|Alle Dateien (*.*)|*.*"
$dlg.FilterIndex = 1
$dlg.InitialDirectory = [Environment]::GetFolderPath('MyDocuments')
if ($dlg.ShowDialog() -ne [System.Windows.Forms.DialogResult]::OK -or $dlg.FileName -eq "") {
Write-Host "Abgebrochen - keine Datei ausgewaehlt."
exit
}
$InputFile = $dlg.FileName
}
if (-not (Test-Path -LiteralPath $InputFile)) {
throw "Eingabedatei nicht gefunden: $InputFile"
}
if ($OutputFile -eq "") {
$OutputFile = [System.IO.Path]::ChangeExtension($InputFile, "") + "_starmoney.txt"
$OutputFile = $OutputFile.Replace("..", ".")
}
# Formatierungshilfen
function Format-Amount([double]$v) {
$s = ("{0:F2}" -f $v) -replace '\s', ''
return $s.Replace('.', ',') # Dezimaltrenner immer Komma
}
function Format-Date([string]$d) {
$dt = [datetime]::ParseExact($d.Trim(), "dd.MM.yyyy", [Globalization.CultureInfo]::InvariantCulture)
return $dt.ToString("dd.MM.yyyy")
}
# StarMoney-Importkopf (Feldanzahl wird daraus ermittelt).
# Umlaute als Platzhalter, danach ersetzt: @ae@, @oe@, @ue@
$headerLine = '"Saldo";"SdoWaehr";"AgBlz";"AgKto";"AgName1";"Storno";"OrigBtg";"Betrag";"BtgWaehr";"OCMTBetr";"OCMTWaehr";"Textschl";"VWZ1";"VWZ2";"VWZ3";"VWZ4";"VWZ5";"VWZ6";"VWZ7";"VWZ8";"VWZ9";"VWZ10";"VWZ11";"VWZ12";"VWZ13";"VWZ14";"BuchDatum";"WertDatum";"Primanota";"Kategorie";"Unterkat";"Kostenst";"BuchText";"Splittbuchung - Auftraggeber / Name";"Splittbuchung - Verwendungszweckzeile 1";"Splittbuchung - Kategorie";"Splittbuchung - Unterkategorie";"Splittbuchung - Kostenstelle";"Splittbuchung - Originalbetrag";"Lfd.Nr";"ID";"Steuersatz";"SteuersatzWaehr";"Steuerbetrag";"SteuerbetragWaehr";"Fibu-Nr.";"Splittbuchung - Steuersatz";"Splittbuchung - SteuersatzWaehr";"Splittbuchung - Steuerbetrag";"Splittbuchung - SteuerbetragWaehr";"Splittbuchung - Fibu-Nr.";"Kommentar";"Abweichender Auftraggeber";"Ende zu Ende Referenz";"Kundenreferenz";"Mandatsreferenz";"Purpose Code";"R@ue@ckgabegrund";"R@ue@ckgabegrund (Code)";"Entgelt (fremd)";"Entgelt (fremd) W@ae@hrung";"Entgelt (eigen)";"Entgelt (eigen) W@ae@hrung";"Zinskompensationsbetrag";"Zinskompensationsbetrag W@ae@hrung";"Ursprungsbetrag";"Ursprungsbetrag W@ae@hrung";"Gl@ae@ubiger-Identifikation"'
$headerLine = $headerLine.Replace('@ae@', $CH_AE).Replace('@oe@', $CH_OE).Replace('@ue@', $CH_UE)
$totalCols = ($headerLine -split '";"' | Measure-Object).Count
# Eingabe zeilenweise lesen und Umsatzzeilen erkennen
$lines = Get-Content -LiteralPath $InputFile -Encoding UTF8
$txStart = -1
for ($i = 0; $i -lt $lines.Count; $i++) {
if ($lines[$i] -like 'Belegdatum*') { $txStart = $i + 1; break }
}
if ($txStart -lt 0) { throw "Kopfzeile 'Belegdatum;Eingangstag;...' nicht gefunden." }
$datePattern = '^\s*\d{2}\.\d{2}\.\d{4}\s*$'
$saldo = 0.0
$outRows = New-Object System.Collections.Generic.List[string]
# Transaktionen zwischenspeichern, danach sortieren/filtern
$txRows = New-Object System.Collections.Generic.List[object]
for ($i = $txStart; $i -lt $lines.Count; $i++) {
$line = $lines[$i]
if ([string]::IsNullOrWhiteSpace($line)) { continue }
$cols = $line.Split(';')
if ($cols.Count -lt

{ continue }
if ($cols[0].Trim() -notmatch '^\d{2}\.\d{2}\.\d{4}$') { continue }
$belegdatum = $cols[0].Trim()
$eingangstag = $cols[1].Trim()
$vwz = $cols[2].Trim()
$fremdWaehr = $cols[3].Trim()
$fremdBetr = $cols[4].Trim()
$kurs = $cols[5].Trim()
$euroBetr = $cols[6].Trim()
$buchWaehr = $cols[7].Trim()
# Betraege parsen und Transaktion zwischenspeichern
$euroVal = [double]::Parse($euroBetr, [Globalization.CultureInfo]::deDE)
# Fremdwaehrung (OCMT): nur wenn abweichend
if ($fremdWaehr -ne '' -and $fremdWaehr -ne $buchWaehr) {
$fremdVal = [double]::Parse($fremdBetr, [Globalization.CultureInfo]::deDE)
$ocmtBetr = Format-Amount $fremdVal
$ocmtWaehr = $fremdWaehr
} else {
$ocmtBetr = Format-Amount $euroVal
$ocmtWaehr = 'EUR'
}
$txRows.Add([pscustomobject]@{
Belegdatum = $belegdatum
Eingangstag = $eingangstag
Vwz = $vwz
EuroVal = $euroVal
BuchWaehr = $buchWaehr
OcmtBetr = $ocmtBetr
OcmtWaehr = $ocmtWaehr
SortKey = [datetime]::ParseExact($belegdatum, "dd.MM.yyyy", [Globalization.CultureInfo]::InvariantCulture).Ticks
SortKey2 = [datetime]::ParseExact($eingangstag, "dd.MM.yyyy", [Globalization.CultureInfo]::InvariantCulture).Ticks
})
}
if ($txRows.Count -eq 0) {
throw "Keine Umsatzzeilen gefunden. Pruefen: Enthaelt die CSV Zeilen mit Format 'TT.MM.JJJJ;TT.MM.JJJJ;Text;Waehrung;Betrag;Kurs;Betrag;Waehrung'?"
}
# StarMoney erwartet Umsatzdateien AUFSTEIGEND (aeltester zuerst).
# Die Karten-CSV liefert neueste zuerst -> Standardmaessig aufsteigend sortieren.
if (-not $KeepOrder) {
$txRows = @($txRows | Sort-Object -Property SortKey, SortKey2)
}
if ($FirstN -gt 0 -and $FirstN -lt $txRows.Count) { $txRows = @($txRows)[0..($FirstN-1)] }
# Aus Zeilen die Importdatei bauen (Saldo als laufende Summe)
$laufendeNr = 1
foreach ($tx in $txRows) {
$vwz = $tx.Vwz
$buchWaehr = $tx.BuchWaehr
$ocmtBetr = $tx.OcmtBetr
$ocmtWaehr = $tx.OcmtWaehr
$saldo += $tx.EuroVal
$betragFmt = Format-Amount $tx.EuroVal
$saldoFmt = Format-Amount $saldo
$origBtgFmt = $betragFmt
$belegdatum = $tx.Belegdatum
$eingangstag = $tx.Eingangstag
# Verwendungszweck: KOMPLETT in VWZ1 (wie beim StarMoney-Export),
# VWZ2..VWZ14 bleiben leer.
$vwzLines = @($vwz)
while ($vwzLines.Count -lt 14) { $vwzLines += '' }
# Zeile aufbauen, exakt im Stil des StarMoney-Testexports:
# numerische Felder ohne Quotes, Splitt-/Steuernummerik unquoted leer
$fields = New-Object System.Collections.Generic.List[string]
$fields.Add($saldoFmt) # 1 Saldo
$fields.Add('"EUR"') # 2 SdoWaehr
$fields.Add('""') # 3 AgBlz
$fields.Add('""') # 4 AgKto
$fields.Add('"' + $vwz + '"') # 5 AgName1
$fields.Add('0') # 6 Storno
$fields.Add($origBtgFmt) # 7 OrigBtg
$fields.Add($betragFmt) # 8 Betrag
$fields.Add('"' + $buchWaehr + '"') # 9 BtgWaehr
$fields.Add($ocmtBetr) # 10 OCMTBetr
$fields.Add('"' + $ocmtWaehr + '"') # 11 OCMTWaehr
$fields.Add('0') # 12 Textschl
foreach ($v in $vwzLines) { $fields.Add('"' + $v + '"') } # 13-26 VWZ1..VWZ14
$fields.Add('"' + (Format-Date $belegdatum) + '"') # 27 BuchDatum
$fields.Add('"' + (Format-Date $eingangstag) + '"') # 28 WertDatum
$fields.Add('""') # 29 Primanota
$fields.Add('""') # 30 Kategorie (leer, StarMoney kategorisiert selbst)
$fields.Add('""') # 31 Unterkat
$fields.Add('""') # 32 Kostenst
$fields.Add('""') # 33 BuchText
$fields.Add('') # 34 Splitt - Auftraggeber
$fields.Add('') # 35 Splitt - VWZ1
$fields.Add('') # 36 Splitt - Kategorie
$fields.Add('') # 37 Splitt - Unterkategorie
$fields.Add('') # 38 Splitt - Kostenstelle
$fields.Add('') # 39 Splitt - Originalbetrag
$fields.Add([string]$laufendeNr) # 40 Lfd.Nr (fortlaufend, siehe Testexport)
$fields.Add([string]$laufendeNr) # 41 ID
$laufendeNr++
$fields.Add('') # 42 Steuersatz
$fields.Add('""') # 43 SteuersatzWaehr
$fields.Add('') # 44 Steuerbetrag
$fields.Add('""') # 45 SteuerbetragWaehr
$fields.Add('""') # 46 Fibu-Nr.
$fields.Add('') # 47 Splitt - Steuersatz
$fields.Add('') # 48 Splitt - SteuersatzWaehr
$fields.Add('') # 49 Splitt - Steuerbetrag
$fields.Add('') # 50 Splitt - SteuerbetragWaehr
$fields.Add('') # 51 Splitt - Fibu-Nr.
$fields.Add('""') # 52 Kommentar
$fields.Add('""') # 53 Abweichender Auftraggeber
$fields.Add('""') # 54 Ende zu Ende Referenz
$fields.Add('""') # 55 Kundenreferenz
$fields.Add('""') # 56 Mandatsreferenz
$fields.Add('""') # 57 Purpose Code
$fields.Add('""') # 58 Rueckgabegrund
$fields.Add('""') # 59 Rueckgabegrund (Code)
$fields.Add('""') # 60 Entgelt (fremd)
$fields.Add('""') # 61 Entgelt (fremd) Waehrung
$fields.Add('""') # 62 Entgelt (eigen)
$fields.Add('""') # 63 Entgelt (eigen) Waehrung
$fields.Add('""') # 64 Zinskompensationsbetrag
$fields.Add('""') # 65 Zinskompensationsbetrag Waehrung
$fields.Add('""') # 66 Ursprungsbetrag
$fields.Add('""') # 67 Ursprungsbetrag Waehrung
$fields.Add('""') # 68 Glaeubiger-Identifikation
if ($fields.Count -ne $totalCols) {
throw ("Interner Fehler: Feldanzahl {0} stimmt nicht mit Kopfzeile ({1}) ueberein." -f $fields.Count, $totalCols)
}
$outRows.Add(($fields -join ';'))
}
# Ausgabe: UTF-8 ohne BOM, Zeilenende CRLF
$utf8NoBom = New-Object System.Text.UTF8Encoding($false)
[System.IO.File]::WriteAllText($OutputFile, ($headerLine + "`r`n" + ($outRows -join "`r`n") + "`r`n"), $utf8NoBom)
Write-Host ("Fertig: {0} Umsaetze konvertiert." -f $outRows.Count)
Write-Host ("Ausgabedatei: {0}" -f (Resolve-Path -LiteralPath $OutputFile))