import rieter_ekalk as rek import pandas as pd import argparse import json import os import configparser order_dienstleistungen = [ "Pflichtenheft_Autom_Schnittstellen", "Erstellung_Steuerungslayout", "Schaltplanerstellung_incl_Korrekturen", "Projektkoordination", "Materialdispo", "Abstimmung_mit_E_Werkstatt", "Erstellen_E_Montageunterlagen", "PC_Installation", "Oberfläche_Simulation", "SPS_Test_im_Haus_Simulation", "Bedienerhandbuch", "SPS_Doku", "PC_Doku", "Summe_Dienstleistungen_Hardwareplanung", "Schaltschrankbau", "Unterverteilerbau", "Klemmkastenbau_je_2h", "Bedientableaubau", "Vormontage_im_Haus", "Summe_Dienstleistungen_Elektrowerkstatt", "Summe_Dienstleistungen_in_LL", ] order_ergebnisse = [ "E_Werkstatt", "Schaltschrankbau_extern_Mehrkosten", "Dienstleistung_in_LL", "Pflichtenheft", "SPS_Programmierung", "PC_Programmierung_Visualisierung", "Montage_elektrisch", "Inbetriebnahmetest_Hardware_durch_Montage", "SPS_Inbetriebsetzung", "PC_Inbetriebsetzung", "Inbetriebnahmeunterstützung_durch_Montage", "Dokumentation", "Bedienungsanleitung_Emmert", "Schulung_vor_Ort_beim_Kunden", "Abnahme", "SPS_Anlagenbetreuung", "PC_Anlagenbetreuung", "Anlagenbetreuung_durch_Montage", "GESAMT", ] order_hardware = [ "schaltschrankgehaeuse_b1x1200_zubehoer", "schaltschrankgehaeuse_b2x800_zubehoer", "schaltschrankgehaeuse_b1x1200+1x800_zubehoer", "sps_simatic_s7_cpu315_2_pn_dp", "speicherkarte_fuer_sps_512_kb", "sps_simatic_s7_cpu317_2_pn_dp", "speicherkarte_fuer_sps2_mb", "sps_simatic_s7_1515_2", "sps_simatic_s7_1517_3", "sps_simatic_s7_1518_4", "sps_et200_1512sp", "memory_card_2_gb", "et200_sp_ea_ebene", "netzwerk_fernwartung", "abgang_400v", "abgang_24_v", "anlagenrechner", "anlagenrechner_ohne_bildschirm", "pulteinbau_monitor_srline_rflat_24fhd", "kurzhubtastatur_kbt06_mit_touchpad_uslayout", "netzwerk_display_adapter_lindy", "zusaetzlicher_bildschirm", "schaltschrank", "unterverteiler_fuer_1neuenhauser_pm", "unterverteiler_fuer_1flyer", "unterverteiler_fuer_2flyer", "unterverteiler_fuer_1flyer_f40_mit_integrierter_putzmaschine", "unterverteiler_fuer_2flyer_f40_mit_integrierter_putzmaschine", "unterverteiler_fuer_puffer", "unterverteiler_fuer_5_rsm_fa", "korrektur_5_rsm_zusaetzlich_im_unterverteiler", "unterverteiler_fuer_10_rsm_fa", "korrektur_10_rsm_zusaetzlich_im_unterverteiler", "unterverteiler_fuer_3_rsm_fa_mit_umfahrung_steckbar", "korrektur_3_rsm_zusaetzlich_im_unterverteiler", "unterverteiler_fuer_4_rsm_direct", "korrektur_4_rsm_zusaetzlich_im_unterverteiler", "unterverteiler_fuer_12_rsm_direct", "korrektur_12_rsm_zusaetzlich_im_unterverteiler", "unterverteiler_fuer_8_rsm_direct", "korrektur_8_rsm_direct_zusaetzlich_im_unterverteiler", "busverteiler_6_rsm_direct", "korrektur_6_rsm_zusaetzlich_im_busverteiler", "busverteiler_8_rsm_direct", "korrektur_8_rsm_zusaetzlich_im_busverteiler", "antrieb_unidirektional_halbleiter", "antrieb_bidirektional_halbleiter", "antrieb_unidirektional_schuetz", "antrieb_bidirektional_schuetz", "motorschutzschalter", "wendeschuetzschaltung", "frequenzumrichter", "bedienstation_1fach_kpl", "bedienst_2fach_wechs_bcd_10f", "bedienstation_2fach_kpl", "halter_bedientableau_2fach", "bedienstation_3fach_kpl", "halter_bedientableau_3fach", "bedienstation_4fach_kpl", "halter_bedientableau_4fach", "bedienstation_6fach_kpl", "halter_bedienstation_6fach", "drucktaster_automatische_umfahrung", "halter_fuer_drucktaster", "ET200_SP", "et_200sp_bundle_profinet_im_155_6pn_st_ba_2xrj45", "korrektur_et_200sp_bundle_profinet_im_155_6pn_st_ba_2xrj45", "et200_sp_eingangskarte_8_de", "korrektur_et200_sp_eingangskarte_8_de", "et200_sp_eingangskarte_16_de", "et200_sp_eingangskarte_8_do", "korrektur_et200_sp_eingangskarte_8_do", "et200_sp_eingangskarte_16_do", "et200_sp_base_unit_neue_last_mit_potKlemmen", "korrektur_et200_sp_base_unit_neue_last_mit_potKlemmen", "et200_sp_base_unit_links_gebrueckt_mit_pot_klemmen", "et200_sp_base_unit_neue_last", "korrektur_et200_sp_base_unit_neue_last", "et200_sp_base_unit_links_gebrueckt", "korrektur_et200_sp_base_unit_links_gebrueckt", "SLIO", "et_200sp_bundle_profinet_im_155_6pn_st_ba_2xrj45_SLIO", "korrektur_et_200sp_bundle_profinet_im_155_6pn_st_ba_2xrj45_SLIO", "slio_eingangskarte_4_de", "korrektur_slio_eingangskarte_4_de", "slio_eingangskarte_8_de", "korrektur_slio_eingangskarte_8_de", "slio_ausgangskarte_4_do", "korrektur_slio_ausgangskarte_4_do", "slio_ausgangskarte_8_do", "korrektur_slio_ausgangskarte_8_do", "slio_power_modul", "korrektur_slio_power_modul", "slio_4_x_dc_24v_4_x_dc_0v", "korrektur_slio_4_x_dc_24v_4_x_dc_0v", "slio_8_x_dc_24v", "slio_8_x_dc_0v", "korrektur_slio_8_x_dc_0v", "movimot_fu_mit_anschaltung", "sensor_optisch_traverse", "sensorhalter_ohne_sensor", "reflexionslichtschranke_rsm_direct", "stoppersensor_induktiv_mit_halter", "sensor_spulenpruefung_voll_leer", "seilzugschalter", "seil_fuer_seilzugschalter", "blitzleuchte", "spulenumsetzstation", "sensorkabel_je_20m", "stopper_weichenkabel_je_5m", "motorkabel_je_30m", "kabelpritschen_leitern_200_60", "kabelpritsche_rsm_100_60", "kabelpritsche_rsm_50_35", "klemmkasten_rsm", "klemmkasten_direct_in_rsm", "erdung", "kleinteile_rohre_schellen_kabelbinder_ect", "kabel_fuer_klemmkasten_und_bts_60m", "kabel_fuer_1fach_bts_zug_wechseln", "zuleitung_75_m_unterverteiler_4x4mm2_400vac", "zuleitung_75_m_unterverteiler_12x4mm2_24_vdc", "korrektur_zuleitung_75_m_unterverteiler_12x4mm2_24_vdc", "zuleitung_75_m_unterverteiler_12x2_5mm2_24_vdc", "korrektur_zuleitung_75_m_unterverteiler_12x2_5mm2_24_vdc", "zuleitung_55_m_klemmkasten_rsm_mitte_14g1_5_mm", "zuleitung_55_m_klemmkasten_rsm_mitte_14g1_0_mm", "profinetkabel", "korrektur_profinetkabel", "schnittstellen_8x1mm2_30m", "Summe_Landsberg", "Summe_vorOrt", "Summe_gesamt", ] order_eas = [ 'bedienstation_1fach_Not_Aus', 'bedienstation_einfach_Zug_Wechseln', 'bedienstation_automatische_Umfahrung', 'bedienstation_zweifach_Wechs_BCD_10f', 'bedienstation_zweifach_Not_Aus_Reset', 'bedienst_dreifach', 'bedienst_vierfach', 'bedienst_sechsfach', 'EAs_Unterverteiler_direct', 'Sensor_Traversenabfrage_optisch', 'Reflexionslichtschranke_RSM_DIRECT', 'Sensor induktiv Flyer+PM', 'Seilzugschalter', 'Weiche', 'Weiche_nach_PM_bipolar', 'gemeinsame_Weichenrueckstellung', 'Dreifach_Weiche_DIRECT', 'Kreuzungsweiche', 'Stopper', 'Ventil_RA_3_2_abhebbar', 'Ventil_Doppelstreckenantrieb_5_2_abhebbar', 'Blitzleuchte_Stoerung', 'Schnittstelle_Flyer_ElectroJet', 'Schnittstelle_Putzmaschine_Neuhauser', 'FEldbux_UV_EinAusgang', 'Spulenumsetzstation', 'RA_unidirektional', 'RA_unidirektional_abhebbar', 'RA_unidirektional_mit_gemeinsamer_Wendung', 'RA_unidirektional_ohne_SPS_Ansteuerung', 'RA_bidirektional', 'RA_bidirektional_abhebbar', 'RA_bidirektional_abhebbar_gemeinsWend', 'RA_bidirektional_ohne_SPS_Ansteuerung', 'RA_in_RSM_bidirektional', 'Doppelstreckenantrieb', 'Doppelstreckenantriebgemeinsame_Wendung', 'gemeinsame_Wendung', 'Frequenzumrichter', 'Summe Komponenten', 'Summe Komponenten inkcl. Reserve', ] order_emo = [ 'Schaltschrank_aufstellen', 'Unterverteiler_montieren', 'Pritsche_montieren_umbauen_demontieren', 'Pritsche_in_RSM_montieren', 'Motor_verdrahten_und_anschliessen', 'Tableau_befestigen_und_anschliessen', 'Schnittstelle_Flyer_Putzmaschine', 'Sensoren_montieren', 'Seilzugschalter_installieren', 'Blitzleuchte_installieren', 'Weiche_Stopper_anschliessen', 'Erdung', 'Summe', 'Summe inkl. Mehraufwand', ] class cfg(): """ Liest die config-Datei ein, in der Stückpreise und Zeiteinheiten pro Bauteil wie in der rieter_ekalk Excel-Datei verwendet angegeben sind, und schreibt sie in ein Dictionary. """ def __init__(self, path="Sivas_Daten.cfg"): """ :param path: Die config-Datei, in der Stückpreise und Zeiteinheiten der jeweiligen Bauteile aufgelistet sind z.B.[HW_Einzelpreise] # Schaltschrank Einzelpreis schaltschrankgehaeuse_b1x800_zubehoer = 2000 """ self._hasConfig = True if os.path.exists(path): self._cfg = configparser.ConfigParser(inline_comment_prefixes="#") self._cfg.optionxform = str self._cfg.read_file(open(path)) else: self._hasConfig = False self._cfg = None def exists(self): return self._hasConfig def isfloat(self, num): try: float(num) return True except ValueError: return False def getTypedDict(self, section:str): """ Schreibt die Zuordnungen von Bauteil:Stückpreis/Zeiteinheit (je nach gewählter Überschrift) aus der config-Datei in ein Dictionary. :param section: Überschrift in der config-Datei z.B. "HW_Einzelpreise" """ if section not in self._cfg.sections(): return dict() res = dict() for key, val in self._cfg.items(section): if val.lower() in ['true']: res[key] =True elif val.lower() in ['false']: res[key] =False elif val.startswith("-"): res[key] = float(val) elif self.isfloat(val): res[key] = float(val) else: res[key] = val return res def to_dicts(eas:rek.EA, hw:rek.HW, emo:rek.EMO, dl:rek.Dienstleistung, erg:rek.Ergebnis): dEas = eas.getSEAs(order_eas) dEas['Summe Komponenten'] = [eas.gesamt_E(), eas.gesamt_A()] dEas['Summe Komponenten inkcl. Reserve'] = [eas.gesamt_E_incl_reserve(), eas.gesamt_A_incl_reserve()] dhardware = hw.to_dict() hoursEMO = emo.to_dict() dDienstleistung = dl.to_dict() dSummary = erg.summary_costs(hw) return (dEas, dhardware, hoursEMO, dDienstleistung, dSummary) def to_json(eas:rek.EA, hw:rek.HW, emo:rek.EMO, dl:rek.Dienstleistung, erg:rek.Ergebnis, outfile): (dEas, hardware, hoursEMO, dienstleistung, ergebnisse) = to_dicts(eas, hw, emo, dl, erg) dOut = { 'ergebnisse': ergebnisse, 'hardware': hardware, 'eas': dEas, 'dienstleistung': dienstleistung, 'emo': hoursEMO, } with open(outfile, 'w', encoding ='utf8') as json_file: json.dump(dOut, json_file, ensure_ascii=False, indent=2) def to_excel(eas:rek.EA, hw:rek.HW, emo:rek.EMO, dl:rek.Dienstleistung, erg:rek.Ergebnis, outfile): (dEas, hardware, hoursEMO, dienstleistung, ergebnisse) = to_dicts(eas, hw, emo, dl, erg) df_temp = pd.DataFrame.from_dict(data=dEas, orient='index', columns=['S.E', 'S.A']) df_eas = pd.DataFrame(data=df_temp, index=order_eas) df_temp = pd.DataFrame.from_dict(data=hardware, orient='index', columns=['Strück']) df_hardware = pd.DataFrame(data=df_temp, index=order_hardware) df_temp = pd.DataFrame.from_dict(data=hoursEMO, orient='index', columns=['Aufwand [h]']) df_emo = pd.DataFrame(data=df_temp, index=order_emo) df_temp = pd.DataFrame.from_dict(data=dienstleistung, orient='index', columns=['Aufwand [h]']) df_dienst = pd.DataFrame(data=df_temp, index=order_dienstleistungen) df_temp = pd.DataFrame.from_dict(data=ergebnisse, orient='index', columns=['Aufwand [€]']) df_aufwand = pd.DataFrame(data=df_temp, index=order_ergebnisse) #df = pd.DataFrame.from_dict(data=dienstleistung, orient='index', columns=['Dienstleistungen']) with pd.ExcelWriter(outfile) as writer: df_aufwand.to_excel(writer, sheet_name='Kostenaufstellung') df_hardware.to_excel(writer, sheet_name='Hardware') df_dienst.to_excel(writer, sheet_name='Dienstleistungen') df_eas.to_excel(writer, sheet_name='EAs') df_emo.to_excel(writer, sheet_name='EMO') # TODO Mengengerüst, ev. Anschlussleistung und Ausgangsstrom def run_calc(infile, SivasConfig): infileCfg = cfg(infile) Anzahl_MG = infileCfg.getTypedDict("allgemein") rsm_direct_eingabe = infileCfg.getTypedDict("rsm_direct") rsm_fa_eingabe = infileCfg.getTypedDict("rsm_fa") flyer_f40_eingabe = infileCfg.getTypedDict("flyer_f40") neuenhauser_eingabe = infileCfg.getTypedDict("neuenhauser") flyer_eingabe = infileCfg.getTypedDict("flyer") verbindungsstrecken_w_eingabe = infileCfg.getTypedDict("verbindungsstrecken_w") puffer_eingabe = infileCfg.getTypedDict("puffer") turm_eingabe = infileCfg.getTypedDict("turm") mg = rek.MG(Anzahl_MG, rsm_direct=rsm_direct_eingabe, rsm_fa=rsm_fa_eingabe, flyer_f40=flyer_f40_eingabe, neuenhauser=neuenhauser_eingabe, flyer=flyer_eingabe, verbindungsstrecken_w=verbindungsstrecken_w_eingabe, puffer=puffer_eingabe, turm=turm_eingabe) anStr = SivasConfig.getTypedDict("Antriebsstrom") cosPhi = SivasConfig.getTypedDict("cos phi") al = rek.Anschlussl(anStr, cosPhi) Anzahl_AL ={} al.calc(Anzahl_AL, mg) # self.assertEqual(al._ANZAHL.get("Anzahl_Motor"), 48) # self.assertAlmostEqual(al._ANZAHL.get("Summe_Strom_Motor"), 26.4) # self.assertAlmostEqual(al._ANZAHL.get("Summe_Strom_Motor_SPS_Peripherie"), 29.4) # self.assertAlmostEqual(al._ANZAHL.get("GZF"), 16.2) # self.assertAlmostEqual(al._ANZAHL.get("Res"), 1.62) # self.assertAlmostEqual(al._ANZAHL.get("Gesamtstrom"), 17.82) # self.assertAlmostEqual(al._Anschlussspannung, 400) # self.assertAlmostEqual(al._ANZAHL.get("Leistung"), 12.345696) # self.assertAlmostEqual(al._ANZAHL.get("Gesamtanschlussleistung"), 13) Anzahl_EAS = infileCfg.getTypedDict("EAS") eas = rek.EA(Anzahl_EAS, mg) hwep = SivasConfig.getTypedDict("HW_Einzelpreise") hwhp = SivasConfig.getTypedDict("HW_Zeiten Hardwareplanung") hwzew = SivasConfig.getTypedDict("HW_Zeiten Elektro-Werkstatt") Anzahl_HW = infileCfg.getTypedDict("HW") hw = rek.HW(hwep, hwhp, hwzew) hw.calc(Anzahl_HW, mg, eas) emoz = SivasConfig.getTypedDict("ElektSro-Montagezeiten") emo = rek.EMO(emoz) emo.calc(eas, hw, mg) Anzahl_DL = infileCfg.getTypedDict("DL") dl = rek.Dienstleistung(Anzahl_DL, hw) Anzahl_Ergebnis = infileCfg.getTypedDict("Ergebnis") kph = SivasConfig.getTypedDict("Kosten pro h") erg = rek.Ergebnis(kph) erg.calc(Anzahl_Ergebnis, hw, dl, emo) return (eas, hw, emo, dl, erg) if __name__ == '__main__': parser = argparse.ArgumentParser(description='calculation of a system according to Bös', prog='ecalc') parser.add_argument('-i', '--infile', action='store', help='name of the input file', default="jayjay.cfg") parser.add_argument('-x', '--xlsx', action='store', help='name of the output .xlsx file. If none given, name of the input file is used.') parser.add_argument('-c', '--config', action='store', help='name of the config file inside of cfg folder to use. Default is Sivas_Daten.cfg', default="Sivas_Daten.cfg") parser.add_argument('-j', '--json', action='store', help='name of the json file as output. If none given, name of the input file is used. ') args = parser.parse_args() sivasCfgFilePath = os.path.join(os.environ.get('ECALC_CFG'), args.config) RieterConfig = cfg(sivasCfgFilePath) inFilePath = os.path.join(os.environ.get('ECALC_WORK'), args.infile) if os.path.isfile(inFilePath): (fname, ext) = os.path.splitext(args.infile) (eas, hw, emo, dl, erg) = run_calc(inFilePath, RieterConfig) if args.xlsx: xlsPath = os.path.join(os.environ.get('ECALC_WORK'), args.xlsx) else: xlsPath = os.path.join(os.environ.get('ECALC_WORK'), fname + '.xlsx') to_excel(eas, hw, emo, dl, erg, xlsPath) if args.json: jsonPath = os.path.join(os.environ.get('ECALC_WORK'), args.json) else: jsonPath = os.path.join(os.environ.get('ECALC_WORK'), fname + '.json') to_json(eas, hw, emo, dl, erg, jsonPath) else: print("no such file in ECALC_WORK") # os.environ.get('ECALC_BIN') # os.environ.get('ECALC_WORK') # os.environ.get('ECALC_CFG') # os.environ.get('ECALC_LIB')