
| Current Path : /home/ift/52_procpy/fibu/ |
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/ift/52_procpy/fibu/account2.py |
# coding: utf8
import os,sys,re,glob,time,datetime
import codecs
import random
import sqlite3
import base64
import hashlib
#******************************************************************************
class Account (object):
def __init__ (self):
if os.path.isfile("test.db"):
os.remove("test.db")
self.db = sqlite3.connect(":memory:")
self.db.row_factory = sqlite3.Row
cursor = self.db.cursor()
cursor.execute("create table if not exists buchungen " +
"(KTODIR,DATUM,BETRAG,KTOA,KTOB,REMARK,FORMEL default '')")
try:
cursor.execute("create index KTODIR_IDX on buchungen (KTODIR)" )
cursor.execute("create index DATUM_IDX on buchungen (DATUM)" )
cursor.execute("create index KTOA_IDX on buchungen (KTOA)" )
cursor.execute("create index KTOB_IDX on buchungen (KTOB)" )
except Exception as e:
pass
cursor.execute("create table if not exists bezeichner (KTODIR,KTO,NAME,SUM)")
try:
cursor.execute("create index KTODIR_IDY on bezeichner (KTODIR)" )
cursor.execute("create index KTO_IDX on bezeichner (KTO)" )
except Exception as e:
pass
self.idem = []
self.ktofiles = {}
self.sort_konten_list = "LOHN,SOND,LS,SZ,KS,KR,KE,KI,KA,KV,AV,RV,PV".split(",")
self.mark("")
#********************************************************************************
def t1 (self,ktodir):
self.sync_ukto(ktodir,"2007")
# self.parse_kto(ktodir)
# self.db.commit()
#********************************************************************************
def parse_kto (self,ktodir):
ktofile = glob.glob(ktodir + "/*.kto")
print (ktodir + "/*.kto")
print ktofile
if len(ktofile) > 1:
return("ERROR 101. More than one ktofile found in " + ktodir)
if len(ktofile) == 1:
ktokey = None
for zeile in (open(ktofile[0]).read()).split("\n"):
if not ktokey:
m = re.search(r"\((.*?)\)",zeile) # erste Zeile: Hashes einlesen
if m:
ktokey = m.group(1)[0:8]
uktokey = m.group(1)[8:]
self.ktofiles[ktodir] = [ktokey,uktokey]
continue
m = re.search(r"^(\d\d\d\d\d\d\d\d) +(\-?\d+\.\d\d) +\-?(\S*) *(\S+) +(\-?\d+\.\d\d) +(.*)$",zeile)
if m:
datum = m.group(1)
betrag = str(m.group(2))
ktoa = m.group(3)
ktob = m.group(4)
remark = m.group(6)
qstr = ("insert into buchungen " +
"(KTODIR,DATUM,BETRAG,KTOA,KTOB,REMARK) values " +
"('" + ktodir + "','" + datum + "','" + betrag + "','" +
ktoa + "-','" + ktob + "-','" + remark + "')")
self.db.cursor().execute(qstr)
m = re.search(r"^( |\S+) +(\S+) +(\-?\d+\.\d\d) *$",zeile)
if m:
kto = re.sub(r"^ -$","",m.group(1)+"-")
name = re.sub(r"^ +$","",m.group(2))
qstr = ("insert into bezeichner (KTODIR,KTO,NAME,SUM) values " +
"('" + ktodir + "','" + kto + "','" + name + "','" + m.group(3) + "')")
self.db.cursor().execute(qstr)
return(ktofile[0])
#********************************************************************************
def sync_ukto (self,ktodir,ukto): # Konto mit einem Unterkonto synchronisieren
m = re.search(r"^(.*)\-([123456789ABCIJKLMNP])$",ukto)
# --------------- 1. Teil-Zeitraum bestimmen
part = ""
if m:
part = m.group(2)
ukto = m.group(1)
start = None
ukto = re.sub(r"[\\\/]","/",ukto,9999)
if part: # Zeitraum bestimmen
try:
intv = { "A" : ["1001","1099","-A"],
"B" : ["1101","1199","-B"],
"C" : ["1201","1299","-C"],
"I" : ["0101","0399","-I"],
"J" : ["0401","0699","-J"],
"K" : ["0701","0999","-K"],
"L" : ["1001","1299","-L"],
"M" : ["0101","0699","-M"],
"N" : ["0701","1299","-N"],
"P" : ["0101","1299","-P"] } [ part ]
except:
intv = [ "0"+m.group(2)+"01","0"+m.group(2)+"99","-"+m.group(2) ]
else:
intv = ["0000","9999",""]
#------------ 2. Kontofile einlesen, soweit noch nicht geschehen
if not ktodir in self.ktofiles:
self.parse_kto(ktodir)
if not ktodir+"/"+ukto in self.ktofiles:
new_ktofile = self.parse_kto(ktodir+"/"+ukto)
if self.ktofiles[ktodir+"/"+ukto][0] == self.ktofiles[ktodir][1]:
return()
# self.write_kto(ktodir+"/"+ukto
cursor = self.db.cursor()
query_string = "select DATUM,BETRAG,KTOA,KTOB,REMARK from buchungen "
query_string = query_string + " where KTODIR = '" + ktodir + "' "
query_string = query_string + " and (KTOA like '" + ukto + "-%' or KTOB like '" + ukto + "-%')"
query_string = query_string + " order by DATUM,KTOA,KTOB"
cursor.execute(query_string)
print ukto , " <--- UKTO"
gesamt = 0.00
text = []
maxa = 0
maxb = 0
while (0 == 0): # Zeilen des Kontos schreiben
entry = cursor.fetchone()
if not entry:
break
betrag = float(entry[1])
ktoa = entry[2][:-1]
ktob = entry[3][:-1]
ul = len(ukto)
anz = 0
if ktoa[0:ul] == ukto:
ktoa = ktoa[ul:]
if ktoa == "":
ktoa = "-"
anz = anz + 1
if ktob[0:ul] == ukto:
ktob = ktob[ul:]
if ktob == "":
ktob = "-"
if anz == 0:
o = ktoa
ktoa = ktob
ktob = o
betrag = -betrag
anz = anz + 1
if anz == 1:
datum = entry[0]
remark = entry[4]
maxa = max(maxa,len(ktoa))
maxb = max(maxb,len(ktob))
text.append([entry[0],betrag,ktoa,ktob,entry[4]])
maxa = "%-" + str(max(9,maxa)) + "s"
maxb = "%-" + str(max(9,maxb)) + "s"
text.sort(key=self.sort_konten)
zaehler = 0
gesamt = 0.00
while zaehler < len(text):
gesamt = gesamt + float(text[zaehler][1])
text[zaehler] = ( text[zaehler][0] + " " + ("%13.2f" % text[zaehler][1]) + " " +
(maxa % text[zaehler][2]) + " " + (maxb % text[zaehler][3]) + " " +
("%13.2f" % gesamt) + " " + text[zaehler][4] )
zaehler = zaehler + 1
text = "\n".join(text)+"\n"
text = text.encode("utf8")
ktotext1 = re.sub(r"^\s*(.*?)\s*","\\1",text,re.DOTALL)
ktotext1 = re.sub(r"\s+"," ",ktotext1,9999999,re.DOTALL)
addfiles = glob.glob("ktodir/*")
addtext = ""
for addfile in addfiles:
if re.search(r"\.kto$",addfile) or "EXCLUDE" in addfile:
continue
addtext = addtext + base64.urlsafe_b64encode(hashlib.md5(open(ktodir+"/"+addfile).read()).digest())
addfiles = ",".join(addfiles)
uktohash = base64.urlsafe_b64encode(hashlib.md5(addfiles+ktotext1).digest())[0:8]
ktohash = self.ktofiles[ktodir][1]
print new_ktofile
open(new_ktofile,"w").write( ("%-40s" % ukto) + "(" + ktohash + uktohash + ") \n\n" + text)
#********************************************************************************
def xxsync (self,ukto):
ktofile = glob.glob(dir+"*/*.kto")
if not len(ktofile) == 1:
return("ERROR 101. No ktofile found or more than one ktofile.")
ktofile = ktofile[0]
m1 = re.search(r"^(.*?)\-([123456789ABCIJKLMNP])\.[a-z]+$",ktofile)
if m1:
dir = dir + "-" + m1.group(2)
text = open(ktofile).read()
m2 = re.search(r"^(.*?)\(.*?\).*?\n *(\S*)",text,re.DOTALL)
self.add(dir,text)
self.db.commit()
#********************************************************************************
def sync (self,ktodir,ukto): # Unterkonto mit seinem Parent synchronisieren
m = re.search(r"^(.*)\-([123456789ABCIJKLMNP])$",ukto)
# --------------- 1. Teil-Zeitraum bestimmen
part = ""
if m:
part = m.group(2)
ukto = m.group(1)
start = None
ukto = re.sub(r"[\\\/]","/",ukto,9999)
if part: # Zeitraum bestimmen
try:
intv = { "A" : ["1001","1099","-A"],
"B" : ["1101","1199","-B"],
"C" : ["1201","1299","-C"],
"I" : ["0101","0399","-I"],
"J" : ["0401","0699","-J"],
"K" : ["0701","0999","-K"],
"L" : ["1001","1299","-L"],
"M" : ["0101","0699","-M"],
"N" : ["0701","1299","-N"],
"P" : ["0101","1299","-P"] } [ part ]
except:
intv = [ "0"+m.group(2)+"01","0"+m.group(2)+"99","-"+m.group(2) ]
else:
intv = ["0000","9999",""]
#------------ 2. Kontofile einlesen, soweit noch nicht geschehen
if not ktodir in self.ktofiles:
self.parse_kto(ktodir)
if not ktodir+"/"+ukto in self.ktofiles:
self.parse_kto(ktodir+"/"+ukto)
ktofile = glob.glob(ktofile + "/" + ukto + ".kto")
if len(ktofile) > 1:
return("ERROR 101. More than one ktofile found in " + ktodir)
if len(ktofile) == 1:
ktokey = None
for zeile in open(ktofile).read().split("\n"):
if not ktokey:
m = re.search(r"\(.*?\)",zeile) # erste Zeile: Hashes einlesen
if m:
ktokey = m.group(1)[0:8]
uktokey = m.group(1)[8:]
continue
m = re.search(r"^(\d\d\d\d\d\d\d\d) +(\-?\d+\.\d\d) +\-?(\S*) *(\S+) +(\-?\d+\.\d\d) +(.*)$",zeile)
if m:
datum = m.group(1)
betrag = str(m.group(2))
ktoa = m.group(3)
ktob = m.group(4)
remark = m.group(5)
formel = "x"
m = re.search(r"^(.*?) +\{ *(.*)? * \}",remark)
if m:
remark = m.group(1)
formel = m.group(2)
ktoc = self.ukto_from_betrag(betrag)
try:
timediff = datetime.datetime.strptime(datum,"%Y%m%d")
except:
year = "%04u" % min(9999,max(1970,int(datum[0:4])))
month = "%02u" % min(12,max(1,int(datum[4:6])))
day = "%02u" % min(28,max(1,int(datum[6:8])))
timediff = datetime.datetime.strptime(year+month+day,"%Y%m%d")
timediff = "%1u" % (timediff - datetime.datetime.strptime("20000101","%Y%m%d")).days
while (0 == 0):
bnr = "B" + ("%12u" % random.randint(100000000001,999999999900))
qstr = ("insert into " + self.dbtable +
"(BNR,DATUM,BETRAG,KTOA,KTOB,KTOC,REMARK,TIMEDIFF,REMUPPER,FORMEL) values " +
"('" + bnr + "','" + datum + "','" + betrag + "','" +
ktoa + "-','" + ktob + "-','" + ktoc + "-','" + remark + "','" + timediff
+ "','" + remark.upper() + "','" + formel + "')")
self.db.cursor().execute(qstr)
# try:
# break
# except:
# print "WARNING 24: DOUBLE ID", bnr
#
# text = open(ktofile[0]).read()
# m = re.search(r"^(.*?)\((.*?)\).*?\n(.*)$",text,re.DOTALL)
# ktohash = m.group(2)[0:8]
# filehash = m.group(2)[8:]
# ktotext = m.group(3)
# aktuellen Datenbank-Hash fuer das Konto ermitteln
qu_string = ("select group_concat(KTOA),group_concat(KTOB),group_concat(REMARK) from " +
self.dbtable + " where (KTOA like '" + ukto + "-%' or KTOB like '" + ukto + "-%') " +
" and DATUM >= '" + start + intv[0] + "' and DATUM <= '" + ende + intv[1] + "' " +
" order by DATUM,KTOA,KTOB")
cursor = self.db.cursor()
cursor.execute(qu_string)
text1 = cursor.fetchone()
ktohash_new = [""]
# print ukto
# print qu_string
for o in text1:
if o:
ktohash_new.append(re.sub(r" +"," ",o,99999999))
if ktohash_new == [""]:
ktohash_new = "" # wenn es gar keine Buchungen im Unterkonto gibt, dann ktohash auf "" setzen
else:
ktohash_new = base64.urlsafe_b64encode(hashlib.md5("".join(ktohash_new).encode("utf8")).digest())[0:8]
# print ktohash_new
if len(ktofile) > 1:
return("ERROR 101. More than one ktofile found in " + ktodir)
addfiles = glob.glob("ktodir/*")
addtext = ""
for addfile in addfiles:
if re.search(r"\.kto$",addfile) or "EXCLUDE" in addfile:
continue
addtext = addtext + base64.urlsafe_b64encode(hashlib.md5(open(ktodir+"/"+addfile).read()).digest())
addfiles = ",".join(addfiles)
if len(ktofile) == 1: # es gibt schon ein ktofile, also mal sehen, ob dieses noch mit der Datenbank synchron ist
text = open(ktofile[0]).read()
m = re.search(r"^(.*?)\((.*?)\).*?\n(.*)$",text,re.DOTALL)
ktohash = m.group(2)[0:8]
filehash = m.group(2)[8:]
ktotext = m.group(3)
# while (0 == 0):
# self.rule(ktodir,ktotext)
# if len(ktotext) == 2:
# if ktotext[0] == ktotext[1]:
# break
# else:
# ktotext.pop(0)
# else:
# break
ktotext1 = re.sub(r"^\s*(.*?)\s*","\\1",ktotext,re.DOTALL)
ktotext1 = re.sub(r"\s+"," ",ktotext1,9999999,re.DOTALL)
filehash_new = base64.urlsafe_b64encode(hashlib.md5(addfiles+ktotext).digest())[0:8]
else: # es gibt noch kein Ktofile
ktohash = ""
filehash = ""
filehash_new = ""
if ktohash_new in (ktohash,""): # wenn das Unterkonto sich nicht geaendert hat, dann aus dem Kontoauszug
if not filehash == filehash_new: # das Unterkonto neu einlesen, aber nur, wenn der Kontoauszug sich
buchungen = self.parse_kto(ktotext.split("\n")) # geaendert hatte
for buchung in buchungen:
# buchung[2] = re.sub(r"^20..-","",buchung[2])
# buchung[3] = re.sub(r"^20..-","",buchung[3])
# if not "Saldovortrag" in buchung[4]:
self.add(buchung[0],buchung[1],ukto+"-"+buchung[2],ukto+"-"+buchung[3],buchung[4])
self.db.commit()
filehash_new = ""
if filehash_new in (filehash,""):
if not ktohash == ktohash_new:
cursor = self.db.cursor()
query_string = ( "select DATUM,BETRAG,KTOA,KTOB,REMARK from " + self.dbtable +
" where DATUM <= '" + str(ende) + intv[1] +
"' and DATUM >= '" + str(start) + intv[0] + "'")
if not ukto == "":
query_string = query_string + " and (KTOA like '" + ukto + "-%' or KTOB like '" + ukto + "-%')"
query_string = query_string + " order by DATUM,KTOA,KTOB"
cursor.execute(query_string)
print ukto , " <--- UKTO"
# print query_string
gesamt = 0.00
text = []
maxa = 0
maxb = 0
while (0 == 0): # Zeilen des Kontos schreiben
entry = cursor.fetchone()
# print entry
if not entry:
break
betrag = float(entry[1])
ktoa = entry[2][:-1]
ktob = entry[3][:-1]
ul = len(ukto)
anz = 0
if ktoa[0:ul] == ukto:
ktoa = ktoa[ul:]
if ktoa == "":
ktoa = "-"
anz = anz + 1
if ktob[0:ul] == ukto:
ktob = ktob[ul:]
if ktob == "":
ktob = "-"
if anz == 0:
o = ktoa
ktoa = ktob
ktob = o
betrag = -betrag
anz = anz + 1
if anz == 1:
datum = entry[0]
remark = entry[4]
maxa = max(maxa,len(ktoa))
maxb = max(maxb,len(ktob))
text.append([entry[0],betrag,ktoa,ktob,entry[4]])
maxa = "%-" + str(max(9,maxa)) + "s"
maxb = "%-" + str(max(9,maxb)) + "s"
text.sort(key=self.sort_konten)
zaehler = 0
gesamt = 0.00
while zaehler < len(text):
gesamt = gesamt + float(text[zaehler][1])
text[zaehler] = ( text[zaehler][0] + " " + ("%13.2f" % text[zaehler][1]) + " " +
(maxa % text[zaehler][2]) + " " + (maxb % text[zaehler][3]) + " " +
("%13.2f" % gesamt) + " " + text[zaehler][4] )
zaehler = zaehler + 1
text = "\n".join(text)+"\n"
text = text.encode("utf8")
ktotext1 = re.sub(r"^\s*(.*?)\s*","\\1",text,re.DOTALL)
ktotext1 = re.sub(r"\s+"," ",ktotext1,9999999,re.DOTALL)
filehash_new = base64.urlsafe_b64encode(hashlib.md5(addfiles+text).digest())[0:8]
open(file,"w").write("%-40s" % ukto + "(" + ktohash_new + filehash_new + ") \n\n" + text)
print ""
print start,ende
print "FILE: " + file
print "KTODIR: " + ktodir
print "PART: " + part
print "UKTO: " + ukto
print "UDIR0: " + udir0
print "JAHR: " + jahr
print "KTOHASH: " + ktohash
print "KTOHASH_NEW: " + ktohash_new
print "FILEHASH: " + filehash
print "FILEHASH_NEW: " + filehash_new
return()
text = self.print_ukto (ukto1,udir,start+intv[0],ende+intv[1],saldovortrag)
unterkonten = text[1]
text = text[0]
# self.saldovortraege[file] = text[0:250] # es ist nicht klar, ob das ueberhaupt eine Verbesserung bringen wuerde
try:
open(file,"w").write("")
except:
return()
if text == "":
os.unlink(file)
try:
os.rmdir(ktodir)
except:
pass
else:
open (file,"w").write(text)
for o in unterkonten:
try:
os.mkdir(ktodir+"/"+o)
except:
pass
return(file)
#***********************************************************************
def make_filehash (self,ktodir,ktotext):
addfiles = glob.glob("ktodir/*")
addfiles.sort(key=lambda x: x.lower())
addtext = ""
for addfile in addfiles:
if re.search(r"\.kto$",addfile) or "EXCLUDE" in addfile:
continue
addtext = addtext + base64.urlsafe_b64encode(hashlib.md5(open(ktodir+"/"+addfile).read()).digest())
#********************************************************************************
def rule (self,ktodir,ktotext):
pass
#********************************************************************************
def xxsync (self,dir):
ktofile = glob.glob(dir+"/*.kto")
if not len(ktofile) == 1:
return("ERROR 101. No ktofile found or more than one ktofile.")
ktofile = ktofile[0]
ukto = re.sub(r"^(.*?) .*$","",open(ktofile).read(200))
while (0 == 0):
act_hash = self.get_hash(dir) # den hash aus der kto-datei auslesen
parent_hash = act_hash[0:8] # aufspalten in den hash des uebergeordneten kontos
act_hash = act_hash[8:16] # und des eigenen hases
new_hash = self.make_hash(dir) # neuen hash berechnen
if not act_hash == new_hash: # es hat sich was geandert
self.cursor.execute("delete from " + self.dbtable + " where DIR = '" + ukto + "'")
buchungen = open(ktofile).read()
self.add(dir,buchungen)
#**********************************************************
def make_hash (self,dir):
text = os.path.abspath(dir)
text = re.sub(r"^.*[\\\/](.*)$","\\1",text) + "---"
for file in os.listdir(dir):
if os.path.isdir(dir+"/"+file) or "EXCLUDE" in file:
continue
if re.search(r"\.kto$",file):
text1 = open(file).read()
text1 = re.sub(r"^.*?\((.*?)\)","\\1",text1)
text1 = re.sub(r" +"," ",text1,99999999)
else:
text1 = open(file).read(9500)
text = text + "-" + file + "-" + text1
text = base64.urlsafe_b64encode(hashlib.md5(text).digest())[0:8]
return(text)
#**********************************************************
def get_hash (self,dir):
ktofile = glob.glob(dir+"/*.kto")
if not len(ktofile) == 1:
return("ERROR 101. No ktofile found or more than one ktofile.")
ktofile = ktofile[0]
text = open(ktofile).read(1000).split("\n")[0]
m = re.search(r"\((.*?)\)",text)
if m:
return(m.group(1))
else:
return("ERROR 102. No ktohash found")
#**********************************************************
def buchhaltung (self,buchh,rootdir=None):
self.buchh = buchh
if rootdir:
self.buchh.rootdir = rootdir
for o in self.buchh.ukto_list().split("\n"):
m = re.search("^ *(\S+) *(\S+) *$",o)
if m:
o = re.sub(r"[\\\/]","-",m.group(1),9999)
o = re.sub(r"-[123456789ABCIJKLMNP]$","",o)
self.ktoname[o] = m.group(2)
#**********************************************************
def name (self,ukto,dir=None):
if dir:
ukto = re.sub(r"[\\\/]","-",dir+"/"+ukto)
if ukto in self.ktoname: # and not re.search(r"[0123456789ABCIJKLMN]$",ukto):
return(self.ktoname[ukto])
return("")
#**********************************************************
def mark (self,remark=""):
t = time.clock()
if 't0' in vars(self):
print ("%13.9f" % (t-self.t0)) + " " + remark
self.t0 = t
#******************************************************************************
def add (self,datum="",betrag="",ktoa="",ktob="",remark=""):
ktoa = re.sub(r"(^|-)-","\\1",ktoa,9999)
ktob = re.sub(r"(^|-)-","\\1",ktob,9999)
if type(datum) == type([]):
for buchung in datum:
self.add(*buchung)
return()
if type(datum) == type({}):
betrag = str(float((datum.setdefault('betrag', 0))))
remark = datum.setdefault('remark', "")
ktoa = datum.setdefault('ktoa', "")
ktob = datum.setdefault('ktob', "")
datum = str(datum.setdefault('datum', ""))
m = re.search(r"^(.*?)\[(\d+)\-(\d+)\](.*)$",datum)
if m:
nr = m.group(2)
fmt = "%0" + str(len(m.group(2))) + "u"
while (0 == 0):
self.add(m.group(1)+nr+m.group(4),betrag,ktoa,ktob,remark)
nr = fmt % (int(nr) + 1)
if nr > m.group(3):
return()
if not re.search(r"^\d\d\d\d\d\d\d\d$",datum):
for line in datum.split("\n"):
m = re.search(r"^([0123456789\[\-\]]+) +(\-?\d+\.\d\d) +(\S+) +(\S+) +(.*?) *$",line)
if m:
self.add(m.group(1),m.group(2),m.group(3),m.group(4),m.group(5))
return()
try:
timediff = datetime.datetime.strptime(datum,"%Y%m%d")
except:
year = "%04u" % min(9999,max(1970,int(datum[0:4])))
month = "%02u" % min(12,max(1,int(datum[4:6])))
day = "%02u" % min(28,max(1,int(datum[6:8])))
timediff = datetime.datetime.strptime(year+month+day,"%Y%m%d")
# print timediff - datetime.datetime.strptime("20000101","%Y%m%d")
timediff = "%1u" % (timediff - datetime.datetime.strptime("20000101","%Y%m%d")).days
ktoc = self.ukto_from_betrag(str(betrag))
ktoa = re.sub(r"-BETRAG(-|$)","-"+ktoc+"\\1",ktoa)
ktob = re.sub(r"-BETRAG(-|$)","-"+ktoc+"\\1",ktob)
while (0 == 0):
bnr = "B" + ("%12u" % random.randint(100000000001,999999999900))
qstr = ("insert into " + self.dbtable + "(BNR,DATUM,BETRAG,KTOA,KTOB,KTOC,REMARK,TIMEDIFF,REMUPPER) values " +
"('" + bnr + "','" + datum + "','" + str(betrag) + "','" +
ktoa + "-','" + ktob + "-','" + ktoc + "-','" +
remark + "','" + timediff
+ "','" + remark.upper()
+ "')")
self.db.cursor().execute(qstr)
try:
break
except:
print "WARNING 24: DOUBLE ID", bnr
#******************************************************************************
def assign_buchungen (self,kto0,text):
for cond in text.split("\n"):
m = re.search(r"^ *([\d\[\]\-\%]+) +(\S+) +(\S+) +(\S+) +([\d\-\.]+|) +(.*?) *$",cond)
if not m:
continue
datum = m.group(1)
ktoa = m.group(3)
kto1 = "'"+re.sub(r"[\[\]]","",m.group(4)) + "-'"
kto1 = re.sub(r"-BETRAG-'","-'||KTOC",kto1)
pattern = m.group(6).upper()
m = re.search(r"\[(.*?)\]",cond)
if m:
pattern = re.sub(r"XXX",m.group(1).upper(),pattern,9999)
usteuer = ""
if pattern[0:3] in ["++|","+-|"]:
usteuer = ", REMARK = '" + pattern[0:2] + "' || REMARK "
pattern = pattern[3:]
cursor = self.db.cursor()
qu_string = ( "update " + self.dbtable + " set KTOB = " + kto1 + usteuer +
" where KTOA like '" + ktoa + "' and KTOB like '" + kto0 + "-" + "' and DATUM like '" + datum + "'" )
p = []
for o in pattern.split("|"):
if o:
p.append( "\n REMUPPER LIKE '%" + o + "%' " )
if len(p) > 0:
qu_string = qu_string + " and (" + " or ".join(p) + ") "
# print qu_string
cursor.execute( qu_string )
#******************************************************************************
def koinzidente_buchungen (self,zeitraum_vs_mindestbetrag,kontoliste):
cursor = self.db.cursor()
qu_string = ( "select f1.BNR,f1.DATUM,f1.BETRAG,f1.KTOA,f1.KTOB,f1.REMARK," +
" f2.BNR,f2.DATUM,f2.BETRAG,f2.KTOA,f2.KTOB,f2.REMARK\n" +
"from " + self.dbtable + " as f1, " + self.dbtable + " as f2\n" +
"where not f1.BNR = f2.BNR and not f1.TIMEDIFF < f2.TIMEDIFF and\n" +
"not f1.DATUM < f2.DATUM and " +
"abs(f1.BETRAG) = abs(f2.BETRAG)\n" )
zeitraeume = []
for o in zeitraum_vs_mindestbetrag:
zeitraeume.append("\n (f1.TIMEDIFF - f2.TIMEDIFF < " + str(o) + " and not abs(f1.BETRAG) < " +
str(zeitraum_vs_mindestbetrag[o]) + ")")
if len(zeitraeume) > 0:
qu_string = qu_string + "and (" + " or ".join(zeitraeume) + "\n) \n"
konten = []
for kto in kontoliste.split(","):
konten.append("\n f1.KTOA like '" + kto + "%' or f2.KTOA like '" + kto + "%' or " +
"f1.KTOB like '" + kto + "%' or f2.KTOB like '" + kto + "%'")
if len(konten) > 0:
qu_string = qu_string + "and ( " + " or ".join(konten) + "\n) \n"
# return()
cursor.execute( qu_string )
while (0 == 0):
entry = cursor.fetchone()
if not entry:
break
print entry
#******************************************************************************
def koinzidente_buchungen_2 (self,zeitraum_vs_mindestbetrag,kto0,kto1):
cursor = self.db.cursor()
qu_string = "select BNR,DATUM,BETRAG,KTOA,KTOB,REMARK,TIMEDIFF from " + self.dbtable + " \n"
cursor.exectue()
# konten = []
# kto0 = kto0 + "-"
# kto1 = kto1 + "-"
# konten.append("\n KTOA = '" + kto0 + "' or KTOB = '" + kto0 + "'")
# if len(konten) > 0:
# qu_string = qu_string + " where ( " + " or ".join(konten) + "\n) \n"
qu_string = qu_string + " order by DATUM"
cursor.execute( qu_string )
entries = {}
matched_entries = []
zaehler = 0
while (0 == 0):
zaehler = zaehler + 1
entry = cursor.fetchone()
if not entry:
break
entry0 = list(entry)
entry0[6] = int(entry0[6])
day = int(entry[6])
id = re.sub(r"^\-","",entry[2])
if id in entries and len(entries[id]) == 1:
entry1 = entries[id][0]
for zaehler in (0,1,2,3,4,5,6,7):
entries
diff = day - int(entries[id][0][6])
entry0 = list(entry)
entry1 = list(entries[id][0])
matched = True
id1 = re.sub("\.","",id)
id1 = re.sub(r"^(.*?0)0*","\\1",id1)
id1 = ktoneu[0:min(5,len(id1))]
ktoneu = kto1 + id1 + "-"
if entry0[3] == kto0 and entry1[3] == kto0 and not entry0[2] == entry1[2]:
entry0[3] = ktoneu
entry1[3] = ktoneu
elif entry0[4] == kto0 and entry1[4] == kto0 and not entry0[2] == entry1[2]:
entry0[4] = ktoneu
entry1[4] = ktoneu
elif entry0[3] == kto0 and entry1[4] == kto0 and entry0[2] == entry1[2]:
entry0[3] = ktoneu
entry1[4] = ktoneu
elif entry0[4] == kto0 and entry1[3] == kto0 and entry0[2] == entry1[2]:
entry0[4] = ktoneu
entry1[3] = ktoneu
else:
matched = False
if len( {entry0[3]:1,entry0[4]:1,entry1[3]:1,entry1[4]:1}.keys() ) == 2:
matched = False
if len( {entry0[3]:1,entry0[4]:1,entry1[3]:1,entry1[4]:1}.keys() ) == 2:
matched = False
if len(ktoneu) < 4 and diff > 3 or len(ktoneu) < 5 and diff > 15 or len(ktoneu) < 120 and diff > 5:
matched = False
if matched:
o = entry0[5] + " / " + entry1[5]
o1 = entry1[5] + " / " + entry0[5]
entry0[5] = o
entry1[5] = o1
matched_entries.append(entry0)
matched_entries.append(entry1)
del entries[id]
if matched == False:
try:
entries[id].append(entry)
except:
entries[id] = [entry]
if zaehler % 100 == 0:
entries1 = {}
for o in entries:
for entry in entries[o]:
if day - int(entry[6]) > 50:
continue
id = re.sub(r"^\-","",entry[2])
try:
entries1[abs(float(entry[2]))].append(entry)
except:
entries1[abs(float(entry[2]))] = [entry]
entries = entries1
for entry in matched_entries:
# print entry
qu_string = ( "update " + self.dbtable + " set KTOA = '" + entry[3] + "', " +
" KTOB = '" + entry[4] + "', REMARK ='" + entry[5] + "'" +
" where BNR = '" + entry[0] + "'")
cursor.execute( qu_string )
# print entry
#******************************************************************************
def ukto_from_betrag (self,betrag):
id = re.sub(r"^\-","",betrag)
id = re.sub("\.","",id)
id = re.sub(r"^(.*?0)0*$","\\1",id)
id = id + "00000" # damit immer 5 Zeichen lang
id = id[0:min(5,len(id))]
# if int(id) in self.idem:
# id = str(self.idem[int(id)])
return(id)
#******************************************************************************
def set_idem (self,idem):
self.idem = {}
for o in idem:
o1 = o.split(",")
o2 = o1[0]
for o3 in o1[1:]:
self.idem[int(o3)] = int(o2)
# print self.idem
#******************************************************************************
def fixpoint (self,list_of_functions):
fields = ["DATUM","BETRAG","KTOA","KTOB","REMARK","TIMEDIFF"]
cursor = self.db.cursor()
cursor.execute("select BNR,DATUM,BETRAG,KTOA,KTOB,REMARK,TIMEDIFF from " + self.dbtable +
" where not TIMEDIFF = ''")
fixpoints = {}
while (0 == 0):
entry = cursor.fetchone()
if not entry:
break
fixpoints[entry[0]] = dict(zip(fields,entry[1:]))
zaehler = 0
while (0 == 0):
zaehler = zaehler + 1
fixpoint_reached = True
for entry in fixpoints:
entry0 = entry.copy()
entry["FUNC"](entry)
fixpoint_reached = fixpoint_reached and (entry0 == entry)
if fixpoint_reached or zaehler > 1000:
break
for entry in fixpoints:
cursor.execute("update " + self.dbtable + " set DATUM = '" + str(entry["DATUM"]) + "'" +
+ ",BETRAG = '" + "%3.2f" % float(entry["BETRAG"]) + "'" +
+ ",KTOA = '" + entry["KTOA"] + "'" +
+ ",KTOB = '" + entry["KTOB"] + "'" +
+ ",REMARK = '" + entry["REMARK"] + "'")
#******************************************************************************
def import_file (self,item):
textliste = []
itemlist = []
for item0 in item.split(","):
for item1 in glob.glob(self.rootdir+"/"+item0):
itemlist.append(item1)
itemlist.sort()
for item2 in itemlist:
self.import_file1(item2,textliste)
return(textliste)
#******************************************************************************
def import_file1 (self,item,textliste):
if os.path.isdir(item):
dateiliste = os.listdir(item)
dateiliste.sort()
dir = item + "/"
else:
dateiliste = [item]
dir = ""
for datei in dateiliste:
textliste.append( self.read_ktofile(re.sub("^[\\\/]","",dir+"/"+datei)) )
#******************************************************************************
def read_ktofile (self,datei):
text = None
m = re.search(r"^(\S+)\.(pdf|PDF)$",datei)
if m: # caching of pdf files
datei1 = m.group(1)
dir = "./"
m2 = re.search(r"^(.*)[\\\/](.*)$",datei1)
if m2:
dir = m2.group(1) + "/"
datei1 = m2.group(2)
if os.path.isfile(dir+datei1+".ocr"):
datei = dir + datei1 + ".ocr"
elif os.path.isfile(dir+datei1+".txt"):
datei = dir + datei1 + ".txt"
else:
text = os.popen("ps2ascii "+datei).read()
text = re.sub(chr(12),"",text,99999999)
codecs.open(dir+datei1+".txt","w",encoding="utf8").write(text)
datei = dir + datei1 + ".txt"
if text:
return("["+datei+"]\n"+self.normalize_text(text))
if os.path.isfile(datei):
ttt = codecs.open(datei,"r",encoding="utf8").read().encode("utf8")
return( "["+datei+"]\n"+self.normalize_text(ttt) )
return(datei)
#**********************************************************************************
def normalize_text (self,text):
text = re.sub(r"ä", "ae",text,99999999)
text = re.sub(r"ö", "oe",text,99999999)
text = re.sub(r"ü", "ue",text,99999999)
text = re.sub(r"Ä", "Ae",text,99999999)
text = re.sub(r"Ö", "Oe",text,99999999)
text = re.sub(r"Ü", "Ue",text,99999999)
text = re.sub(r"ß", "ss",text,99999999)
text = re.sub(r"a\"", "ae",text,99999999)
text = re.sub(r"o\"", "oe",text,99999999)
text = re.sub(r"u\"", "ue",text,99999999)
text = re.sub(r"A\"", "Ae",text,99999999)
text = re.sub(r"O\"", "Oe",text,99999999)
text = re.sub(r"U\"", "Ue",text,99999999)
text = re.sub(r"s\"", "ss",text,99999999)
text = re.sub(chr(13),"", text,99999999)
return(text)
#**********************************************************************************
def sort_konten (self,buchung):
zaehler = 1
text = buchung[2] + " " + buchung[3]
rem = buchung[4]
rem = re.sub(r"^(\+\+|\+\-)","",rem)
rem = re.sub(r"^ +\d+ v\.H\..*?\(","",rem)
rem = re.sub(r"\) *$","Z",rem)
for o in self.sort_konten_list:
if ("-"+o) in text:
return(buchung[0] + rem + ("%03u" % zaehler))
zaehler = zaehler + 1
return(buchung[0] + rem + "999")
#**********************************************************************************
def ukto (self,ukto,start="00000000",ende="99999999",saldovortrag=None):
cursor = self.db.cursor()
query_string = ( "select DATUM,BETRAG,KTOA,KTOB,REMARK from " + self.dbtable +
" where DATUM <= '" + str(ende) + "'" )
if not ukto == "":
query_string = query_string + " and (KTOA like '" + ukto + "-%' or KTOB like '" + ukto + "-%')"
if not start[6:8] == "00" or saldovortrag: # nicht noetig, alle Buchungen von Anfang an zu berechnen
query_string = query_string + " and DATUM >= '" + str(start) + "'"
query_string = query_string + " order by DATUM,KTOA,KTOB"
# print query_string
cursor.execute(query_string)
ul = len(ukto)
sums = {"": 0.00}
text = []
if start[6:8] == "00":
if saldovortrag:
sums = { "" : saldovortrag }
text = [ [ start,sums[""],"-","11-1805","Startsaldo" ] ]
maxa = 0
maxb = 0
while (0 == 0):
entry = cursor.fetchone()
if not entry:
break
betrag = float(entry[1])
ktoa = entry[2][:-1]
ktob = entry[3][:-1]
anz = 0
if ktoa[0:ul] == ukto:
ktoa = ktoa[ul:]
self.ukto_sums(sums,ktoa,betrag,entry[0]>start)
if ktoa == "":
ktoa = "-"
anz = anz + 1
if ktob[0:ul] == ukto:
ktob = ktob[ul:]
self.ukto_sums(sums,ktob,-betrag,entry[0]>start)
if ktob == "":
ktob = "-"
if anz == 0:
o = ktoa
ktoa = ktob
ktob = o
betrag = -betrag
anz = anz + 1
if anz == 1:
datum = entry[0]
remark = entry[4]
if entry[0] < start:
betrag = sums[""]
datum = start
remark = "Startsaldo"
ktoa = "-"
ktob = "11-1805"
text = []
text1 = [datum,betrag,ktoa,ktob,remark]
# text1 = [ datum + " " + ("%13.2f" % betrag) + " ", ktoa, ktob,
# " " + ("%13.2f" % sums[""]) + " " + remark ]
maxa = max(maxa,len(ktoa))
maxb = max(maxb,len(ktob))
# text1 = [ datum + " " + ("%13.2f" % betrag) + " ", + ("%-14s" % ktoa) + " " +
# ("%-25s" % ktob) + ("%13.2f" % sums[""]) + " " + remark )
# print text1
text.append(text1)
# if saldovortrag:
# if type(saldovortrag) == type(1.1):
# pass
# else:
# self.saldovortraege[ukto] = sums[""]
text.sort(key=self.sort_konten)
zaehler = 0
maxa = "%-" + str(max(9,maxa)) + "s"
maxb = "%-" + str(max(9,maxb)) + "s"
gesamt = 0.00
# if saldovortrag:
# gesamt = saldovortrag
while zaehler < len(text):
gesamt = gesamt + float(text[zaehler][1])
text[zaehler] = ( text[zaehler][0] + " " + ("%13.2f" % text[zaehler][1]) + " " +
(maxa % text[zaehler][2]) + " " + (maxb % text[zaehler][3]) + " " +
("%13.2f" % gesamt) + " " + text[zaehler][4] )
zaehler = zaehler + 1
if len(text) == 0:
text == None
elif len(text) == 1 and "Saldovortrag" in text[0]:
if re.search(" 0\.00 +Saldovortrag",text):
text = None
else:
text = []
return(text,sums)
#**********************************************************************************
def saldo_gesamt (self,ukto,ende="99999999",sums={}):
cursor = self.db.cursor()
query_string = "select KTOA,sum(BETRAG) from " + self.dbtable + " where DATUM <= '" + str(ende)
if not ukto == "":
query_string = query_string + "' and KTOA like '" + ukto + "-%"
query_string = query_string + "' group by KTOA"
fac = 1.0
for i in (1,2):
# print query_string
cursor.execute(query_string)
while (0 == 0):
entry = cursor.fetchone()
# print entry
if not entry:
break
k = re.sub("^"+ukto,"",entry[0])
self.ukto_sums(sums,re.sub(r"^-","",k[:-1]),fac*entry[1])
query_string = re.sub(r" KTOA"," KTOB",query_string,99)
fac = -1.0
sums_keys = sums.keys()
sums_keys.sort()
text1 = ""
for k in sums_keys:
level = re.sub(r"-"," ", re.sub(r"[^-]","",k,9999),9999 )
text1 = text1 + ("%-49s" % (("%-22s" % k) + self.name(k)) ) + level + ("%13.2f" % sums[k]) + "\n"
return (text1,sums)
#******************************************************************************
def ukto_sums (self,sums,ktox,betrag,bed=None):
# if not bed and re.search(r"^(12|13)\-",ktox):
# betrag = 0.00
while (0 == 0):
# print ktox
if not ktox in sums:
sums[ktox] = betrag
else:
sums[ktox] = sums[ktox] + betrag
if ktox == "":
break
ktox = re.sub("(^|-)[^-]+$","",ktox)
#******************************************************************************
def print_ukto (self,ukto,udir,start="00000000",ende="99999999",saldovortrag=None):
# print "AA", ukto,udir,start,ende
(text1,sums) = self.ukto(ukto,start,ende,saldovortrag)
if text1 == None:
return("")
text = ("%-40s" % (udir + " " + self.name(ukto))) + ("%13.2f" % float(sums[""])) + "\n\n"
list_of_unterkonten = sums.keys()
list_of_unterkonten.sort()
text2 = []
unterkonten = []
for k in list_of_unterkonten:
self.kto_list[ukto+k] = 1
k0 = re.sub(r"^-","",k)
level = re.sub(r"-"," ", re.sub(r"[^-]","",k,9999),9999 )
text2.append(
("%-49s" % (("%-22s" % k0) + self.name(ukto+k)) ) + level + ("%13.2f" % sums[k]) )
if level == " ":
k1 = self.name(ukto+k)
if not k1 == "":
k0 = k0 + "__" + k1
unterkonten.append(k0)
self.saldo (ukto,ende)
text = text + "\n".join(text1) + "\n\n\n" + "\n".join(text2) + "\n\n"
return([text.encode("utf8"),unterkonten])
#******************************************************************************
def saldo (self,ukto,start="00000000",ende="99999999"):
cursor = self.db.cursor()
cursor.execute("select SUM(BETRAG) from " + self.dbtable +
" where KTOA like '" + ukto + "-%'" +
" and DATUM > '" + str(start) + "' and DATUM < '" + str(ende) + "'")
sum = cursor.fetchone()[0]
if sum == None:
sum = 0.00
cursor.execute("select SUM(BETRAG) from " + self.dbtable +
" where KTOB like '" + ukto + "%'" +
" and DATUM > '" + str(start) + "' and DATUM < '" + str(ende) + "'")
sum1 = cursor.fetchone()[0]
if not sum1 == None:
sum = sum - sum1
return(sum)
#**********************************************************************************
def xxparse_kto (self,texte,uktoa="",uktob="",filter=None):
if not type(texte) == type([]):
texte = self.import_file(texte)
buchungen = []
for text in texte:
for zeile in text.split("\n"):
if filter and not filter.search(zeile):
continue
m = re.search(r"^(\d\d\d\d\d\d\d\d) +(\-?\d+\.\d\d) +\-?(\S*) *(\S+) +(\-?\d+\.\d\d) +(.*)$",zeile)
if m:
ktoa = uktoa + "-" + m.group(3)
ktob = uktob + "-" + m.group(4)
ktoa = re.sub(r"--","-",ktoa,9999)
ktob = re.sub(r"--","-",ktob,9999)
ktoa = re.sub(r"(^-|-$)","",ktoa,9999)
ktob = re.sub(r"(^-|-$)","",ktob,9999)
buchungen.append([m.group(1),m.group(2),ktoa,ktob,m.group(6)])
return(buchungen)
#******************************************************************************
def generate_konten (self,saldovortrag=False):
jahre = []
for o in os.listdir(self.rootdir):
if re.search(r"^\d\d\d\d$",o):
jahre.append(o)
jahre.sort()
if not self.db_exists:
self.buchh.load_konten()
self.db_exists = True
self.mark("generate_konten")
for ukto in self.buchh.ukto_list().split("\n"):
if re.search(r"^\s*$",ukto):
continue
m = re.search(r"^( *)(.*)$",ukto)
ukto = m.group(2).strip()
m1 = re.search(r"^(.*?) +(.*)",ukto)
if m1:
ukto = m1.group(1)
o = re.sub(r"[\\\/]","-",ukto,9999)
o = re.sub(r"-[123456789ABCIJKLMNP]","",o)
self.ktoname[o] = m1.group(2)
if len(m.group(1)) == 0:
if re.search(r"^(\d\d\d\d\d\d\d\d)\_(\d\d\d\d\d\d\d\d)",ukto):
self.write_ukto(ukto)
self.mark(ukto)
else:
for jahr in jahre:
self.write_ukto(jahr+"/"+ukto)
self.mark(jahr + " " + ukto)
# if len(ukto) == 5:
# self.ktoname[ukto[1]] = ukto[4]
# self.write_ukto( ukto[0], ukto[1], ukto[2], ukto[3], saldovortrag )
# self.mark(ukto[0]+ukto[1])
#
# konten = self.kto_list.keys()
# konten.sort()
#
# text = []
# for kto in konten:
# text1 = dir + "/JAHR/ " + ("%-30s" % kto) + " JAHR0000 JAHR999"
# if re.search("\-1[01][\- ]",text1) or "-" not in text1:
# text1 = text1 + "9"
# else:
# text1 = text1 + "8"
# text1 = text1 + " " + self.name(kto)
# text.append(text1)
#
# try:
# open(dir+"/konten.txt","w").write("\n".join(text)+"\n\n")
# except Exception as e:
# print "ERROR 15", str(e)
#******************************************************************************
def assign (self,buchung):
if not text in self.qual_strings:
qual_string = []
for zeile in text.split("\n"):
m = re.search("(.*?) +([\+\-]*) +(.*)",zeile)
if m:
qual_string.append([m.group(1),m.group(2),re.compile(m.group(3).lower())])
self.qual_strings[text] = qual_string
else:
qual_string = self.qual_strings[text]
buchung0 = buchung[:]
buchung1 = " ".join(buchung[:-1]).lower() # bcz the last parameter is a function handle (or None)
for bed in self.qual_strings[text]:
if bed[2].search(buchung1):
if not bed[0] in (buchung[2],buchung[3]) and not buchung[4][0:2] == " ":
buchung[3] = bed[0]
if not buchung[4][0:len(bed[1])] == bed[1]:
buchung[4] = bed[1] + buchung[4]
return(None)
if buchung0 == buchung:
return(None)
return(tuple(buchung))
#****************************************************************************
def clean (self):
print "CLEAN"
def rmdir (x):
# print x
if os.path.isdir(x):
try:
os.rmdir(x)
except:
pass
dirnr = 6
while dirnr > 0:
dirnr = dirnr - 1
map (os.unlink, glob.glob(self.rootdir + "/????/" + "*/"*dirnr + "*.kto"))
map (rmdir, glob.glob(self.rootdir + "/????/" + "*/"*dirnr))
#****************************************************************************
def make_kto (self,ukto=None,editor=None):
m = re.search(r"^(.*)\.$",ukto)
if m:
ukto = editor
editor = m.group(1)
kto = re.sub(r"[\\\/]$","",os.path.relpath(".",self.rootdir))
if ukto:
ukto = re.sub(r"[\\\/]$","",ukto)
if kto == ".":
kto = ukto
else:
kto = kto + "/" + ukto
kto = re.sub(r"__(.*?)(\\|\/|-|$)","\\2",kto,9999)
if editor == "bilanz":
(text1,sums) = self.saldo_gesamt("",kto+"0000")
sums1 = {}
for k in sums:
if re.search(r"^(12|13|14|15|16)(-|$)",k):
sums1[k] = - sums[k]
(text1,sums1) = self.saldo_gesamt("",kto+"9999",sums1)
text1 = self.make_bilanz(text1)
print text1
else:
file = self.write_ukto(kto)
if editor:
try:
os.system(editor + " " + file)
except:
pass
#****************************************************************************
def make_bilanz (self,text0):
text = ""
bilanz_konten = re.sub(r",","|",self.buchh.bilanz_konten(),9999)
bilanz_konten = '^([^-]+|' + bilanz_konten + ')(|\-[^-]+)$'
for zeile in text0.split("\n"):
m = re.search(r"^(\S+)",zeile)
if not m:
continue
ukto = m.group(1)
if ukto.count("-") == 0:
text = text + "\n" + zeile + "\n"
elif re.search(bilanz_konten,ukto):
text = text + zeile + "\n"
return(text)
if __name__ == "__main__":
Account.__dict__[sys.argv[1]](Account(),*sys.argv[2:])