From 02fd5e59d8152b3053e113844f7302b452f3312c Mon Sep 17 00:00:00 2001 From: "s.steuer" Date: Sun, 12 Nov 2023 00:43:48 +0100 Subject: [PATCH] =?UTF-8?q?compare=5Flists.py=20an=20ver=C3=A4ndertes=20JS?= =?UTF-8?q?ON-Format=20von=20Hr.=20Jakob=20angeglichen,=20da=20alle=20JSON?= =?UTF-8?q?-Subkeys=20nun=20in=20einer=20Liste=20liegen,=20sodass=20f?= =?UTF-8?q?=C3=BCr=20den=20Zugriff=20auf=20die=20Subkeys=20nun=20zus=C3=A4?= =?UTF-8?q?tzlich=20[0]=20ben=C3=B6tigt=20wird=20/=20Zudem=20Excel-Export?= =?UTF-8?q?=20umgeschrieben.=20Es=20wird=20nun=20die=20neue=20Excel-Macro-?= =?UTF-8?q?Datei=20(lib/vba=5Fformat=5Fexcel.xlsm)=20kopiert.=20Anschlie?= =?UTF-8?q?=C3=9Fend=20werden=20die=20Daten=20(Sortierung,=20Teilenummer,?= =?UTF-8?q?=20Migrationsstauts,=20etc.)=20in=20die=20Excel=20geschrieben.?= =?UTF-8?q?=20Das=20VBA-Makro=20sorgt=20dann=20beim=20ersten=20=C3=96ffnen?= =?UTF-8?q?=20der=20Excel=20daf=C3=BCr,=20dass=20die=20Daten=20automatisch?= =?UTF-8?q?=20in=20einer=20intelligenten=20Tabelle=20liegen=20sowie=20dass?= =?UTF-8?q?=20die=20bereits=20migrierten=20Nummern=20gr=C3=BCn=20und=20die?= =?UTF-8?q?=20noch=20nicht=20migrierten=20Teilenummern=20rot=20angezeigt?= =?UTF-8?q?=20werden.=20/=20Zudem=20wird=20nun=20Argparse-Help=20angezeigt?= =?UTF-8?q?,=20wenn=20Parameter=20fehlen=20/=20Argparse-Help=20versch?= =?UTF-8?q?=C3=B6nert?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/compare_lists.py | 68 ++++++++++++++++++++++++++++++++------------ 1 file changed, 50 insertions(+), 18 deletions(-) diff --git a/lib/compare_lists.py b/lib/compare_lists.py index 7b7ff09..74ec1eb 100644 --- a/lib/compare_lists.py +++ b/lib/compare_lists.py @@ -3,6 +3,7 @@ import argparse import os import json import pandas as pd +import openpyxl """ Dieses Programm kann: @@ -13,10 +14,13 @@ Dieses Programm kann: class Compare: + lib_dir = os.environ.get('CREMIG_LIB') data_dir = os.environ.get('CREMIG_DATA') out_dir = os.environ.get('CREMIG_WORK') ruledesigner_csv_filename = os.environ.get('RD_DATABASE_NAME') - ruledesigner_csv_path = os.path.join(data_dir, ruledesigner_csv_filename) + ruledesigner_csv_filepath = os.path.join(data_dir, ruledesigner_csv_filename) + vba_macro_filename = os.environ.get('VBA_MACRO_NAME') + vba_macro_filepath = os.path.join(lib_dir, vba_macro_filename) def __init__(self, main_sivas_id): self.main_sivas_id = main_sivas_id @@ -24,6 +28,7 @@ class Compare: self.sivas_ids = self.read_sivas_ids() self.ruledesigner_ids = self.read_ruledesigner_ids() + def read_sivas_ids(self): # Metohde liest die JSON-Datei ein, in der alle Sivas-Teilenummern aufgelistet sind, die zusammen mit der Hauptnummer migriert werden müssen @@ -37,19 +42,21 @@ class Compare: update_database.get_sivas_dbase(self.main_sivas_id, Compare.data_dir) return self.read_sivas_ids() + def read_ruledesigner_ids(self): # Methode liest die CSV-Datei ein, in der alle RuleDesigner-Nummern aufgelistet sind try: - df = pd.read_csv(Compare.ruledesigner_csv_path, sep=';', converters={"Teilenummer":str}) - return tuple(df["Teilenummer"]) + df = pd.read_csv(Compare.ruledesigner_csv_filepath, sep=';', converters={"Teilenummern":str}) + return tuple(df["Teilenummern"]) except FileNotFoundError: # CSV-Datei wurde noch nicht ins %CREMIG_DATA% kopiert update_database.get_rd_dbase(Compare.data_dir) return self.read_ruledesigner_ids() + def check_migration_status(self): # Methode prüft, ob die Sivas-Nummern bereits migriert wurden @@ -59,6 +66,7 @@ class Compare: migrated[id] = True if id in self.ruledesigner_ids else False return migrated + def create_sorting_string(self, id): # Methode setzt rekursiv einen String zusammen, der anzeigt, wo sich eine Teilenummer in der Hierarchie der obersten Baugruppe befindet. @@ -66,12 +74,13 @@ class Compare: # Die Teilenummer "123456" ist das Halbzeug der Teilenummer "234567". "234567" ist wiederum in der Baugruppe "345678" eingebaut. # Die Methode gibt dann folgenden String zurück: 345678-234567-123456 - parent = self.sivas_ids[id]['Parent'] + parent = self.sivas_ids[id][0]['Parent'] if parent not in self.sivas_ids: return f"{parent}-{id}" recur_val = self.create_sorting_string(parent) return f"{recur_val}-{id}" + def create_excel_export(self): # Spalten in Excel-Datei: Sortierung, Teilenummer, Bezeichnung, Bestandsabfrage, Teilebeurteilung, Zusatzbemerkung @@ -93,8 +102,8 @@ class Compare: for id in self.sivas_ids: sorting.append(self.create_sorting_string(id)) prt_num.append(id) - description.append(self.sivas_ids[id]['Bezeichnung']) - migration_status.append("VERFÜGBAR" if migrated[id] is True else False) + description.append(self.sivas_ids[id][0]['Bezeichnung']) + migration_status.append("VERFÜGBAR" if migrated[id] is True else "IMPORTIEREN") evaluation.append('') comment.append('') @@ -107,21 +116,44 @@ class Compare: "Bemerkung": comment } - filename = os.path.join(Compare.out_dir, self.main_sivas_id + ".xlsx") - df = pd.DataFrame.from_dict(data) - df.to_excel(filename, sheet_name="Ergebnis", index_label="Sortierung") + destiny_filepath = os.path.join(Compare.out_dir, self.main_sivas_id + ".xlsm") + + workbook = openpyxl.load_workbook(Compare.vba_macro_filepath, keep_vba=True) + worksheet = workbook.active + + # Überschriften eintragen + for header, column in zip(data, worksheet.iter_cols(min_row=1, max_col=len(data), max_row=1)): + for cell in column: + cell.value = header + + # Werte (unter Überschriften) eintragen + for value, column in (zip(data.values(), worksheet.iter_cols(min_row=2, max_col=len(data), max_row=len(sorting)))): + for cell, element in zip(column, value): + cell.value = element + + # Umbenennung des Blattes ist erforderlich, weil VBA Makro erst wirksam wird, wenn das Blatt nicht mehr "Sheet1" heißt + # Die Umbenennung darf nicht vor der Eintragung der Daten erfolgen, weil es sonst Probleme mit der bedingten Formatierung gibt + worksheet.title = "Ergebnis" + + workbook.save(destiny_filepath) print(f"Excel-Datei erfolgreich in '{Compare.out_dir}' geschrieben...") + def parent_children_mapping(self): # Methode erstellt dict mit allen Parents (Keys) der json-Datei und weist den Parents deren Kinder als Werte zu. parent_children = {} for id in self.sivas_ids: - parent = self.sivas_ids[id]["Parent"] + parent = self.sivas_ids[id][0]["Parent"] if parent not in parent_children: parent_children[parent] = [] parent_children[parent].append(id) return parent_children + + def get_excel_comments_for_treeview(self): + workbook = openpyxl.load() + pass + def create_treeview(self): symbols = { @@ -144,15 +176,15 @@ class Compare: parent_children = self.parent_children_mapping() - max_tree_depth = max(id_value["Position"].count(".") for id_value in self.sivas_ids.values()) + max_tree_depth = max(id_value[0]["Position"].count(".") for id_value in self.sivas_ids.values()) max_sivas_num_len = max([len(id) for id in self.sivas_ids.keys()]) - max_description_len = max([len(id_value["Bezeichnung"]) for id_value in self.sivas_ids.values()]) + max_description_len = max([len(id_value[0]["Bezeichnung"]) for id_value in self.sivas_ids.values()]) for i, id in enumerate(self.sivas_ids): - parent = self.sivas_ids[id]["Parent"] - description = self.sivas_ids[id]["Bezeichnung"] - current_key_level = self.sivas_ids[id]["Position"].count(".") + parent = self.sivas_ids[id][0]["Parent"] + description = self.sivas_ids[id][0]["Bezeichnung"] + current_key_level = self.sivas_ids[id][0]["Position"].count(".") # Aktueller Verbinder: └── , wenn letzter Knotenpunkt, sonst ├── connector = symbols['elbow'] if id == parent_children[parent][-1] else symbols['t'] @@ -174,7 +206,7 @@ class Compare: if (i + 1) != len(self.sivas_ids): next_key = list(self.sivas_ids)[i + 1] - next_key_level = self.sivas_ids[next_key]["Position"].count(".") + next_key_level = self.sivas_ids[next_key][0]["Position"].count(".") else: # Zu migrierende Nummer ist ein bearbeitetes Halbzeug. Programm muss hier beendet werden, da ansonsten später die # nächste Teilenummer der json benötigt wird. Diese exisitert aber nicht, weil die json nur eine Teilenummer enthält @@ -205,7 +237,7 @@ class Compare: if __name__ == '__main__': parser = argparse.ArgumentParser(description='Das Programm gibt Auskunft über den aktuellen Migrationsstand', prog='compare_lists') - parser.add_argument('-n', '--number', action='store', required=True, help='Eingabe der SIVAS-Teilenummer, für die der Migrationsstatus angezeigt werden soll') + parser.add_argument('-n', '--number', action='store', required=True, help='Eingabe der SIVAS-Teilenummer, für die der Migrationsstatus angezeigt werden soll', metavar="id") parser.add_argument('-t', '--tree', action='store_true', help='Erzeugt Baumdarstellung aller Teilenummern. grün = Teilenummer vorhanden, rot = Migration ausstehend') parser.add_argument('-e', '--excel', action='store_true', help='Erzeugt Excel-Datei in der alle Teilenummern, die migriert werden müssen, aufgelistet sind') @@ -218,4 +250,4 @@ elif args.tree: treeview_comparison = Compare(args.number) treeview_comparison.create_treeview() else: - print("Bitte entweder '-e' für Excel-Export oder '-t' für Treeview-Ausgabe angeben.") \ No newline at end of file + parser.print_help() \ No newline at end of file