Compare commits
5 Commits
e083f3c2ac
...
58b16509da
| Author | SHA1 | Date | |
|---|---|---|---|
| 58b16509da | |||
| 39bd9e01e2 | |||
| 21528e2353 | |||
| d905896891 | |||
| 1635610aff |
@@ -1,5 +1,5 @@
|
|||||||
@echo off
|
@echo off
|
||||||
:start
|
:start
|
||||||
set /p "id=Baugruppennummer: "
|
set /p "id=Artikelnummer: "
|
||||||
CALL 04_compare_lists.bat --sivasid "%id%" -t
|
CALL 04_compare_lists.bat "%id%" tree --rm_bom_ids_cfg %CREMIG_CFG%\BOM-Settings.cfg ExcludedPartnumbersInBOM --rm_summary_ids_cfg %CREMIG_CFG%\BOM-Settings.cfg ExcludedPartnumbersInSummary
|
||||||
goto start
|
goto start
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
[ExcludedPartnumbersInBOM]
|
||||||
|
#============================================================================================================================
|
||||||
|
# Teilenummern, die in der Migrationsübersicht (u.a. im Baum von CreoMigrate) nicht dargestellt sein sollen
|
||||||
|
#============================================================================================================================
|
||||||
|
|
||||||
|
MA0000008
|
||||||
|
|
||||||
|
[ExcludedPartnumbersInSummary]
|
||||||
|
#============================================================================================================================
|
||||||
|
# Teilenummern, die in der Zusammenfassung der Migrationsübersicht nicht enthalten sein sollen
|
||||||
|
# Wenn die Nummer bereits in der Sektion "ExcludedPartnumbersInBOM" enthalten ist, muss sie hier nicht nochmal aufgelistet werden
|
||||||
|
#============================================================================================================================
|
||||||
|
|
||||||
@@ -28,7 +28,7 @@ def build_gui(model, configs, env, sivasid=None, uselocal=True):
|
|||||||
controller.set_env(env)
|
controller.set_env(env)
|
||||||
controller.set_config(configs)
|
controller.set_config(configs)
|
||||||
if sivasid:
|
if sivasid:
|
||||||
controller.get_csv_files_of_asm(sivasid, uselocal)
|
controller.get_csv_files_of_asm(sivasid, load_local_bom=uselocal, load_local_teilestamm=uselocal, load_local_rd_ids=uselocal)
|
||||||
|
|
||||||
logic = GuiLogic(model, configs)
|
logic = GuiLogic(model, configs)
|
||||||
model.add_logic(logic)
|
model.add_logic(logic)
|
||||||
|
|||||||
+145
-68
@@ -1,7 +1,8 @@
|
|||||||
from manage_configs import SivasBOM, RuleDesignerDatabaseConfig, MigrationStatus, SivasTeilestamm
|
from manage_configs import SivasBOM, RuleDesignerDatabaseConfig, MigrationStatus, SivasTeilestamm, BOMConfig
|
||||||
import argparse
|
import argparse
|
||||||
import os
|
import os
|
||||||
import openpyxl
|
import openpyxl
|
||||||
|
from itertools import zip_longest
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Dieses Programm kann:
|
Dieses Programm kann:
|
||||||
@@ -10,6 +11,23 @@ Dieses Programm kann:
|
|||||||
- die oben Darstellung in der Excel-Datei als Baum in der Konsole ausgeben
|
- die oben Darstellung in der Excel-Datei als Baum in der Konsole ausgeben
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
class GetExcludedIDsFromCFG(argparse.Action):
|
||||||
|
def __call__(self, parser, namespace, values, option_string = None):
|
||||||
|
bom_config = BOMConfig(os.path.dirname(values[0]), os.path.basename(values[0]))
|
||||||
|
excluded_ids = bom_config.get_excluded_ids(values[1])
|
||||||
|
setattr(namespace, self.dest, excluded_ids)
|
||||||
|
|
||||||
|
class LStrip(argparse.Action):
|
||||||
|
def __call__(self, parser, namespace, values, option_string = None):
|
||||||
|
setattr(namespace, self.dest, values.lstrip())
|
||||||
|
|
||||||
|
class LocateSQLCredentials(argparse.Action):
|
||||||
|
def __call__(self, parser, namespace, values, option_string = None):
|
||||||
|
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!")
|
||||||
|
setattr(namespace, self.dest, True)
|
||||||
|
|
||||||
|
|
||||||
class ExcelExport:
|
class ExcelExport:
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(self,
|
||||||
@@ -168,21 +186,26 @@ class Treeview:
|
|||||||
|
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(self,
|
||||||
asm_id,
|
asm_id:str,
|
||||||
asm_json_dir,
|
asm_json_dir:str,
|
||||||
asm_json_filename,
|
asm_json_filename:str,
|
||||||
asm_csv_dir,
|
asm_csv_dir:str,
|
||||||
asm_csv_filename,
|
asm_csv_filename:str,
|
||||||
rd_dbase_dir,
|
rd_dbase_dir:str,
|
||||||
rd_dbase_filename,
|
rd_dbase_filename:bool=False,
|
||||||
load_local_asm_json,
|
load_local_asm_json:bool=False,
|
||||||
load_local_asm_csv,
|
load_local_asm_csv:bool=False,
|
||||||
load_local_rd_dbase,
|
load_local_rd_dbase:bool=False,
|
||||||
no_blue_ids):
|
no_blue_ids:bool=False,
|
||||||
|
excluded_bom_ids:list=None,
|
||||||
|
excluded_summary_ids:list=None):
|
||||||
|
|
||||||
self.asm_id = asm_id
|
self.asm_id = asm_id
|
||||||
self.asm_bom = SivasBOM(asm_json_dir, asm_json_filename, load_local_asm_json)
|
self.asm_bom = SivasBOM(asm_id, asm_json_dir, asm_json_filename, load_local_asm_json, excluded_bom_ids)
|
||||||
self.asm_teilestamm = SivasTeilestamm(asm_csv_dir, asm_csv_filename, load_local_asm_csv)
|
self.asm_teilestamm = SivasTeilestamm(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.all_excluded_summary_ids = excluded_summary_ids
|
||||||
|
self._excluded_summary_ids_in_bom = None
|
||||||
self.no_blue_ids = no_blue_ids
|
self.no_blue_ids = no_blue_ids
|
||||||
self._migration_status = None
|
self._migration_status = None
|
||||||
self._longest_entry = None
|
self._longest_entry = None
|
||||||
@@ -250,17 +273,39 @@ class Treeview:
|
|||||||
next_prefix = self._set_next_prefix(prefix, id, last_child)
|
next_prefix = self._set_next_prefix(prefix, id, last_child)
|
||||||
self._print_tree(parent_id=id, prefix=next_prefix)
|
self._print_tree(parent_id=id, prefix=next_prefix)
|
||||||
|
|
||||||
|
def _remove_ids_from_summary_amount(self, ids: list) -> list:
|
||||||
|
"""
|
||||||
|
Reduziert die Anzahl in der Zusammenfassung (z.B. der nicht migrierten Teilenummern),
|
||||||
|
um die Anzahl an Teilenummern, die vom User aus der Zusammenfassung ausgeschlossen wurden
|
||||||
|
"""
|
||||||
|
|
||||||
|
if self.all_excluded_summary_ids is None:
|
||||||
|
return ids
|
||||||
|
return list(filter(lambda id: id not in self.excluded_summary_ids_in_bom, ids))
|
||||||
|
|
||||||
|
@property
|
||||||
|
def excluded_summary_ids_in_bom(self) -> list:
|
||||||
|
""" Gibt alle Teilenummern zurück, die im Baum vorliegen, aber nicht in der Anzahl der Zusammenfassung enthalten sein sollen"""
|
||||||
|
|
||||||
|
if self._excluded_summary_ids_in_bom is None:
|
||||||
|
self._excluded_summary_ids_in_bom = list(filter(lambda id: id in self.asm_bom.bom_data, self.all_excluded_summary_ids))
|
||||||
|
return self._excluded_summary_ids_in_bom
|
||||||
|
|
||||||
def _print_summary(self):
|
def _print_summary(self):
|
||||||
|
|
||||||
amount_in_rd = len(self.migration_status.ids_in_rd)
|
ids_in_rd = self.migration_status.ids_in_rd
|
||||||
amount_pending = len(self.migration_status.ids_pending)
|
ids_pending = self.migration_status.ids_pending
|
||||||
|
|
||||||
|
amount_in_rd = len(self._remove_ids_from_summary_amount(ids_in_rd))
|
||||||
|
amount_pending = len(self._remove_ids_from_summary_amount(ids_pending))
|
||||||
|
|
||||||
if not self.no_blue_ids:
|
if not self.no_blue_ids:
|
||||||
amount_in_work = len(self.migration_status.ids_in_progress)
|
ids_in_progress = self.migration_status.ids_in_progress
|
||||||
|
amount_in_work = len(self._remove_ids_from_summary_amount(ids_in_progress))
|
||||||
amount_released = amount_in_rd - amount_in_work
|
amount_released = amount_in_rd - amount_in_work
|
||||||
|
|
||||||
progress = int(amount_in_rd / len(self.asm_bom.child_ids) * 100)
|
child_ids = self.asm_bom.child_ids
|
||||||
|
progress = int(amount_in_rd / len(self._remove_ids_from_summary_amount(child_ids)) * 100)
|
||||||
|
|
||||||
column_width = 5
|
column_width = 5
|
||||||
border_padding = "".ljust(column_width, "─")
|
border_padding = "".ljust(column_width, "─")
|
||||||
@@ -285,14 +330,35 @@ class Treeview:
|
|||||||
│ Auswertung {empty_padding}│
|
│ Auswertung {empty_padding}│
|
||||||
├─┬───────────────────────────────────────┬─{border_padding}┤
|
├─┬───────────────────────────────────────┬─{border_padding}┤
|
||||||
"""
|
"""
|
||||||
|
progress_segment = f"""
|
||||||
progress = f"""
|
|
||||||
├─┴───────────────────────────────────────┼─{border_padding}┤
|
├─┴───────────────────────────────────────┼─{border_padding}┤
|
||||||
│ Migrationsfortschritt │ {f"{progress}%".ljust(column_width)}│
|
│ Migrationsfortschritt │ {f"{progress}%".ljust(column_width)}│
|
||||||
╰─────────────────────────────────────────┴─{border_padding}╯
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
print(header + green_entry + blue_entry + red_entry + progress)
|
bottom_row = f"╰─────────────────────────────────────────┴─{border_padding}╯"
|
||||||
|
|
||||||
|
|
||||||
|
exclusion_description = ""
|
||||||
|
excluded_id_list = ""
|
||||||
|
|
||||||
|
if self.asm_bom.excluded_ids_in_bom or self.excluded_summary_ids_in_bom:
|
||||||
|
|
||||||
|
exclusion_description = f"""├─────────────────────────────────────────┴─{border_padding}┤
|
||||||
|
│ {empty_padding}│
|
||||||
|
├───────────────────────────────────────────{border_padding}┤
|
||||||
|
│ Ausgeschlossene Teilenummern {empty_padding}│
|
||||||
|
│──────────────────────┬────────────────────{border_padding}┤
|
||||||
|
│ Baum │ Auswertung {empty_padding}│
|
||||||
|
├──────────────────────┼────────────────────{border_padding}┤
|
||||||
|
"""
|
||||||
|
|
||||||
|
for bom_id, smry_id in zip_longest(self.asm_bom.excluded_ids_in_bom, self.excluded_summary_ids_in_bom, fillvalue=9*" "):
|
||||||
|
excluded_id_list += f"│ { bom_id} │ {smry_id} {empty_padding}│\n"
|
||||||
|
|
||||||
|
bottom_row = f"╰──────────────────────┴────────────────────{border_padding}╯"
|
||||||
|
|
||||||
|
|
||||||
|
print(header + green_entry + blue_entry + red_entry + progress_segment + exclusion_description + excluded_id_list + bottom_row)
|
||||||
|
|
||||||
def _print_entry(self, child_id, prefix, connector, color):
|
def _print_entry(self, child_id, prefix, connector, color):
|
||||||
|
|
||||||
@@ -352,58 +418,69 @@ class Treeview:
|
|||||||
|
|
||||||
return Treeview.console_colors["GREEN"]
|
return Treeview.console_colors["GREEN"]
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
parser = argparse.ArgumentParser(description='Programm gibt Auskunft über den aktuellen Migrationsstand', prog='Display Migration Status')
|
|
||||||
parser.add_argument('-s', '--sivasid', action='store', required=True, help='Eingabe der SIVAS-Teilenummer, für die der Migrationsstatus angezeigt werden soll', metavar="id")
|
def main():
|
||||||
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 = argparse.ArgumentParser(description='Programm gibt Auskunft über den aktuellen Migrationsstand einer SIVAS-Teilenummer',
|
||||||
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%')
|
prog='compare_lists',
|
||||||
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%")
|
formatter_class=lambda prog: argparse.HelpFormatter(prog, max_help_position=50)) # Hilfetext auch bei längeren Argumenten in gleicher Zeile wie Argument darstellen
|
||||||
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('-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')
|
# Custom Actions
|
||||||
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.register("action", "GetIDsFromCFG", GetExcludedIDsFromCFG)
|
||||||
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.register("action", "lstrip", LStrip)
|
||||||
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.register("action", "LocateSQLCredentials", LocateSQLCredentials)
|
||||||
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')
|
|
||||||
|
parser.add_argument('sivas_id', action='lstrip', help='Teilenummer, für die Migrationsüberblick generiert werden soll.', metavar="SIVAS-Teilenummer")
|
||||||
|
parser.add_argument('output_type', choices=["tree", "excel"], help="'tree' = Darstellung des Überblicks als Baum in der Konsole. 'excel' = Export des Überblicks als Excel")
|
||||||
|
parser.add_argument('--rd_ids_filepath', action='store', default=os.path.join(os.environ.get("CREMIG_DATA"), "RD_Teilenummern.csv"), help='Verzeichnis der CSV-Datei mit den RuleDesigner-Nummern. Default: $CREMIG_DATA', metavar="filepath")
|
||||||
|
parser.add_argument('--local_rd_ids', action='store_true', default=False, help='Lokales laden der CSV mit den RuleDesigner-Nummern (RD-Teilenummer.csv) statt Kopieren von Server')
|
||||||
|
parser.add_argument('--bom_filedir', action='store', default=os.environ.get("CREMIG_DATA"),help='Verzeichnis der JSON-Datei mit den Stücklisteninformationen. Default: $CREMIG_DATA', metavar='dir')
|
||||||
|
parser.add_argument('--local_bom', action='store_true', default=False, help='Lokales laden der JSON mit den Stücklisteninformationen statt Generierung')
|
||||||
|
parser.add_argument('--teilestamm_filedir', action='store', default=os.environ.get("CREMIG_DATA"), help='Verzeichnis der CSV mit den SIVAS-Teilestamminformationen. Default: $CREMIG_DATA', metavar='dir')
|
||||||
|
parser.add_argument('--local_teilestamm', action='store_true', default=False, help='Lokales Laden der CSV mit den Teilestamminformationen statt Generierung')
|
||||||
|
parser.add_argument('--no_blue_ids', action="store_true", default=False, help='Nummern, die in RD vorliegen, aber nicht freigegeben sind, gleich wie freigegeben Nummern einfärben')
|
||||||
|
|
||||||
|
exclude_from_overview = parser.add_mutually_exclusive_group()
|
||||||
|
exclude_from_overview.add_argument('--rm_bom_ids_str', action="store", nargs="*", default=None, dest="excluded_bom_ids", help="Angabe aller Nummern, die vom Migrationsüberblick ausgeschlossen sein sollen", metavar="id1 id2")
|
||||||
|
exclude_from_overview.add_argument('--rm_bom_ids_cfg', action="GetIDsFromCFG", nargs=2, default=None, dest="excluded_bom_ids", help="cfg-Pfad & Sektion, in der Nummern aufgelistet sind, die nicht im Überblick dargestellt sein sollen", metavar=("path", "section"))
|
||||||
|
|
||||||
|
exclude_from_summary = parser.add_mutually_exclusive_group()
|
||||||
|
exclude_from_summary.add_argument('--rm_summary_ids_str', action="store", nargs="*", default=None, dest="excluded_summary_ids", help="Angabe aller Nummern, die von der Zusammenfassung ausgeschlossen sein sollen", metavar="id1 id2")
|
||||||
|
exclude_from_summary.add_argument('--rm_summary_ids_cfg', action="GetIDsFromCFG", nargs=2, default=None, dest="excluded_summary_ids", help="cfg-Pfad & Sektion, in der Nummern aufgelistet sind, die von der Zusammenfassung ausgeschlossen sein sollen", metavar=("path", "section"))
|
||||||
|
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
asm_id = args.sivasid.lstrip()
|
match args.output_type:
|
||||||
asm_bom_filename = f'{asm_id}.json'
|
case "excel":
|
||||||
asm_metadata_filename = f'{asm_id}.csv'
|
excel_comparison = ExcelExport(asm_id=args.sivas_id,
|
||||||
|
asm_json_dir=args.bom_filedir,
|
||||||
if not args.no_blue_ids:
|
asm_json_filename=f'{args.sivas_id}.json',
|
||||||
if not os.path.isfile(os.environ.get("RD_SQL_DATABASE_CREDENTIALS")):
|
asm_csv_dir=args.teilestamm_filedir,
|
||||||
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!")
|
asm_csv_filename=f"{args.sivas_id}.csv",
|
||||||
args.no_blue_ids = True
|
rd_dbase_dir=os.path.dirname(args.rd_ids_filepath),
|
||||||
|
rd_dbase_filename=os.path.basename(args.rd_ids_filepath),
|
||||||
if args.excel:
|
load_local_asm_json=args.local_bom,
|
||||||
excel_comparison = ExcelExport(asm_id=asm_id,
|
load_local_asm_csv=args.local_teilestamm,
|
||||||
asm_json_dir=args.asm_json_filedir,
|
load_local_rd_dbase=args.local_rd_ids,
|
||||||
asm_json_filename=asm_bom_filename,
|
|
||||||
asm_csv_dir=args.rd_ids_filedir,
|
|
||||||
asm_csv_filename=asm_metadata_filename,
|
|
||||||
rd_dbase_dir=args.rd_ids_filedir,
|
|
||||||
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)
|
no_blue_ids=args.no_blue_ids)
|
||||||
|
|
||||||
excel_comparison.write_excel()
|
excel_comparison.write_excel()
|
||||||
elif args.tree:
|
case "tree":
|
||||||
treeview_comparison = Treeview(asm_id=asm_id,
|
treeview_comparison = Treeview(asm_id=args.sivas_id,
|
||||||
asm_json_dir=args.asm_json_filedir,
|
asm_json_dir=args.bom_filedir,
|
||||||
asm_json_filename=asm_bom_filename,
|
asm_json_filename=f'{args.sivas_id}.json',
|
||||||
asm_csv_dir=args.rd_ids_filedir,
|
asm_csv_dir=args.teilestamm_filedir,
|
||||||
asm_csv_filename=asm_metadata_filename,
|
asm_csv_filename=f'{args.sivas_id}.csv',
|
||||||
rd_dbase_dir=args.rd_ids_filedir,
|
rd_dbase_dir=os.path.dirname(args.rd_ids_filepath),
|
||||||
rd_dbase_filename=args.rd_ids_filename,
|
rd_dbase_filename=os.path.basename(args.rd_ids_filepath),
|
||||||
load_local_asm_json=args.asm_json_local,
|
load_local_asm_json=args.local_bom,
|
||||||
load_local_asm_csv=args.asm_csv_local,
|
load_local_asm_csv=args.local_teilestamm,
|
||||||
load_local_rd_dbase=args.rd_ids_local,
|
load_local_rd_dbase=args.local_rd_ids,
|
||||||
no_blue_ids=args.no_blue_ids)
|
no_blue_ids=args.no_blue_ids,
|
||||||
|
excluded_bom_ids=args.excluded_bom_ids,
|
||||||
|
excluded_summary_ids=args.excluded_summary_ids)
|
||||||
|
|
||||||
treeview_comparison.generate_tree()
|
treeview_comparison.generate_tree()
|
||||||
else:
|
|
||||||
parser.print_help()
|
main()
|
||||||
+9
-7
@@ -115,21 +115,23 @@ class Controller(Observer):
|
|||||||
orange[red] = True
|
orange[red] = True
|
||||||
return orange
|
return orange
|
||||||
|
|
||||||
def get_csv_files_of_asm(self, asm_id, load_local_asm_json=False, load_local_rd_dbase=False):
|
def get_csv_files_of_asm(self, asm_id, load_local_bom=False, load_local_teilestamm=False, load_local_rd_ids=False):
|
||||||
|
|
||||||
""" Holt sich die Metadaten der Stücklistenpositionen als CSV"""
|
""" Holt sich die Metadaten der Stücklistenpositionen als CSV"""
|
||||||
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")
|
||||||
|
|
||||||
sivas_bom = SivasBOM(data_dir, asm_id + '.json', load_local_asm_json)
|
excluded_bom_ids = self._config.bom_config.get_excluded_ids("ExcludedPartnumbersInBOM")
|
||||||
|
|
||||||
|
sivas_bom = SivasBOM(asm_id, data_dir, asm_id + '.json', load_local_bom, excluded_bom_ids)
|
||||||
sivas_bom.extend_asm_bom(asm_id, {"Parent": None, "Position": "10/0"}) # Ergänzt Stücklistendaten um eine fiktive Baugruppe "None", in der die Haupt-Teilenummer als Pos. 1 vorliegt. Dadurch können auch Teilenummern ohne Stückliste korrekt abgebildet werden
|
sivas_bom.extend_asm_bom(asm_id, {"Parent": None, "Position": "10/0"}) # Ergänzt Stücklistendaten um eine fiktive Baugruppe "None", in der die Haupt-Teilenummer als Pos. 1 vorliegt. Dadurch können auch Teilenummern ohne Stückliste korrekt abgebildet werden
|
||||||
|
|
||||||
rd_data = RuleDesignerDatabaseConfig(data_dir, rd_dbase_filename, load_local_rd_dbase)
|
rd_data = RuleDesignerDatabaseConfig(data_dir, rd_dbase_filename, load_local_rd_ids)
|
||||||
|
|
||||||
migration_status = MigrationStatus(sivas_bom.child_ids, rd_data.ids)
|
migration_status = MigrationStatus(sivas_bom.child_ids, rd_data.ids)
|
||||||
pending_ids = migration_status.ids_pending
|
pending_ids = migration_status.ids_pending
|
||||||
|
|
||||||
sivas_teilestamm = SivasTeilestamm(data_dir, asm_id + '.csv')
|
sivas_teilestamm = SivasTeilestamm(data_dir, asm_id + '.csv', load_local_csv=load_local_teilestamm)
|
||||||
sivas_teilestamm.create_csvs(pending_ids)
|
sivas_teilestamm.create_csvs(pending_ids)
|
||||||
|
|
||||||
self._model.set_red_ids(pending_ids)
|
self._model.set_red_ids(pending_ids)
|
||||||
@@ -154,11 +156,11 @@ class Controller(Observer):
|
|||||||
|
|
||||||
def get_current_asm_id(self):
|
def get_current_asm_id(self):
|
||||||
self._model.get_asm_id()
|
self._model.get_asm_id()
|
||||||
def set_current_asm_id(self, asm_id, load_local_asm_json=False, load_local_rd_dbase=False):
|
def set_current_asm_id(self, asm_id, load_local_bom=False, load_local_teilestamm=False, load_local_rd_ids=False):
|
||||||
# TODO save current given data. In case, ask whether you should save or drop
|
# TODO save current given data. In case, ask whether you should save or drop
|
||||||
self._model.set_asm_id(asm_id)
|
self._model.set_asm_id(asm_id)
|
||||||
# hole alle Daten vom Server
|
# hole alle Daten vom Server
|
||||||
self.get_csv_files_of_asm(asm_id, load_local_asm_json, load_local_rd_dbase)
|
self.get_csv_files_of_asm(asm_id, load_local_bom, load_local_teilestamm, load_local_rd_ids)
|
||||||
|
|
||||||
def set_current_item_id(self, cid):
|
def set_current_item_id(self, cid):
|
||||||
"""setze eine neue Item ID """
|
"""setze eine neue Item ID """
|
||||||
@@ -289,7 +291,7 @@ class Controller(Observer):
|
|||||||
elif key == 'cb_ladelokal_asm':
|
elif key == 'cb_ladelokal_asm':
|
||||||
current_asmid = self.data_from_view('asm_id')
|
current_asmid = self.data_from_view('asm_id')
|
||||||
# hole dir nur die lokalen Daten. Keine Datenbankabfrage
|
# hole dir nur die lokalen Daten. Keine Datenbankabfrage
|
||||||
self.set_current_asm_id(current_asmid, load_local_asm_json=True, load_local_rd_dbase=True)
|
self.set_current_asm_id(current_asmid, load_local_bom=True, load_local_teilestamm=True, load_local_rd_ids=True)
|
||||||
elif key == 'cb_3dsuchen':
|
elif key == 'cb_3dsuchen':
|
||||||
self.suche_3d()
|
self.suche_3d()
|
||||||
|
|
||||||
|
|||||||
+109
-11
@@ -99,9 +99,19 @@ class RuleDesignerSQLData(SQLBasedConfig):
|
|||||||
class SivasBOM(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,
|
||||||
|
asm_id,
|
||||||
|
config_dir: str,
|
||||||
|
config_file: str,
|
||||||
|
load_local_json=False,
|
||||||
|
excluded_ids: list=None):
|
||||||
|
|
||||||
super().__init__(config_dir, config_file)
|
super().__init__(config_dir, config_file)
|
||||||
|
|
||||||
|
self.main_id = asm_id
|
||||||
self._load_local_json = load_local_json
|
self._load_local_json = load_local_json
|
||||||
|
self.excluded_ids_by_user = excluded_ids
|
||||||
|
self._excluded_ids_in_bom = None
|
||||||
self._bom_data = None
|
self._bom_data = None
|
||||||
self._child_ids = None
|
self._child_ids = None
|
||||||
self._parent_children = None
|
self._parent_children = None
|
||||||
@@ -112,6 +122,7 @@ class SivasBOM(JsonBasedConfig):
|
|||||||
def create_asm_json(self) -> bool:
|
def create_asm_json(self) -> bool:
|
||||||
"""Erstellt JSON mit den aktuellen Baugruppeninformationen"""
|
"""Erstellt JSON mit den aktuellen Baugruppeninformationen"""
|
||||||
|
|
||||||
|
if not self._load_local_json:
|
||||||
update_database.get_sivas_bom(self._config_file.removesuffix(".json"))
|
update_database.get_sivas_bom(self._config_file.removesuffix(".json"))
|
||||||
|
|
||||||
|
|
||||||
@@ -135,16 +146,19 @@ class SivasBOM(JsonBasedConfig):
|
|||||||
|
|
||||||
self._bom_data = {}
|
self._bom_data = {}
|
||||||
|
|
||||||
if not self._load_local_json:
|
|
||||||
try:
|
try:
|
||||||
self.create_asm_json()
|
self.create_asm_json()
|
||||||
except ValueError:
|
except ValueError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self._bom_data = self.load_json_from_file()
|
self._bom_data = self.load_json_from_file()
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
if self.excluded_ids_by_user is not None:
|
||||||
|
self._remove_excluded_ids_from_bom()
|
||||||
|
|
||||||
return self._bom_data
|
return self._bom_data
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@@ -201,13 +215,81 @@ class SivasBOM(JsonBasedConfig):
|
|||||||
self._bom_data[id].append(metadata)
|
self._bom_data[id].append(metadata)
|
||||||
return self._bom_data
|
return self._bom_data
|
||||||
|
|
||||||
|
def _remove_excluded_ids_from_bom(self) -> None:
|
||||||
|
"""Entfernt ID's aus den Stücklistendaten, die nicht enthalten sein sollen"""
|
||||||
|
|
||||||
|
# Ausgeschlossene Teilenummern, die vom User angegeben wurden, können nicht einfach aus der Stückliste entfernt werden.
|
||||||
|
# Sie müssen zunächst aufbereiten werden, denn:
|
||||||
|
# - Ausgeschlossene Nummern, die kein Bestandteil der aktuellen Baugruppe sind, sind nicht von Interesse
|
||||||
|
# - Kinder von ausgeschlossenen Teilenummern, die vom User nicht angegeben wurden sind ggf. von Interesse, müssen aber zunächst
|
||||||
|
# ermittelt werden
|
||||||
|
|
||||||
|
ids_to_remove = self.excluded_ids_in_bom
|
||||||
|
|
||||||
|
if not ids_to_remove:
|
||||||
|
return
|
||||||
|
|
||||||
|
if self.main_id in ids_to_remove:
|
||||||
|
raise ValueError(f"Haupt-Teilenummer '{self.main_id}' darf nicht ausgeschlossen sein. Bitte $CREMIG_CFG/BOM-Settings.cfg -> Sektion 'ExcludedPartnumbersInBOM' prüfen, falls diese Datei zur Definition der ausgeschlossenen Teilenummern verwendet wurde")
|
||||||
|
|
||||||
|
filtered_bom_data = {}
|
||||||
|
for id, usages in self.bom_data.items():
|
||||||
|
|
||||||
|
if id in ids_to_remove:
|
||||||
|
continue
|
||||||
|
|
||||||
|
for properties in usages:
|
||||||
|
|
||||||
|
if properties["Parent"] in ids_to_remove:
|
||||||
|
continue
|
||||||
|
if id not in filtered_bom_data:
|
||||||
|
filtered_bom_data[id] = []
|
||||||
|
|
||||||
|
filtered_bom_data[id].append(properties)
|
||||||
|
|
||||||
|
self._bom_data = filtered_bom_data
|
||||||
|
|
||||||
|
@property
|
||||||
|
def excluded_ids_in_bom(self) -> list:
|
||||||
|
|
||||||
|
""" Gibt alle Teilenummern zurück, die in der SIVAS-Stückliste vorliegen, aber davon ausgeschlossen sein sollen. """
|
||||||
|
|
||||||
|
if self._excluded_ids_in_bom is None:
|
||||||
|
|
||||||
|
excluded_ids_by_user = self.excluded_ids_by_user
|
||||||
|
|
||||||
|
to_remove = {}
|
||||||
|
for id, usages in self.bom_data.items():
|
||||||
|
|
||||||
|
# Teilenummern zunächst als ausgeschlossen anzusehen und das später zu widerrufen erleichtert die Definition der Logik
|
||||||
|
to_remove[id] = True
|
||||||
|
|
||||||
|
# Teilenummern, die vom User ausgeschlossen wurden, aber kein Bestandteil dieser Baugruppe sind, interessieren uns nicht!
|
||||||
|
if id in excluded_ids_by_user:
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Kinder von ausgeschlossenen Teilenummern werden ebenfalls als ausgeschlossen betrachtet, außer sie sind Kinder von
|
||||||
|
# weiteren Teilenummern, die nicht augeschlossen sein sollen
|
||||||
|
# Hinweis:
|
||||||
|
# Für die Prüfung, ob das Kind in weiteren Teilenummern verbaut ist, würde sich die Methode "parent_children" anbieten.
|
||||||
|
# Die ist aber Lazy, sprich, wenn wir die jetzt aufrufen, arbeitet sie mit den Stücklistendaten, vor dem die Teilenummern
|
||||||
|
# entfernt wurden. Die Laziness dafür zu entfernen macht aber auch keinen Sinn, weil diese Methode bei der Erstellung von
|
||||||
|
# baumförmigen Migrationsübersichten ständig aufgerufen wird, d.h. die Performance würde darunter stark leiden!
|
||||||
|
|
||||||
|
for properties in usages:
|
||||||
|
if properties["Parent"] not in excluded_ids_by_user:
|
||||||
|
to_remove[id] = False
|
||||||
|
|
||||||
|
self._excluded_ids_in_bom = list(filter(lambda id: to_remove[id] is True, to_remove))
|
||||||
|
return self._excluded_ids_in_bom
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def longest_child_id(self) -> str:
|
def longest_child_id(self) -> str:
|
||||||
"""Gibt die längste Teilenummer von allen Stücklistenpositionen zurück"""
|
"""Gibt die längste Teilenummer von allen Stücklistenpositionen zurück"""
|
||||||
|
|
||||||
if self._longest_child_id is None:
|
if self._longest_child_id is None:
|
||||||
self._longest_child_id = max(self.child_ids)
|
self._longest_child_id = max(self.child_ids)
|
||||||
return max(self.child_ids)
|
return self._longest_child_id
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def max_bom_depth(self) -> int:
|
def max_bom_depth(self) -> int:
|
||||||
@@ -225,13 +307,13 @@ class SivasBOM(JsonBasedConfig):
|
|||||||
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._bom_data:
|
if id not in self.bom_data:
|
||||||
raise ValueError("Teilenummer befindet sich nicht in der Baugruppe!")
|
raise ValueError("Teilenummer befindet sich nicht in der Baugruppe!")
|
||||||
|
|
||||||
if property_name not in self._bom_data[id][0]:
|
if property_name not in self.bom_data[id][0]:
|
||||||
return
|
return
|
||||||
|
|
||||||
return self._bom_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)"""
|
||||||
@@ -345,10 +427,10 @@ class SivasTeilestamm(CSVBasedConfig):
|
|||||||
self._load_local_csv = load_local_csv
|
self._load_local_csv = load_local_csv
|
||||||
self._data = None
|
self._data = None
|
||||||
|
|
||||||
@staticmethod
|
def create_csvs(self, 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)"""
|
||||||
|
|
||||||
|
if not self._load_local_csv:
|
||||||
update_database.get_sivas_teilestamm(ids)
|
update_database.get_sivas_teilestamm(ids)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@@ -356,10 +438,7 @@ class SivasTeilestamm(CSVBasedConfig):
|
|||||||
"""Gibt CSV-Daten als Dataframe zurück"""
|
"""Gibt CSV-Daten als Dataframe zurück"""
|
||||||
|
|
||||||
if self._data is None:
|
if self._data is None:
|
||||||
|
|
||||||
if not self._load_local_csv:
|
|
||||||
self.create_csvs(self._config_file.removesuffix(".csv"))
|
self.create_csvs(self._config_file.removesuffix(".csv"))
|
||||||
|
|
||||||
self._data = self.load_csv_from_file()
|
self._data = self.load_csv_from_file()
|
||||||
|
|
||||||
return self._data
|
return self._data
|
||||||
@@ -687,6 +766,24 @@ class GuiConfig(IniBasedConfig):
|
|||||||
config_file=spezific_file
|
config_file=spezific_file
|
||||||
super().__init__(config_dir, config_file=config_file)
|
super().__init__(config_dir, config_file=config_file)
|
||||||
|
|
||||||
|
class BOMConfig(IniBasedConfig):
|
||||||
|
def __init__(self, config_dir=os.environ.get("CREMIG_CFG"), config_file="BOM-Settings.cfg"):
|
||||||
|
self._config_dir = config_dir
|
||||||
|
self.config_file = config_file
|
||||||
|
super().__init__(config_dir, config_file)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def config_dir(self):
|
||||||
|
return self._config_dir
|
||||||
|
|
||||||
|
@config_dir.setter
|
||||||
|
def config_dir(self, directory):
|
||||||
|
if not os.path.isdir(directory):
|
||||||
|
raise ValueError("Verzeichnis existiert nicht!")
|
||||||
|
self._config_dir = directory
|
||||||
|
|
||||||
|
def get_excluded_ids(self, section_name:str="ExcludedPartnumbersInBOM") -> tuple:
|
||||||
|
return tuple(self.get_section_options(section_name))
|
||||||
|
|
||||||
class Configs:
|
class Configs:
|
||||||
"""Sammlung aller Configdateien """
|
"""Sammlung aller Configdateien """
|
||||||
@@ -707,6 +804,7 @@ class Configs:
|
|||||||
|
|
||||||
self.TOSGruppen = TOSGroupsConfig(cfg_dir)
|
self.TOSGruppen = TOSGroupsConfig(cfg_dir)
|
||||||
self.Materialien = MaterialTransConfig(cfg_dir)
|
self.Materialien = MaterialTransConfig(cfg_dir)
|
||||||
|
self.bom_config = BOMConfig(cfg_dir)
|
||||||
self._teilenummern = None
|
self._teilenummern = None
|
||||||
self._blacklist = None
|
self._blacklist = None
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user