import argparse import configparser import os import shutil import subprocess import sys import csv """ Diese Library erzeugt Dateien mit RuleDesigner-, bzw. SIVAS-Informationen, bzw. stellt diese durch Kopieren / Verschieben von bereits vorhandenen Dateien auf Netzlaufwerken bereit """ def get_blacklist(outdir): """ Schreibt Teilenummern aus der nachfolgenden .ini-Datei in eine .txt-Datei: -> Dateipfad: //ruledesigner/RDF_Daten/Configurator/CustomVaulting/ERP_BOM.ini' -> Abschnitt: 'Settings' -> Schlüssel: 'PartNumbersToDrop' Bei diesen Teilenummern darf keine Stücklistenübergabe an SIVAS erfolgen, da sich die Stücklistenstruktur zwischen dem CAD und SIVAS unterscheidet (vorrangig bei Baugruppen mit Lieferantenbeistellungen) """ blacklist_net_share = os.environ.get("BLACKLIST_DATABASE_SOURCE") blacklist_ini_filename = os.environ.get("BLACKLIST_DATABASE_NAME") blacklist_source_path = os.path.join(blacklist_net_share, blacklist_ini_filename) config = configparser.RawConfigParser() if not os.path.isfile(blacklist_source_path): raise FileNotFoundError(f"Kein Zugriff auf ini-Datei '{blacklist_source_path}' mit den Blacklist-Teilenummern möglich. Bitte $BLACKLIST_DATABASE_SOURCE & $BLACKLIST_DATABASE_NAME in cremig_setenv.bat sowie VPN-Verbindung prüfen") try: config.read(blacklist_source_path) except configparser.DuplicateOptionError: pass content = config.get('Settings','PartNumbersToDrop') if isinstance(content, list): content = content[0] # Manchmal wird String mit den Blacklist-Nummern in einer Liste geschrieben - warum wissen die Götter... if len(content) == 0: raise ValueError(f"Öffnen der Blacklist-Datei'{blacklist_ini_filename}' in '{blacklist_net_share}' fehlgeschlagen") blacklist = content.split(';') outfile = os.path.join(outdir, 'blacklist.txt') print(f"Schreibe Blacklist-Teilenummern in '{outfile}'...") with open(outfile, 'w', encoding='utf-8') as fh: fh.write('\n'.join(blacklist)) def get_ruledesigner_ids(out_dir=os.environ.get('CREMIG_DATA')): """Kopiert CSV-Datei, in der alle RuleDesigner-Teilenummern aufgelistet sind, vom Netzlaufwerk in ein lokales Verzeichnis""" rd_csv_source_dir = os.environ.get("RD_DATABASE_SOURCE") rd_csv_filename = os.environ.get("RD_DATABASE_NAME") csv_source_path = os.path.join(rd_csv_source_dir, rd_csv_filename) csv_destiny_path = os.path.join(out_dir, rd_csv_filename) if not os.path.isfile(csv_source_path): raise FileNotFoundError(f"CSV-Datei mit RuleDesigner-Teilenummern existiert nicht unter '{csv_source_path}'. Bitte $RD_DATABASE_SOURCE & $RD_DATABASE_NAME in cremig_setenv.bat prüfen.") if not os.path.isdir(out_dir): raise NotADirectoryError(f"Zielverzeichnis '{out_dir}' für CSV-Datei mit RuleDesigner-Teilenummern existiert nicht. Bitte $CREMIG_DATA in cremig_setenv.bat und VPN-Verbindung prüfen") print(f"Kopiere '{rd_csv_source_dir}\\{rd_csv_filename}'...") shutil.copyfile(csv_source_path, csv_destiny_path) def get_sivas_bom(sivas_id, out_dir=os.environ.get('CREMIG_DATA')): """Generiert JSON-Datei, in der die Stücklisteninformationen zu einer SIVAS-Teilenummer mit Stammstückliste gespeichert sind. Die Erstellung der JSON-Datei erfolgt unter Verwendung des externen Sivas2Json-Programms von Hr. Jakob""" sivas2json_exe_path = os.environ.get('SIVAS_BOM') sivas_id = sivas_id.replace(".json", "") if not os.path.isfile(sivas2json_exe_path): raise FileNotFoundError(f"Programmpfad '{sivas2json_exe_path}' nicht erreichbar. Bitte prüfen, ob Zugriff auf Laufwerk Y: besteht. Andernfalls $SIVAS_BOM in cremig_setenv.bat sowie VPN-Verbindung prüfen") if not os.path.isdir(out_dir): raise NotADirectoryError(f"Ausgabeverzeichnis '{out_dir}' für die Stücklisten-JSON existiert nicht. Bitte $SIVAS_BOM in cremig_setenv.bat oder VPN-Verbindung prüfen.") print(f"Erstelle JSON mit Stücklisteninformationen...") subprocess.run(f'{sivas2json_exe_path} -o {out_dir} --format json -number "{sivas_id}"') if not os.path.isfile(os.path.join(out_dir, sivas_id + ".json")): raise ValueError(f"{sivas_id}.json konnte nicht erzeugt werden. Evtl. Nummer ohne Stückliste.") def get_sivas_teilestamm(sivas_ids, out_dir=os.environ.get('CREMIG_DATA'), overwrite=True): """ Generiert für jede angegebene SIVAS-Teilenummer eine CSV-Datei, in der die Teilestamm-Informationen gespeichert sind Es kann eine oder mehrere Nummern angegeben werden. Mehrere Nummern sind entweder als kommaseparierter String oder in Form einer Liste anzugeben """ sivas_teilestamm_exe = os.environ.get('SIVAS_TEILESTAMM') if not os.path.isfile(sivas_teilestamm_exe): raise FileNotFoundError(f"Programmpfad '{sivas_teilestamm_exe}' nicht erreichbar. Bitte prüfen, ob Zugriff auf Laufwerk Y: besteht. Andernfalls $SIVAS_TEILESTAMM in cremig_setenv.bat sowie VPN-Verbindung prüfen") if not os.path.isdir(out_dir): raise NotADirectoryError(f"Ausgabeverzeichnis '{out_dir}' für die Teilestamm-CSV existiert nicht. Bitte $SIVAS_TEILESTAMM in cremig_setenv.bat oder VPN-Verbindung prüfen.") if isinstance(sivas_ids, str): sivas_ids = list(set(sivas_ids.strip().split(","))) ids_to_generate = [] for id in sivas_ids: if not overwrite and os.path.isfile(os.path.join(out_dir, id + ".csv")): continue ids_to_generate.append(id) if len(ids_to_generate) == 0: print("CSV-Datei(en) existieren bereits oder angegebene Teilenummer(n) sind bereits migriert") return ids_to_generate_str = ",".join([f'"{id}"' for id in ids_to_generate]) # Anführungszeichen erforderlich, damit Art.Nr. mit Leerzeichen, z.B. "TOS Auswahl ILS" funktionieren os.environ["SIVAS_EXCEL_EXPORT_DIR"] = out_dir # Umgebungsvariable legt Ausgabeverzeichnis der CSV-Dateien im Programm 'KSbExcelExportSivasTeilestamm' fest. Der Variablenname ist durch genanntes Programm vorgegeben, siehe help-Text des Programms! print(f"Erstelle CSV(s) mit Teilestamminformationen...") subprocess.run(f'{sivas_teilestamm_exe} -teilenr={ids_to_generate_str} -open_target_dir=n') # Prüft Existenz der angegebenen SIVAS-Nummern, indem geschaut wird, ob die CSV-Dateien 2 Zeilen aufweisen # Nicht über Returncode des Subprocess ermittelbar, da dieser immer 0 ist, auch wenn die Nr. nicht in SIVAS existiert for id in ids_to_generate: csv_path = os.path.join(out_dir, id + ".csv") with open(csv_path, encoding="utf-8", newline="") as csv_file: csv_data = csv.reader(csv_file, delimiter=";") line_nums = sum(1 for row in csv_data) if line_nums != 2: raise ValueError(f"SIVAS-Teilenummer '{id}' existiert nicht! Bitte prüfen, ob Nummer korrekt geschrieben wurde!") if __name__ == '__main__': parser = argparse.ArgumentParser(description='Erzeugt Dateien mit RuleDesigner-, bzw. SIVAS-Informationen, bzw. stellt diese bereit', prog='update_database') parser.add_argument('-b', '--blacklist', action='store_true', help='Schreibe .txt-Datei mit allen Teilenummern, bei denen keine Stücklistenübergabe aus dem CAD nach SIVAS erfolgen darf') parser.add_argument('-d', '--out_dir', action='store', default=os.environ.get('CREMIG_DATA'), help='Ausgabeverzeichnis für Datei', metavar="dir") parser.add_argument('-m', '--bom', action='store_true', help='Schreibe Stückliste einer SIVAS-Teilenummer als JSON-Datei') parser.add_argument('-o', '--overwrite', action='store_true', default=False, help='Überschreibe Datei, wenn diese bereits in Zielverzeichnis vorliegt') parser.add_argument('-r', '--rd_ids', action='store_true' ,help='Kopiere CSV-Datei, in der alle RuleDesigner-Teilenummern aufgelistet sind') parser.add_argument('-s', '--sivasid', action='store', help='SIVAS-Teilenummer', metavar='id') parser.add_argument('-t', '--teilestamm', action='store_true', help='Schreibe Teilestamm-Medataten einer SIVAS-Teilenummer als CSV-Datei') args = parser.parse_args() if len(sys.argv) == 1: parser.print_help() if args.rd_ids: get_ruledesigner_ids(args.out_dir) if args.blacklist: get_blacklist(args.out_dir) if args.sivasid: if args.teilestamm: get_sivas_teilestamm(args.sivasid, args.out_dir, overwrite = True) if args.bom: get_sivas_bom(args.sivasid, args.out_dir)