fügt erste Version von FiBu-Konto.ahk hinzu
This commit is contained in:
parent
feeb431c84
commit
7f4b66df18
1 changed files with 570 additions and 0 deletions
570
FiBu-Konto.ahk
Normal file
570
FiBu-Konto.ahk
Normal file
|
@ -0,0 +1,570 @@
|
|||
/*
|
||||
|
||||
Dieses Script vereinfacht das Buchen mit der Sherpa, indem FiBu-Konten
|
||||
schnell gesucht und ausgewählt werden können. Das Suchfenster wird dafür
|
||||
mit der Tastenkombination STRG+ALT+k (K wie Konto) geöffnet.
|
||||
|
||||
Es basiert auf AutoHotKey v2 und ist deshalb nur für Windows verfügbar.
|
||||
|
||||
Installation:
|
||||
1. AutoHotKey v2 herunterladen & installieren: https://www.autohotkey.com/
|
||||
2. Dieses Script (FiBu-Konto.ahk) z. B. in den AutoHotKey-Ordner ablegen
|
||||
(Dokumente -> AutoHotKey)
|
||||
3. FiBu-Konto.ahk doppelklicken (ein neues System-Icon öffnet sich)
|
||||
|
||||
Einrichtung (Kontenplan aus Summen- und Saldenliste importieren):
|
||||
- In den Sherpa-Einstellungen sicherstellen, dass der Export mit UTF-8-
|
||||
Zeichensatz geschieht (Allgemein -> Finanzbuchhaltung -> Exportoptionen).
|
||||
Diese Einstellung muss für jeden Kontext/Gliederung gesetzt werden.
|
||||
- In Sherpa: Finanzbuchhaltung -> Summen- und Saldenliste -> Anzeigen
|
||||
-> "Nur bebuchte Konten" ausschalten (alle anzeigen)
|
||||
-> CSV-Datei exportieren
|
||||
- System-Icon rechtsklicken, "Summen- und Saldenliste importieren",
|
||||
Datei auswählen
|
||||
- Die SuSa-Datei kann jetzt gelöscht werden
|
||||
|
||||
Benutzung:
|
||||
- Cursor in der Sherpa in das Soll-/Haben-Eingabefeld setzen
|
||||
- STRG+ALT+k öffnet das Fenster
|
||||
- Enter-Taste schreibt das 4-stellige FiBu-Konto in das Soll-/Haben-Feld
|
||||
- Escape-Taste schließt das Fenster
|
||||
|
||||
Tipps:
|
||||
- Die Suche findet alle Konten, die die Zeichen in der richtigen Reihenfolge
|
||||
enthalten, diese müssen aber nicht direkt aufeinander folgen. Ein Beispiel:
|
||||
"vblkr" findet "Verbindlichkeiten an Kreisverbände"
|
||||
- Das Script kann automatisch bei Systemstart ausgeführt werden, sodass das
|
||||
Suchfenster immer verfügbar ist: Rechtsklick auf das System-Icon
|
||||
-> "Bei Systemstart starten"
|
||||
- Das Script kann nach der Eingabe des FiBu-Kontos Strg+S drücken, z. B. um
|
||||
den Buchungsstapel regelmäßig zu speichern
|
||||
- Außerdem kann das FiBu-Konto vorgelesen werden, um eine akustische Rück-
|
||||
meldung zu erhalten und dadurch Fehler zu vermeiden
|
||||
|
||||
Lizenz: GPL v3
|
||||
Ansprechperson: Florian Kürsch <florian.kuersch@hamburg.gruene.de>
|
||||
Version: 0.1
|
||||
Stand: 2024-10-23
|
||||
*/
|
||||
|
||||
#Requires AutoHotkey v2.0
|
||||
|
||||
FileEncoding("UTF-8")
|
||||
autostartShortcutPath := A_Startup . "\FiBu-Konto.lnk"
|
||||
configDir := A_AppData . "\AHK-FiBu-Konto"
|
||||
ktoListPath := configDir . "\fibu-konten.txt"
|
||||
autosaveConfigPath := configDir . "\autosave_enabled"
|
||||
voiceConfigPath := configDir . "\voice_enabled"
|
||||
|
||||
DirCreate(configDir)
|
||||
|
||||
defaultKtoList := [
|
||||
"0000 Importiere die FiBu-Konten über die SuSa-Liste"
|
||||
]
|
||||
|
||||
isActive := false
|
||||
|
||||
voice := ComObject("SAPI.SpVoice")
|
||||
voice.Volume := 100 ; Volume from 0 to 100
|
||||
voice.Rate := 0 ; Rate from -10 (slow) to 10 (fast)
|
||||
|
||||
A_TrayMenu.Delete()
|
||||
A_TrayMenu.Insert("1&", "Konten-Suche öffnen (Strg+Alt+k)", (*) => open())
|
||||
A_TrayMenu.Insert("2&") ; separator
|
||||
A_TrayMenu.Insert("3&", "Summen- && Saldenliste importieren...", (*) => import_susa_file())
|
||||
A_TrayMenu.Insert("4&", "Beim Systemstart starten", toggle_autostart)
|
||||
if (is_autostart_enabled()) {
|
||||
A_TrayMenu.Check("4&")
|
||||
}
|
||||
A_TrayMenu.Insert("5&", "Nach Eingabe des Kontos Strg+S drücken", toggle_autosave)
|
||||
if (is_autosave_enabled()) {
|
||||
A_TrayMenu.Check("5&")
|
||||
}
|
||||
A_TrayMenu.Insert("6&", "Konto vorlesen", toggle_voice)
|
||||
if (is_voice_enabled()) {
|
||||
A_TrayMenu.Check("6&")
|
||||
}
|
||||
A_TrayMenu.Insert("7&") ; separator
|
||||
A_TrayMenu.Insert("8&", "Beenden", (*) => ExitApp())
|
||||
|
||||
myGui := Gui("+AlwaysOnTop -Caption +ToolWindow -MinimizeBox", "FiBu-Konto auswählen")
|
||||
myGui.SetFont("s10")
|
||||
myGui.OnEvent("Escape", on_escape_pressed)
|
||||
guiHwnd := myGui.Hwnd
|
||||
OnMessage(0x0006, handle_activation)
|
||||
|
||||
myEdit := myGui.Add("Edit", "w500 vMyEdit")
|
||||
myEdit.OnEvent("Change", on_text_changed)
|
||||
myListBox := myGui.Add("ListBox", "r15 w500 vmyListBox")
|
||||
okButton := myGui.Add("Button", "Default w80", "OK")
|
||||
okButton.OnEvent("Click", on_okBtn_clicked)
|
||||
|
||||
ktoList := read_array_from_file(ktoListPath, defaultKtoList)
|
||||
apply_list(ktoList)
|
||||
|
||||
if (not is_kto_list_imported()) {
|
||||
import_susa_file()
|
||||
}
|
||||
|
||||
|
||||
^!k:: ; Ctrl+Alt+k
|
||||
{
|
||||
open()
|
||||
}
|
||||
|
||||
on_escape_pressed(*) {
|
||||
close()
|
||||
}
|
||||
|
||||
handle_activation(wParam, lParam, msg, hwnd) {
|
||||
if (hwnd = guiHwnd && !wParam) {
|
||||
on_focus_lost()
|
||||
}
|
||||
}
|
||||
|
||||
on_focus_lost() {
|
||||
close()
|
||||
}
|
||||
|
||||
on_okBtn_clicked(*) { ; auch wenn Enter gedrückt wird
|
||||
if (myListBox.Value = 0) {
|
||||
return
|
||||
}
|
||||
kto := SubStr(myListBox.Text, 1, 4) ; FiBu-Konten sind 4-stellig
|
||||
close()
|
||||
|
||||
if(is_voice_enabled()) {
|
||||
textToSpeak := RegExReplace(myListBox.Text, "^\d{4}\s+")
|
||||
textToSpeak := RegExReplace(textToSpeak, "U)\s*\(.*\)$") ; U) ungreedy
|
||||
textToSpeak := textToSpeak . ", " . RegExReplace(kto, "(.)", "$1 ")
|
||||
SetTimer () => say(textToSpeak), -1 ; async
|
||||
}
|
||||
|
||||
SendText(kto)
|
||||
|
||||
if(is_autosave_enabled()) {
|
||||
SendInput "^s" ; ctrl + s
|
||||
}
|
||||
}
|
||||
|
||||
open() {
|
||||
global isActive
|
||||
isActive := true
|
||||
show_gui_on_active_monitor()
|
||||
myEdit.Focus()
|
||||
}
|
||||
|
||||
close() {
|
||||
global isActive
|
||||
myGui.Hide()
|
||||
isActive := false
|
||||
}
|
||||
|
||||
; Wir wollen aus dem Textfeld heraus Elemente aus der Liste auswählen.
|
||||
; Deshalb registrieren wir einen globalen Hotkey, der nur ausgeführt
|
||||
; wird, wenn das Fenster aktiv ist (es gibt kein KeyPress-Event o. Ä.
|
||||
; für das Textfeld).
|
||||
#HotIf isActive
|
||||
Up:: {
|
||||
up_by(1)
|
||||
}
|
||||
PgUp:: {
|
||||
up_by(10)
|
||||
}
|
||||
up_by(offset) {
|
||||
val := myListBox.Value - offset
|
||||
if (val < 1) {
|
||||
val := 1
|
||||
}
|
||||
myListBox.Value := val
|
||||
}
|
||||
Down:: {
|
||||
down_by(1)
|
||||
}
|
||||
PgDn:: {
|
||||
down_by(10)
|
||||
}
|
||||
down_by(offset) {
|
||||
val := myListBox.Value + offset
|
||||
len := ControlGetItems(myListBox).Length
|
||||
if (val > len) {
|
||||
val := len
|
||||
}
|
||||
myListBox.Value := val
|
||||
}
|
||||
#HotIf
|
||||
|
||||
|
||||
on_text_changed(*) {
|
||||
do_search_delayed()
|
||||
}
|
||||
|
||||
|
||||
searchUpdateTimer := do_search
|
||||
|
||||
do_search_delayed() {
|
||||
global searchUpdateTimer
|
||||
if (searchUpdateTimer != 0) {
|
||||
SetTimer searchUpdateTimer, 0 ; clear
|
||||
}
|
||||
searchUpdateTimer := do_search
|
||||
SetTimer(searchUpdateTimer, -50) ; 50 ms delay / negative: exec once
|
||||
}
|
||||
|
||||
|
||||
do_search() {
|
||||
searchText := myEdit.Text
|
||||
filteredList := filter_list(ktoList, searchText)
|
||||
apply_list(filteredList)
|
||||
select_best_match(filteredList, searchText)
|
||||
}
|
||||
|
||||
|
||||
filter_list(originalList, searchText) {
|
||||
filteredList := []
|
||||
Loop originalList.Length {
|
||||
if is_subsequence(originalList[A_Index], searchText) {
|
||||
filteredList.Push(originalList[A_Index])
|
||||
}
|
||||
}
|
||||
return filteredList
|
||||
}
|
||||
|
||||
apply_list(newList) {
|
||||
myListBox.Opt("-Redraw")
|
||||
myListBox.Delete()
|
||||
if(newList.Length = 0) {
|
||||
okButton.Enabled := false
|
||||
myListBox.Opt("+Redraw")
|
||||
return
|
||||
}
|
||||
okButton.Enabled := true
|
||||
myListBox.Add(newList)
|
||||
myListBox.Opt("+Redraw")
|
||||
}
|
||||
|
||||
select_best_match(filteredList, searchText) {
|
||||
if (filteredList.Length = 0) {
|
||||
return
|
||||
}
|
||||
if (searchText = "") {
|
||||
myListBox.Choose(1)
|
||||
return
|
||||
}
|
||||
exact_match := find_best_exact_match(filteredList, searchText)
|
||||
if (exact_match > 0) {
|
||||
myListBox.Choose(exact_match)
|
||||
return
|
||||
}
|
||||
grouped_match := find_best_grouped_match(filteredList, searchText)
|
||||
if (grouped_match > 0) {
|
||||
myListBox.Choose(grouped_match)
|
||||
return
|
||||
}
|
||||
subsequence_match := find_best_subsequence_match(filteredList, searchText)
|
||||
if (subsequence_match > 0) {
|
||||
myListBox.Choose(subsequence_match)
|
||||
return
|
||||
}
|
||||
;myListBox.Choose(1) ; fallback
|
||||
}
|
||||
|
||||
|
||||
find_best_exact_match(list, searchText) {
|
||||
/*
|
||||
Beispiel: Suche nach "43"
|
||||
- "4243 ..."
|
||||
- "4300 ..." <= Selektion, weil die 43 am Anfang steht
|
||||
- "4301 ..."
|
||||
*/
|
||||
return find_best_match(list, searchText, match_substring)
|
||||
}
|
||||
|
||||
match_substring(sourceText, searchText) {
|
||||
startPos := InStr(sourceText, searchText, false) ; false = case-insensitive
|
||||
length := startPos = 0 ? 0 : StrLen(searchText)
|
||||
return {startPos: startPos, length: length}
|
||||
}
|
||||
|
||||
find_best_grouped_match(list, searchText) {
|
||||
/*
|
||||
Beispiel: Suche nach "pa ra"
|
||||
- "1803 Forderungen Pfand (Ford Pfand)"
|
||||
- "4301 PA Allg Raummiete & Nebenkosten (PA Allg MietRaum)" <= Selektion, weil "ra" in einem neuen Wort beginnt
|
||||
- "4321 PA PT Raummiete & Nebenkosten (PA PT MietRaum)" <= nicht selektiert, obwohl der Match kürzer ist
|
||||
*/
|
||||
return find_best_match(list, searchText, match_group)
|
||||
}
|
||||
|
||||
match_group(sourceText, searchText) {
|
||||
pattern := "iU)" . RegExReplace(searchText, "\s+", ".* ")
|
||||
startPos := RegExMatch(sourceText, pattern, &match)
|
||||
return {startPos: startPos, length: 1} ; Länge wird ignoriert
|
||||
}
|
||||
|
||||
find_best_subsequence_match(list, searchText) {
|
||||
/*
|
||||
Beispiel: Suche nach "para"
|
||||
Hier wird die 3. Zeile selektiert, weil "p" weit links steht und das Match früher Endet als in der 2. Zeile
|
||||
- "1650 Sparbücher (Sparbuch)"
|
||||
- "4100 Personalausgaben (Ausg Personal) <= "p" steht an der gleichen Position, aber das Match ist deutlich länger
|
||||
- "4301 PA Allg Raummiete & Nebenkosten (PA Allg MietRaum)"
|
||||
*/
|
||||
return find_best_match(list, searchText, match_subsequence)
|
||||
}
|
||||
|
||||
match_subsequence(sourceText, searchText) {
|
||||
pattern := "iU)" . RegExReplace(searchText, "(.)", "$1.*")
|
||||
; i: case-insensitive / U: ungreedy
|
||||
startPos := RegExMatch(sourceText, pattern, &match)
|
||||
length := startPos = 0 ? 0 : match.Len
|
||||
return {startPos: startPos, length: length}
|
||||
}
|
||||
|
||||
find_best_match(list, searchText, match_func) {
|
||||
if (list.Length = 0 or searchText = "") {
|
||||
return 0
|
||||
}
|
||||
bestListIdx := 0
|
||||
bestListIdxMatchPos := 0 ; 0 = not found / fist index = 1
|
||||
bestListIdxMatchLength := 0
|
||||
loop list.Length {
|
||||
row := list[A_Index]
|
||||
matchInfo := match_func(row, searchText)
|
||||
matchPos := matchInfo.startPos
|
||||
matchLength := matchInfo.length
|
||||
if (matchPos = 0) {
|
||||
continue
|
||||
}
|
||||
if (bestListIdxMatchPos = 0
|
||||
or matchPos < bestListIdxMatchPos
|
||||
or (matchPos = bestListIdxMatchPos and matchLength < bestListIdxMatchLength)) {
|
||||
bestListIdx := A_Index
|
||||
bestListIdxMatchPos := matchPos
|
||||
bestListIdxMatchLength := matchLength
|
||||
}
|
||||
}
|
||||
return bestListIdx
|
||||
}
|
||||
|
||||
is_subsequence(sourceText, searchText) {
|
||||
return match_subsequence(sourceText, searchText).startPos > 0 ? true : false
|
||||
}
|
||||
|
||||
import_susa_file() {
|
||||
MsgBox("
|
||||
(
|
||||
Das Suchfenster benötigt eine Liste aller FiBu-Konten. Am einfachsten geht das über die Summen- und Saldenliste:
|
||||
|
||||
1. In den Sherpa-Einstellungen sicherstellen, dass der Export mit UTF-8-
|
||||
Zeichensatz geschieht (Allgemein => Finanzbuchhaltung => Exportoptionen).
|
||||
Hinweis: Diese Einstellung gilt nur für die aktuelle Gliederung.
|
||||
|
||||
2. In Sherpa: Finanzbuchhaltung => Summen- und Saldenliste => Anzeigen
|
||||
-> "Nur bebuchte Konten" ausschalten (alle anzeigen)
|
||||
-> CSV-Datei exportieren
|
||||
|
||||
Wenn die SuSa-Liste bereit ist, klicke bitte OK.
|
||||
)", "Summen- und Saldenliste importieren")
|
||||
|
||||
selectedFile := FileSelect("1", "", "Summen- und Saldenliste auswählen (UTF-8)", "CSV-Dateien (*.csv)")
|
||||
; "1": File Must Exist
|
||||
if (selectedFile = "") {
|
||||
return
|
||||
}
|
||||
|
||||
newKtoList := create_kto_list_from_susa_file(selectedFile)
|
||||
write_array_to_file(newKtoList, ktoListPath)
|
||||
|
||||
global ktoList
|
||||
ktoList := newKtoList
|
||||
apply_list(ktoList)
|
||||
|
||||
MsgBox("
|
||||
(
|
||||
FiBu-Konten erfolgreich importiert. Du kannst die SuSa-Datei jetzt löschen.
|
||||
|
||||
Das Suchfenster kannst du mit STRG+ALT+k öffnen, nachdem du den Cursor in ein Textfeld gesetzt hast.
|
||||
)", "Import erfolgreich")
|
||||
}
|
||||
|
||||
is_kto_list_imported() {
|
||||
return FileExist(ktoListPath) != ""
|
||||
}
|
||||
|
||||
create_kto_list_from_susa_file(susaFile) {
|
||||
newKtoList := []
|
||||
|
||||
Loop read, susaFile {
|
||||
if (A_Index = 1) {
|
||||
Continue ; erste Zeile überspringen
|
||||
}
|
||||
lineNumber := A_Index
|
||||
; workaround: das AutoHotKey CSV-Parsing erwartet Komma, Sherpa exportiert Semikolon
|
||||
; todo: prüfen, was mit Kommata in Feldern passiert
|
||||
line := StrReplace(A_LoopReadLine, ";", ",")
|
||||
newKtoLine := ""
|
||||
Loop parse, line, "CSV" {
|
||||
if (A_Index = 4) {
|
||||
break ; nur die ersten 3 Spalten sind für uns interessant
|
||||
}
|
||||
field := A_LoopField
|
||||
if (A_Index = 3) { ; Kurzname
|
||||
field := "(" . field . ")"
|
||||
}
|
||||
field := Trim(field)
|
||||
newKtoLine := newKtoLine . " " . field
|
||||
}
|
||||
newKtoList.Push(Trim(newKtoLine))
|
||||
}
|
||||
|
||||
return newKtoList
|
||||
}
|
||||
|
||||
write_array_to_file(myArray, filePath) {
|
||||
file := FileOpen(filePath, "w")
|
||||
for line in myArray {
|
||||
file.WriteLine(line)
|
||||
}
|
||||
file.Close()
|
||||
}
|
||||
|
||||
read_array_from_file(filePath, defaultArray) {
|
||||
if ( FileExist(filePath) = "" ) {
|
||||
return defaultArray
|
||||
}
|
||||
myArray := []
|
||||
Loop Read, filePath {
|
||||
myArray.Push(A_LoopReadLine)
|
||||
}
|
||||
return myArray
|
||||
}
|
||||
|
||||
toggle_autostart(itemName, itemPos, myMenu) {
|
||||
if (is_autostart_enabled()) {
|
||||
FileDelete(autostartShortcutPath)
|
||||
myMenu.Uncheck(itemName)
|
||||
} else {
|
||||
FileCreateShortcut(A_ScriptFullPath, autostartShortcutPath)
|
||||
myMenu.Check(itemName)
|
||||
}
|
||||
}
|
||||
|
||||
is_autostart_enabled() {
|
||||
return FileExist(autostartShortcutPath) != ""
|
||||
}
|
||||
|
||||
toggle_autosave(itemName, itemPos, myMenu) {
|
||||
if (is_autosave_enabled()) {
|
||||
FileDelete(autosaveConfigPath)
|
||||
myMenu.Uncheck(itemName)
|
||||
} else {
|
||||
FileAppend "", autosaveConfigPath
|
||||
myMenu.Check(itemName)
|
||||
}
|
||||
}
|
||||
|
||||
is_autosave_enabled() {
|
||||
return FileExist(autosaveConfigPath) != ""
|
||||
}
|
||||
|
||||
|
||||
toggle_voice(itemName, itemPos, myMenu) {
|
||||
if (is_voice_enabled()) {
|
||||
FileDelete(voiceConfigPath)
|
||||
myMenu.Uncheck(itemName)
|
||||
} else {
|
||||
FileAppend "", voiceConfigPath
|
||||
myMenu.Check(itemName)
|
||||
}
|
||||
}
|
||||
|
||||
is_voice_enabled() {
|
||||
return FileExist(voiceConfigPath) != ""
|
||||
}
|
||||
|
||||
|
||||
show_gui_on_active_monitor() {
|
||||
activeWin := WinExist("A")
|
||||
if (not activeWin) {
|
||||
myGui.Show()
|
||||
return
|
||||
}
|
||||
WinGetPos(&winX, &winY, &winWidth, &winHeight, activeWin)
|
||||
winCenterX := winX + winWidth // 2
|
||||
winCenterY := winY + winHeight // 2
|
||||
|
||||
myGui.Show()
|
||||
; GetPos ist erst verfügbar, wenn das Fenster sichtbar ist
|
||||
myGui.GetPos(&guiX, &guiY, &guiWidth, &guiHeight)
|
||||
|
||||
monitorIndex := get_monitor_index_from_window(winCenterX, winCenterY)
|
||||
monitorInfo := get_monitor_info(monitorIndex)
|
||||
guiX := monitorInfo.left + (monitorInfo.right - monitorInfo.left) // 2 - guiWidth // 2
|
||||
guiY := monitorInfo.top + (monitorInfo.bottom - monitorInfo.top) // 2 - guiHeight // 2
|
||||
|
||||
myGui.Show(Format("x{} y{}", guiX, guiY))
|
||||
}
|
||||
|
||||
get_monitor_index_from_window(x, y) {
|
||||
monitorCount := MonitorGetCount()
|
||||
Loop monitorCount {
|
||||
monitorInfo := get_monitor_info(A_Index)
|
||||
if (x >= monitorInfo.left && x < monitorInfo.right && y >= monitorInfo.top && y < monitorInfo.bottom) {
|
||||
return A_Index
|
||||
}
|
||||
}
|
||||
return 1
|
||||
}
|
||||
|
||||
get_monitor_info(monitorIndex) {
|
||||
MonitorGet(monitorIndex, &left, &top, &right, &bottom)
|
||||
MonitorGetWorkArea(monitorIndex, &workLeft, &workTop, &workRight, &workBottom)
|
||||
return {left: workLeft, top: workTop, right: workRight, bottom: workBottom}
|
||||
}
|
||||
|
||||
say(textToSpeak) {
|
||||
; todo: diese Liste als CSV-Datei speichern/laden
|
||||
voice.Skip("Sentence", 1)
|
||||
textToSpeak := StrReplace(textToSpeak, "Pers Net ", "Personal Netto: ", true)
|
||||
textToSpeak := StrReplace(textToSpeak, "Pers SV ", "Personal Sozialversicherung: ", true)
|
||||
textToSpeak := StrReplace(textToSpeak, "Pers FA ", "Personal Finanzamt: ", true)
|
||||
textToSpeak := StrReplace(textToSpeak, "Pers ", "Personal ", true)
|
||||
textToSpeak := StrReplace(textToSpeak, "GB Inv ", "Geschäftsbetrieb Inventar: ", true)
|
||||
textToSpeak := StrReplace(textToSpeak, "GB Bü ", "Geschäftsbetrieb Büro: ", true)
|
||||
textToSpeak := StrReplace(textToSpeak, "GB DL ", "Geschäftsbetrieb Dienstleistungen: ", true)
|
||||
textToSpeak := StrReplace(textToSpeak, "GB Sonst ", "Geschäftsbetrieb Sonstiges: ", true)
|
||||
textToSpeak := StrReplace(textToSpeak, "GB ", "Geschäftsbetrieb ", true)
|
||||
textToSpeak := StrReplace(textToSpeak, "PA Allg ", "Politische Arbeit allgemein: ", true)
|
||||
textToSpeak := StrReplace(textToSpeak, "PA PT ", "Politische Arbeit Parteitage: ", true)
|
||||
textToSpeak := StrReplace(textToSpeak, "PA VA ", "Politische Arbeit Veranstaltungen: ", true)
|
||||
textToSpeak := StrReplace(textToSpeak, "PA Gre ", "Politische Arbeit Gremien: ", true)
|
||||
textToSpeak := StrReplace(textToSpeak, "PA ", "Politische Arbeit ", true)
|
||||
textToSpeak := StrReplace(textToSpeak, "WK EU ", "Wahlkampf Europa-Wahl: ", true)
|
||||
textToSpeak := StrReplace(textToSpeak, "WK BTW ", "Wahlkampf Bundestagswahl: ", true)
|
||||
textToSpeak := StrReplace(textToSpeak, "WK Bü ", "Wahlkampf Bürgerschaftswahl: ", true)
|
||||
textToSpeak := StrReplace(textToSpeak, "WK BV ", "Wahlkampf Bezirkswahl: ", true)
|
||||
textToSpeak := StrReplace(textToSpeak, "WK ", "Wahlkampf ", true)
|
||||
textToSpeak := StrReplace(textToSpeak, "VZ GB ", "Verrechnungszuschuss eingehend, Geschäftsbetrieb: ", true)
|
||||
textToSpeak := StrReplace(textToSpeak, "VZ PA ", "Verrechnungszuschuss eingehend, Politische Arbeit: ", true)
|
||||
textToSpeak := StrReplace(textToSpeak, "VZ WK ", "Verrechnungszuschuss eingehend, Wahlkampf: ", true)
|
||||
textToSpeak := StrReplace(textToSpeak, "VZ ", "Verrechnungszuschuss eingehend ", true)
|
||||
textToSpeak := StrReplace(textToSpeak, "vz GB ", "Verrechnungszuschuss ausgehend, Geschäftsbetrieb: ", true)
|
||||
textToSpeak := StrReplace(textToSpeak, "vz PA ", "Verrechnungszuschuss ausgehend, Politische Arbeit: ", true)
|
||||
textToSpeak := StrReplace(textToSpeak, "vz WK ", "Verrechnungszuschuss ausgehend, Wahlkampf: ", true)
|
||||
textToSpeak := StrReplace(textToSpeak, "vz ", "Verrechnungszuschuss ausgehend ", true)
|
||||
textToSpeak := StrReplace(textToSpeak, "EZ ", "Echter Zuschuss eingehend ", true)
|
||||
textToSpeak := StrReplace(textToSpeak, "ez ", "Echter Zuschuss ausgehend ", true)
|
||||
textToSpeak := StrReplace(textToSpeak, "GBV", "Geschäftsbesorgungsvertrag", true)
|
||||
textToSpeak := StrReplace(textToSpeak, "auß ", "außerhalb ", true)
|
||||
textToSpeak := StrReplace(textToSpeak, "HH", "Hamburg", true)
|
||||
textToSpeak := StrReplace(textToSpeak, "BV", "Bundesverband", true)
|
||||
textToSpeak := StrReplace(textToSpeak, "LV", "Landesverband", true)
|
||||
textToSpeak := StrReplace(textToSpeak, "KV", "Kreisverband", true)
|
||||
textToSpeak := StrReplace(textToSpeak, "GJ", "Grüne Jugend", true)
|
||||
textToSpeak := StrReplace(textToSpeak, "Gl.", "Gliederung", true)
|
||||
textToSpeak := StrReplace(textToSpeak, "Fr ", "Fraktion ", true)
|
||||
textToSpeak := StrReplace(textToSpeak, "FiBu", "Finanzbuchhaltung", true)
|
||||
textToSpeak := StrReplace(textToSpeak, "USt", "Umsatzsteuer", true)
|
||||
voice.Speak(textToSpeak, 0x1)
|
||||
}
|
Loading…
Reference in a new issue