import pandas as pd import configparser import os.path import argparse """ Erstellung einer Excel-Datei mit aktuellen Preisen aus Sivas ist leicht möglich. Diese soll in einer config-Datei für die Berechnung der rieter-eKalkulation verwendet werden. Den Parametern der rieter_ekalk werden die entsprechenden Sivas-Nummern zugewiesen, und damit die aktuellen Preise. Diese Zuordnung von Parametern und ihren aktuellen Preisen wird wieder in eine config-Datei geschrieben, die mit den Preisen der Sivas_Daten.cfg-Datei abzugleichen ist, auf die rieter_ekalk zugreift. """ class Kosten(): """ Liest die Sivas-Excel-Liste ein und schreibt eine neue config Datei mit den aktuellen Preisen der in rieter-ekalk verwendeten Sivas-IDs. """ def __init__(self, pathNew="Zuordnung_Teilenummern.cfg", pathOld="Sivas_Daten.cfg", sivasData="grid_export.xlsx"): """ :param pathNew: cfg-Datei, die den Bauteilen ihre Sivas-Nummern zuweist z.B. "schaltschrankgehaeuse_b2x800_zubehoer = 790821101" :param pathOld: cfg-Datei, die in rieter_ekalk verwendet wird und den Bauteilen Preise zuweist z.B. "schaltschrankgehaeuse_b2x800_zubehoer = 4663.45" :param sivasData: Excel-Datei mit Sivas-Nummern und entsprechenden Preisen, Überschrift: Teilenummer, Laufende Materialkosten """ df = pd.read_excel(sivasData, header=0, index_col=0, usecols=["Teilenummer", "Laufende Materialkosten" ]) self._kosten = df.to_dict() self._given = True if os.path.exists(pathNew): self._zuordnung = configparser.ConfigParser(inline_comment_prefixes="#") self._zuordnung.read_file(open(pathNew)) else: self._given = False self._zuordnung = None self._default = configparser.ConfigParser(inline_comment_prefixes="#") self._default.read_file(open(pathOld)) # wird verwendet, um die Werte der alten config zu speichern self._HW_Einzelpreise = None def exists(self): return self._given def getNewPricesAsDict(self, not_found_keys): """ Gibt die neuen Preise als Dict zurück. :param not_found_keys: Dict von Bauteilen, denen eine Nummer zugeordnet ist, die in Sivas nicht existiert z.B. {'schaltschrankgehaeuse_b1x800_zubehoer': '----'} """ faktoren = self.getZuordnungTeilenummernAsDict("Faktoren") newDict = {} for key, val in self.getZuordnungTeilenummernAsDict("HW_Einzelpreise").items(): number = val.strip() self.getPriceFromNumber(key, number, newDict, not_found_keys) if "+" in number: del not_found_keys[key] split_sivas_ids = number.split('+') self.getPriceFromAddedNumbers(key, split_sivas_ids, newDict, not_found_keys) if key in faktoren: newDict[key] *= float(faktoren[key]) return newDict def getPriceFromAddedNumbers(self, key, split_sivas_ids, newDict, not_found_keys): """ Trägt die Zuordnung Bauteil:Gesamtpreis in das newDict Dictionary ein, wenn das Bauteil mehrere Sivas-Nummern beinhaltet. Ist die Nummer eines Summanden nicht in Sivas enthalten, wird er in das Dict "not_found_keys" eingetragen. :param split_sivas_ids: Liste von Sivas IDs, die addiert werden z.B. [' 827072204', ' 721000041'] :param key: Name z.B. "anlagenrechner_ohne_bildschirm" :param newDict: z.B. {'schaltschrankgehaeuse_b2x800_zubehoer':9490.23, ...} :param not_found_keys: Dict von Bauteilen, denen eine Nummer zugeordnet ist, die in Sivas nicht existiert z.B. {'schaltschrankgehaeuse_b1x800_zubehoer': '----'} """ price = 0 for summand in split_sivas_ids: summand = summand.strip() # summand: einzelner Summand z.B. '827072204' if summand in self._kosten["Laufende Materialkosten"]: cost = self._kosten["Laufende Materialkosten"][summand] # cost: Einzelpreis eines Summanden [€] if type(cost) is type(int) or type(float): price += cost # price: Gesamtpreis newDict.update({key: price}) else: not_found_keys.update({key:summand}) def getPriceFromNumber(self, key, number, newDict, not_found_keys): """ Trägt die Zuordnung Bauteil:Gesamtpreis in das newDict Dictionary ein, wenn das Bauteil eine Sivas-Nummer beinhaltet. In Sivas nicht existierende Nummern werden in das Dict "not_found_keys" zurückgegeben. :param key: Name z.B. "anlagenrechner_ohne_bildschirm" :param number: Sivas Nummer zum key z.B. '827072204' :param newDict: z.B. {'schaltschrankgehaeuse_b2x800_zubehoer':9490.23, ...} :param not_found_keys: Dict von Bauteilen, denen eine Nummer zugeordnet ist, die in Sivas nicht existiert z.B. {'schaltschrankgehaeuse_b1x800_zubehoer': '----'} """ if number in self._kosten["Laufende Materialkosten"]: price = self._kosten["Laufende Materialkosten"][number] if price is int or float: newDict.update({key: price}) else: not_found_keys.update({key:number}) def getDefaultDictAsFloat(self, section_name): res = dict() for key, val in self._default.items(section_name): res[key] = float(val) return res def getZuordnungTeilenummernAsDict(self, section_name): res = dict() for key, val in self._zuordnung.items(section_name): res[key] = val return res def writeNewConfig(self, name='Sivas_Abgleich.cfg'): config = configparser.ConfigParser() config["HW_Einzelpreise"] = latest_costs config["Preise durch Sivas nicht ermittelbar"] = not_found_in_sivas print("writing new config file", name) with open(name, 'w') as configfile: config.write(configfile) def writePriceIncrements(self, name='Preis_Increments.xlsx'): not_found_in_sivas = dict() latest_costs = self.getNewPricesAsDict(not_found_in_sivas) sivas_numbers = list() old_prices = list() new_prices = list() for sivas_number in latest_costs.keys(): sivas_numbers.append(sivas_number) old_prices.append(self.getDefaultDictAsFloat("HW_Einzelpreise").get(sivas_number)) new_prices.append(latest_costs.get(sivas_number)) data = {"Sivas-Nummern":sivas_numbers, "Alte Preise":old_prices, "Neue Preise":new_prices} df = pd.DataFrame.from_dict(data) print("write price increments", name) df.to_excel(name, sheet_name="Preisänderungen", index_label="Sivas-Nummern") if __name__ == '__main__': parser = argparse.ArgumentParser(description='calculation of a system according to Bös', prog='ecalc') parser.add_argument('-o', '--outfile', action='store', help='name of the output excel file', default="Preis_Increments.xlsx") args = parser.parse_args() base = os.environ.get('ECALC_CFG') zuordCfgFilePath = os.path.join(base, "Zuordnung_Teilenummern.cfg") sivasCfgFilePath = os.path.join(base, "Sivas_Daten.cfg") gridExportFilePath = os.path.join(base, "grid_export.xlsx") if not os.path.exists(zuordCfgFilePath): print("no Zuordnung_Teilenummern.cfg in ECALC_CFG") if not os.path.exists(sivasCfgFilePath): print("no Sivas_Daten.cfg in ECALC_CFG") if not os.path.exists(gridExportFilePath): print("no grid_export.xlsx with prices from SIVAS in ECALC_CFG") # lies die alten config und die Excel-Liste mit den Sivas-Daten costs = Kosten(zuordCfgFilePath, sivasCfgFilePath, gridExportFilePath) not_found_in_sivas = dict() latest_costs = costs.getNewPricesAsDict(not_found_in_sivas) # schreibe die neue config mit den aktuellen Preisen outCfg = os.path.join(os.environ.get('ECALC_WORK'), "Sivas_Abgleich.cfg") costs.writeNewConfig(outCfg) # schreibe die Preisänderungen in eine Excel-Datei outPath = os.path.join(os.environ.get('ECALC_WORK'), args.outfile) costs.writePriceIncrements(outPath)