In 'manage_configs.py' Klasse 'SivasAssemblyData' in 'SivasBOM' und Klasse 'TeilestammMetadata' in 'SivasTeilestamm' umbenannt, da eindeutiger. In 'controller.py' Namen entsprechend aktualisiert. Zudem in 'manage_configs.py' Klasse 'SivasBOM' die Methode 'asm_data' in 'bom_data' umbenannt. Darüber hinaus gibt die Methode nun ein leeres Dict zurück, wenn keine JSON vorliegt oder keine generiert werden konnte. Dies wurde vorgesehen, um im Migrationsüberblick (Treeview) sowie dem Migrationstool (CreoMigrate) auch Teilenummern ohne Stückliste, d.h. ohne JSON abbilden zu können (genaue Funktionsweise siehe mehrzeiliger Kommentar in genannter Methode). Abgesehen davon Methode 'property_names' komplett entfernt, da diese fehlerhaft funktioniert hat, da jedes Mal durch alle Kinder der Assembly geloopt wurde und die Eigenschaften des aktuellen Kindes wie z.B. 'Bezeichnung', 'Parent', etc. ausgelesen wurden. Der Fehler liegt darin, dass die Eigenschaften der Nummer aus der vorherigen Iteration komplett überschrieben, aber nicht ergänzt wurden, falls in der aktuellen Iteration Eigenschaften vorliegen, die in der vorherigen noch nicht vorlagen. Um dieses Problem ganz zu umgehen, wurden die Methoden 'get_prop_val_for_all_ids' und 'all_bom_properties' umgeschrieben, sodass die Eigenschaften direkt innerhalb dieser Funktionen geholt werden

This commit is contained in:
2025-04-20 12:05:46 +02:00
parent 56ff5010c7
commit 623f4a12e1
2 changed files with 74 additions and 73 deletions
+2 -2
View File
@@ -2,7 +2,7 @@ import os
from tkinter import messagebox from tkinter import messagebox
import update_database 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 Contains the logic for the MVC of CreoMigrate Gui
@@ -120,7 +120,7 @@ class Controller(Observer):
data_dir = self.get_env("data") data_dir = self.get_env("data")
rd_dbase_filename = self.get_env("rd_dbase_filename") 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) rd_data = RuleDesignerDatabaseConfig(data_dir, rd_dbase_filename, load_local_rd_dbase)
migration_status = MigrationStatus(asm_data.child_ids, rd_data.ids) migration_status = MigrationStatus(asm_data.child_ids, rd_data.ids)
+66 -65
View File
@@ -19,12 +19,9 @@ class JsonBasedConfig:
def load_json_from_file(self): def load_json_from_file(self):
"""lade das json file vom gegeben Pfad in ein json Objekt""" """lade das json file vom gegeben Pfad in ein json Objekt"""
try:
with open(self._config_path, 'r', encoding='utf-8') as fh: with open(self._config_path, 'r', encoding='utf-8') as fh:
content = fh.read() content = fh.read()
return json.loads(content) return json.loads(content)
except FileNotFoundError:
raise ValueError("Bitte prüfen, ob korrekte Teilenummer, bzw. korrekter Dateiname angegeben wurde.")
def from_json(self, json_str): def from_json(self, json_str):
"""nimm den Json String zur Initialisierung des Objektes""" """nimm den Json String zur Initialisierung des Objektes"""
@@ -99,45 +96,63 @@ class RuleDesignerSQLData(SQLBasedConfig):
return self._rd_statuses return self._rd_statuses
class SivasAssemblyData(JsonBasedConfig): class SivasBOM(JsonBasedConfig):
"""Auslesen der Assembly-Informationen zu einer angegebenen Baugruppennummer""" """Auslesen der Assembly-Informationen zu einer angegebenen Baugruppennummer"""
def __init__(self, config_dir: str, config_file: str, load_local_json=False): def __init__(self, config_dir: str, config_file: str, load_local_json=False):
super().__init__(config_dir, config_file) super().__init__(config_dir, config_file)
self._load_local_json = load_local_json self._load_local_json = load_local_json
self._asm_data = None self._bom_data = None
self._child_ids = None self._child_ids = None
self._parent_children = None self._parent_children = None
self._longest_child_id = None self._longest_child_id = None
self._max_bom_depth = None self._max_bom_depth = None
self._property_names = None
self._all_bom_properties = None self._all_bom_properties = None
def create_asm_json(self): def create_asm_json(self) -> bool:
"""Erstellt JSON mit den aktuellen Baugruppeninformationen""" """Erstellt JSON mit den aktuellen Baugruppeninformationen"""
try:
update_database.get_sivas_bom(self._config_file.removesuffix(".json")) update_database.get_sivas_bom(self._config_file.removesuffix(".json"))
except:
raise ValueError("JSON-Datei mit Baugruppeninformationen konnte nicht erstellt werden!")
@property @property
def asm_data(self) -> dict: def bom_data(self) -> dict:
"""Liest die Baugruppen-JSON ein und gibt deren Informationen zurück""" """ Liest die JSON-Datei der Baugruppenstückliste ein und speichert die Informationen als dict. """
if self._asm_data is None:
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: if not self._load_local_json:
try:
self.create_asm_json() 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._bom_data
return self._asm_data
@property @property
def child_ids(self) -> set: def child_ids(self) -> set:
"""Gibt alle Teilenummern der Stückliste zurück (auch Teilenummern aus tieferen Baugruppenebenen)""" """Gibt alle Teilenummern der Stückliste zurück (auch Teilenummern aus tieferen Baugruppenebenen)"""
if self._child_ids is None: 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 return self._child_ids
@property @property
@@ -147,7 +162,7 @@ class SivasAssemblyData(JsonBasedConfig):
if self._parent_children is None: if self._parent_children is None:
unordered_parent_children = {} 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: for parent_property in parent_properties:
parent_id = parent_property["Parent"] parent_id = parent_property["Parent"]
child_posnr_in_parent_bom = int(parent_property["Position"].lstrip(".").split("/")[0]) child_posnr_in_parent_bom = int(parent_property["Position"].lstrip(".").split("/")[0])
@@ -180,20 +195,11 @@ class SivasAssemblyData(JsonBasedConfig):
] ]
}""" }"""
if id not in self.bom_data:
self._bom_data[id] = []
property_names = self.property_names self._bom_data[id].append(metadata)
return self._bom_data
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
self._asm_data[id].append(metadata)
return self._asm_data
@property @property
def longest_child_id(self) -> str: def longest_child_id(self) -> str:
@@ -209,44 +215,32 @@ class SivasAssemblyData(JsonBasedConfig):
if self._max_bom_depth is None: if self._max_bom_depth is None:
bom_levels = [] bom_levels = []
for parents in self.asm_data.values(): for parents in self.bom_data.values():
for parent in parents: for parent in parents:
current_bom_level = parent["Position"].count(".") current_bom_level = parent["Position"].count(".")
bom_levels.append(current_bom_level) bom_levels.append(current_bom_level)
self._max_bom_depth = max(bom_levels) self._max_bom_depth = max(bom_levels)
return self._max_bom_depth 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: 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""" """Gibt eine Eigenschaft von einer einzelnen Teilenummer aus der Stückliste zurück"""
if id not in self._asm_data: if id not in self._bom_data:
raise KeyError("Angegebene Teilenummer befindet sich nicht in der Baugruppe!") raise ValueError("Teilenummer befindet sich nicht in der Baugruppe!")
if property_name not in self._asm_data[id][0]: if property_name not in self._bom_data[id][0]:
raise ValueError(f"Teilenummer besitzt nicht die angegebene Eigenschaft '{property_name}'") 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: 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)""" """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 = {} id_property_mapping = {}
for child, parent_data in self.asm_data.items(): for child_id, asm_usages in self.bom_data.items():
for properties in parent_data: child_properties = asm_usages[0]
if property_name in properties: id_property_mapping[child_id] = None if property_name not in child_properties else child_properties[property_name]
id_property_mapping[child] = properties[property_name]
return id_property_mapping return id_property_mapping
@property @property
@@ -254,9 +248,16 @@ class SivasAssemblyData(JsonBasedConfig):
"""Gibt alle Eigenschaften zu den Teilenummern der Stückliste zurück (z.B. Bezeichnung)""" """Gibt alle Eigenschaften zu den Teilenummern der Stückliste zurück (z.B. Bezeichnung)"""
if self._all_bom_properties is None: if self._all_bom_properties is None:
self._all_bom_properties = {} 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 return self._all_bom_properties
@@ -338,34 +339,34 @@ class MigrationStatus:
return self._ids_pending return self._ids_pending
class TeilestammMetadata(CSVBasedConfig): class SivasTeilestamm(CSVBasedConfig):
def __init__(self, config_dir, config_file, load_local_csv=False): def __init__(self, config_dir, config_file, load_local_csv=False):
super().__init__(config_dir, config_file) super().__init__(config_dir, config_file)
self._load_local_csv = load_local_csv self._load_local_csv = load_local_csv
self._csv_data = None self._data = None
@staticmethod @staticmethod
def create_csvs(ids): def create_csvs(ids):
"""Erstellt CSV-Datei(en) mit den Teilestamminformationen zu der / den angegebenen Teilenummer(n)""" """Erstellt CSV-Datei(en) mit den Teilestamminformationen zu der / den angegebenen Teilenummer(n)"""
try:
update_database.get_sivas_teilestamm(ids) update_database.get_sivas_teilestamm(ids)
except:
raise ValueError("CSV(s) konnte nicht generiert werden!")
@property @property
def csv_data(self): def teilestamm_data(self):
"""Gibt CSV-Daten als Dataframe zurück""" """Gibt CSV-Daten als Dataframe zurück"""
if self._csv_data is None:
if self._data is None:
if not self._load_local_csv: if not self._load_local_csv:
self.create_csvs(self._config_file.removesuffix(".csv")) self.create_csvs(self._config_file.removesuffix(".csv"))
self._csv_data = self.load_csv_from_file() self._data = self.load_csv_from_file()
return self._csv_data
return self._data
def get_property_values(self, property_name) -> str: def get_property_values(self, property_name) -> str:
"""Gibt Wert aus der CSV für den angegebenen Spaltennamen zurück""" """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 return ret