In Treeview bzw. Excel-Export des Migrationsüberblicks werden Nummern nun blau markiert, wenn diese zwar in RuleDesigner migriert wurden, dort aber nocht keine Freigabe erfolgt ist. Hierfür wird der RuleDesigner-Status der Nummern live aus der RuleDesigner-Datenbank abgerufen. Dadurch ergibt sich ein detaillierterer Überblick über den aktuellen Migrationsstand, da der Großteil der Migrationsarbeit erst nach der Migration ins PDM erfolgt (Aufbereitung der Modelle, Zusammenbau der Baugruppe, etc.). Abgesehen davon wird die Bezeichnung der obersten Baugruppe jetzt ebenfalls im Migrationsüberblick angezeigt, was bisher nicht der Fall war. Hierfür wird eine CSV-Datei des SIVAS-Teilestamms zur Baugruppennummer abgeleitet daraus 'Bezeichnung 1' ausgelesen.
This commit is contained in:
@@ -1,5 +1,4 @@
|
|||||||
@echo off
|
@echo off
|
||||||
CALL 01_get_rd_dbase.bat
|
|
||||||
CALL manage_interpreter.bat activate_interpreter
|
CALL manage_interpreter.bat activate_interpreter
|
||||||
python %CREMIG_LIB%\compare_lists.py %*
|
python %CREMIG_LIB%\compare_lists.py %*
|
||||||
CALL manage_interpreter.bat deactivate_interpreter
|
CALL manage_interpreter.bat deactivate_interpreter
|
||||||
|
|||||||
@@ -32,7 +32,11 @@ set SIVAS_TEILESTAMM=\\195.243.223.3\sivas\jit\programme\KSbExcelExportSivasTeil
|
|||||||
set SIVAS_EXCEL_EXPORT_DIR=%CREMIG_DATA%
|
set SIVAS_EXCEL_EXPORT_DIR=%CREMIG_DATA%
|
||||||
set SIEMENS_DATA_PREP_TOOL=C:\Program Files\Siemens\Solid Edge 2023\Program\DataPrepUtility.exe
|
set SIEMENS_DATA_PREP_TOOL=C:\Program Files\Siemens\Solid Edge 2023\Program\DataPrepUtility.exe
|
||||||
set LOG_EDITOR=notepad.exe
|
set LOG_EDITOR=notepad.exe
|
||||||
|
set RD_SQL_DATABASE_CREDENTIALS=\\fileserver01\abteilungen\Entwicklung\Administration\Lizenzen\RDSQLDatabaseCredentials.bat
|
||||||
|
|
||||||
|
if exist %RD_SQL_DATABASE_CREDENTIALS% (
|
||||||
|
call %RD_SQL_DATABASE_CREDENTIALS%
|
||||||
|
)
|
||||||
|
|
||||||
rem Um den Python-Interpreter auf U:\ zu nutzen, Kommentar (rem) in nachfolgender Zeile entfernen
|
rem Um den Python-Interpreter auf U:\ zu nutzen, Kommentar (rem) in nachfolgender Zeile entfernen
|
||||||
rem set NETWORK_INTERPRETER_PATH=\\ssg.local\freigaben\Allgemein\Programmierumgebung\Python312
|
rem set NETWORK_INTERPRETER_PATH=\\ssg.local\freigaben\Allgemein\Programmierumgebung\Python312
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
[Status]
|
||||||
|
0=VERFÜGBAR
|
||||||
|
1=IN BEARBEITUNG
|
||||||
|
2=IN ÜBERARBEITUNG
|
||||||
|
3=FREIGEGEBEN
|
||||||
|
4=FREIGEGEBEN
|
||||||
|
10=VORLÄUFIG
|
||||||
|
11=PROTOTYP
|
||||||
|
12=IN PRÜFUNG
|
||||||
|
13=UNGÜLTIG
|
||||||
|
101=BAGATELLÄNDERUNG
|
||||||
|
102=REVISION VERFÜGBAR
|
||||||
|
103=ZUR PRÜFUNG
|
||||||
|
104=REVISION IN PRÜFUNG
|
||||||
|
105=REVISION ZUR PRÜFUNG
|
||||||
|
106=GESPERRT
|
||||||
+120
-54
@@ -1,5 +1,4 @@
|
|||||||
from manage_configs import SivasAssemblyData, RuleDesignerDatabaseConfig, MigrationStatus, TeilestammMetadata
|
from manage_configs import SivasAssemblyData, RuleDesignerDatabaseConfig, MigrationStatus, TeilestammMetadata
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
import os
|
import os
|
||||||
import openpyxl
|
import openpyxl
|
||||||
@@ -8,7 +7,7 @@ import openpyxl
|
|||||||
Dieses Programm kann:
|
Dieses Programm kann:
|
||||||
- eine Excel-Datei exportieren, in der alle Teilenummern aufgelistet sind, die in Verbindung mit einer angegebenen Nummer migriert werden müssen.
|
- eine Excel-Datei exportieren, in der alle Teilenummern aufgelistet sind, die in Verbindung mit einer angegebenen Nummer migriert werden müssen.
|
||||||
Sie gibt dabei Auskunft darüber, welche Teilenummern bereits migriert wurden und welche noch migriert werden müssen.
|
Sie gibt dabei Auskunft darüber, welche Teilenummern bereits migriert wurden und welche noch migriert werden müssen.
|
||||||
- die oben beschriebene Darstellung in einer Excel-Datei auch als Treeview auf der Kommandozeile darstellen
|
- die oben Darstellung in der Excel-Datei als Baum in der Konsole ausgeben
|
||||||
"""
|
"""
|
||||||
|
|
||||||
class ExcelExport:
|
class ExcelExport:
|
||||||
@@ -17,12 +16,17 @@ class ExcelExport:
|
|||||||
asm_id,
|
asm_id,
|
||||||
asm_json_dir,
|
asm_json_dir,
|
||||||
asm_json_filename,
|
asm_json_filename,
|
||||||
|
asm_csv_dir,
|
||||||
|
asm_csv_filename,
|
||||||
rd_dbase_dir,
|
rd_dbase_dir,
|
||||||
rd_dbase_filename,
|
rd_dbase_filename,
|
||||||
load_local_asm_json,
|
load_local_asm_json,
|
||||||
load_local_rd_dbase):
|
load_local_asm_csv,
|
||||||
|
load_local_rd_dbase,
|
||||||
|
no_blue_ids):
|
||||||
self.asm_id = asm_id
|
self.asm_id = asm_id
|
||||||
self.asm_data = SivasAssemblyData(asm_json_dir, asm_json_filename, load_local_asm_json)
|
self.asm_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.rd_data = RuleDesignerDatabaseConfig(rd_dbase_dir, rd_dbase_filename, load_local_rd_dbase)
|
||||||
self._migration_status = None
|
self._migration_status = None
|
||||||
|
|
||||||
@@ -70,8 +74,12 @@ class ExcelExport:
|
|||||||
# Alle weiteren Spalten bleiben leer, da sie händisch vom User zu befüllen sind
|
# Alle weiteren Spalten bleiben leer, da sie händisch vom User zu befüllen sind
|
||||||
|
|
||||||
sorting = self._create_sorting_string()
|
sorting = self._create_sorting_string()
|
||||||
migrated_ids = self.migration_status.green_ids
|
migrated_ids = self.migration_status.ids_in_rd
|
||||||
descriptions = self.asm_data.get_bom_property_values("Bezeichnung")
|
child_descriptions:dict = self.asm_data.get_bom_property_values("Bezeichnung")
|
||||||
|
parent_description:str = self.asm_metadata.get_property_values("Bezeichnung1")
|
||||||
|
|
||||||
|
descriptions = child_descriptions.copy()
|
||||||
|
descriptions[asm_id] = parent_description
|
||||||
|
|
||||||
prt_num = []
|
prt_num = []
|
||||||
description = []
|
description = []
|
||||||
@@ -82,13 +90,22 @@ class ExcelExport:
|
|||||||
for id_str in sorting:
|
for id_str in sorting:
|
||||||
id = id_str.split("-")[-1]
|
id = id_str.split("-")[-1]
|
||||||
prt_num.append(id)
|
prt_num.append(id)
|
||||||
|
assessment.append('')
|
||||||
|
comment.append('')
|
||||||
|
|
||||||
if id not in descriptions:
|
if id not in descriptions:
|
||||||
description.append("")
|
description.append("")
|
||||||
else:
|
else:
|
||||||
description.append(descriptions[id])
|
description.append(descriptions[id])
|
||||||
migration_status.append("VERFÜGBAR" if id in migrated_ids else "IMPORTIEREN")
|
|
||||||
assessment.append('')
|
if id in migrated_ids:
|
||||||
comment.append('')
|
if id in self.migration_status.ids_in_progress:
|
||||||
|
migration_status.append("PDM-Migration abgeschlossen")
|
||||||
|
else:
|
||||||
|
migration_status.append("Migration abgeschlossen (freigegeben)")
|
||||||
|
|
||||||
|
else:
|
||||||
|
migration_status.append("Migration ausstehend")
|
||||||
|
|
||||||
data = {
|
data = {
|
||||||
"Sortierung": sorting,
|
"Sortierung": sorting,
|
||||||
@@ -145,6 +162,7 @@ class Treeview:
|
|||||||
|
|
||||||
console_colors = {"RED": "\033[41m",
|
console_colors = {"RED": "\033[41m",
|
||||||
"GREEN": "\033[42m",
|
"GREEN": "\033[42m",
|
||||||
|
"BLUE": "\033[44m",
|
||||||
"RESET": "\033[0m"
|
"RESET": "\033[0m"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -159,11 +177,13 @@ class Treeview:
|
|||||||
rd_dbase_filename,
|
rd_dbase_filename,
|
||||||
load_local_asm_json,
|
load_local_asm_json,
|
||||||
load_local_asm_csv,
|
load_local_asm_csv,
|
||||||
load_local_rd_dbase):
|
load_local_rd_dbase,
|
||||||
|
no_blue_ids):
|
||||||
self.asm_id = asm_id
|
self.asm_id = asm_id
|
||||||
self.asm_bom_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.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.rd_data = RuleDesignerDatabaseConfig(rd_dbase_dir, rd_dbase_filename, load_local_rd_dbase)
|
||||||
|
self.no_blue_ids = no_blue_ids
|
||||||
self._migration_status = None
|
self._migration_status = None
|
||||||
self._longest_entry = None
|
self._longest_entry = None
|
||||||
|
|
||||||
@@ -176,16 +196,20 @@ class Treeview:
|
|||||||
@property
|
@property
|
||||||
def longest_entry(self):
|
def longest_entry(self):
|
||||||
|
|
||||||
# Längster Eintrag wird zur Bestimmung der Leerraum-Breite zwischen Teilenummer und Bezeichnung im Baum benötigt
|
if self._longest_entry is None:
|
||||||
# Es hätte für die Berechnung sowohl ein anderer Farbcode, als auch ein anderes Verbindersymbol angegeben werden können,
|
longest_color_code = max(Treeview.console_colors.values(), key=len)
|
||||||
# da die Anderen gleich lang wie die Angegebenen sind
|
longest_connector_symbol = max(Treeview.connector_symbols.values(), key=len)
|
||||||
|
|
||||||
|
padding_after_id = 2
|
||||||
|
|
||||||
if self._longest_entry is None:
|
if self._longest_entry is None:
|
||||||
self._longest_entry = self.asm_bom_data.max_bom_depth * len(Treeview.prefix_types["PIPE"]) \
|
|
||||||
|
self._longest_entry = (self.asm_bom_data.max_bom_depth) * len(Treeview.prefix_types["PIPE"]) \
|
||||||
|
+ len(longest_connector_symbol) \
|
||||||
|
+ len(longest_color_code) \
|
||||||
+ len(self.asm_bom_data.longest_child_id) \
|
+ len(self.asm_bom_data.longest_child_id) \
|
||||||
+ len(Treeview.connector_symbols["T"]) \
|
|
||||||
+ len(Treeview.console_colors["RESET"]) \
|
+ len(Treeview.console_colors["RESET"]) \
|
||||||
+ len(Treeview.console_colors["RED"])
|
+ padding_after_id
|
||||||
return self._longest_entry
|
return self._longest_entry
|
||||||
|
|
||||||
def generate_tree(self):
|
def generate_tree(self):
|
||||||
@@ -230,29 +254,50 @@ class Treeview:
|
|||||||
|
|
||||||
def _tree_summary(self):
|
def _tree_summary(self):
|
||||||
|
|
||||||
amount_migrated_ids = len(self.migration_status.green_ids)
|
amount_in_rd = len(self.migration_status.ids_in_rd)
|
||||||
amount_unmigrated_ids = len(self.migration_status.red_ids)
|
amount_pending = len(self.migration_status.ids_pending)
|
||||||
|
|
||||||
progress = int(amount_migrated_ids / len(self.asm_bom_data.child_ids) * 100)
|
if not self.no_blue_ids:
|
||||||
|
amount_in_work = len(self.migration_status.ids_in_progress)
|
||||||
|
amount_released = amount_in_rd - amount_in_work
|
||||||
|
|
||||||
|
progress = int(amount_in_rd / len(self.asm_bom_data.child_ids) * 100)
|
||||||
|
|
||||||
column_width = 5
|
column_width = 5
|
||||||
border_padding = "".ljust(column_width, "─")
|
border_padding = "".ljust(column_width, "─")
|
||||||
empty_padding = "".ljust(column_width, " ")
|
empty_padding = "".ljust(column_width, " ")
|
||||||
|
|
||||||
print(f"""
|
|
||||||
╭─────────────────────────────────────{border_padding}╮
|
red_entry = f"│{Treeview.console_colors['RED'] } {Treeview.console_colors['RESET']}│ Migration ausstehend │ {str(amount_pending).ljust(column_width)}│"
|
||||||
|
|
||||||
|
if not self.no_blue_ids:
|
||||||
|
blue_entry = f"│{Treeview.console_colors['BLUE'] } {Treeview.console_colors['RESET']}│ PDM-Migration abgeschlossen │ {str(amount_in_work).ljust(column_width)}│\n"
|
||||||
|
green_entry = f"│{Treeview.console_colors['GREEN']} {Treeview.console_colors['RESET']}│ Migration abgeschlossen (Freigegeben) │ {str(amount_released).ljust(column_width)}│\n"
|
||||||
|
|
||||||
|
else:
|
||||||
|
blue_entry = ""
|
||||||
|
green_entry = f"│{Treeview.console_colors['GREEN']} {Treeview.console_colors['RESET']}│ Migration abgeschlossen │ {str(amount_in_rd).ljust(column_width)}│\n"
|
||||||
|
red_entry = f"│{Treeview.console_colors['RED'] } {Treeview.console_colors['RESET']}│ Migration ausstehend │ {str(amount_pending).ljust(column_width)}│"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
header = f"""
|
||||||
|
╭───────────────────────────────────────────{border_padding}╮
|
||||||
│ Auswertung {empty_padding}│
|
│ Auswertung {empty_padding}│
|
||||||
├───────────────────────────────────┬─{border_padding}┤
|
├─┬───────────────────────────────────────┬─{border_padding}┤
|
||||||
│ Anzahl abgeschlossene Migrationen │ {str(amount_migrated_ids).ljust(column_width)}│
|
"""
|
||||||
│ Anzahl fehlende Migrationen │ {str(amount_unmigrated_ids).ljust(column_width)}│
|
|
||||||
├───────────────────────────────────┼─{border_padding}┤
|
progress = f"""
|
||||||
|
├─┴───────────────────────────────────────┼─{border_padding}┤
|
||||||
│ Migrationsfortschritt │ {f"{progress}%".ljust(column_width)}│
|
│ Migrationsfortschritt │ {f"{progress}%".ljust(column_width)}│
|
||||||
╰───────────────────────────────────┴─{border_padding}╯
|
╰─────────────────────────────────────────┴─{border_padding}╯
|
||||||
""")
|
"""
|
||||||
|
|
||||||
|
print(header + green_entry + blue_entry + red_entry + progress)
|
||||||
|
|
||||||
def _print_entry(self, child_id, prefix, connector, color):
|
def _print_entry(self, child_id, prefix, connector, color):
|
||||||
|
|
||||||
"""Prints tree entry"""
|
"""Eintrag in die Konsole drucken"""
|
||||||
|
|
||||||
|
|
||||||
text_before_description = f"{prefix}{connector}{color}{child_id}{Treeview.console_colors['RESET']}".ljust(self.longest_entry)
|
text_before_description = f"{prefix}{connector}{color}{child_id}{Treeview.console_colors['RESET']}".ljust(self.longest_entry)
|
||||||
@@ -263,33 +308,42 @@ class Treeview:
|
|||||||
|
|
||||||
def _last_child_check(self, child_index, children):
|
def _last_child_check(self, child_index, children):
|
||||||
|
|
||||||
"""Checks, if current child is the last child of the assembly"""
|
"""Prüft, ob aktuelle ID das letzte Kind der Baugruppe ist"""
|
||||||
|
|
||||||
return True if child_index == len(children) - 1 else False
|
return True if child_index == len(children) - 1 else False
|
||||||
|
|
||||||
|
|
||||||
def _set_connector_symbol(self, child_is_last_child):
|
def _set_connector_symbol(self, child_is_last_child):
|
||||||
|
|
||||||
"""Chooses connector symbol for current tree entry"""
|
"""Legt Verbindungssymbol für aktuellen Eintrag im Baum fest"""
|
||||||
|
|
||||||
return Treeview.connector_symbols["ELBOW"] if child_is_last_child else Treeview.connector_symbols["T"]
|
return Treeview.connector_symbols["ELBOW"] if child_is_last_child else Treeview.connector_symbols["T"]
|
||||||
|
|
||||||
|
|
||||||
def _prefix(self, prefix, child_is_last_child):
|
def _prefix(self, prefix, child_is_last_child):
|
||||||
|
|
||||||
"""Creates prefix (part before the connector symbol) for each tree entry"""
|
"""Erstellt für jeden Eintrag im Baum einen Präfix (Teil vor dem Verbindersymbol) fest"""
|
||||||
|
|
||||||
prefix += Treeview.prefix_types["EMPTY"] if child_is_last_child else Treeview.prefix_types["PIPE"]
|
prefix += Treeview.prefix_types["EMPTY"] if child_is_last_child else Treeview.prefix_types["PIPE"]
|
||||||
return prefix
|
return prefix
|
||||||
|
|
||||||
|
|
||||||
def _set_text_background_color(self, partnumber):
|
def _set_text_background_color(self, id):
|
||||||
|
|
||||||
"""Sets background color of partnumber in console depending on its migration status
|
"""Legt Hintergrundfarbe der Teilenummer basierend auf ihrem Migrationsstatus fest:
|
||||||
- Migration completed: green
|
|
||||||
- Migration pending: red"""
|
|
||||||
|
|
||||||
return Treeview.console_colors["GREEN"] if self.migration_status.id_status[partnumber] is True else Treeview.console_colors["RED"]
|
- grün: Migration vollständig abgeschlossen und freigegeben
|
||||||
|
- blau: Migration ins PDM abgeschlossen
|
||||||
|
- rot: Migration ausstehend"""
|
||||||
|
|
||||||
|
if id in self.migration_status.ids_pending:
|
||||||
|
return Treeview.console_colors["RED"]
|
||||||
|
|
||||||
|
if not self.no_blue_ids:
|
||||||
|
if id in self.migration_status.ids_in_progress:
|
||||||
|
return Treeview.console_colors["BLUE"]
|
||||||
|
|
||||||
|
return Treeview.console_colors["GREEN"]
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
@@ -297,13 +351,14 @@ if __name__ == '__main__':
|
|||||||
parser.add_argument('-s', '--sivasid', action='store', required=True, help='Eingabe der SIVAS-Teilenummer, für die der Migrationsstatus angezeigt werden soll', metavar="id")
|
parser.add_argument('-s', '--sivasid', 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='Visualisiert Baugruppenstruktur als Baumstruktur mit farbiger Hervorhebung der Stücklistenpositionen in Abhängigkeit vom Migrationsstatus')
|
parser.add_argument('-t', '--tree', action='store_true', help='Visualisiert Baugruppenstruktur als Baumstruktur mit farbiger Hervorhebung der Stücklistenpositionen in Abhängigkeit vom Migrationsstatus')
|
||||||
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('-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('-rd_ids_filedir', 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('-rd_ids_filename', 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('-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('-rd_ids_local', 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('-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('-asm_json_filedir', 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('-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('-asm_json_local', 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('-asm_csv_filedir', 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('-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')
|
parser.add_argument('-asm_csv_local', 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('-no_blue_ids', action='store_true', default=False, help='Legt fest, ob blaue IDs im Baum angezeigt werden sollen. Erforderlich, wenn keine Verbindung zu RDServer besteht, da SQL-Abfrage durchgeführt werden muss')
|
||||||
|
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
@@ -311,26 +366,37 @@ if __name__ == '__main__':
|
|||||||
asm_bom_filename = f'{asm_id}.json'
|
asm_bom_filename = f'{asm_id}.json'
|
||||||
asm_metadata_filename = f'{asm_id}.csv'
|
asm_metadata_filename = f'{asm_id}.csv'
|
||||||
|
|
||||||
|
if not args.no_blue_ids:
|
||||||
|
if not os.path.isfile(os.environ.get("RD_SQL_DATABASE_CREDENTIALS")):
|
||||||
|
print(f"ACHTUNG: Blau hinterlegte Nummern (Teilenummern die ins PDM migriert wurden, aber aktuell nicht freigegeben sind) werden nicht dargestellt, da nicht auf die Login-Daten für die RD-SQL-Datenbank zugegriffen werden kann. Bitte prüfen, ob die Login-Datei '{os.environ.get("RD_SQL_DATABASE_CREDENTIALS")}' existiert. Auch prüfen, ob die Netzlaufwerke verbunden sind!")
|
||||||
|
args.no_blue_ids = True
|
||||||
|
|
||||||
if args.excel:
|
if args.excel:
|
||||||
excel_comparison = ExcelExport(asm_id=asm_id,
|
excel_comparison = ExcelExport(asm_id=asm_id,
|
||||||
asm_json_dir=args.asm_json_dir,
|
asm_json_dir=args.asm_json_filedir,
|
||||||
asm_json_filename=asm_bom_filename,
|
asm_json_filename=asm_bom_filename,
|
||||||
rd_dbase_dir=args.rd_dbase_dir,
|
asm_csv_dir=args.rd_ids_filedir,
|
||||||
rd_dbase_filename=args.rd_dbase_filename,
|
asm_csv_filename=asm_metadata_filename,
|
||||||
load_local_asm_json=args.local_asm_json,
|
rd_dbase_dir=args.rd_ids_filedir,
|
||||||
load_local_rd_dbase=args.local_rd_csv)
|
rd_dbase_filename=args.rd_ids_filename,
|
||||||
|
load_local_asm_json=args.asm_json_local,
|
||||||
|
load_local_asm_csv=args.asm_csv_local,
|
||||||
|
load_local_rd_dbase=args.asm_csv_local,
|
||||||
|
no_blue_ids=args.no_blue_ids)
|
||||||
|
|
||||||
excel_comparison.write_excel()
|
excel_comparison.write_excel()
|
||||||
elif args.tree:
|
elif args.tree:
|
||||||
treeview_comparison = Treeview(asm_id=asm_id,
|
treeview_comparison = Treeview(asm_id=asm_id,
|
||||||
asm_json_dir=args.asm_json_dir,
|
asm_json_dir=args.asm_json_filedir,
|
||||||
asm_json_filename=asm_bom_filename,
|
asm_json_filename=asm_bom_filename,
|
||||||
asm_csv_dir=args.asm_csv_dir,
|
asm_csv_dir=args.rd_ids_filedir,
|
||||||
asm_csv_filename=asm_metadata_filename,
|
asm_csv_filename=asm_metadata_filename,
|
||||||
rd_dbase_dir=args.rd_dbase_dir,
|
rd_dbase_dir=args.rd_ids_filedir,
|
||||||
rd_dbase_filename=args.rd_dbase_filename,
|
rd_dbase_filename=args.rd_ids_filename,
|
||||||
load_local_asm_json=args.local_asm_json,
|
load_local_asm_json=args.asm_json_local,
|
||||||
load_local_asm_csv=args.local_asm_csv,
|
load_local_asm_csv=args.asm_csv_local,
|
||||||
load_local_rd_dbase=args.local_rd_csv)
|
load_local_rd_dbase=args.rd_ids_local,
|
||||||
|
no_blue_ids=args.no_blue_ids)
|
||||||
|
|
||||||
treeview_comparison.generate_tree()
|
treeview_comparison.generate_tree()
|
||||||
else:
|
else:
|
||||||
|
|||||||
+2
-2
@@ -126,12 +126,12 @@ class Controller(Observer):
|
|||||||
|
|
||||||
if not load_local_asm_json:
|
if not load_local_asm_json:
|
||||||
try:
|
try:
|
||||||
update_database.get_sivas_teilestamm(migration_status.red_ids, data_dir)
|
update_database.get_sivas_teilestamm(migration_status.ids_pending, data_dir)
|
||||||
except:
|
except:
|
||||||
self.message_error('Abfrage hat nicht funktioniert', 'sivas_db_error')
|
self.message_error('Abfrage hat nicht funktioniert', 'sivas_db_error')
|
||||||
return
|
return
|
||||||
|
|
||||||
self._model.set_red_ids(migration_status.red_ids)
|
self._model.set_red_ids(migration_status.ids_pending)
|
||||||
self._model.set_parent_children(asm_data.parent_children)
|
self._model.set_parent_children(asm_data.parent_children)
|
||||||
self._model.set_asm_id(asm_id)
|
self._model.set_asm_id(asm_id)
|
||||||
self._model.set_bom_properties(asm_data.all_bom_properties)
|
self._model.set_bom_properties(asm_data.all_bom_properties)
|
||||||
|
|||||||
+85
-13
@@ -1,5 +1,6 @@
|
|||||||
import os
|
import os
|
||||||
import json
|
import json
|
||||||
|
import pymssql
|
||||||
from configparser import ConfigParser
|
from configparser import ConfigParser
|
||||||
import pandas as pd
|
import pandas as pd
|
||||||
import update_database
|
import update_database
|
||||||
@@ -18,9 +19,12 @@ 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"""
|
||||||
@@ -40,6 +44,61 @@ class CSVBasedConfig:
|
|||||||
return pd.read_csv(self._config_path, sep=";", dtype="object")
|
return pd.read_csv(self._config_path, sep=";", dtype="object")
|
||||||
|
|
||||||
|
|
||||||
|
class SQLBasedConfig:
|
||||||
|
def __init__(self, server, user, pw, dbase):
|
||||||
|
self._server = server
|
||||||
|
self._user = user
|
||||||
|
self._pw = pw
|
||||||
|
self._dbase = dbase
|
||||||
|
|
||||||
|
def query_db(self, sql_statement) -> list:
|
||||||
|
|
||||||
|
"""Führt Datenbankabfrage aus und gibt Daten zurück"""
|
||||||
|
with pymssql.connect(self._server, self._user, self._pw, self._dbase) as conn:
|
||||||
|
with conn.cursor(as_dict=True) as cursor:
|
||||||
|
try:
|
||||||
|
cursor.execute(sql_statement)
|
||||||
|
except pymssql.ProgrammingError:
|
||||||
|
print("SQL-Statement konnte nicht verarbeitet werden!")
|
||||||
|
raise
|
||||||
|
ret = cursor.fetchall()
|
||||||
|
return ret
|
||||||
|
|
||||||
|
class RuleDesignerSQLData(SQLBasedConfig):
|
||||||
|
def __init__(self,
|
||||||
|
server=os.environ.get("RD_SQL_DATABASE_SERVER"),
|
||||||
|
user=os.environ.get("RD_SQL_DATABASE_USER"),
|
||||||
|
pw=os.environ.get("RD_SQL_DATABASE_PW"),
|
||||||
|
dbase=os.environ.get("RD_SQL_DATABASE_NAME")):
|
||||||
|
super().__init__(server, user, pw, dbase)
|
||||||
|
self._rd_statuses = None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def rd_statuses(self) -> dict:
|
||||||
|
"""Gibt Teilenummer und zugehörigen Status zurück"""
|
||||||
|
|
||||||
|
if self._rd_statuses is None:
|
||||||
|
|
||||||
|
# Datenbankabfrage aller Teilenummern (codCodice) und der zugehörigen Status (codStatus)
|
||||||
|
sql_statement = "SELECT [codCodice] AS ID, [codStatus] AS STATUS FROM [FUSION_PDM].[dbo].[CODICI]"
|
||||||
|
sql_data = self.query_db(sql_statement)
|
||||||
|
|
||||||
|
# Jeder Teilenummer den sprechenden Stsatusnamen, statt der internen Statusnummer zuweisen
|
||||||
|
# Dafür laden der Mapping-Datei für die Statusnummern (z.B. 3 = "FREIGEGEBEN")
|
||||||
|
rd_status_cfg = IniBasedConfig(os.environ.get("CREMIG_CFG"), "RuleDesignerStatusnamen.cfg")
|
||||||
|
rd_status_sections = rd_status_cfg.sections()
|
||||||
|
rd_status_names = rd_status_cfg.get_dict(rd_status_sections[0])
|
||||||
|
|
||||||
|
|
||||||
|
self._rd_statuses = {}
|
||||||
|
for id_status_dict in sql_data:
|
||||||
|
id = id_status_dict["ID"]
|
||||||
|
status = id_status_dict["STATUS"]
|
||||||
|
self._rd_statuses[id] = rd_status_names[str(status)]
|
||||||
|
|
||||||
|
return self._rd_statuses
|
||||||
|
|
||||||
|
|
||||||
class SivasAssemblyData(JsonBasedConfig):
|
class SivasAssemblyData(JsonBasedConfig):
|
||||||
"""Auslesen der Assembly-Informationen zu einer angegebenen Baugruppennummer"""
|
"""Auslesen der Assembly-Informationen zu einer angegebenen Baugruppennummer"""
|
||||||
|
|
||||||
@@ -196,9 +255,11 @@ class MigrationStatus:
|
|||||||
def __init__(self, asm_child_ids: tuple, rd_ids: tuple):
|
def __init__(self, asm_child_ids: tuple, rd_ids: tuple):
|
||||||
self.asm_child_ids = asm_child_ids
|
self.asm_child_ids = asm_child_ids
|
||||||
self.rd_ids = rd_ids
|
self.rd_ids = rd_ids
|
||||||
|
self._rd_statuses = None
|
||||||
self._overview = None
|
self._overview = None
|
||||||
self._green_ids = None
|
self._ids_in_rd = None
|
||||||
self._red_ids = None
|
self._ids_in_progress = None
|
||||||
|
self._ids_pending = None
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def id_status(self) -> dict:
|
def id_status(self) -> dict:
|
||||||
@@ -210,25 +271,36 @@ class MigrationStatus:
|
|||||||
return self._overview
|
return self._overview
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def green_ids(self) -> list:
|
def ids_in_rd(self) -> list:
|
||||||
"""Gibt alle Stücklistenpositionen zurück, die migriert sind"""
|
"""Gibt alle Stücklistenpositionen zurück, die migriert sind"""
|
||||||
|
|
||||||
if self._green_ids is None:
|
if self._ids_in_rd is None:
|
||||||
self._green_ids = [id for id, status in self.id_status.items() if status is True]
|
self._ids_in_rd = [id for id, status in self.id_status.items() if status is True]
|
||||||
return self._green_ids
|
return self._ids_in_rd
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def yellow_ids(self) -> list:
|
def ids_in_progress(self) -> list:
|
||||||
"""Gibt migrierte Stücklistenpositionen zurück, die aktuell eine Freigabe der Baugruppe verhindern, da sie sich derzeit in Arbeit befinden"""
|
"""Gibt migrierte Stücklistenpositionen zurück, die aktuell eine Freigabe der Baugruppe verhindern, da sie sich in Arbeit befinden"""
|
||||||
pass
|
|
||||||
|
|
||||||
|
if self._ids_in_progress is None:
|
||||||
|
|
||||||
|
rd_sql_data = RuleDesignerSQLData()
|
||||||
|
rd_statuses = rd_sql_data.rd_statuses
|
||||||
|
|
||||||
|
self._ids_in_progress = []
|
||||||
|
for id in self.ids_in_rd:
|
||||||
|
if rd_statuses[id] != "FREIGEGEBEN":
|
||||||
|
self._ids_in_progress.append(id)
|
||||||
|
return self._ids_in_progress
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def red_ids(self) -> list:
|
def ids_pending(self) -> list:
|
||||||
"""Gibt alle Stücklistenpositionen zurück, die noch nicht migriert sind"""
|
"""Gibt alle Stücklistenpositionen zurück, die noch nicht migriert sind"""
|
||||||
|
|
||||||
if self._red_ids is None:
|
if self._ids_pending is None:
|
||||||
self._red_ids = [id for id, status in self.id_status.items() if status is False]
|
self._ids_pending = [id for id, status in self.id_status.items() if status is False]
|
||||||
return self._red_ids
|
return self._ids_pending
|
||||||
|
|
||||||
|
|
||||||
class TeilestammMetadata(CSVBasedConfig):
|
class TeilestammMetadata(CSVBasedConfig):
|
||||||
|
|||||||
Binary file not shown.
Reference in New Issue
Block a user