
| Current Path : /home/cgabriel/ |
Linux ift1.ift-informatik.de 5.4.0-216-generic #236-Ubuntu SMP Fri Apr 11 19:53:21 UTC 2025 x86_64 |
| Current File : //home/cgabriel/konto.py |
# coding: utf
import os,sys,re,glob,time,base64,hashlib,random,functools,hashlib,json,datetime,collections
#******************************************************************************
class Konto ():
#******************************************************************************
def __init__ (self,params={}):
self.t0 = 0
self.digits = 5
self.nformat3 = "%3.2f"
self.nformat9 = "%9.2f"
self.nformat13 = "%13.2f"
self.dformat = "%0" + str(self.digits) + "u"
self.len_hkey_str = "22"
self.len_hkey_nr = int(self.len_hkey_str)
self.acc_line_parser = re.compile(r"^(\d\d\d\d)(MM|\d\d)(DD|\d\d\+?) +(\S+) +(\S+) +(\S+) +(\-?\d+\.\d\d\d?|\-+|\.+) +(.*?) *$")
self.pre_proc_parser = re.compile(r"^(\d\d\d\d)(MM|\d\d)(DD|\d\d)\+?( +\S+)( +\S+ +\S+ +)(\-?\d+\.\d\d\d?|\-+|\.+)( +.*?) *$")
self.merge_parser = re.compile(r"^(\d\d\d\d)(MM|\d\d)(DD|\d\d)\+?( +\S+)( +\S+ +\S+ +)(\-?\d+\.\d\d\d?|\-+|\.+)( +)(.*?) *$")
self.merge_parser1 = re.compile(r"^(.*?\-?\d+\.\d\d*.*?)(\-?\d+\.\d\d*|\-+|\.+) +(.*)$")
self.sortieren = 1
self.max_offset = 5
self.total_salden = {}
self.salden_expand = "(-[^- ]+){0,99},"
self.dataset = {}
self.ktotyp = None
if "ktotyp" in params:
self.ktotyp = params["ktotyp"]
self.overlap = 0
# ktodir = os.path.abspath(".")
localdir = os.path.abspath(".")
if "base" in params:
localdir = params["base"]
self.set_basedir(localdir)
self.mark("---")
ferientage_bw = "1224,1225,1226,1231,0101,0106,0501,1003,1101"
ferientage_bw = ferientage_bw + ",250418,250421,250529,250609,250619"
ferientage_bw = ferientage_bw + ",260403,260406,260514,260525,260604"
self.ferientage = ferientage_bw.split(",")
# os.chdir(ktodir)
#**********************************************************************************
def set_basedir (self,path):
if not os.path.isdir(path):
m = re.search(r"^(.*)[\\\/](.*)[\\\/]*$",path)
if m:
path = m.group(1)
else:
path = os.path.abspath(".")
path = re.sub(r"[\\\/]+$","",path+"/")
self.ktofile_path = path
self.base_dir = "" # Search for a base directory with acc and sum files
while (0 == 0): # check if we are in a directory with acc files
acc_files = glob.glob(path+"/2*.acc") + glob.glob(path+"/base/*.acc") + glob.glob(path+"/.base/*.acc") + glob.glob(path+"/??_ktobase/*.acc")
# print(acc_files)
if len(acc_files) > 0:
m = re.search(r"^(.*[\\\/])(.*)$",os.path.abspath(acc_files[0]))
if m:
self.base_dir = m.group(1)
frm = glob.glob(self.base_dir + "/*.frm")
if len(frm) > 0:
frm = re.sub(r"^.*[\\\/]","",frm[0])
nachkomma = frm[0]
self.digits = int(frm[1])
self.nformat3 = "%"+frm[2]+"."+nachkomma+"f"
self.nformat9 = "%"+("%1u"%int(frm[3:5]))+"."+nachkomma+"f"
self.nformat13 = "%"+("%1u"%int(frm[5:7]))+"."+nachkomma+"f"
# print(nachkomma,self.nformat3,self.nformat9,self.nformat13)
break
m = re.search(r"^(.*)[\\\/](.*)[\\\/]*$",path)
if m:
path = m.group(1)
else:
break
if not self.base_dir == "":
self.base_dir = re.sub(r"//$","/",self.base_dir + "/")
#**********************************************************************************
def read_config (self,dir=""):
if dir == "":
dir = self.base_dir + "/*.data"
for config_file in glob.glob(dir):
config1 = open(config_file).read()
try:
dataset = json.loads(config1)
except:
dataset = None
if dataset: # json files
for o in dataset.keys():
self.dataset[ o.replace("-","").lower() ] = dataset[o]
else: # proprietary pseudo csv files
felder = config1.split("\n")
for zeile in felder:
m = re.search(r"^(\S+)\: *(.*?)\"",zeile)
if m and not m.group(1).lower() in self.dataset:
self.dataset[ m.group(1).lower() ] = m.group(2)
return(self.dataset)
#**********************************************************************************
def mark (self,remark=""):
if remark == "":
remark = ktofile
t = time.perf_counter()
if self.t0 > 0:
if not self.export_file_exists == None:
print ( (self.nformat9 % ((t-self.t0)*1000)) + " ms for: " + remark, flush=True )
self.t0 = t
#**********************************************************************************
def kto (self,pattern=None,ktofile0=None):
self.ktofile = None
if self.base_dir == "":
print("No accounting base dir found.")
return("Error 135")
if pattern == "SORT": # Sortieren aller acc und sum files. Dies ist sinnvoll fuer das syncen
for acc_file in glob.glob(self.base_dir+"*.acc") + glob.glob(self.base_dir+"*.sum"):
file_text = re.sub(r"\n+$","",open(acc_file).read()).split("\n")
file_text.sort()
open(acc_file,"w").write("\n".join(file_text) + "\n")
return("Accounting base files sorted.")
ktofile = None
pattern_add = ""
self.sortclass = ""
# print("-----------------------",pattern,ktofile0)
if pattern in ("w","x","m","q"): # Periodische Saldenliste anfertigen
self.sortclass = pattern.upper()
pattern = None
elif not pattern == None:
if os.path.isfile(pattern):
ktofile = pattern
pattern = None
elif pattern[0] in [":",".","-"]:
pattern_add = pattern
pattern = None
# print("-----------------------",pattern,ktofile0)
# print(pattern_add,pattern,ktofile)
if ktofile == None:
text = os.popen("less ~/i").read().split("\n")
text.reverse()
for zeile in text:
# print(zeile)
m = re.search(r"^ *(\S+) +(\S+) *$",zeile)
if m:
if os.path.isfile(m.group(2)):
ktofile = m.group(2)
break
if ktofile == None:
ktofile = glob.glob("*.kto") + glob.glob("*.kto.html")
if len(ktofile) == 1:
ktofile = ktofile[0]
else:
ktofile = None
# print("---",pattern_add,pattern,ktofile)
if pattern == None and not ktofile == None and os.path.isfile(ktofile):
ktotext = open(ktofile).read()
ktotext = re.sub(r"^\<PRE\>","",ktotext)
ktotext = re.sub(r"\<\/PRE\> *\n *$","",ktotext,re.DOTALL)
m = re.search(r"^(\S+)",ktotext)
if m:
pattern = "^" + m.group(1)
if pattern[0:2] == "^.":
pattern = pattern[2:]
else:
ktofile = None
if not pattern_add == "":
ktofile = None
# print("-----------------------",pattern,ktofile0)
self.text1 = None
if pattern == None:
return()
self.export_file_exists = ktofile
self.text1 = self.update_konto(ktofile,pattern+pattern_add)
if not self.text1 == None:
if ktofile == None:
if os.path.isfile("tmp.kto.html"):
open("tmp.kto.html","w").write(self.text1)
else:
# print("!!!")
if ktofile0 == None:
print(self.text1)
elif not ktofile0 == "__server__":
print(ktofile0)
open(ktofile0,"w").write(self.text1)
elif self.text1 == "CONFLICT":
if not ktofile == "__server__":
print("\n=======================\n\n !! CONFLICT !! \n\n=======================\n\n")
return(self.hkey) # Im Konfliktfalle den jeweils gueltigen Lizenz Key liefern
elif not ktofile0 == "__server__":
open(ktofile,"w").write(self.text1)
if not ktofile == None and not ktofile0 == "__server__":
os.system("echo '#!/bin/sh\njoe "+ktofile+"\n' > ~/i")
os.system("chmod 775 ~/i")
return("")
#**********************************************************************************
def zerlege (self):
ktobj = {}
if not self.text1:
return(ktobj)
text1 = self.text1.split("\n")
m = re.search(r"^(\S+) +(\S+) +(\S+) *$",self.title)
if m:
ktobj["id"] = m.group(1)
ktobj["hash"] = m.group(2)
ktobj["saldo"] = m.group(3)
ktobj["zeilen"] = []
for zeile in self.formatted_acc:
m = re.search(r"^(\S+) +(\S+) +(\S+) +(\S+) +(\S+) +(.*)$",zeile)
ktobj["zeilen"].append({"datum":m.group(1),
"betrag":m.group(2),
"kto1":m.group(3),
"kto2":m.group(4),
"saldo":m.group(5),
"remark":m.group(6)})
ktobj["salden"] = []
for saldo in self.salden_aktuell:
m = re.search(r"^(\S*) +(.*)$",saldo)
if m:
ktobj["salden"].append({"kto":m.group(1),"saldo":m.group(2)})
else:
ktobj["salden"].append({"kto":"","saldo":""})
return(ktobj)
#**********************************************************************************
def update_konto (self,ktofile,search_pattern,salden_expand=None): # Updates an actual konto
self.search_pattern = search_pattern
if not salden_expand == None:
self.salden_expand = salden_expand
self.parse_pattern()
# print(self.search_pattern,self.grep_pattern)
self.mark("B. Pattern parsed.")
# self.list_of_sum_files = glob.glob(base_dir+".*sum)
#
# if not len(self.list_of_acc_files) == len(self.list_of_sum_files):
# print("Kto database not proper.")
# return("Error 207.")
self.extract_account_lines() # Prepare formatted konto and salden
self.mark("D. Extract lines.")
self.format_kto()
print("WEWE",self.hkey)
self.startdatum0 = self.startdatum
self.enddatum0 = self.enddatum
self.mark("E. ktofile formatted.")
self.change_acc_files = 0
res = "null"
while not ktofile == None:
print(ktofile)
text = open(ktofile).read()
self.processed_acc = text.split("\n")
if not self.sortclass == "": # only add elaborated sorting
self.replace_accountings()
self.change_acc_files = 1
break
print("VERGLEICH",self.hkey,text[0:200])
m = re.search("^(.*?)\n *\n(\d\d\d\d....\+? +[^ ]+ +\S+ .*?\n) *\n",text,re.DOTALL) # Check whether processed file has changed
print(m)
self.mark("F. Processed ktofile hashkey. ")
if m:
relevant_text_in_ktofile = m.group(2)
print("QQWW",len(relevant_text_in_ktofile))
self.actual_hkey = hashlib.md5(relevant_text_in_ktofile.encode("utf-8")).hexdigest()[0:self.len_hkey_nr]
print("DDDDDD",self.actual_hkey,self.hkey)
open(ktofile+"11","w").write(relevant_text_in_ktofile)
if self.actual_hkey == self.hkey:
self.mark("No change.")
return(None)
self.mark("... fits.")
res = self.replace_accountings() # apply the diffs between formatted_acc and processed_acc to extracted_acc.
self.mark("G. Replace accounting lines.")
print("RRR",res)
if res == "null": # alles schon erledigt, die Formatierung wurde ja oben gemacht
self.mark("-> No action needed.")
break
if res.replace("x","") == "":
self.mark("-> perform merge.")
self.hkey = "x"
self.format_kto()
text1 = "<PRE>" + self.title + "\n\n" + "\n".join(self.formatted_acc) + "\n\n</PRE>\n"
return(text1)
m = re.search("^.*? ([012KEP3456789abcdef]{"+self.len_hkey_str+"}) ",text) # keine gueltige Formatierung,
if not m: # also auch nichts mehr machen, und Server Version uebernehmen
break
if self.actual_hkey == m.group(1): # hier stimmt jetzt offenbar die Signatur der Buchungszeilen mit der eingetragenen Signatur der Datei
break # die Datei hat sich offenbar nicht geaendert, also koennen wir die Server Version nehmen
print("WWWWWW",m.group(1),self.hkey)
if not (m.group(1) == self.hkey or # the key which is found in the existing kto-file allows to change
"KEEP" in m.group(1)): # the result of the computed sub account so we take the chance
return("CONFLICT")
break # formerly, instead of the return(conflict)
# ansonsten die Aenderungen jetzt uebernehmen
ktotext_to_change = self.format_kto(1) # make a new formatted_acc from the extracted_acc again.
self.startdatum0 = min(self.startdatum,self.startdatum0)
self.enddatum0 = max(self.enddatum,self.enddatum0)
self.mark("H. Ktofile formatted again.")
# print("KKK",ktotext_to_change)
if ktotext_to_change == "change":
self.pre_process(ktofile)
self.extracted_acc = self.extracted_acc_0
continue
self.change_acc_files = 1
break
self.mark("I. Compute salden.")
# if len(konto_files_found) == 0 or re.search(r"([0123456789abcdef]{"+self.len_hkey_str+"})\.kto",ktofile):
# ktofile = self.hkey + ".kto.html"
self.mark("J. Write result file.")
text1 = "<PRE>" + self.title + "\n\n" + "\n".join(self.formatted_acc) + "\n\n"
# print(text1)
if self.change_acc_files and not res == "merge":
self.list_of_acc_files = glob.glob(self.base_dir+"*.acc")
self.list_of_acc_files.sort()
self.subtract_account_lines() # delete the former lines of the search
self.mark("K. Delete former accounting lines.")
self.add_account_lines(ktofile) # add the new ones
self.mark("L. Add changed accounting lines.")
self.update_sum_files() # also update the sumfiles
self.mark("M. Update sum files.")
self.extract_account_lines() # Prepare formatted konto and salden
self.mark("N. Reload kto file.")
self.format_kto()
self.mark("O. ktofile formatted again.")
text1 = "<PRE>" + self.title + "\n\n" + "\n".join(self.formatted_acc) + "\n\n"
# if res == "null":
# self.change_acc_files = 1 # jetzt sagt self.change_acc_files nur noch aus, ob eine zwischen tmp version gespeichert werden muss
self.ownkey = ""
self.pformat = self.nformat9
self.format_salden()
if self.overlap > 9:
self.pformat = "%" + str(max(9,self.overlap-3)) + "u"
self.format_salden()
text1 = text1 + "\n".join(self.salden_aktuell) + "\n" + "</PRE>\n"
return(text1)
#**********************************************************************************
def check_hash (self,ktotext): # geht auch ganz ohne Objekt
if os.path.isfile(ktotext):
ktotext = open(ktotext).read()
print(ktotext[0:100])
m = re.search("^(.*?)\n *\n(.*\n\d\d\d\d....\+? +[^ ]+ +\S+ .*?\n)",ktotext,re.DOTALL) # Check whether processed file has changed
if m:
ktotext = m.group(2)
hkey = hashlib.md5(ktotext.encode("utf-8")).hexdigest()
print(hkey)
#**********************************************************************************
def read_saldo (self,search_pattern,salden_expand=None):
# self.mark("read saldo " + search_pattern)
self.search_pattern = "^" + search_pattern
if not salden_expand == None:
self.salden_expand = salden_expand
# print(self.search_pattern)
self.parse_pattern()
# print(self.grep_pattern)
if self.grep_pattern[0] == " ":
self.ukto = self.grep_pattern[1:]
self.ukto = re.sub(r"-$","",self.ukto)
# print(self.ukto)
self.startdatum = (self.startdatum + "00000000")[0:8]
self.enddatum = (self.enddatum + "99999999")[0:8]
salden_liste = self.format_salden()
# print(salden_liste)
if len(salden_liste) == 0:
return(0.00)
return(float(salden_liste[0][2]))
# print(self.startdatum,self.enddatum,self.ukto)
#**********************************************************************************
def salden_text (self):
erg = "\n".join(self.salden_aktuell)+"\n"
if not re.search(r"\.",erg):
erg = " 0.00\n"
return(erg)
#**********************************************************************************
def extract_account_lines (self):
# This function extracts the matching lines of a request into a sorted array
# self.mark("A. Compute query for transaction file " + pattern1 + " " + str(interval)[0:40] + " ...")
# print("111",self.interval_long,"--"+self.grep_pattern+"--")
if not self.interval_long == "":
if self.grep_pattern == "":
self.extracted_acc = os.popen(self.egrep + "grep -h -i ^" + self.interval_long + " " + self.base_dir + "*.acc").read().split("\n")
else:
self.extracted_acc = os.popen(self.egrep + "grep -h -i ^" + self.interval_long + " " + self.base_dir + "*.acc | grep -h -i '" + self.grep_pattern + "'").read().split("\n")
else:
if self.grep_pattern == "":
self.extracted_acc = os.popen("less " + self.base_dir + "*.acc").read().split("\n")
else:
self.extracted_acc = os.popen(self.egrep + "grep -h -i '" + self.grep_pattern + "' " + self.base_dir + "*.acc").read().split("\n")
self.extracted_acc.sort()
#**********************************************************************************
def parse_pattern (self): # parse the search pattern
self.grep_pattern = re.sub(r"\^"," ",self.search_pattern,9999)
self.interval_long = ""
self.interval_short = ""
self.egrep = ""
self.mode = ""
self.startdatum = "00000000"
self.enddatum = "99999999"
m = re.search(r"^(.*)([\.\:])(.*)$",self.grep_pattern)
if m:
self.grep_pattern = m.group(1)
self.mode = m.group(2)
self.interval_long = "20" + m.group(3)[0:2]
months = m.group(3)[2:]
self.interval_short = m.group(3)
if months == "A":
months = "10"
first_m = "10"
last_m = "10"
elif months == "B":
months = "11"
first_m = "11"
last_m = "11"
elif months == "C":
months = "12"
first_m = "12"
last_m = "12"
elif months == "I":
months = "0[123]"
first_m = "01"
last_m = "03"
elif months == "J":
months = "0[456]"
first_m = "04"
last_m = "06"
elif months == "K":
months = "0[789]"
first_m = "07"
last_m = "09"
elif months == "L":
months = "1[012]"
first_m = "10"
last_m = "12"
elif months == "M":
months = "0[123456]"
first_m = "01"
last_m = "06"
elif months == "N":
months = "\\(07\\|08\\|09\\|10\\|11\\|12\\)" # "[01][789012]"
first_m = "07"
last_m = "12"
egrep = "e"
elif months == "P" or months == "":
months = ""
first_m = "01"
last_m = "12"
elif not months == "":
months = "0" + months
first_m = months
last_m = months
if self.mode == ":":
intervals = []
jahr = "2000"
while (0 == 0):
intervals.append(jahr)
jahr = str(int(jahr)+1)
if jahr == self.interval_long:
break
if last_m == "12":
intervals.append(jahr)
else:
month = "01"
while (0 == 0):
intervals.append(jahr+month)
if month in (last_m,"12"):
break
month = "%02u" % (int(month) + 1)
self.interval_long = "\\(" + "\\|".join(intervals) + "\\)"
self.egrep = "e"
self.startdatum = intervals[0]
self.enddatum = intervals[-1]
else:
self.startdatum = self.interval_long + first_m + "00"
self.enddatum = self.interval_long + last_m + "99"
self.interval_long = self.interval_long + months
# print(self.startdatum,self.enddatum)
# if self.search_pattern[0] == "^":
# self.start_kto = re.sub(r"[\^ ]",""self.grep_pattern,9999)
# else:
# self.start_kto = None
#**********************************************************************************
def format_kto (self,mode=0):
ktotext_changed = self.parse_ktotext()
if not ktotext_changed == "":
return(ktotext_changed)
# ktotext: datum betrag kto1 kto2 saldo bemerkung original_line
if self.ukto == "":
self.buchungen.sort(key=lambda x:x[0]+str(x[1])+x[3]+x[4])
else:
# ktotext.sort(key=lambda x:str(x[5]+1)+x[0])
self.buchungen.sort(key=lambda x:x[0]+str(x[5]+1)+x[2]+x[3]+x[4])
gesamt = 0.00
self.startdatum = "00000000"
self.enddatum = "00000000"
dbl_marks = {}
self.formatted_acc = []
self.extracted_acc = [] # das orig-File muss in der neuen Sortierung auch neu geschrieben werden,
# damit man am Ende den Patch auf das formatierte Konto-File anwenden kann.
has_doublettes = 0
datum = ""
saldo = ""
self.total_salden = {}
buchungsanzahl = {}
for zeile in self.buchungen: # step through all accounting lines
ust = ""
if "v.H." in zeile[4]:
ust = " "
betrag = zeile[1]
ktoa = zeile[2]
ktob = zeile[3]
datum = zeile[0]
if not ktoa.startswith(self.ukto):
o = ktoa
ktoa = ktob
ktob = o
betrag = re.sub(r"^--","","-"+betrag)
if mode == 0 and not ktoa.startswith(self.ukto) and self.grep_pattern[0] == " ":
self.mark("SKIP: " + self.ukto + " " + zeile[0] + " " + zeile[1] + " " + zeile[2] + " " + zeile[3])
continue
# print(betrag,zeile)
betrag = eval(betrag)
if self.sortclass: # diese Gesamtberechnung aller Salden fuer das formatierte Konto ist zu zeitaufwendig.
# Deswegen dieses caching mit den .sum-Files.
# Fuer eine Leistungsberechnung braucht man aber "m"
# print(self.sortclass)
if self.sortclass == "W":
class_marker = int(datum[2:4] + ("%02u" % int(datetime.datetime.strptime(datum,"%Y%m%d").isocalendar()[1])))
# print(class_marker)
if datum[4:6] == "12" and ("%04u" % class_marker)[2:4] == "01":
class_marker = 100 * ( int(datum[2:4]) + 1 ) + 1
elif self.sortclass == "M":
class_marker = int( datum[2:6] )
elif self.sortclass == "Q":
class_marker = int( datum[2:4] + str(1+int((int(datum[4:6])-1)/3)) )
if not self.sortclass == "X":
self.compute_salden(self.total_salden,buchungsanzahl,ktoa, betrag,1,datum,class_marker)
self.compute_salden(self.total_salden,buchungsanzahl,ktob,-betrag,1,datum,class_marker)
if self.ukto == "":
gesamt = gesamt + betrag
saldo = self.nformat13 % gesamt
else:
if zeile[5] == 0: # zeile[5]: the number of matching ukto in ktoa or ktob
if mode == 0:
saldo = " ...."
else:
saldo = " 0.00" # for uploading into acc-files
# saldo = "%13.2f" % gesamt
elif self.maxsaldo == 0 or zeile[5] == 1:
gesamt = gesamt + betrag
saldo = self.nformat13 % gesamt
elif zeile[5] == 2:
saldo = self.nformat13 % gesamt
dbl_z = datum + " " + (self.nformat13 % betrag) + " " + (self.format_maxa % ktoa) + " " + (self.format_maxb % ktob)
rem_z = ust + re.sub(r" +"," ",zeile[4],9999)
zeile1 = dbl_z + " " + saldo + " " + rem_z
dbl_mark = dbl_z + rem_z # wenn Doubletten gefunden werden, diese eindeutig markieren
# if "abc" in dbl_mark:
# for oo in dbl_marks:
# print(oo)
# print("--------------------")
if not (dbl_mark in dbl_marks.keys()):
# print(">>",dbl_mark,"1235")
dbl_marks[dbl_mark] = 0
else:
dbl_marks[dbl_mark] = dbl_marks[dbl_mark] + 1
zeile1 = zeile1 + " DOUBLETTE " + str(dbl_marks[dbl_mark])
has_doublettes = 1
self.extracted_acc.append(zeile[6])
self.formatted_acc.append(zeile1)
if "Jahres-Netto" in rem_z:
self.extracted_acc.append("---")
self.formatted_acc.append("---")
if self.startdatum == "00000000":
self.startdatum = datum
if not datum == "":
self.enddatum = datum
if self.ukto == "":
self.ukto = "." + self.search_pattern # das zeigt an, dass da kein Konto hintersteckt
interval = ""
else:
interval = self.mode + self.interval_short
if self.grep_pattern[-1] == "-":
add_minus = "-"
else:
add_minus = ""
try:
self.hkey
except:
self.hkey = ""
if self.hkey[:1] == "x":
self.hkey = "x" * str_len_hkey
else:
self.hkey = "\n".join(self.formatted_acc) + "\n"
print(self.hkey[0:500])
print("QQWW1",len(self.hkey))
self.hkey = hashlib.md5(self.hkey.encode("utf-8")).hexdigest()
print("QQWW11",self.hkey)
self.hkey = self.hkey[0:self.len_hkey_nr]
self.title = ("%-50s"%(re.sub(r"\.$","",self.ukto+add_minus+interval))) + " " + self.hkey + " " + (self.nformat13%gesamt)
# print(self.title)
# if not self.ukto == "":
# print("UKTO: " + self.ukto + saldo)
#
# if has_doublettes:
# print("Attention: Doublettes!")
# return(saldo)
return(ktotext_changed)
#**********************************************************************************
def parse_ktotext(self):
self.buchungen = []
unique_strings = {}
self.maxa = 10
self.maxb = 10
self.maxc = 0
self.maxd = 0
self.maxsaldo = 0
self.ukto = ""
ukto0 = ""
pattern = self.grep_pattern.strip().upper()
if self.grep_pattern[0] == " ":
self.ukto = self.grep_pattern[1:]
self.ukto = re.sub(r"-$","",self.ukto)
if len(pattern) > 0 and pattern[-1] == "-":
pattern = pattern[:-1]
zaehler = -1
add_month = 0
vvv = re.compile(r"^(\d\d\d\d)(MM|\d\d)(DD|\d\d)(\+?) +(\S+) +(\S+) +(\S+) +(\-?\d+\.\d\d\d?|\-+|\.+) +(.*?) *$")
ktotext_changed = 0
for zeile in self.extracted_acc:
# print("------",zeile)
mm = vvv.search(zeile)
if not mm: # Einlesen der Kontobezeichnungen
continue
datum = mm.group(1) + mm.group(2) + mm.group(3)
betrag = mm.group(5)
if mm.group(2) == "MM" or mm.group(3) == "DD" or mm.group(4) == "+" or not re.search(r"^\-?\d+\.\d\d\d?",betrag):
return("change")
remark = mm.group(9)
uniqu = []
ktoa = mm.group(6)
if ktoa == None:
self.mark(zeile)
if ktoa.startswith("-"):
ktoa = self.ukto + ktoa
ktob = mm.group(7)
if "--" in ktoa or "--" in ktob:
continue
turn_kto = 0
# ktoa = self.parse_ktotext_compute_kto(m.group(5),self.ukto,uniqu)
# ktob = self.parse_ktotext_compute_kto(m.group(6),self.ukto,uniqu)
if ktoa > ktob: # to avoid swing back anf forth
o = ktoa
ktoa = ktob
ktob = o
betrag = re.sub(r"^--","","-"+betrag)
turn_kto = 1 - turn_kto
if not ktoa.upper().startswith(pattern):
o = ktoa
ktoa = ktob
ktob = o
betrag = re.sub(r"^--","","-"+betrag)
saldo = 0
if not self.grep_pattern[0] == " " and not self.ukto == None: # find self.ukto dynamically
if self.ukto == "":
if pattern in ktoa.upper():
self.ukto = ktoa
for kto in (ktoa,ktob):
if pattern in kto.upper():
while (0 == 0):
if not pattern in self.ukto:
break
if kto.startswith(self.ukto):
break
m = re.search(r"^(.*)\-(.*)$",self.ukto)
if m:
self.ukto = m.group(1)
else:
self.ukto = ""
self.mark(" fit ukto: " + self.ukto.replace("^",""))
if not pattern in self.ukto.upper():
self.ukto = None
self.mark("No ukto found.")
salden = None
break
if self.ukto:
while (0 == 0):
m = re.search(r"^(.*)\-(.*)$",self.ukto)
if not m or not pattern in m.group(1).upper():
break
self.ukto = m.group(1)
ukto0 = re.sub(r"\^","",self.ukto)
if self.ukto:
saldo = ( int( self.ukto and ktoa.startswith(self.ukto)) +
int( self.ukto and ktob.startswith(self.ukto)) )
if uniqu == []:
uniqu = [ktoa,ktob]
self.maxsaldo = max(self.maxsaldo,saldo)
uniqu1 = []
for k in uniqu:
uniqu1.append(re.sub(r"\-\d\d\d\d\d$","-BETRAG",k))
uniqu = uniqu1
betrag1 = re.sub("\-","",betrag) + ","
remark1 = "," + re.sub(r"[\+\- ]","",remark,9999)
uniqu = betrag1 + ",".join(uniqu) + remark1
# if datum in unique_strings: # to avoid double entries
# if uniqu in unique_strings[datum]:
# continue # der Eintrag mit diesem unique-String existiert schon, daher nicht nochmal nehmen
# else:
# unique_strings[datum].append(uniqu)
# else:
# unique_strings[datum] = [uniqu]
ktoa = ktoa.replace("^","")
ktob = ktob.replace("^","")
if ktoa[0] == "-":
self.maxc = max(self.maxc,len(ktoa))
else:
self.maxa = max(self.maxa,len(ktoa))
if ktob[0] == "-":
self.maxd = max(self.maxd,len(ktob))
else:
self.maxb = max(self.maxb,len(ktob))
self.buchungen.append([datum,betrag,ktoa,ktob,remark,saldo,zeile])
if self.ukto == None:
self.ukto = ""
self.ukto = self.ukto.replace("^","")
if self.maxc > 0:
self.maxa = max(self.maxa,len(self.ukto)+self.maxc)
if self.maxd > 0:
self.maxb = max(self.maxb,len(self.ukto)+self.maxd)
self.format_maxa = "%-" + str(self.maxa) + "s"
self.format_maxb = "%-" + str(self.maxb) + "s"
self.maxsaldo = str(self.maxsaldo)
return("")
#*******************************************************************************************
def format_salden (self,ktoparse=None): # Moeglichkeit zum freien Waehlen von Kontensalden geschaffen
faktor = 1
# kto = self.ukto
self.salden_aktuell = []
ktofiles1 = glob.glob(self.base_dir+"*.acc")
ktofiles1.sort()
ktofiles = []
# print(self.base_dir)
# self.mark("A")
for ktofile in ktofiles1:
# print(ktofile + " ...")
ktofile_sum = ktofile[:-4] + ".sum"
if not os.path.isfile(ktofile_sum):
self.mark(" " + ktofile + " not found, so retrieve it:")
self.update_sum_files(ktofile)
m = re.search(r"(\d+)\.acc$",ktofile)
if len(ktofiles) < 2:
if (m.group(1) + "000000")[0:6] < self.startdatum:
ktofiles = []
if (m.group(1) + "000000")[0:6] > self.enddatum:
break
else:
ktofiles.append(ktofile_sum)
if ktoparse == None:
if not self.ukto == None and not self.ukto == "" and self.ukto[0] in ("-","."):
return()
ktoparse = "^" + self.ukto + self.salden_expand
len_ukto = len(self.ukto) + 1
else:
self.ukto = ""
len_ukto = 0
# print(ktoparse)
self.enddatum = (self.enddatum + "99999999")[0:6]
self.startdatum = (self.startdatum + "00000000")[0:6]
if self.enddatum[4:6] > "12":
self.enddatum = self.enddatum[0:4] + "12"
ktotexts = []
# print("KTOPARSE",ktoparse)
for ktofile in ktofiles: # retrieving of the relevant lines via grep
# print("KTOFILE",ktofile)
ktotexts.append([])
# print("grep -P '" + ktoparse + "' " + ktofile)
for zeile in os.popen("grep -P '" + ktoparse + "' " + ktofile).read().split("\n")[:-1]:
ktotexts[-1].append(zeile.split(","))
# for o in ktotexts[0]:
# print(o)
salden_liste = []
max_offset = self.max_offset
max_kto_ordnung = 0
kto0 = " "
title_leistung = ""
integr_leistung = ""
self.overlap = 0
while (0 == 0): # alle konten-Salden gleichzeitig nach vorne schieben, dabei auf luecken achten
kto = None
for ktotext in ktotexts:
if len(ktotext) == 0:
continue
if kto == None:
kto = ktotext[0][0]
else:
kto = min(ktotext[0][0],kto)
if kto == None:
break
betrag = 0.00
nr = 0
if len(ktotexts[0]) > 0 and kto == ktotexts[0][0][0]: # in the first line there is the kto. Find in the first file the position
zeile = ktotexts[0][0][1:] # nicht entfernen!
datum0 = zeile.pop(0)
if self.startdatum >= datum0:
datpos = 12*( int(self.startdatum[0:4]) - int(datum0[0:4]) ) + int(self.startdatum[4:6]) - int(datum0[4:6]) - 1
# print("START",self.startdatum,datum0,kto,datpos)
if datpos < 0:
betrag = 0.00
nr = 0
elif datpos >= len(zeile):
# print(kto,zeile)
if zeile[-1][-self.digits-1] == "/":
betrag = betrag - float(zeile[-1][:-self.digits-1])
nr = nr - int(zeile[-1][-self.digits:])
else:
ind = zeile[-1].index("/")
betrag = betrag - float(zeile[-1][:ind-1])
nr = nr - int(zeile[-1][ind:])
else:
if zeile[datpos][-self.digits-1] == "/":
betrag = betrag - float(zeile[datpos][:-self.digits-1])
nr = nr - int(zeile[datpos][-self.digits:])
else:
ind = zeile[datpos].index("/")
betrag = betrag - float(zeile[datpos][:ind-1])
nr = nr - int(zeile[datpos][ind:])
# print(" ",kto,nr,datpos)
if len(ktotexts[-1]) > 0 and kto == ktotexts[-1][0][0]: # im letzten Salden-File die genaue Monatsspalte finden
# zeile = ktotexts[-1][0][1:] # nicht entfernen!
zeile = ktotexts[-1].pop(0)[1:]
datum0 = zeile.pop(0)
if self.enddatum >= datum0:
datpos = 12*( int(self.enddatum[0:4]) - int(datum0[0:4]) ) + int(self.enddatum[4:6]) - int(datum0[4:6])
if datpos >= len(zeile):
if zeile[-1][-self.digits-1] == "/":
betrag = betrag + float(zeile[-1][:-self.digits-1])
nr = nr + int(zeile[-1][-self.digits:])
else:
ind = zeile[-1].index("/")
betrag = betrag + float(zeile[-1][:ind-1])
nr = nr + int(zeile[-1][ind:])
else:
if zeile[datpos][-self.digits-1] == "/":
betrag = betrag + float(zeile[datpos][:-self.digits-1])
nr = nr + int(zeile[datpos][-self.digits:])
else:
ind = zeile[datpos].index("/")
betrag = betrag + float(zeile[datpos][:ind-1])
nr = nr + int(zeile[datpos][ind:])
# print(" ",kto,nr,datpos)
for ktotext in ktotexts[:-1]: # nur bei sum-up Werten relevant (Zwischen-sum-Files)
if len(ktotext) > 0 and ktotext[0][0] == kto:
zeile = ktotext.pop(0)
if zeile[-1][-self.digits-1] == "/":
betrag = betrag + float(zeile[-1][:-self.digits-1])
nr = nr + int(zeile[-1][-self.digits:])
else:
ind = zeile[-1].index("/")
betrag = betrag + float(zeile[-1][:ind-1])
nr = nr + int(zeile[-1][ind:])
# print(zeile,nr)
if self.ukto in self.total_salden:
leistung = self.total_salden[self.ukto]
lkeys = list(leistung.keys())
lkeys.sort()
title_leistung = ""
integr_leistung = ""
int3 = 0.00
pformat = re.sub("\.\df","u",self.pformat) # vormals \.2f
for o in lkeys:
# print(o,self.pformat,pformat)
title_leistung = title_leistung + ";" + (pformat % o)
int3 = int3 + float(leistung[o])
integr_leistung = integr_leistung + ";" + (self.pformat % int3)
if nr > 0:
betrag = self.nformat3 % (faktor*betrag)
leistung1 = ""
if not title_leistung == "":
if kto in self.total_salden:
leistung = self.total_salden[kto]
for o in lkeys:
# print(o)
if o in leistung:
o1 = self.pformat % leistung[o]
self.overlap = max(self.overlap,len(o1))
leistung1 = leistung1 + ";" + o1
else:
leistung1 = leistung1 + ";" + (self.pformat % 0)
kto = kto[len_ukto:]
kto_ordnung = max(0,len(re.sub("[^\-]","",kto)))
if kto == "":
kto_ordnung = -1
max_offset = max(max_offset,len(kto) + len(betrag) - 4*kto_ordnung)
max_offset = max(max_offset,len_ukto)
max_kto_ordnung = max(max_kto_ordnung,kto_ordnung)
salden_liste.append([kto,kto_ordnung,betrag,leistung1])
max_l = 0
max_s = 0
while 0 == 0:
for salden_zeile in salden_liste:
kto = salden_zeile[0]
if not self.ktotyp == None:
bed = 0
if not "-" in kto:
bed = 1
else:
for ktyp in self.ktotyp:
if re.search("^"+ktyp+r"-[^\-]+$",kto):
bed = 1
break
if bed == 0:
continue
kto_ordnung = salden_zeile[1]
betrag = salden_zeile[2]
leistung = salden_zeile[3]
kto_spacing = "%-" + ("%2u"% (max_offset+kto_ordnung*4-len(betrag)+2) ) + "s"
if kto_ordnung == 0 and max_kto_ordnung > 0: # additional spacing
self.salden_aktuell.append("")
text3 = (kto_spacing%kto) + betrag
if leistung == "":
self.salden_aktuell.append( text3 )
else:
max_l = max(max_l,len(text3))
add_space = (max_s - len(text3)) * " "
self.salden_aktuell.append( text3 + add_space + leistung)
if kto_ordnung == -1 and max_kto_ordnung < 1:
self.salden_aktuell.append("")
if max_s == max_l:
break
max_s = max_l
self.salden_aktuell = []
if not title_leistung == "":
self.salden_aktuell = self.salden_aktuell + [ "", max_s * " " + title_leistung, max_s * " " + integr_leistung, "" ]
return(salden_liste)
# print(max_kto_ordnung)
# print(self.salden_aktuell)
#**********************************************************************************
def replace_accountings (self):
# Here we create the array add_lines (lines which are added in processed_acc), del_lines (lines which
# are deleted in processed_acc), line_numbers_of_deleted (the line numbers in the array of the original
# formatted_acc which have been deleted in processed_acc).
self.differences_to_consider()
self.add_del_lines()
if self.hkey[0].replace("x","") == "": # das ist ein Merge hkey
zaehler = 0
for zeile in self.add_lines:
mm = self.merge_parser1(zeile)
if mm:
self.add_lines[zaehler] = m.group(1)+m.group(2)+"[LOCAL]"+m.group(3)
zaehler = zaehler + 1
for zeile in self.del_lines:
mm = self.merge_parser1(zeile)
if mm:
self.add_lines.append(m.group(1)+m.group(2)+"[SERVER]"+m.group(3))
if len(self.add_lines) + len(self.del_lines) == 0:
return("null")
# Now we apply these changes to the original raw file extracted_acc :
new_extracted_acc = self.add_lines[:] # new version of the text of extracted_acc. We start with the added lines
# Deleted lines:
# Because the line-by-line correspondency of extracted_acc and formatted_acc we can apply the numbers in line_numbers_of_deleted
# directly to extracted_acc (by considering an offset of 2 because of the both additional header lines made from the formatting)
self.dates_of_deleted_lines = [] # we collect all months of all lines which have been deleted for later purposes
zaehler = 0
for zeile in self.extracted_acc:
if zaehler in self.line_numbers_of_deleted: # Zeile wird uebersprungen, nur Monat (weiss nicht mehr, wofuer) gemerkt
if not zeile[0:6] in self.dates_of_deleted_lines:
self.dates_of_deleted_lines.append(zeile[0:6])
else:
new_extracted_acc.append(zeile)
zaehler = zaehler + 1
self.extracted_acc_0 = self.extracted_acc
self.extracted_acc = new_extracted_acc
self.extracted_acc.sort()
if self.hkey[0].replace("x","") == "":
self.add_lines = []
self.del_lines = []
return("x")
return("ok")
#**********************************************************************************
def differences_to_consider (self):
set_of_formatted_lines = set( self.formatted_acc )
set_of_processed_lines = set( self.processed_acc )
# First, we determine the vice versa differences of the sets of lines in formatted_acc and processed_acc:
set_of_added_lines = set_of_processed_lines.difference(set_of_formatted_lines)
set_of_deleted_lines = set_of_formatted_lines.difference(set_of_processed_lines)
# Changes which may consist simply by changing spaces or the sum in the fifth column of an account set
# should be skipped. So we calculate now all these normalisations and map it to the original line.
# Also lines which are not an account entry should be skipped.
# (Actually, we could do it one-step by normalize all the lines in formatted_acc and processed_acc. But it is
# costly to normalize all this lines, even, if these are not affected by changes. So it is waste of ressources.
# Hence, it makes sense firstly make a raw difference set_of_added_lines and set_of_deleted_lines which
# afterwards can be reduced by normalization.)
set_of_normalized_added_lines, self.dict_of_normalized_added_lines_to_orig_added_lines = self.normalize_acc_line_set(set_of_added_lines)
set_of_normalized_deleted_lines, self.dict_of_normalized_deleted_lines_to_orig_deleted_lines = self.normalize_acc_line_set(set_of_deleted_lines)
# print(self.dict_of_normalized_added_lines_to_orig_added_lines)
# print(self.dict_of_normalized_deleted_lines_to_orig_deleted_lines)
# The sets of the normalized added and deleted reduced lines sets are calculated by deleted elements common to both of this sets
self.reduced_set_of_normalized_added_lines = set_of_normalized_added_lines.difference(set_of_normalized_deleted_lines)
self.reduced_set_of_normalized_deleted_lines = set_of_normalized_deleted_lines.difference(set_of_normalized_added_lines)
# print(self.reduced_set_of_normalized_added_lines)
# print(self.reduced_set_of_normalized_deleted_lines)
# As a last step, we find back the original lines by the both dictionaries:
#********************************************************************************************
def add_del_lines (self):
self.add_lines = []
for normalized_line in self.reduced_set_of_normalized_added_lines:
orig_zeile = self.dict_of_normalized_added_lines_to_orig_added_lines[ normalized_line ]
self.add_lines.append( orig_zeile )
self.del_lines = []
self.line_numbers_of_deleted = []
for normalized_line in self.reduced_set_of_normalized_deleted_lines:
orig_zeile = self.dict_of_normalized_deleted_lines_to_orig_deleted_lines[ normalized_line ]
self.del_lines.append("-" + orig_zeile )
self.line_numbers_of_deleted.append( self.formatted_acc.index( orig_zeile ) )
# print(self.del_lines)
#********************************************************************************************
def normalize_ktotext (self,zeilena,zeilenb):
self.grep_pattern = " "
self.sortclass = None
self.search_pattern = ""
self.formatted_acc = zeilena
self.processed_acc = zeilenb
self.differences_to_consider()
print("LL1",len(self.reduced_set_of_normalized_added_lines) )
print("LL2",len(self.reduced_set_of_normalized_deleted_lines) )
return( len(self.reduced_set_of_normalized_added_lines) +
len(self.reduced_set_of_normalized_deleted_lines) )
#********************************************************************************************
def pre_process (self,ktofile):
add_month = 0
text3 = []
dict_text3 = []
for zeile in open(ktofile).read().split("\n"):
m = self.pre_proc_parser.search(zeile)
# print("ZZZZZ",zeile)
if not m:
text3.append(zeile)
continue
jahr = m.group(1)
monat = m.group(2)
tag = m.group(3)
betrag = m.group(4)
rest = m.group(5) + m.group(6) + m.group(7)
check_workdays = 0
if monat == "MM" or tag == "DD" or zeile[8] == "+" or add_month > 0:
if monat == "MM":
monate = ["01","02","03","04","05","06","07","08","09","10","11","12"]
else:
monate = [monat]
if tag == "DD":
tage = ["01","02","03","04","05","06","07","08","09","10",
"11","12","13","14","15","16","17","18","19","20",
"21","22","23","24","25","26","27","28","29","30","31"]
check_workdays = 1
else:
tage = [tag]
if zeile[8] == "+":
add_month = add_month + 1
# print("----------------------","hier",zeile)
# if add_month == 0 and len(monate) == 1 and len(tage) == 1:
# new_zeile = zeile
for monat in monate:
for tag in tage:
if add_month > 0 and len(monate) == 1 and len(tage) == 1:
monat = int(monat) + add_month
jahr = zeile[0:4]
while monat > 12:
jahr = int(jahr) + 1
monat = monat - 12
monat = "%02u" % monat
jahr = "%04u" % int(jahr)
if check_workdays == 1:
datum = jahr + monat + tag
try:
workday = datetime.datetime.strptime(datum,"%Y%m%d").weekday()
except Exception as e:
continue
if workday > 4:
continue
if datum[4:] in self.ferientage or datum[2:] in self.ferientage:
continue
if not re.search(r"^ *(\-?\d+\.\d\d\d?) *$",betrag):
betrag1 = re.sub("AA","add_month",betrag,99)
print("BBBBB",betrag1)
try:
betrag1 = " " + ( self.nformat3 % eval(betrag1) ) + " "
except:
betrag1 = " 0.00 "
else:
betrag1 = betrag
self.text_append(jahr + monat + tag + betrag1 + rest,text3,dict_text3)
else:
betrag1 = re.sub("AA","add_month",betrag,99)
if not re.search(r"^ *(\-?\d+\.\d\d\d?) *$",betrag1):
try:
betrag1 = " " + ( self.nformat3 % eval(betrag1) ) + " "
except:
betrag1 = " 0.00 "
else:
betrag1 = betrag
if betrag1 == betrag:
new_zeile = zeile
else:
new_zeile = jahr + monat + tag + betrag1 + rest
if not new_zeile in text3:
self.text_append(new_zeile,text3,dict_text3)
open(ktofile,"w").write("\n".join(text3)+"\n")
#********************************************************************************************
def text_append(self,zeile,text3,dict_text3):
m = self.acc_line_parser.search(zeile)
if m:
zeile1 = m.group(1) + m.group(2) + m.group(3) + " " + (self.nformat3%eval(m.group(4))) + " " + m.group(5) + " " + m.group(6) + " 0.00 " + m.group(8)
if zeile1 in dict_text3:
return()
else:
dict_text3.append(zeile1)
text3.append(zeile)
#********************************************************************************************
def normalize_acc_line_set (self,line_set):
normalized_lines = []
dict_normalized_lines_to_orig_lines = {}
for zeile in line_set: # ueber Aequivalenzbeziehung weitere uebereinstimmende Zeilen herausfinden
m = self.acc_line_parser.search(zeile)
if m:
try:
zeile1 = m.group(1) + m.group(2) + m.group(3) + " " + (self.nformat3%eval(m.group(4))) + " " + m.group(5) + " " + m.group(6) + " 0.00 " + m.group(8)
except:
zeile1 = zeile
else:
continue # nur Buchungszeilen sind zu beruecksichtigen
# print(zeile1)
normalized_lines.append(zeile1)
dict_normalized_lines_to_orig_lines[zeile1] = zeile
return(set(normalized_lines),dict_normalized_lines_to_orig_lines)
#*******************************************************************************************
def impacts_acc_file(self,ktofile,mode=0):
m = re.search(r"(\D|^)(\d+)\.acc",ktofile)
if not m:
return(False)
zeitraum = m.group(2)
if mode == 1:
return(zeitraum)
# print(self.startdatum,self.enddatum)
if zeitraum < self.startdatum0[0:len(zeitraum)]:
return(False)
if zeitraum > self.enddatum0[0:len(zeitraum)]:
return(False)
return(zeitraum)
#*******************************************************************************************
def subtract_account_lines (self):
# This function deletes accounting lines from the acc-files due to a pattern
if self.del_lines == []: # ist wichtig fuer den Fall der Merge Datei
return()
for ktofile in self.list_of_acc_files:
if not self.impacts_acc_file(ktofile):
continue
# print(ktofile)
if not self.interval_long == "":
if self.grep_pattern == "":
os.system(self.egrep + "grep -i -v ^" + self.interval_long + " " + ktofile + " > " + ktofile + "__")
else:
os.system(self.egrep + "grep -i -v ^" + self.interval_long + " " + ktofile + " > " + ktofile + "__")
os.system(self.egrep + "grep -i ^" + self.interval_long + " " + ktofile + " | grep -i -v '" + self.grep_pattern + "' >> " + ktofile + "__")
else:
if self.grep_pattern == "":
os.system(" > __" + self.base_dir + ktofile)
else:
os.system(self.egrep + "grep -i -v '" + self.grep_pattern + "' " + ktofile + " > " + ktofile + "__")
os.system("mv " + ktofile + "__ " + ktofile)
self.mark("D. Subtract old accounting entries from acc files.")
#********************************************************************************************
def add_account_lines (self,ktofile):
if self.add_lines == []: # ist wichtig fuer den Fall der Merge Datei
return()
for acc_file in self.list_of_acc_files:
zeitraum = self.impacts_acc_file(acc_file)
if zeitraum:
os.system("grep ^" + zeitraum + " " + ktofile + " >> " + acc_file)
if self.sortieren == 1: # hier die acc-Files wieder sortieren
file_text = re.sub(r"\n+$","",open(acc_file).read()).split("\n")
file_text.sort()
open(acc_file,"w").write("\n".join(file_text) + "\n")
# self.mark("C. " + ktofile + " sorted.")
# os.system("sort " + ktofile + " > " + "__" + ktofile)
# os.system("mv __" + ktofile + " " + ktofile)
#*************************************************************************
def update_sum_files (self,acc_file=None):
salden_files = []
if acc_file:
list_of_changed_lines = open(acc_file).read().split("\n")
mode = 1
list_of_acc_files = [acc_file]
else:
list_of_changed_lines = self.add_lines + self.del_lines
mode = 0
list_of_acc_files = self.list_of_acc_files
# print("\n".join(list_of_changed_lines))
for acc_file in list_of_acc_files:
abschnitt = self.impacts_acc_file(acc_file,mode)
if not abschnitt:
continue
diff_salden = {}
buchung_im_lfd_monat = {}
salden_file = acc_file[0:-4] + ".sum"
salden_files.append(salden_file)
salden_text = []
if os.path.isfile(salden_file):
salden_text = open(salden_file).read().strip().split("\n") # update der salden_files
update_salden = 0
for diff_buchung in ( list_of_changed_lines ):
# print("DD",diff_buchung)
m = re.search("^(\-?)(\d\d\d\d\d\d\d\d) +(\S+) +(\S+) +(\S+) +(\-?\d+\.\d\d\d?|\.+)",diff_buchung)
if m:
if update_salden == 0:
update_salden = 1
self.mark("--> Check " + acc_file + ".")
datum = m.group(2)
if datum.startswith(abschnitt):
betrag = eval(m.group(3))
ktoa = m.group(4)
if ktoa.startswith("-"):
ktoa = self.ukto + ktoa
ktob = m.group(5)
add_buchung = 1
if m.group(1).startswith("-"):
betrag = -betrag
add_buchung = -1
monat3 = int(datum[0:6])
self.compute_salden(diff_salden,buchung_im_lfd_monat,ktoa, betrag,add_buchung,datum,monat3)
self.compute_salden(diff_salden,buchung_im_lfd_monat,ktob,-betrag,add_buchung,datum,monat3)
kto_to_del = []
update_salden = 0
for kto in list(diff_salden.keys()):
if update_salden == 0:
update_salden = 1
self.mark("--> Diff salden computed.")
interval0 = -1 # suchen, ob es schon eine gueltige Zeile gibt
interval1 = len(salden_text)
while (0 == 0):
if interval0 + 1 == interval1: # not found
interval9 = -1
break
interval9 = interval0 + int((interval1 - interval0)/2)
# print(interval0,interval9,interval1,kto)
# time.sleep(0.01)
if salden_text[interval9].startswith(kto+","):
break
if (kto + ",") > salden_text[interval9]:
interval0 = interval9
else:
interval1 = interval9
if interval9 > -1: # wenn es schon eine Konto-Zeile im Salden-File gibt, diese integrieren
werte = salden_text[interval9].split(",")
werte.pop(0)
if len(werte) > 0:
monat = int(werte.pop(0))
betrag0 = 0.00
nr0 = 0
for betrag in werte:
if betrag[-self.digits-1] == "/":
nr = int(betrag[-self.digits:])
betrag = float(betrag[:-self.digits-1])
else:
# print(kto,betrag)
ind = betrag.index("/")
betrag = int(m.group(1))
nr = float(m.group(2))
if not monat in diff_salden[kto]:
diff_salden[kto][monat] = 0.00
buchung_im_lfd_monat[kto][monat] = 0
diff_salden[kto][monat] = diff_salden[kto][monat] + betrag - betrag0
buchung_im_lfd_monat[kto][monat] = buchung_im_lfd_monat[kto][monat] + nr - nr0
betrag0 = betrag
nr0 = nr
monat = monat + 1
if str(monat)[4:6] == "13":
monat = int(str(int(str(monat)[0:4]) + 1) + "01")
monate = list(diff_salden[kto].keys())
monat = min(monate)
mmax = max(monate)
zeile = kto + ","
betraege = []
sum = 0.00 # @@@@
nr = 0
while (0 == 0):
# nr = 0
if monat in diff_salden[kto]:
sum = sum + diff_salden[kto][monat]
nr = nr + buchung_im_lfd_monat[kto][monat]
if len(betraege) > 0:
betraege.append((self.nformat3%sum)+"/"+(self.dformat%nr))
elif abs(sum) > 0.000001 or nr > 0: # just start when something interesting started
betraege.append((self.nformat3%sum)+"/"+(self.dformat%nr))
zeile = zeile + str(monat) + ","
monat = monat + 1
if str(monat)[4:6] == "13":
monat = int(str(int(str(monat)[0:4]) + 1) + "01")
if monat > mmax:
break
# while (0 == 0): # truncate the tail if there is nothing interesting anymore
# if len(betraege) < 2:
# break
# if not betraege[-1] == betraege[-2]:
# break
# betraege.pop()
if len(betraege) == 0:
kto_to_del.append(kto)
else:
zeile = zeile + ",".join(betraege)
if len(kto_to_del) > 0 and kto in kto_to_del:
kto_to_del.remove(kto)
if interval9 > -1:
salden_text[interval9] = zeile # update line
else:
salden_text.insert(interval1,zeile) # line was not existing, so enter it
if update_salden == 1:
self.mark("F. Salden list updated.")
if len(kto_to_del) == 0:
salden_text = "\n".join(salden_text) + "\n"
else:
salden_text = "\n" + "\n".join(salden_text) + "\n"
self.mark(" ---")
for delkto in kto_to_del:
ind = salden_text.index("\n"+delkto+",")
salden_text = salden_text[:ind] + salden_text[ind+len(delkto)+2:]
salden_text = salden_text[1:]
# self.mark(" .... kto s deleted from sum-file:\n" + "\n".join(kto_to_del))
open(salden_file,"w").write(salden_text) # update der salden_files
#**********************************************************************************
def compute_salden (self,salden,buchung,ukto,betrag,add_buchung,datum,monat): # Splits the accounting entry and
# and computes the changes for every
while (0 == 0): # sub account
if not ukto in salden:
salden[ukto] = {}
buchung[ukto] = {}
if not monat in salden[ukto]:
salden[ukto][monat] = 0.00
buchung[ukto][monat] = 0
salden[ukto][monat] = salden[ukto][monat] + betrag
buchung[ukto][monat] = buchung[ukto][monat] + add_buchung
m = re.search(r"^(.*)\-(.+)$",ukto)
if m:
ukto = m.group(1)
else:
return()
#*************************************************************************
def test_extract_lines (self,basedir,pattern):
self.update_konto(basedir,pattern)
# print("\n".join(self.formatted_acc)+"\n")
# print("\n".join(self.salden_aktuell)+"\n")
#******************************************************************************
def sort (self,pattern,file=None):
if file == None:
files = glob.glob("*.kto") + glob.glob("*.kto.html")
if len(files) == 1:
file = files[0]
else:
return()
if pattern == "..":
self.sort_numbers(file)
return()
if pattern == "kto":
self.sort_numbers1(file)
return()
text = open(file).read()
text_match = []
text_rest = []
for zeile in text.split("\n"):
if re.search(pattern,zeile,re.IGNORECASE):
text_match.append(zeile)
else:
text_rest.append(zeile)
text = "\n".join(text_rest) + "\n" + "\n".join(text_match) + "\n"
if os.path.isfile(file+"~"):
os.unlink(file+"~")
# os.rename(file,file+"~")
open(file,"w").write(text)
#******************************************************************************
def sort_numbers (self,file):
text = open(file).read()
text_match = []
text_rest = []
for zeile in text.split("\n"):
m = re.search(r"\d\d\d\d\d\d\d\d +\-?(\d+\.\d\d\d?) ",zeile)
if m:
text_match.append([zeile,float(m.group(1))])
else:
text_rest.append(zeile)
text_match.sort(key=lambda x:x[1])
text_match1 = []
for tt in text_match:
text_match1.append(tt[0])
text = "\n".join(text_rest) + "\n" + "\n".join(text_match1) + "\n"
if os.path.isfile(file+"~"):
os.unlink(file+"~")
# os.rename(file,file+"~")
open(file,"w").write(text)
#******************************************************************************
def sort_numbers1 (self,file):
text = open(file).read()
text_match = []
text_rest = []
for zeile in text.split("\n"):
m = re.search(r"(\d\d\d\d\d\d\d\d) +\-?(\d+\.\d\d\d?) +(\d+?)\-(\S+?)\-(\S+) ",zeile)
if m:
text_match.append([zeile,m.group(5)])
else:
text_rest.append(zeile)
text_match.sort(key=lambda x:x[1])
text_match1 = []
for tt in text_match:
text_match1.append(tt[0])
text = "\n".join(text_rest) + "\n" + "\n".join(text_match1) + "\n"
if os.path.isfile(file+"~"):
os.unlink(file+"~")
# os.rename(file,file+"~")
open(file,"w").write(text)
#*************************************************************************
def _norm(self, line):
"""
Normalisierung:
- Marker entfernen
- Saldo entfernen (letzte Spalte)
- Whitespace vereinheitlichen
"""
if not line:
return ""
line = line.strip()
# Marker entfernen
if line.startswith("[LOCAL]"):
line = line[7:].strip()
if line.startswith("[SERVER]"):
line = line[8:].strip()
parts = line.split()
if len(parts) <= 1:
return line
core = parts[:-1] # alles außer Saldo
return " ".join(core)
#*************************************************************************
def _add_marker(self, line, marker):
"""
Marker vorne hinzufügen wenn nicht vorhanden
"""
line = line.strip()
if line.startswith("[LOCAL]") or line.startswith("[SERVER]"):
return line
return marker + " " + line
#*************************************************************************
def xxggg (self):
diff_salden = {}
dates_of_deleted_entries = [] # das wird eine Liste aus Monaten, in denen gar keine Buchungen mehr stehen
# ---- 1. Vergleich zwischen dem originalen result.format und result.kto
add_lines = []
del_lines = []
if os.path.isfile(file+".format") and os.path.isfile(file+".kto"):
sortierte_zeilen = open(file + ".format").read().split("\n")
text0 = set(open(file + ".kto").read().split("\n"))
diff_sort_z = set(sortierte_zeilen).difference(text0) # erstmal die Differenzen ohne Aequivalenzbildung berechnen
diff_text0 = text0.difference(set(sortierte_zeilen))
equivalent_zeilen = {}
diff_sort_z_reduce = []
diff_text0_reduce = []
vvv = re.compile(r"^(\d\d\d\d)(..)(\d\d) +(\S+) +(\S+) +(\S+) +(\-?\d+\.\d\d\d?|\-+|\.+) +(.*?) *$") # zweiter Schritt:
for zeile in diff_sort_z: # ueber Aequivalenzbeziehung weitere uebereinstimmende zeilen herausfinden
m = vvv.search(zeile)
if m:
zeile1 = m.group(1) + m.group(2) + m.group(3) + " " + (self.nformat3%eval(m.group(4))) + " " + m.group(5) + " " + m.group(6) + " 0.00 " + m.group(8)
else:
continue # nur Buchungszeilen sind zu beruecksichtigen
equivalent_zeilen[zeile1] = zeile
diff_sort_z_reduce.append(zeile1)
diff_sort_z_reduce = set(diff_sort_z_reduce)
for zeile in diff_text0:
m = vvv.search(zeile)
if m:
zeile1 = m.group(1) + m.group(2) + m.group(3) + " " + (self.nformat3%eval(m.group(4))) + " " + m.group(5) + " " + m.group(6) + " 0.00 " + m.group(8)
else:
continue # nur Buchungszeilen sind zu beruecksichtigen
diff_text0_reduce.append(zeile1)
diff_text0_reduce = set(diff_text0_reduce)
diff_sort_z_reduce_diff = diff_sort_z_reduce.difference(diff_text0_reduce)
diff_text0_reduce_diff = diff_text0_reduce.difference(diff_sort_z_reduce)
# print(diff_sort_z_reduce_diff)
# print(diff_text0_reduce_diff)
# In diff_sort_z_reduce_diff stehen die reduzierten Zeilen aus der result.format, die geloescht werden muessen
lines_to_delete = []
for zeile1 in diff_sort_z_reduce_diff:
zeile = equivalent_zeilen[zeile1]
lines_to_delete.append(sortierte_zeilen.index(zeile)-2)
del_lines.append("< " + zeile)
# Jetzt die neue result.orig schreiben:
# print(lines_to_delete)
result_orig = []
zaehler = 0
del_datum = {}
for zeile in open(file+".orig").read().split("\n"):
if zaehler in lines_to_delete:
# print("DEL",zeile)
del_datum[zeile[0:6]] = 1
else:
result_orig.append(zeile)
zaehler = zaehler + 1
for zeile in diff_text0_reduce_diff:
add_lines.append("> " + zeile)
result_orig.insert(-1,zeile)
result_orig = "\n".join(result_orig)
dates_of_deleted_entries = []
for ddatum in del_datum.keys():
if re.search(r"^\d\d\d\d\d\d$",ddatum):
if "\n" + ddatum in result_orig:
continue
if result_orig.startswith(ddatum):
continue
dates_of_deleted_entries.append(ddatum)
if len(del_lines) > 0 or len(add_lines) > 0:
open(file+".orig","w").write(result_orig)
else:
os.unlink(file+".orig")
os.unlink(file+".par")
return()
# print("-----------")
# print(result_orig)
# print("-----------")
# --- 2. Jetzt zusammensetzen
(startdate,enddate) = self.sort_transaction(file+".orig")
if os.path.isfile(file+".par"):
m = re.search(r"(\S*?),(\S*?),(\S*?)",open(file+".par").read())
if m: # In der result.par stehen die urspruenglichen Request-Daten.
pattern = m.group(1) # Diese Abfrage wiederholen, und die erhaltenen Buchungssaetze aus
interval = m.group(2) # den acc-Dateien ABZIEHEN
egrep = m.group(3)
if interval == "None":
interval = None
self.split_subtract([startdate,enddate,pattern,interval,egrep],file)
list_of_files = glob.glob("*.acc")
list_of_files.sort()
for ktofile in list_of_files: # hier die geaenderte result.orig auf die acc-Files richtig verteilen
salden_file = re.sub(r"\.acc$",".sum",ktofile)
abschnitt = re.sub(r"\.acc$","",ktofile)
m = re.search(r"^(\d+)\.acc",ktofile)
if not m:
continue
zeitraum = m.group(1)
# print(zeitraum,startdate,enddate)
if os.path.isfile(salden_file):
if zeitraum < startdate[0:len(zeitraum)]:
continue
if zeitraum > enddate[0:len(zeitraum)]:
continue
os.system("grep ^" + m.group(1) + " " + file + ".orig >> " + ktofile)
if sortieren == 1: # hier die acc-Files wieder sortieren
file_text = re.sub(r"\n+$","",open(ktofile).read()).split("\n")
file_text.sort()
open(ktofile,"w").write("\n".join(file_text) + "\n")
self.mark("C. " + ktofile + " sorted.")
# os.system("sort " + ktofile + " > " + "__" + ktofile)
# os.system("mv __" + ktofile + " " + ktofile)
# ------ 3. Jetzt die Salden-Files nachziehen:
diff_salden = {}
is_buchung = {}
init_salden = ""
salden_text = []
if os.path.isfile(salden_file):
salden_text = open(salden_file).read().strip().split("\n") # update der salden_files
else:
init_salden = open(ktofile).read()
update_salden = 0
for diff_buchung in ( init_salden.split("\n") + add_lines + del_lines ):
m = re.search("^([\<\>] +|)(\d\d\d\d\d\d\d\d) +(\S+) +(\S+) +(\S+) +(\-?\d+\.\d\d\d?|\.+)",diff_buchung)
if m:
if update_salden == 0:
update_salden = 1
self.mark("D. Update " + ktofile + ".")
datum = m.group(2)
if datum.startswith(abschnitt):
betrag = eval(m.group(3))
ktoa = m.group(4)
ktob = m.group(5)
if m.group(1).startswith("<"):
betrag = -betrag
self.compute_salden(diff_salden,is_buchung,ktoa, betrag,datum)
self.compute_salden(diff_salden,is_buchung,ktob,-betrag,datum)
tt = 0
# tt = 1
# if tt == 1:
# for kt in list(diff_salden.keys()):
# for monat in diff_salden[kt]:
# if "ger-LOHN-AN" in kt:
# print(kt,monat,diff_salden[kt][monat])
salden_text.sort()
salden_text1 = []
del_element = []
update_salden = 0
for kto in list(diff_salden.keys()):
# if tt == 1:
# print(kto)
if update_salden == 0:
update_salden = 1
self.mark("E. Diff salden computed.")
interval0 = 0 # suchen, ob es schon eine gueltige Zeile gibt
interval1 = len(salden_text) - 1
while (0 == 0):
if interval0 > interval1:
interval9 = -1
break
interval9 = interval0 + int((interval1 - interval0)/2)
# if tt == 1:
# print(interval0,interval9,interval1,kto)
# if tt == 1:
# print(" ",salden_text[interval9])
# print(kto)
if salden_text[interval9].startswith(kto+","):
break
if (kto + ",") > salden_text[interval9]:
interval0 = interval9 + 1
else:
interval1 = interval9 - 1
if interval9 > -1: # wenn es schon eine Konto-Zeile im Salden-File gibt, diese integrieren
# if tt == 1:
# print(salden_text[interval9])
werte = salden_text[interval9].split(",")
# if tt == 1:
# print(werte)
werte.pop(0)
if len(werte) > 0:
monat = int(werte.pop(0))
betrag0 = 0.00
nr0 = 0
for betrag in werte:
nr = int(betrag[-self.max_months:])
betrag = float(betrag[:-self.max_months])
if not monat in diff_salden[kto]:
diff_salden[kto][monat] = 0.00
is_buchung[kto][monat] = 0
diff_salden[kto][monat] = diff_salden[kto][monat] + betrag - betrag0
if monat in dates_of_deleted_entries:
is_buchung[kto][monat] = 0
else:
is_buchung[kto][monat] = 1
betrag0 = betrag
nr0 = nr
monat = monat + 1
if str(monat)[4:6] == "13":
monat = int(str(int(str(monat)[0:4]) + 1) + "01")
monate = list(diff_salden[kto].keys())
monat = min(monate)
mmax = max(monate)
zeile = kto + "," + str(monat) + ","
betraege = []
sum = 0.00
nr = 0
while (0 == 0):
if monat in diff_salden[kto]:
sum = sum + diff_salden[kto][monat]
nr = nr + is_buchung[kto][monat]
betraege.append((self.nformat3%sum)+("%04u"%nr))
monat = monat + 1
if str(monat)[4:6] == "13":
monat = int(str(int(str(monat)[0:4]) + 1) + "01")
if monat > mmax:
break
while (0 == 0):
if len(betraege) < 2:
break
if not betraege[-1] == betraege[-2]:
break
betraege.pop()
zeile = zeile + ",".join(betraege)
if len(betraege) == 1 and float(betraege[0][:-self.max_months]) == 0.00:
if interval9 > -1:
salden_text[interval9] = "---DELETE---" # loesche die Zeile
else:
pass # Zeile ist Null, gar nicht erst eintragen
else:
if interval9 > -1:
salden_text[interval9] = zeile # Zeile updaten
else:
salden_text1.append(zeile) # Zeile existierte nicht, also eintragen
if update_salden == 1:
self.mark("F. Salden list updated.")
# while len(del_element) > 0:
# salden_text.pop( del_element.pop() )
salden_text = salden_text + salden_text1
salden_text.sort()
salden_text = "\n".join(salden_text) + "\n"
salden_text = re.sub(r"---DELETE---\n","",salden_text,99999999)
open(salden_file,"w").write(salden_text) # update der salden_files
os.system("mv " + file + ".orig " + file + ".old")
self.mark("G. ... closed.")
#**********************************************************************************
def xxsort_transaction (self,file):
os.system("sort " + file + " > " + "__" + file)
os.system("mv __" + file + " " + file)
startdate = os.popen("head -n 1 " + file).read()[0:8]
enddate = os.popen("tail -n 1 " + file).read()[0:8]
if not re.search(r"^\d\d\d\d\d\d\d\d$",startdate):
startdate = "00000000"
if not re.search(r"^\d\d\d\d\d\d\d\d$",enddate):
enddate = "99999999"
return(startdate,enddate)
#**********************************************************************************
def xxsplit (self,pattern="",file="result"):
if os.path.isfile(file+".orig"):
self.add()
return()
split_pars = self.split1(pattern,file)
self.split_subtract(split_pars,file)
#**********************************************************************************
def xxsplit1 (self,pattern="",file="result"):
self.mark("")
pattern1 = re.sub(r"\^"," ",pattern,9999)
(pattern1,interval,egrep,interval0) = self.parse_pattern(pattern1)
self.mark("A. Compute query for transaction file " + pattern1 + " " + str(interval)[0:40] + " ...")
if interval:
if pattern1 == "":
os.system(egrep + "grep -h -i ^" + interval + " *.acc > " + file + ".orig")
else:
os.system(egrep + "grep -h -i ^" + interval + " *.acc | grep -h -i '" + pattern1 + "' > " + file + ".orig")
else:
if pattern1 == "":
os.system("less *.acc > " + file + ".orig")
else:
os.system(egrep + "grep -h -i '" + pattern1 + "' *.acc > " + file + ".orig")
(startdate,enddate) = self.sort_transaction(file + ".orig")
# text0 = open(file+".orig").read().split("\n") # Doubletten-Vermeidung
# if len(text0) > len(set(text0)):
# print("Attention: Doublettes!")
# text0.sort()
# zeile0 = "-----"
# text1 = []
# zaehler = 0
# for zeile in text0:
# if len(zeile) == 0:
# continue
# zeile1 = zeile.replace(" ","")
# if zeile1 == zeile0:
# zaehler = zaehler + 1
# text1.append(zeile + " DOUBLETTE " + str(zaehler))
# else:
# text1.append(zeile)
# zaehler = 0
# zeile0 = zeile1
# open(file+".orig","w").write("\n".join(text1)+"\n")
open(file+".par","w").write(pattern1+","+str(interval)+","+egrep+"\n")
self.mark("B. Transaction file generated.")
if len(glob.glob("*.acc")) == len(glob.glob("*.sum")):
self.format_kto(pattern1,interval0,pattern)
self.mark("C. ... and formatted.")
return([startdate,enddate,pattern1,interval,egrep])
#**********************************************************************************
def xxsplit_subtract (self,pars,file="result"):
startdate = pars[0]
enddate = pars[1]
pattern = pars[2]
interval = pars[3]
egrep = pars[4]
pattern1 = re.sub(r"\^"," ",pattern,9999)
list_of_files = glob.glob("*.acc")
for ktofile in list_of_files:
m = re.search(r"^(\d+)\.acc",ktofile)
if not m:
continue
zeitraum = m.group(1)
if zeitraum < startdate[0:len(zeitraum)]:
continue
if zeitraum > enddate[0:len(zeitraum)]:
continue
if interval:
if pattern1 == "":
os.system(egrep + "grep -i -v ^" + interval + " " + ktofile + " > __" + ktofile)
else:
os.system(egrep + "grep -i -v ^" + interval + " " + ktofile + " > __" + ktofile)
os.system(egrep + "grep -i ^" + interval + " " + ktofile + " | grep -i -v '" + pattern1 + "' >> __" + ktofile)
else:
if pattern1 == "":
os.system(" > __" + ktofile)
else:
os.system(egrep + "grep -i -v '" + pattern1 + "' " + ktofile + " > __" + ktofile)
os.system("mv __" + ktofile + " " + ktofile)
self.mark("D. Clear acc files.")
#**********************************************************************************
def xxxxformat_kto (self,pattern,interval,pattern0,file="result"):
if interval:
interval = interval
else:
interval = ""
try:
text = open(file+".orig").read()
except Exception as e:
print(e)
return()
result = self.parse_ktotext(text.split("\n"),pattern)
if not result:
return(None)
(ktotext,self.format_maxa,self.format_maxb,self.maxsaldo,ukto) = result
# print("UKTO: " + ukto)
if False and ukto == "":
ktotext.sort(key=lambda x:x[0]+str(x[1])+x[3]+x[4])
else:
# ktotext.sort(key=lambda x:str(x[5]+1)+x[0])
ktotext.sort(key=lambda x:x[0]+str(x[5]+1)+x[2]+x[3]+x[4])
text_match1 = []
text_match2 = []
result_match = []
gesamt = 0.00
datum = "00000000"
datum0 = "00000000"
orig_text_new_sorted = [] # das orig-File muss in der neuen Sortierung auch neu geschrieben werden,
# damit man am Ende den Patch auf das formatierte Konto-File anwenden kann.
dbl_marks = {}
has_doublettes = 0
for zeile in ktotext:
ust = ""
if "v.H." in zeile[4]:
ust = " "
ktoa = zeile[2]
ktob = zeile[3]
datum = zeile[0]
# print(ukto,zeile)
betrag = float(zeile[1])
if ukto == "" or zeile[5] == 0:
saldo = " ...."
# saldo = "%13.2f" % gesamt
elif self.maxsaldo == 0 or zeile[5] == 1:
# print("hier")
gesamt = gesamt + betrag
saldo = self.nformat13 % gesamt
elif zeile[5] == 2:
# saldo = " ----"
saldo = self.nformat13 % gesamt
dbl_z = datum + " " + (self.nformat13 % betrag) + " " + (self.format_maxa % ktoa) + " " + (self.format_maxb % ktob)
rem_z = ust + re.sub(r" +"," ",zeile[4],9999)
zeile1 = dbl_z + " " + saldo + " " + rem_z
dbl_mark = dbl_z + rem_z # wenn Doubletten gefunden werden, diese eindeutig markieren
if not dbl_mark in dbl_marks:
dbl_marks[dbl_mark] = 0
else:
dbl_marks[dbl_mark] = dbl_marks[dbl_mark] + 1
zeile1 = zeile1 + " DOUBLETTE " + str(dbl_marks[dbl_mark])
has_doublettes = 1
# print(zeile1)
if True or zeile[5] == 1:
text_match1.append(zeile1)
else:
text_match2.append(zeile1)
if datum0 == "00000000":
datum0 = datum
orig_text_new_sorted.append(zeile[6])
# text_match1 = "" + ("%-50s"%(pattern0)) + ("%13.2f"%gesamt) + "\n\n" + "\n".join(text_match1) + "\n"
text_match1 = "" + ("%-50s"%(re.sub(r"\.$","",ukto+interval))) + (self.nformat13%gesamt) + "\n\n" + "\n".join(text_match1) + "\n"
text_match2 = "\n".join(text_match2) + "\n"
salden_text = self.format_salden(ukto,datum,datum0,"^"+ukto+"(-[^- ]+){0,99},")
text_match1 = text_match1 + "\n" + re.sub(ukto+"(-| )","","\n".join(salden_text),99999999) + "\n\n" + text_match2
open(file+".format","w").write(text_match1)
open(file+".kto","w").write(text_match1)
open(file+".orig","w").write("\n".join(orig_text_new_sorted)+"\n")
if has_doublettes:
print("Attention: Doublettes!")
# exit()
def xxxxapply_patch (self,file,patch,offset=0): # verbessern! Kann der patch Befehl auch direkt auf result.txt angewendet werden?
text0 = open(file).read()
text0 = re.sub("\n","--CR--\n",text0,99999999)
text = text0.split("\n")
del_datum = {}
nr = -1
bed = False
for zeile in open(patch).read().split("\n"):
if len(zeile) == 0:
continue
if zeile[0] == ">" and nr < len(text): # Zeile einzufuegen
if len(zeile) > 9 and not " " in zeile[2:10]: # das ist tatsaechlich eine Buchungszeile,
bed = True # denn sie faengt mit einem Datum an
text[nr] = text[nr] + zeile[2:] + "--CR--"
elif zeile[0] == "<": # Zeile zu loeschen
if len(zeile) > 9 and not " " in zeile[2:10]: # das ist tatsaechlich eine Buchungszeile,
bed = True # denn sie faengt mit einem Datum an
del_datum[zeile[2:8]] = 1 # vormerken, dass in diesem Monat eine Buchung geloescht wurde
continue
else:
m = re.search(r"^(\d+)(,\d+|)([acd])",zeile) # eine Zeile, in der eine Update-Information steht,
if m: # (diese Info wirkt sich dann aus auf die naechsten Zeilen)
# print(zeile)
act = m.group(3)
nr1 = int(m.group(1)) - 1 - offset
nr2 = nr1
if len(m.group(2)) > 0:
nr2 = int(m.group(2)[1:]) - 1 - offset
if act in "ac":
nr = max(0,min(nr1,len(text)-1))
if act in "dc": # Zeilen entfernen
while (nr1 < len(text)):
# print("ZZZ",zeile,nr1)
# print("DDD",text[nr1],nr1)
text[nr1] = ""
nr1 = nr1 + 1
if nr1 > nr2:
break
text = "".join(text)
text = re.sub(r"--CR--","\n",text,99999999)
text = re.sub(r"\n$","",text,re.DOTALL)
if not bed:
return(None)
dates_of_deleted_entries = []
for ddatum in del_datum.keys():
if re.search(r"^\d\d\d\d\d\d$",ddatum):
if "\n" + ddatum in text:
continue
if text.startswith(ddatum):
continue
dates_of_deleted_entries.append(ddatum)
open(file,"w").write(text)
return(dates_of_deleted_entries) # die Monate, in denen jetzt gar keine Buchungen mehr sind, werden zurueckgegeben
#****************************************************************************************************************
def xxkto (self,pattern=""):
ktodir = os.path.abspath(".")
if pattern == "SORT": # Sortieren aller acc und sum files. Dies ist sinnvoll fuer das syncen
for acc_file in glob.glob("*.acc") + glob.glob("*.sum"):
file_text = re.sub(r"\n+$","",open(acc_file).read()).split("\n")
file_text.sort()
open(acc_file,"w").write("\n".join(file_text) + "\n")
return()
ktofile = []
for kfile in glob.glob("*.kto"):
if not ".db." in kfile and "result.kto" not in kfile:
ktofile.append(kfile)
if len(ktofile) > 1:
print("More than one ktofile.")
return()
if len(ktofile) == 1:
ktofile = ktofile[0]
else:
ktofile = None
if ktofile:
ktodir = re.sub(r"^(.*)[\\\/](.*).kto$","\\1",os.path.abspath(ktofile))
ktotext = open(ktodir+"/"+ktofile).read()
pattern0 = "^" + re.sub(r"^(\S*) (.*)$","\\1",ktotext[0:50])
else:
ktotext = ""
ktodir = re.sub(r"[\\\/]$","",os.path.abspath("."))
while (0 == 0): # check if we are in a directory with acc files
x = glob.glob("2*.acc") + glob.glob("base/*.acc") + glob.glob(".base/*.acc")
if len(x) > 0:
y = glob.glob("2*.sum") + glob.glob("base/*.sum") + glob.glob(".base/*.sum")
m = re.search(r"^(.*)[\\\/](.*)$",x[0])
if m:
os.chdir(m.group(1))
break
os.chdir("..")
# os.system("ls")
if os.path.isfile("result.orig"):
hkey = os.popen("md5sum result.kto").read()[0:12]
if hkey + ".kto" == ktofile or hkey in ktotext[0:200]:
open("result.kto","w").write(ktotext)
udir = None
if ktofile:
udir = ktodir
if pattern == "":
pattern = pattern0 # wenn kein pattern angegeben, nimm das pattern aus dem ktofile
else:
m = re.search(r"^(.*)([\.\:])(.*)",pattern0)
if m:
p0 = m.group(1)
m0 = m.group(2)
i0 = m.group(3)
else:
p0 = pattern0
m0 = None
i0 = None
m = re.search(r"^(.*)([\.\:])(.*)",pattern)
if m:
p1 = m.group(1)
m1 = m.group(2)
i1 = m.group(3)
else:
p1 = pattern
m1 = None
i1 = None
if not i1:
i1 = i0
if not i1:
i1 = ""
if p1 in p0:
p1 = ""
p2 = re.sub(r"-$","",p0 + "-" + p1)
if p0 == "" or not p2[1:] in ktotext:
p2 = p1
if len(p0) > 0 and p2.startswith(p0):
udir = ktodir + "/" + p1
# p2 = "^" + p2
print("UDIR",udir)
try:
os.mkdir(udir)
except:
pass
if m0 == m1:
if not m1:
m1 = ""
pattern = p2 + m1 + i1
pattern = re.sub(r"\.$","",pattern)
print("PATTERN",pattern)
if os.path.isfile("result.orig"):
if pattern == "":
self.add(1)
else:
self.add()
if os.path.isfile("result.kto"):
os.unlink("result.kto")
if pattern == "":
os.chdir(ktodir)
return()
split_pars = self.split1(pattern)
if os.path.isfile(ktodir+"/result.orig"):
os.chdir(ktodir)
return()
if os.path.isfile("result.orig"):
if udir:
for kfile in glob.glob(udir+"/*.kto"):
os.unlink(kfile)
else:
udir = ktodir
hkey = os.popen("md5sum result.kto").read()[0:12]
ktotext = open("result.kto").read()
ktotext = re.sub(r"^(\S+ )( +\S+)","\\1 " + hkey + "\\2",ktotext)
if ktofile == None or re.search(r"^[abcdef0123456789]{12}\.kto$",ktofile):
open(udir+"/"+hkey+".kto","w").write(ktotext)
else:
open(udir+"/"+ktofile,"w").write(ktotext)
os.chdir(ktodir)
#
#**********************************************************************************
if __name__ == "__main__":
# Konto.__dict__[sys.argv[1]](Konto(),*sys.argv[2:])
if len(sys.argv) > 1 and sys.argv[1].startswith("test"):
Konto.__dict__[sys.argv[1]](Konto(),*sys.argv[2:])
elif len(sys.argv) > 1 and sys.argv[1] == "sort":
Konto.__dict__["sort"](Konto(),*sys.argv[2:])
elif len(sys.argv) > 1 and sys.argv[1] == "check":
Konto.__dict__["check_hash"](Konto(),*sys.argv[2:])
elif len(sys.argv) > 1 and sys.argv[1] == "saldo":
print(Konto.__dict__["read_saldo"](Konto(),*sys.argv[2:]))
else:
Konto.__dict__["kto"](Konto(),*sys.argv[1:])