diff --git a/lib/controller.py b/lib/controller.py index 9ee4678..606011a 100644 --- a/lib/controller.py +++ b/lib/controller.py @@ -2,7 +2,7 @@ import os from tkinter import messagebox import update_database -from manage_configs import SivasAssemblyData, RuleDesignerDatabaseConfig, MigrationStatus +from manage_configs import SivasBOM, RuleDesignerDatabaseConfig, MigrationStatus """ Contains the logic for the MVC of CreoMigrate Gui @@ -120,7 +120,7 @@ class Controller(Observer): data_dir = self.get_env("data") rd_dbase_filename = self.get_env("rd_dbase_filename") - asm_data = SivasAssemblyData(data_dir, asm_id + '.json', load_local_asm_json) + asm_data = SivasBOM(data_dir, asm_id + '.json', load_local_asm_json) rd_data = RuleDesignerDatabaseConfig(data_dir, rd_dbase_filename, load_local_rd_dbase) migration_status = MigrationStatus(asm_data.child_ids, rd_data.ids) diff --git a/lib/manage_configs.py b/lib/manage_configs.py index c1243c8..82f8839 100644 --- a/lib/manage_configs.py +++ b/lib/manage_configs.py @@ -19,12 +19,9 @@ class JsonBasedConfig: def load_json_from_file(self): """lade das json file vom gegeben Pfad in ein json Objekt""" - try: - with open(self._config_path, 'r', encoding='utf-8') as fh: - content = fh.read() - return json.loads(content) - except FileNotFoundError: - raise ValueError("Bitte prüfen, ob korrekte Teilenummer, bzw. korrekter Dateiname angegeben wurde.") + with open(self._config_path, 'r', encoding='utf-8') as fh: + content = fh.read() + return json.loads(content) def from_json(self, json_str): """nimm den Json String zur Initialisierung des Objektes""" @@ -99,45 +96,63 @@ class RuleDesignerSQLData(SQLBasedConfig): return self._rd_statuses -class SivasAssemblyData(JsonBasedConfig): +class SivasBOM(JsonBasedConfig): """Auslesen der Assembly-Informationen zu einer angegebenen Baugruppennummer""" def __init__(self, config_dir: str, config_file: str, load_local_json=False): super().__init__(config_dir, config_file) self._load_local_json = load_local_json - self._asm_data = None + self._bom_data = None self._child_ids = None self._parent_children = None self._longest_child_id = None self._max_bom_depth = None - self._property_names = None self._all_bom_properties = None - def create_asm_json(self): + def create_asm_json(self) -> bool: """Erstellt JSON mit den aktuellen Baugruppeninformationen""" - try: - update_database.get_sivas_bom(self._config_file.removesuffix(".json")) - except: - raise ValueError("JSON-Datei mit Baugruppeninformationen konnte nicht erstellt werden!") + + update_database.get_sivas_bom(self._config_file.removesuffix(".json")) + @property - def asm_data(self) -> dict: - """Liest die Baugruppen-JSON ein und gibt deren Informationen zurück""" - if self._asm_data is None: + def bom_data(self) -> dict: + """ Liest die JSON-Datei der Baugruppenstückliste ein und speichert die Informationen als dict. """ + + if self._bom_data is None: + + """ + Falls die JSON nicht existiert oder nicht generiert werden kann, soll die Möglichkeit bestehen, + diese eigenständig zu erweitern, da in der JSON z.B. die Nummer der obersten Baugruppe standardmäßig + nicht vorliegt. Generierungs- und Einlese-Fehler werden daher bewusst ignoriert, um stattdessen ein leeres + dict zurückzugeben, das anschließend erweitert werden kann. + + Die Möglichkeit zur Erweiterung der Stückliste ermöglicht es zudem, Teilenummern ohne Stückliste abzubilden. + Das funktioniert, indem man die Teilenummer ohne eigene Stückliste als Kind einer fiktiven Baugruppe "None" + ansieht / definiert. Dadurch ist keine separate Logik erforderlich, die sich nur mit Teilenummern + ohne Stückliste befasst. + """ + + self._bom_data = {} if not self._load_local_json: - self.create_asm_json() + try: + self.create_asm_json() + except ValueError: + pass + try: + self._bom_data = self.load_json_from_file() + except FileNotFoundError: + pass - self._asm_data = self.load_json_from_file() - - return self._asm_data + return self._bom_data @property def child_ids(self) -> set: """Gibt alle Teilenummern der Stückliste zurück (auch Teilenummern aus tieferen Baugruppenebenen)""" if self._child_ids is None: - self._child_ids = set(self.asm_data.keys()) + self._child_ids = set(self.bom_data.keys()) return self._child_ids @property @@ -147,7 +162,7 @@ class SivasAssemblyData(JsonBasedConfig): if self._parent_children is None: unordered_parent_children = {} - for child_id, parent_properties in self.asm_data.items(): + for child_id, parent_properties in self.bom_data.items(): for parent_property in parent_properties: parent_id = parent_property["Parent"] child_posnr_in_parent_bom = int(parent_property["Position"].lstrip(".").split("/")[0]) @@ -180,20 +195,11 @@ class SivasAssemblyData(JsonBasedConfig): ] }""" - - property_names = self.property_names - - asm_data = self.asm_data - - if id not in asm_data: - self._asm_data[id] = [] - - for property_name in property_names: - if property_name not in metadata: - metadata[property_name] = None + if id not in self.bom_data: + self._bom_data[id] = [] - self._asm_data[id].append(metadata) - return self._asm_data + self._bom_data[id].append(metadata) + return self._bom_data @property def longest_child_id(self) -> str: @@ -209,44 +215,32 @@ class SivasAssemblyData(JsonBasedConfig): if self._max_bom_depth is None: bom_levels = [] - for parents in self.asm_data.values(): + for parents in self.bom_data.values(): for parent in parents: current_bom_level = parent["Position"].count(".") bom_levels.append(current_bom_level) self._max_bom_depth = max(bom_levels) return self._max_bom_depth - @property - def property_names(self) -> list: - """Gibt alle Eigenschaftsnamen zurück, die in der Assembly-json-Datei enthalten sind""" - - if self._property_names is None: - for parent_data in self.asm_data.values(): - self._property_names = list(parent_data[0]) - return self._property_names - def get_prop_val_for_single_id(self, id:str, property_name:str) -> str: """Gibt eine Eigenschaft von einer einzelnen Teilenummer aus der Stückliste zurück""" - if id not in self._asm_data: - raise KeyError("Angegebene Teilenummer befindet sich nicht in der Baugruppe!") + if id not in self._bom_data: + raise ValueError("Teilenummer befindet sich nicht in der Baugruppe!") - if property_name not in self._asm_data[id][0]: - raise ValueError(f"Teilenummer besitzt nicht die angegebene Eigenschaft '{property_name}'") + if property_name not in self._bom_data[id][0]: + return - return self._asm_data[id][0][property_name] + return self._bom_data[id][0][property_name] def get_prop_val_for_all_ids(self, property_name) -> dict: """Gibt eine Eigenschaft zu allen Teilenummern der Stückliste zurück (z.B. Bezeichnung)""" - if property_name not in self.property_names: - raise ValueError("Angegebener Eigenschaftsname exisitert nicht!") - id_property_mapping = {} - for child, parent_data in self.asm_data.items(): - for properties in parent_data: - if property_name in properties: - id_property_mapping[child] = properties[property_name] + for child_id, asm_usages in self.bom_data.items(): + child_properties = asm_usages[0] + id_property_mapping[child_id] = None if property_name not in child_properties else child_properties[property_name] + return id_property_mapping @property @@ -254,9 +248,16 @@ class SivasAssemblyData(JsonBasedConfig): """Gibt alle Eigenschaften zu den Teilenummern der Stückliste zurück (z.B. Bezeichnung)""" if self._all_bom_properties is None: + self._all_bom_properties = {} - for property_name in self.property_names: - self._all_bom_properties[property_name] = self.get_prop_val_for_all_ids(property_name) + + for child_id, asm_usages in self.bom_data.items(): + child_properties = asm_usages[0] + for property_name, property_val in child_properties.items(): + if property_name not in self._all_bom_properties: + self._all_bom_properties[property_name] = {} + self._all_bom_properties[property_name][child_id] = property_val + return self._all_bom_properties @@ -338,34 +339,34 @@ class MigrationStatus: return self._ids_pending -class TeilestammMetadata(CSVBasedConfig): +class SivasTeilestamm(CSVBasedConfig): def __init__(self, config_dir, config_file, load_local_csv=False): super().__init__(config_dir, config_file) self._load_local_csv = load_local_csv - self._csv_data = None + self._data = None @staticmethod def create_csvs(ids): """Erstellt CSV-Datei(en) mit den Teilestamminformationen zu der / den angegebenen Teilenummer(n)""" - try: - update_database.get_sivas_teilestamm(ids) - except: - raise ValueError("CSV(s) konnte nicht generiert werden!") + + update_database.get_sivas_teilestamm(ids) @property - def csv_data(self): + def teilestamm_data(self): """Gibt CSV-Daten als Dataframe zurück""" - if self._csv_data is None: + + if self._data is None: if not self._load_local_csv: self.create_csvs(self._config_file.removesuffix(".csv")) - self._csv_data = self.load_csv_from_file() - return self._csv_data + self._data = self.load_csv_from_file() + + return self._data def get_property_values(self, property_name) -> str: """Gibt Wert aus der CSV für den angegebenen Spaltennamen zurück""" - ret = self.csv_data[property_name][0] + ret = self.teilestamm_data[property_name][0] return ret