Treeview angepasst, damit die Bezeichnung der obersten Baugruppe angezeigt wird, da dies bisher nicht der Fall war. Da die Bezeichnung nicht in der Baugruppen-JSON aufgeführt ist, ist es erforderlich die CSV mit den Teilestamm-Metadaten zur Baugruppennummer herunterzuladen. Damit dies möglich ist, wurde wurde in manage_configs.py eine neue Subclass 'TeilestammMetadata' ergänzt. In compare_lists.py wurden dabei weitere Flags ergänzt, mit denen gesteuert werden kann, ob die Bezeichnung aus der lokalen CSV-Datei gezogen werden sollen, oder ob die CSV mit jedem Programmlauf neu erstellt wird. Defaultmäßig wird sie mit jedem Programmlauf neu erstellt

This commit is contained in:
2025-03-09 21:22:15 +01:00
parent 4f740e81ad
commit 5f3615548b
3 changed files with 111 additions and 33 deletions
+75 -23
View File
@@ -1,4 +1,4 @@
from manage_configs import SivasAssemblyData, RuleDesignerDatabaseConfig, MigrationStatus
from manage_configs import SivasAssemblyData, RuleDesignerDatabaseConfig, MigrationStatus, TeilestammMetadata
import argparse
import os
@@ -13,7 +13,14 @@ Dieses Programm kann:
class ExcelExport:
def __init__(self, asm_id, asm_json_dir, asm_json_filename, rd_dbase_dir, rd_dbase_filename, load_local_asm_json, load_local_rd_dbase):
def __init__(self,
asm_id,
asm_json_dir,
asm_json_filename,
rd_dbase_dir,
rd_dbase_filename,
load_local_asm_json,
load_local_rd_dbase):
self.asm_id = asm_id
self.asm_data = SivasAssemblyData(asm_json_dir, asm_json_filename, load_local_asm_json)
self.rd_data = RuleDesignerDatabaseConfig(rd_dbase_dir, rd_dbase_filename, load_local_rd_dbase)
@@ -142,17 +149,44 @@ class Treeview:
}
def __init__(self, asm_id, asm_json_dir, asm_json_filename, rd_dbase_dir, rd_dbase_filename, load_local_asm_json, load_local_rd_dbase):
def __init__(self,
asm_id,
asm_json_dir,
asm_json_filename,
asm_csv_dir,
asm_csv_filename,
rd_dbase_dir,
rd_dbase_filename,
load_local_asm_json,
load_local_asm_csv,
load_local_rd_dbase):
self.asm_id = asm_id
self.asm_data = SivasAssemblyData(asm_json_dir, asm_json_filename, load_local_asm_json)
self.asm_bom_data = SivasAssemblyData(asm_json_dir, asm_json_filename, load_local_asm_json)
self.asm_metadata = TeilestammMetadata(asm_csv_dir, asm_csv_filename, load_local_asm_csv)
self.rd_data = RuleDesignerDatabaseConfig(rd_dbase_dir, rd_dbase_filename, load_local_rd_dbase)
self._migration_status = None
self._longest_entry = None
@property
def migration_status(self):
if self._migration_status is None:
self._migration_status = MigrationStatus(self.asm_data.child_ids, self.rd_data.ids)
self._migration_status = MigrationStatus(self.asm_bom_data.child_ids, self.rd_data.ids)
return self._migration_status
@property
def longest_entry(self):
# Längster Eintrag wird zur Bestimmung der Leerraum-Breite zwischen Teilenummer und Bezeichnung im Baum benötigt
# Es hätte für die Berechnung sowohl ein anderer Farbcode, als auch ein anderes Verbindersymbol angegeben werden können,
# da die Anderen gleich lang wie die Angegebenen sind
if self._longest_entry is None:
self._longest_entry = self.asm_bom_data.max_bom_depth * len(Treeview.prefix_types["PIPE"]) \
+ len(self.asm_bom_data.longest_child_id) \
+ len(Treeview.connector_symbols["T"]) \
+ len(Treeview.console_colors["RESET"]) \
+ len(Treeview.console_colors["RED"])
return self._longest_entry
def generate_tree(self):
self._tree_header()
@@ -163,8 +197,13 @@ class Treeview:
"""Prints root number (number for which the user wants to see the tree) to the console"""
background_color = self._set_text_background_color(self.asm_id)
print(f"{background_color}{self.asm_id}{Treeview.console_colors['RESET']}")
id = self.asm_id
color = self._set_text_background_color(id)
text_before_description = f"{color}{id}{Treeview.console_colors['RESET']}".ljust(self.longest_entry)
description = self.asm_metadata.get_property_values("Bezeichnung1")
print(f"{text_before_description} {description}")
def _tree_body(self, parent_id=None, prefix=""):
@@ -173,7 +212,7 @@ class Treeview:
if parent_id is None:
parent_id = self.asm_id
parent_children = self.asm_data.parent_children
parent_children = self.asm_bom_data.parent_children
children_ids = parent_children[parent_id]
for index, child_id in enumerate(children_ids):
@@ -194,7 +233,7 @@ class Treeview:
amount_migrated_ids = len(self.migration_status.green_ids)
amount_unmigrated_ids = len(self.migration_status.red_ids)
progress = int(amount_migrated_ids / len(self.asm_data.child_ids) * 100)
progress = int(amount_migrated_ids / len(self.asm_bom_data.child_ids) * 100)
column_width = 5
border_padding = "".ljust(column_width, "")
@@ -215,15 +254,9 @@ class Treeview:
"""Prints tree entry"""
# Necessary for calculating the padding-width after the partnumber
longest_entry = self.asm_data.max_bom_depth * len(Treeview.prefix_types["PIPE"]) \
+ len(connector) \
+ len(self.asm_data.longest_child_id) \
+ len(Treeview.console_colors["RESET"]) \
+ len(Treeview.console_colors["RED"]) # other color codes (ansi escape sequences) could have been used instead since they all have the same length
text_before_description = f"{prefix}{connector}{color}{child_id}{Treeview.console_colors['RESET']}".ljust(longest_entry)
description = self.asm_data.get_bom_property_values("Bezeichnung")[child_id]
text_before_description = f"{prefix}{connector}{color}{child_id}{Treeview.console_colors['RESET']}".ljust(self.longest_entry)
description = self.asm_bom_data.get_bom_property_values("Bezeichnung")[child_id]
print(f"{text_before_description} {description}")
@@ -266,20 +299,39 @@ if __name__ == '__main__':
parser.add_argument('-e', '--excel', action='store_true', help='Exportiert Baugruppenstruktur als Excel-Datei mit farbiger Hervorhebung der Stücklistenpositionen, in Abhängigkeit vom Migrationsstatus')
parser.add_argument('-rddir', '--rd_dbase_dir',required=False, action='store', default=os.environ.get("CREMIG_DATA"), help='Legt das Verzeichnis fest, in dem die CSV-Datei liegt, in der die RuleDesigner-Teilenummern aufgelistet sind. Default: Umgebungsvariable %CREMIG_DATA%')
parser.add_argument('-rdfn', '--rd_dbase_filename', required=False, action='store', default=os.environ.get("RD_DATABASE_NAME"), help='Name der CSV-Datei, in der die RuleDesigner-Teilenummern aufgelistet sind. Default: Umgebungsvariable %RD_DATABASE_NAME%')
parser.add_argument('-asmdir', '--asm_json_dir', required=False, action='store', default=os.environ.get("CREMIG_DATA"), help='Legt das Verzeichnis fest, JSON-Datei mit den Baugruppeninformationen liegen soll. Default: Umgebungsvariable %CREMIG_DATA%', metavar='filename')
parser.add_argument('-ljson', '--local_asm_json', required=False, action='store_true', default=False, help='Legt fest, ob die JSON der Baugruppe bei jedem Programmlauf neu geladen wird, oder ob die lokale Datei eingelesen werden soll. Default: Neu laden bei jedem Programmlauf')
parser.add_argument('-lcsv', '--local_rd_csv', required=False, action='store_true', default=False, help='Legt fest, ob die CSV, die die RuleDesigner-Teilenummern enthält (RD-Teilenummer.csv) bei jedem Programmlauf vom Server in das lokale Verzeichnis kopiert werden soll. Default: Kopieren bei jedem Programmlauf')
parser.add_argument('-asmjdir', '--asm_json_dir', required=False, action='store', default=os.environ.get("CREMIG_DATA"), help='Legt das Verzeichnis fest, in dem die JSON-Datei mit den Baugruppeninformationen liegt. Default: Umgebungsvariable %CREMIG_DATA%', metavar='directory')
parser.add_argument('-asmcdir', '--asm_csv_dir', required=False, action='store', default=os.environ.get("CREMIG_DATA"), help='Legt das Verzeichnis fest, in dem die CSV-Datei mit den Teilestamm-Metadaten der Baugruppennummer liegt. Default: Umgebungsvariable %CREMIG_DATA%', metavar='directory')
parser.add_argument('-lasmjson', '--local_asm_json', required=False, action='store_true', default=False, help='Legt fest, ob die JSON der Baugruppe bei jedem Programmlauf neu geladen wird, oder ob die lokale Datei eingelesen werden soll. Default: Neu laden bei jedem Programmlauf')
parser.add_argument('-lasmcsv', '--local_asm_csv', required=False, action='store_true', default=False, help='Legt fest, ob die Metadaten-CSV der Baugruppennummer bei jedem Programmlauf neu geladen wird. Default: Neu laden bei jedem Programmlauf')
parser.add_argument('-lrdcsv', '--local_rd_csv', required=False, action='store_true', default=False, help='Legt fest, ob die CSV, die die RuleDesigner-Teilenummern enthält (RD-Teilenummer.csv) bei jedem Programmlauf vom Server in das lokale Verzeichnis kopiert werden soll. Default: Kopieren bei jedem Programmlauf')
args = parser.parse_args()
asm_id = args.sivasid.lstrip()
asm_json_filename = f'{asm_id}.json'
asm_bom_filename = f'{asm_id}.json'
asm_metadata_filename = f'{asm_id}.csv'
if args.excel:
excel_comparison = ExcelExport(asm_id, args.asm_json_dir, asm_json_filename, args.rd_dbase_dir, args.rd_dbase_filename, args.local_asm_json, args.local_rd_csv)
excel_comparison = ExcelExport(asm_id=asm_id,
asm_json_dir=args.asm_json_dir,
asm_json_filename=asm_bom_filename,
rd_dbase_dir=args.rd_dbase_dir,
rd_dbase_filename=args.rd_dbase_filename,
load_local_asm_json=args.local_asm_json,
load_local_rd_dbase=args.local_rd_csv)
excel_comparison.write_excel()
elif args.tree:
treeview_comparison = Treeview(asm_id, args.asm_json_dir, asm_json_filename, args.rd_dbase_dir, args.rd_dbase_filename, args.local_asm_json, args.local_rd_csv)
treeview_comparison = Treeview(asm_id=asm_id,
asm_json_dir=args.asm_json_dir,
asm_json_filename=asm_bom_filename,
asm_csv_dir=args.asm_csv_dir,
asm_csv_filename=asm_metadata_filename,
rd_dbase_dir=args.rd_dbase_dir,
rd_dbase_filename=args.rd_dbase_filename,
load_local_asm_json=args.local_asm_json,
load_local_asm_csv=args.local_asm_csv,
load_local_rd_dbase=args.local_rd_csv)
treeview_comparison.generate_tree()
else:
parser.print_help()
+34 -8
View File
@@ -27,8 +27,10 @@ class JsonBasedConfig:
class CSVBasedConfig:
def __init__(self, config_dir, config_file):
def __init__(self, config_dir: str, config_file: str):
"""merke dir den Pfad zu den Configdateien"""
self._config_dir = config_dir
self._config_file = config_file
self._config_path = os.path.join(config_dir, config_file)
def load_csv_from_file(self):
@@ -62,9 +64,6 @@ class SivasAssemblyData(JsonBasedConfig):
"""Liest die Baugruppen-JSON ein und gibt deren Informationen zurück"""
if self._asm_data is None:
if not os.path.isfile(self._config_path):
raise FileNotFoundError(f"{self._config_path} existiert nicht. Bitte prüfen, ob die Nummer richtig geschrieben wurde.")
if not self._load_local_json:
self.create_asm_json()
@@ -182,8 +181,6 @@ class RuleDesignerDatabaseConfig(CSVBasedConfig):
@property
def ids(self):
if self._ids is None:
if not os.path.isfile(self._config_path):
raise FileNotFoundError(f"{self._config_path} existiert nicht. Bitte Batchdatei unter 'bin/01_get_rd_dbase.bat' ausführen!")
if not self._load_local_csv:
self.copy_csv_from_server()
@@ -232,6 +229,37 @@ class MigrationStatus:
return self._red_ids
class TeilestammMetadata(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
@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!")
@property
def csv_data(self):
"""Gibt CSV-Daten als Dataframe zurück"""
if self._csv_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
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]
return ret
class TOSGroupsConfig(JsonBasedConfig):
"""Auslesen der Config Angaben zu den TOS Gruppen"""
@@ -595,5 +623,3 @@ class Configs:
lines = f.read().splitlines()
self._blacklist = lines
return self._blacklist
+2 -2
View File
@@ -63,7 +63,7 @@ def get_rd_dbase(out_dir=os.environ.get('CREMIG_DATA')):
print(f"File with ruldesigner-partnumbers ${csv_source_path} doesn't exist. Check VPN connection and %RD_DATABASE_SOURCE% + %RD_DATABASE_NAME% in cremig_setenv.bat")
sys.exit(0)
def get_sivas_dbase(sivas_id, out_dir):
def get_sivas_dbase(sivas_id, out_dir=os.environ.get('CREMIG_DATA')):
sivas_exe_path = os.environ.get('SIVAS_DATABASE_QUERY')
sivas_id = sivas_id.replace(".json", "")
@@ -86,7 +86,7 @@ def get_sivas_dbase(sivas_id, out_dir):
print(f"Can't execute SIVAS-database query. Check VPN connection and check the path of %SIVAS_DATABASE_QUERY% in cremig_setenv.bat")
return False
def get_sivas_teilestamm(sivas_ids, out_dir, overwrite=True):
def get_sivas_teilestamm(sivas_ids, out_dir=os.environ.get('CREMIG_DATA'), overwrite=True):
"""call the sivas exe for getting all csv files with the item data for the given sivas ids"""
sivas_teilestamm_exe = os.environ.get('SIVAS_TEILESTAMM')