import argparse import csv import config KN_HABEN_MIETE_NK = "4106" KN_HABEN_MIETE = "4105" KN_HABEN_MIETE_CWS = "4107" KOSTENSTELLE_CWS = "100" KN_HABEN_MIETE_FZ = "4107" KOSTENSTELLE_FZ = "200" class Forderung: def __init__(self )->None: self.name:list[str] = [] self.belegdatum:str = "" self.amount:float = 0 self.text:str = "" self.soll:int|None = None self.haben:int|None = 0 self.kostenstelle:int = 0 self.kostentraeger:int = 0 def __str__(self): return f"Name{self.name}, Haben {self.haben}, Soll {self.soll}, Amount {self.amount},Verwendung {self.text}" def printC(forderungen:dict): for key,values in forderungen.items(): print(f"//////////////{key}/////////////////////////////") for nkey,nvalues in values.items(): print(f" {nkey}, {nvalues}") def print_to_file_lexware(forderungen:dict): """ print Forderungen to a file, that can be read by lexware according the following format: "Belegdatum";"Buchungstext"; "Buchungsbetrag"; "Sollkonto";"Habenkonto";"Kostenstelle" 01.03.2025; "Miete Familienzimmer"; 357,08; 12161; 4107; 200 """ print('Start Drucken der Forderugen') names = read_account_names(config.filename_debitoren) #print(names) #printC(forderungen) for period, forderung in forderungen.items(): if forderung !={}: filename = f"output/{period[0]}-{period[1]:02d}_Forderungen_Familienzimmer.csv" print(f"\t ...{filename}") with open(filename, "w",encoding="cp1252", newline="\r\n") as file: file.write("\"Belegdatum\";\"Buchungstext\";\"Buchungsbetrag\";\"Sollkonto\";\"Habenkonto\";\"Kostenstelle\"\n") for key in forderung: f = forderung[key] name = ' '.join(names[key[0]]) file.write(f"01.{period[1]:02d}.{period[0]};\"{name} {f.text}\";{f.amount};{f.soll};{f.haben};{f.kostenstelle}\n") print("Fertig mit Drucken der Forderungen.") def create_forderungen(forderungen:dict, period:tuple, id_subject:tuple, belegdatum:str, amount:float, soll:int|None, haben:str, kostenstelle:str)->dict: """ create the recievables in the dict and incerting the date. if the amount is 0 this nothings added, if tow recievables have the same period and subject, than the amounts will be added """ if amount == 0: return forderungen if period not in forderungen.keys(): forderungen[period] = {} if id_subject not in forderungen[period]: forderungen[period][id_subject] = Forderung() forderungen[period][id_subject].amount = round(amount,2) forderungen[period][id_subject].text = f"{id_subject[1]} {period[0]}-{period[1]:02d}" forderungen[period][id_subject].kostenstelle = kostenstelle forderungen[period][id_subject].haben = haben forderungen[period][id_subject].soll = soll forderungen[period][id_subject].belegdatum = belegdatum else: forderungen[period][id_subject].amount = round(amount+forderungen[period][id_subject].amount) return forderungen def create_forderungen_miete(filename:str, accounts:dict, forderungen:dict, month:int, year:int)->dict: """ Create all recievables for one Month from the "mieten.csv" file, warm (split to Nk and kalt+Parkplatz(+soli), cws, and familyrooms """ print(f"{year} {month} Start Einlesen der Mietendatei von {filename}") try: file = list(csv.DictReader(open(filename, 'r'))) period = (year,month) for line in file: kaltmiete = getFloat(line["Betrag Kaltmiete"]) if kaltmiete > 0: name = getWords(line["Vorname, Name"]) id = getID(accounts, name) if id > 0: #calculate the Miete betriebskosten = getFloat(line["Betrag Betriebskosten"]) stellplatz = getFloat(line["Betrag zusätzlicher Stellpl."]) zusatzVereinbarung = getFloat(line["Betrag Vereinbarung"]) mieteCWS = getFloat(line["Betrag Gemeinschaftsbuero"]) betragFz = getFloat(line["Betrag Gaestezimmer"]) miete = kaltmiete + zusatzVereinbarung + stellplatz warmmiete = miete + betriebskosten datum = f"01.{period[1]:02d}.{period[0]}" create_forderungen(forderungen, period, (id, "Miete Gesamt"),datum, warmmiete, id, "0", "") create_forderungen(forderungen, period, (id, "Miete NK"), "", betriebskosten, None, KN_HABEN_MIETE_NK,"") create_forderungen(forderungen, period, (id, "Miete"),"", miete, None, KN_HABEN_MIETE,"") create_forderungen(forderungen, period, (id, "Miete CWS"),datum, mieteCWS, id, KN_HABEN_MIETE_CWS, KOSTENSTELLE_CWS) create_forderungen(forderungen, period, (id, "Miete Familienzimmer"), datum, betragFz, id, KN_HABEN_MIETE_FZ, KOSTENSTELLE_FZ) else: print(f"Fehler: kein name gefunden!!!{name} {getID(accounts, name)} {line}") print(f"Fertig, {year} {month} Erstellen von {len(forderungen[period])} Forderungen abgeschlossen.") except IOError: print(f"Fehler, Datei {filename} nicht gefunden.") return forderungen def create_forderungen_familienzimmer(filename:str, accounts:dict, forderungen:dict)->dict: """ Create the recievables from the familyrooms from the file from the inputfile, assings it to the accouts, calculate the price, stores results in forderungen """ print(f"Start Einlesen der Buchungen des Familienźimmers von {filename}") priceFamilyRooms = readPriceFamilyRooms(config.filname_price_familyroom) counter_recievables = 0 counter_errors = 0 try: with open(filename, "r") as file: reader = csv.DictReader(file) for row in reader: name = row["Created by"] name = getWords(name) id_subject = (getID(accounts, name), "Familienzimmer") month = getMonth(row["End time"].split(" ")[2]) year = row["End time"].split(" ")[3] period = (year, month) if id_subject[0] > 0: room = row["Room"].replace("\"","") duration = getDuration(row["Duration"]) number_person = getNumberPerson(row["Number of guests"]) price = getPrice(room, priceFamilyRooms, duration, number_person) #print(f"{counter_recievables} \n{name[1]} {id_subject} {room} dauer {duration} Tage, personen {number_person} preis {price}") datum = f"01.{period[1]:02d}.{period[0]}" create_forderungen(forderungen,period,id_subject,datum, price,id_subject[0],KN_HABEN_MIETE_FZ,KOSTENSTELLE_FZ) counter_recievables+=1 else: counter_errors+=1 print(f"Fehler, Name nicht gefunden\n\t{row}") print(f"Fertig mit Erstellen von {counter_recievables} Forderungen, {counter_errors}") except IOError: print(f"Fehler, Datei {filename} nicht gefunden.") return forderungen def getFloat(field:str)->float: """ converts a number from not empty string (english format e.g. 1,946.44) to a float, rounding to 2, digits after the point if the string is empty returns 0 """ if field.isnumeric and len(field)>0: return round(float(field.replace(",", "")),2) else: return 0 def getWords(sentence:str)->list: """ Takes a sequence of chars (sentence), replaces special signs from the alphabet and returns a list of all words without special chars """ result = [] word = '' #sentence = sentence.lower() sentence = sentence.replace("ä", "ae").replace("ö", "oe").replace("ü", "ue").replace("ß", "ss") for c in sentence: if ord("a")<= ord(c) <= ord("z") or ord("A")<= ord(c) <= ord("Z") or ord("0")<= ord(c) <= ord("9"): word = word + c elif len(word)>2: result.append(word) word = "" else: word = "" if len(word)>0: result.append(word) return result def getPrice(room:str, prices:dict, duration:int, numberPerson:int)->int: """ calculate the price for one booking, 15 Euro per night, 5 Euro extra per extra person, if there is no specific number take the max of person """ if numberPerson > 0: return min(prices["proPerson"]*numberPerson+prices["Basis"],prices[room])*duration else: return prices[room]*duration#or 15*duratiion if it was before Okt 2025?? def getNumberPerson(field:str)->int: if len(field) >0: return int(field) else: return 0 def getID(accounts:dict, names:list)->int: for name in names: if name in accounts: return int(accounts[name]) return 0 def getMonth(month:str)->int: month = month.lower() if month == "january" or month =="januar": return 1 elif month == "february" or month =="februar": return 2 elif month == "march" or month =="märz": return 3 elif month == "april": return 4 elif month == "may" or month =="mai": return 5 elif month == "june" or month =="juni": return 6 elif month == "july" or month =="juli": return 7 elif month == "august": return 8 elif month == "september": return 9 elif month == "october" or month =="oktober": return 10 elif month == "november": return 11 elif month == "december" or month =="dezember": return 12 else: return 0 def getDuration(duration:str)->int: duration = duration.split(" ") if duration[1] == "weeks" or duration[1] == "Woche": return int(duration[0]) * 7 elif duration[1] == "days" or duration[1] == "Tage": return int(duration[0]) def read_account_ids(filename:str)->dict: """ Create a dictionary from name to account id for first and last name couples included, names that are not unique will be removed """ print(f"Start Einlesen der Namen und Account IDs von {filename}.") accounts = {} number_accounts = 0 doubles = [] try: with open(filename, "r",encoding=config.encoding_debitoren) as file: for line in file: line = getWords(line) if len(line) >=2: id = line[-1] names = line[:-1] number_accounts += 1 for name in names: if name in accounts: doubles.append(name) else: accounts[name] = int(id) for twin in doubles: if twin in accounts: del accounts[twin] print(f"Fertig mit Einlesen {number_accounts} found.") except IOError: print(f"Fehler, Datei {filename} nicht gefunden.") return accounts def read_account_names(filename:str)->dict: """ Create a dictionary: account id -> name """ print(f"Start Einlesen der Kontonummern und Namen \"{filename}\" ") try: names = {} with open(filename, "r",encoding=config.encoding_debitoren) as file: for line in file: line = getWords(line) if len(line) >=2: id = int(line[-1]) name = line[:-1] names[id] = name print(f"Fertig mit Einlesen, {len(names)} Kontonummer gefunden ") except IOError: print(f"Fehler, Datei {filename} nicht gefunden.") return names def readPriceFamilyRooms(filename:str)->dict: """ read the max price per night for each room from the file """ print(f"Start Einlesen der Preise für die Familienzimmer von {filename}") prices = {} try: with open(filename, "r") as file: for line in file: line = line.strip().replace("\"","").split(config.seperator_price_familyroom) if len(line) == 2: prices[line[0]] = int(line[1]) print(f"Fertig mit Einlesen der Preise") except IOError: print(f"Fehler, Datei {filename} nicht gefunden.") return prices def parse_args() -> argparse.Namespace: """ Defines and parses command line arguments for this script. """ parser = argparse.ArgumentParser() return parser parser.add_argument( "bookings", type=str, help="the file from which the bookings come", ) parser.add_argument( "miete", type=str, help="the file from which the bookings come", ) parser.add_argument( "accounts", type=str, help="the file from which the account id are read", ) return parser.parse_args() def main(args: argparse.Namespace) -> None: print(getWords("Hallo östereich-Ungarn !Achtung! ?ßchlange")) if __name__ == "__main__": main(parse_args()) """ Not used any more def create_forderungen_cws(filename:str, seperator:str, accounts:dict, forderungen:dict)->dict: file = list(csv.DictReader(open(filename, 'r'))) year = file[14]["Raum"] for line in file: name = line["Name"].strip().replace("-", "").replace("ß", "ss").split(" ") id = getID(accounts, name) id_subject = (id,"CWS") if id > 0: for key, value in line.items(): if value !="X": month = getMonth(key) if month>0: period = (year, month) price = int(value) if period not in forderungen.keys(): forderungen[period] = {} if id_subject not in forderungen[period]: forderungen[period][id_subject]= Forderung() forderungen[period][id_subject].amount = price forderungen[period][id_subject].text = f"Miete CWS {period[0]}-{period[1]:02d}" forderungen[period][id_subject].kostenstelle = "100" forderungen[period][id_subject].haben = "4107" forderungen[period][id_subject].soll = id_subject[0] else: forderungen[period][id_subject].amount += price else: print(line) return forderungen """