#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ Import-Skript für Intelectra Webshop Dieses Skript wird remote per SSH von der GUI aufgerufen. Es erwartet eine CSV-Datei als erstes Argument. Mit --passendwie wird die krempl_passendwie Tabelle aktualisiert. """ import csv import pymysql import os import sys import argparse from datetime import datetime from configparser import ConfigParser CONFIG_PATH = os.path.join(os.path.dirname(__file__), 'db_config.ini') REQUIRED_COLUMNS = { 'id', 'altenr', 'originalnummer', 'navisionid', 'zolltarifnummer', 'marke', 'ersatzteilvertreiber', 'ean', 'ersatzteilvorwaerts', 'ersatzteilvorwaertsnavisionid' } REQUIRED_COLUMNS_PASSENDWIE = { 'id', 'navisionid', 'vertreiberid', 'vertreiber', 'bestellcode' } REQUIRED_COLUMNS_GERAETE = { 'id', 'nr', 'marke', 'typ', 'zusatzNummer', 'modellBezeichnung', 'produktionsstart', 'produktionsende', 'wgtext1', 'wgtext2', 'zusatz', 'bezeichnungoriginal', 'typDE', 'typFR' } REQUIRED_COLUMNS_MAPPING = { 'ersatzteil', 'geraet' } def load_db_config(): parser = ConfigParser() parser.read(CONFIG_PATH) config = parser['database'] return { 'host': config.get('host', 'localhost'), 'user': config.get('user'), 'password': config.get('password', ''), 'database': config.get('database', 'webshop-sql'), 'autocommit': True } def connect_to_db(): return pymysql.connect(**load_db_config()) def validate_headers(headers): return REQUIRED_COLUMNS.issubset(set(headers)) def validate_geraete_headers(headers): return REQUIRED_COLUMNS_GERAETE.issubset(set(headers)) def validate_mapping_headers(headers): return REQUIRED_COLUMNS_MAPPING.issubset(set(headers)) def run_import(csv_path): if not os.path.exists(csv_path): print(f"[ERROR] Datei nicht gefunden: {csv_path}") return with open(csv_path, 'r', encoding='utf-8') as f: reader = csv.DictReader(f, delimiter=';') if not validate_headers(reader.fieldnames): print(f"[ERROR] CSV-Header ungültig: {reader.fieldnames}") return conn = connect_to_db() cursor = conn.cursor() backup_table(cursor) cursor.execute("TRUNCATE TABLE krempl_art_22") insert_sql = """ INSERT INTO krempl_art_22 (id, altenr, originalnummer, navisionid, zolltarifnummer, marke, ersatzteilvertreiber, ean, ersatzteilvorwaerts, ersatzteilvorwaertsnavisionid) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s) """ total = 0 batch = [] for row in reader: try: values = ( int(row['id']) if row['id'] else None, row['altenr'], row['originalnummer'], int(row['navisionid']) if row['navisionid'] else None, row['zolltarifnummer'], row['marke'], row['ersatzteilvertreiber'], row['ean'], row['ersatzteilvorwaerts'], int(row['ersatzteilvorwaertsnavisionid']) if row['ersatzteilvorwaertsnavisionid'] else None ) batch.append(values) if len(batch) >= 500: cursor.executemany(insert_sql, batch) conn.commit() total += len(batch) batch.clear() except Exception as e: print(f"[WARN] Zeile übersprungen wegen Fehler: {e}") continue if batch: cursor.executemany(insert_sql, batch) conn.commit() total += len(batch) print(f"[OK] Import abgeschlossen. {total} Datensätze importiert.") # Tabellen-Statistiken aktualisieren für bessere Query-Performance print("[INFO] Aktualisiere Tabellen-Statistiken...") cursor.execute("ANALYZE TABLE krempl_art_22") print("[OK] Statistiken aktualisiert.") cursor.close() conn.close() def backup_table(cursor): name = f"krempl_art_22_backup_{datetime.now().strftime('%Y%m%d_%H%M%S')}" try: cursor.execute(f"CREATE TABLE {name} AS SELECT * FROM krempl_art_22") print(f"[INFO] Backup-Tabelle erstellt: {name}") except Exception as e: print(f"[WARN] Backup fehlgeschlagen: {e}") def run_passendwie_import(csv_path): if not os.path.exists(csv_path): print(f"[ERROR] Datei nicht gefunden: {csv_path}") return with open(csv_path, 'r', encoding='utf-8') as f: reader = csv.DictReader(f, delimiter=';') if not REQUIRED_COLUMNS_PASSENDWIE.issubset(set(reader.fieldnames)): print(f"[ERROR] CSV-Header ungültig: {reader.fieldnames}") return conn = connect_to_db() cursor = conn.cursor() backup_passendwie_table(cursor) insert_sql = """ INSERT INTO krempl_passendwie (id, navisionid, vertreiberid, vertreiber, bestellcode) VALUES (%s, %s, %s, %s, %s) ON DUPLICATE KEY UPDATE navisionid = VALUES(navisionid), vertreiberid = VALUES(vertreiberid), vertreiber = VALUES(vertreiber), bestellcode = VALUES(bestellcode) """ total = 0 batch = [] for row in reader: try: values = ( int(row['id']) if row['id'] else None, int(row['navisionid']) if row['navisionid'] else None, row['vertreiberid'], row['vertreiber'], row['bestellcode'] ) batch.append(values) if len(batch) >= 500: cursor.executemany(insert_sql, batch) conn.commit() total += len(batch) batch.clear() except Exception as e: print(f"[WARN] Zeile übersprungen wegen Fehler: {e}") continue if batch: cursor.executemany(insert_sql, batch) conn.commit() total += len(batch) print(f"[OK] PassendWie-Import abgeschlossen. {total} Datensätze importiert.") # Tabellen-Statistiken aktualisieren für bessere Query-Performance print("[INFO] Aktualisiere Tabellen-Statistiken...") cursor.execute("ANALYZE TABLE krempl_passendwie") print("[OK] Statistiken aktualisiert.") cursor.close() conn.close() def backup_passendwie_table(cursor): # 1. Alle bisherigen Backups suchen cursor.execute("SHOW TABLES LIKE 'krempl_passendwie_backup_%'") backups = [row[0] for row in cursor.fetchall()] # 2. Nach Datum sortieren (Tabellenname enthält Zeitstempel) backups.sort() # 3. Wenn mehr als 2 Backups existieren, die ältesten löschen while len(backups) >= 3: to_delete = backups.pop(0) try: cursor.execute(f"DROP TABLE `{to_delete}`") print(f"[INFO] Altes Backup gelöscht: {to_delete}") except Exception as e: print(f"[WARN] Konnte Backup nicht löschen: {e}") # 4. Neues Backup anlegen name = f"krempl_passendwie_backup_{datetime.now().strftime('%Y%m%d_%H%M%S')}" try: cursor.execute(f"CREATE TABLE `{name}` AS SELECT * FROM krempl_passendwie") print(f"[INFO] Backup-Tabelle erstellt: {name}") except Exception as e: print(f"[WARN] Backup fehlgeschlagen: {e}") def run_geraete_import(csv_path): if not os.path.exists(csv_path): print(f"[ERROR] Datei nicht gefunden: {csv_path}") return with open(csv_path, 'r', encoding='utf-8') as f: reader = csv.DictReader(f, delimiter=';') if not validate_geraete_headers(reader.fieldnames): print(f"[ERROR] CSV-Header ungültig: {reader.fieldnames}") return conn = connect_to_db() cursor = conn.cursor() backup_geraete_table(cursor) insert_sql = """ INSERT INTO krempl_geraete_22 (id, nr, marke, typ, zusatZNummer, modellBezeichnung, produktionsstart, produktionsende, wgtext1, wgtext2, zusatz, bezeichnungoriginal, typDE, typFR) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s) ON DUPLICATE KEY UPDATE nr = VALUES(nr), marke = VALUES(marke), typ = VALUES(typ), zusatZNummer = VALUES(zusatZNummer), modellBezeichnung = VALUES(modellBezeichnung), produktionsstart = VALUES(produktionsstart), produktionsende = VALUES(produktionsende), wgtext1 = VALUES(wgtext1), wgtext2 = VALUES(wgtext2), zusatz = VALUES(zusatz), bezeichnungoriginal = VALUES(bezeichnungoriginal), typDE = VALUES(typDE), typFR = VALUES(typFR) """ total = 0 batch = [] for row in reader: try: values = ( int(row['id']) if row['id'] else None, row['nr'], row['marke'], row['typ'], row['zusatzNummer'], row['modellBezeichnung'], row['produktionsstart'], row['produktionsende'], row['wgtext1'], row['wgtext2'], row['zusatz'], row['bezeichnungoriginal'], row['typDE'], row['typFR'] ) batch.append(values) if len(batch) >= 500: cursor.executemany(insert_sql, batch) conn.commit() total += len(batch) batch.clear() except Exception as e: print(f"[WARN] Zeile übersprungen wegen Fehler: {e}") continue if batch: cursor.executemany(insert_sql, batch) conn.commit() total += len(batch) print(f"[OK] ZusatzDatenOriginalteil-Import abgeschlossen. {total} Datensätze importiert.") # Tabellen-Statistiken aktualisieren für bessere Query-Performance print("[INFO] Aktualisiere Tabellen-Statistiken...") cursor.execute("ANALYZE TABLE krempl_geraete_22") print("[OK] Statistiken aktualisiert.") cursor.close() conn.close() def backup_geraete_table(cursor): # 1. Alle bisherigen Backups suchen cursor.execute("SHOW TABLES LIKE 'krempl_geraete_22_backup_%'") backups = [row[0] for row in cursor.fetchall()] # 2. Nach Datum sortieren (Tabellenname enthält Zeitstempel) backups.sort() # 3. Wenn mehr als 2 Backups existieren, die ältesten löschen while len(backups) >= 3: to_delete = backups.pop(0) try: cursor.execute(f"DROP TABLE `{to_delete}`") print(f"[INFO] Altes Backup gelöscht: {to_delete}") except Exception as e: print(f"[WARN] Konnte Backup nicht löschen: {e}") # 4. Neues Backup anlegen name = f"krempl_geraete_22_backup_{datetime.now().strftime('%Y%m%d_%H%M%S')}" try: cursor.execute(f"CREATE TABLE `{name}` AS SELECT * FROM krempl_geraete_22") print(f"[INFO] Backup-Tabelle erstellt: {name}") except Exception as e: print(f"[WARN] Backup fehlgeschlagen: {e}") def run_mapping_import(csv_path): if not os.path.exists(csv_path): print(f"[ERROR] Datei nicht gefunden: {csv_path}") return with open(csv_path, 'r', encoding='utf-8') as f: reader = csv.DictReader(f, delimiter=';') if not validate_mapping_headers(reader.fieldnames): print(f"[ERROR] CSV-Header ungültig: {reader.fieldnames}") return conn = connect_to_db() cursor = conn.cursor() backup_mapping_table(cursor) insert_sql = """ INSERT INTO krempl_artikelgeraet_22 (ersatzteil, geraet) VALUES (%s, %s) ON DUPLICATE KEY UPDATE geraet = VALUES(geraet) """ total = 0 batch = [] for row in reader: try: values = ( int(row['ersatzteil']) if row['ersatzteil'] else None, int(row['geraet']) if row['geraet'] else None ) batch.append(values) if len(batch) >= 500: cursor.executemany(insert_sql, batch) conn.commit() total += len(batch) batch.clear() except Exception as e: print(f"[WARN] Zeile übersprungen wegen Fehler: {e}") continue if batch: cursor.executemany(insert_sql, batch) conn.commit() total += len(batch) print(f"[OK] KremplMapping-Import abgeschlossen. {total} Datensätze importiert.") # Tabellen-Statistiken aktualisieren für bessere Query-Performance print("[INFO] Aktualisiere Tabellen-Statistiken...") cursor.execute("ANALYZE TABLE krempl_artikelgeraet_22") print("[OK] Statistiken aktualisiert.") cursor.close() conn.close() def backup_mapping_table(cursor): # 1. Alle bisherigen Backups suchen cursor.execute("SHOW TABLES LIKE 'krempl_artikelgeraet_22_backup_%'") backups = [row[0] for row in cursor.fetchall()] # 2. Nach Datum sortieren (Tabellenname enthält Zeitstempel) backups.sort() # 3. Wenn mehr als 2 Backups existieren, die ältesten löschen while len(backups) >= 3: to_delete = backups.pop(0) try: cursor.execute(f"DROP TABLE `{to_delete}`") print(f"[INFO] Altes Backup gelöscht: {to_delete}") except Exception as e: print(f"[WARN] Konnte Backup nicht löschen: {e}") # 4. Neues Backup anlegen name = f"krempl_artikelgeraet_22_backup_{datetime.now().strftime('%Y%m%d_%H%M%S')}" try: cursor.execute(f"CREATE TABLE `{name}` AS SELECT * FROM krempl_artikelgeraet_22") print(f"[INFO] Backup-Tabelle erstellt: {name}") except Exception as e: print(f"[WARN] Backup fehlgeschlagen: {e}") if __name__ == '__main__': parser = argparse.ArgumentParser(description='Import-Skript für Intelectra Webshop') parser.add_argument('csv_file', help='Pfad zur CSV-Datei') parser.add_argument('--passendwie', action='store_true', help='Import in krempl_passendwie Tabelle') parser.add_argument('--geraete', action='store_true', help='Import in krempl_geraete_22 Tabelle') parser.add_argument('--mapping', action='store_true', help='Import in krempl_artikelgeraet_22 Tabelle') args = parser.parse_args() print(f"[INFO] Starte Import für Datei: {args.csv_file}") if args.mapping: run_mapping_import(args.csv_file) elif args.geraete: run_geraete_import(args.csv_file) elif args.passendwie: run_passendwie_import(args.csv_file) else: run_import(args.csv_file)