v1.7.5: Konsolidierung in Plausi-Check-Modus integriert

- Modus "plausi_check_data" (Methode `run_plausibility_checks_batch`) erweitert, um Finanzdaten (Umsatz/MA) vor den Plausibilitätsprüfungen zu konsolidieren.
- Konsolidierungslogik (Wiki > CRM) aus `_process_single_row` in `run_plausibility_checks_batch` übernommen und angepasst.
- Schreibt nun die neu konsolidierten Werte in Spalten AY ("Finaler Umsatz (Wiki>CRM)") und BA ("Finaler Mitarbeiter (Wiki>CRM)").
- Plausibilitäts-Checks verwenden diese frisch konsolidierten Werte als Input.
- Ziel: Ermöglicht einen vollständigen Plausibilitäts-Check-Lauf ohne vorherigen separaten `reeval`-Lauf für die Datenkonsolidierung.
- Logik zur Behandlung von "0"-Werten in `get_numeric_filter_value` und `_get_numeric_value_for_plausi` weiter verfeinert, um "0 als unbekannt" vs. "berechnete 0" zu unterscheiden.
This commit is contained in:
2025-05-13 11:19:06 +00:00
parent 40bfabc4bc
commit 081bf87a5e

View File

@@ -8157,7 +8157,12 @@ class DataProcessor:
def run_plausibility_checks_batch(self, start_sheet_row=None, end_sheet_row=None, limit=None):
self.logger.info(f"Starte Modus 'Plausibilitäts-Checks'. Bereich: {start_sheet_row if start_sheet_row is not None else 'Datenstart'} bis {end_sheet_row if end_sheet_row else 'Sheet-Ende'}, Limit: {limit if limit is not None else 'Unbegrenzt'}")
self.logger.info(f"Starte Modus 'Plausibilitäts-Checks mit Konsolidierung'. Bereich: {start_sheet_row if start_sheet_row is not None else 'Datenstart'} bis {end_sheet_row if end_sheet_row else 'Sheet-Ende'}, Limit: {limit if limit is not None else 'Unbegrenzt'}")
plausi_ts_key = "Plausibilität Prüfdatum"
if plausi_ts_key not in COLUMN_MAP:
self.logger.error(f"FEHLER: Schlüssel '{plausi_ts_key}' nicht in COLUMN_MAP. Abbruch.")
return
if not self.sheet_handler.load_data():
self.logger.error("Konnte Sheet-Daten nicht laden für Plausi-Checks. Abbruch.")
@@ -8166,28 +8171,36 @@ class DataProcessor:
all_data = self.sheet_handler.get_all_data_with_headers()
header_offset = self.sheet_handler._header_rows
# Benötigte Spalten für den Input des Plausi-Checks
required_input_keys = [
"Finaler Umsatz (Wiki>CRM)", "Finaler Mitarbeiter (Wiki>CRM)",
# Spalten für Konsolidierungs-Input
kons_input_keys = [
"CRM Umsatz", "Wiki Umsatz", "CRM Anzahl Mitarbeiter", "Wiki Mitarbeiter"
]
# Spalten für den Output
output_keys = [
# Spalten für Konsolidierungs-Output (und Plausi-Input)
kons_output_keys = [
"Finaler Umsatz (Wiki>CRM)", "Finaler Mitarbeiter (Wiki>CRM)"
]
# Spalten für Plausi-Output
plausi_output_keys = [
"Plausibilität Umsatz", "Plausibilität Mitarbeiter", "Plausibilität Umsatz/MA Ratio",
"Abweichung Umsatz CRM/Wiki", "Abweichung MA CRM/Wiki", "Plausibilität Begründung"
"Abweichung Umsatz CRM/Wiki", "Abweichung MA CRM/Wiki", "Plausibilität Begründung",
plausi_ts_key # Inklusive des neuen Timestamps
]
# Prüfen, ob alle Keys da sind (vereinfacht)
if not all(key in COLUMN_MAP for key in required_input_keys + output_keys):
self.logger.error("Nicht alle benötigten Spalten für Plausi-Checks in COLUMN_MAP. Abbruch.")
all_needed_keys = kons_input_keys + kons_output_keys + plausi_output_keys
if not all(key in COLUMN_MAP for key in all_needed_keys):
missing_k = [k for k in all_needed_keys if k not in COLUMN_MAP]
self.logger.error(f"Nicht alle benötigten Spalten ({missing_k}) für Plausi-Checks mit Konsolidierung in COLUMN_MAP. Abbruch.")
return
updates_fuer_sheet = []
processed_rows_count = 0
now_timestamp_str = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
effective_start_row = start_sheet_row if start_sheet_row is not None else header_offset + 1
effective_end_row = end_sheet_row if end_sheet_row is not None else len(all_data)
self.logger.info(f"Prüfe und konsolidiere Zeilen {effective_start_row} bis {effective_end_row} für Plausi-Checks.")
for row_num_sheet in range(effective_start_row, effective_end_row + 1):
if limit is not None and processed_rows_count >= limit:
self.logger.info(f"Limit von {limit} Zeilen für Plausi-Checks erreicht.")
@@ -8197,55 +8210,101 @@ class DataProcessor:
if row_list_idx >= len(all_data): break
row_data = all_data[row_list_idx]
# --- BEGINN NEUER DEBUG-BLOCK ---
crm_name_log = self._get_cell_value_safe(row_data, "CRM Name")
final_u_val_log = self._get_cell_value_safe(row_data, "Finaler Umsatz (Wiki>CRM)")
final_m_val_log = self._get_cell_value_safe(row_data, "Finaler Mitarbeiter (Wiki>CRM)")
self.logger.debug(f"Zeile {row_num_sheet} ({crm_name_log[:30]}...): Werte für Plausi-Vorabcheck -> Finaler U: '{final_u_val_log}', Finaler MA: '{final_m_val_log}'")
# --- ENDE NEUER DEBUG-BLOCK ---
plausi_input_data = {}
valid_input_for_check = True
for key in required_input_keys:
val = self._get_cell_value_safe(row_data, key)
plausi_input_data[key] = val
if key in ["Finaler Umsatz (Wiki>CRM)", "Finaler Mitarbeiter (Wiki>CRM)"] and \
(not val or str(val).lower() == 'k.a.' or str(val).upper().startswith("FEHLER")):
valid_input_for_check = False
self.logger.debug(f"Zeile {row_num_sheet}: Setze valid_input_for_check=False, da '{key}' den Wert '{str(val)[:30]}...' hat.")
break
if not valid_input_for_check:
self.logger.debug(f"Zeile {row_num_sheet}: Übersprungen für Plausi-Check NACH Detailprüfung (valid_input_for_check=False).")
continue
processed_rows_count +=1
# --- 1. Konsolidierung (Logik aus _process_single_row, Block 3e) ---
final_umsatz_str_konsolidiert = "k.A."
final_ma_str_konsolidiert = "k.A."
crm_umsatz_val_str = self._get_cell_value_safe(row_data, "CRM Umsatz")
# Für Wiki-Werte: Wenn _process_single_row nicht lief, sind final_wiki_data nicht aktuell.
# Wir müssen die Wiki-Werte direkt aus row_data lesen für diesen Modus.
wiki_umsatz_val_str = self._get_cell_value_safe(row_data, "Wiki Umsatz")
crm_ma_val_str = self._get_cell_value_safe(row_data, "CRM Anzahl Mitarbeiter")
wiki_ma_val_str = self._get_cell_value_safe(row_data, "Wiki Mitarbeiter")
try:
plausi_results = self._check_financial_plausibility(plausi_input_data)
updates_fuer_sheet.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["Plausibilität Umsatz"] + 1)}{row_num_sheet}', 'values': [[plausi_results.get("plaus_umsatz_flag", "FEHLER")]]})
# ... (alle anderen Plausi-Spalten hinzufügen) ...
updates_fuer_sheet.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["Plausibilität Mitarbeiter"] + 1)}{row_num_sheet}', 'values': [[plausi_results.get("plaus_ma_flag", "FEHLER")]]})
updates_fuer_sheet.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["Plausibilität Umsatz/MA Ratio"] + 1)}{row_num_sheet}', 'values': [[plausi_results.get("plaus_ratio_flag", "FEHLER")]]})
updates_fuer_sheet.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["Abweichung Umsatz CRM/Wiki"] + 1)}{row_num_sheet}', 'values': [[plausi_results.get("abweichung_umsatz_flag", "FEHLER")]]})
updates_fuer_sheet.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["Abweichung MA CRM/Wiki"] + 1)}{row_num_sheet}', 'values': [[plausi_results.get("abweichung_ma_flag", "FEHLER")]]})
updates_fuer_sheet.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["Plausibilität Begründung"] + 1)}{row_num_sheet}', 'values': [[plausi_results.get("plausi_begruendung_final", "Fehler Begr.")]]})
num_crm_umsatz = get_numeric_filter_value(crm_umsatz_val_str, is_umsatz=True)
num_wiki_umsatz = get_numeric_filter_value(wiki_umsatz_val_str, is_umsatz=True)
num_crm_ma = get_numeric_filter_value(crm_ma_val_str, is_umsatz=False)
num_wiki_ma = get_numeric_filter_value(wiki_ma_val_str, is_umsatz=False)
except Exception as e_plausi_run:
self.logger.error(f"Fehler im Plausi-Check Lauf für Zeile {row_num_sheet}: {e_plausi_run}")
# ... (Fehlerwerte in Plausi-Spalten schreiben) ...
final_num_umsatz = num_wiki_umsatz if num_wiki_umsatz > 0 else num_crm_umsatz
final_num_ma = num_wiki_ma if num_wiki_ma > 0 else num_crm_ma
# String-Konvertierung (0 wird zu "k.A." wenn es aus leer/k.A. Quellen kommt,
# oder zu "0" wenn es z.B. aus "173" (Euro) gerundet wird)
final_umsatz_str_konsolidiert = str(int(round(final_num_umsatz))) if final_num_umsatz > 0 or (final_num_umsatz == 0 and crm_umsatz_val_str == "0" and wiki_umsatz_val_str == "0" ) else 'k.A.'
final_ma_str_konsolidiert = str(int(round(final_num_ma))) if final_num_ma > 0 or (final_num_ma == 0 and crm_ma_val_str == "0" and wiki_ma_val_str == "0") else 'k.A.'
if len(updates_fuer_sheet) >= getattr(Config, 'UPDATE_BATCH_ROW_LIMIT', 50) * 6: # 6 Spalten
self.logger.info(f"Sende Plausi-Check Batch-Update ({len(updates_fuer_sheet)//6} Zeilen)...")
except Exception as e_conso_direct:
self.logger.error(f"Fehler bei direkter Konsolidierung in Plausi-Check für Zeile {row_num_sheet}: {e_conso_direct}")
final_umsatz_str_konsolidiert = "FEHLER_KONSO_DIREKT"
final_ma_str_konsolidiert = "FEHLER_KONSO_DIREKT"
# Update-Dicts für die konsolidierten Werte vorbereiten
current_row_updates = []
current_row_updates.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["Finaler Umsatz (Wiki>CRM)"] + 1)}{row_num_sheet}', 'values': [[final_umsatz_str_konsolidiert]]})
current_row_updates.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["Finaler Mitarbeiter (Wiki>CRM)"] + 1)}{row_num_sheet}', 'values': [[final_ma_str_konsolidiert]]})
# --- 2. Plausibilitäts-Checks (basierend auf den gerade konsolidierten Werten) ---
# Bedingung, um Plausi-Check überhaupt zu starten (Input-Werte müssen vorhanden sein)
valid_input_for_plausi_check = True
if final_umsatz_str_konsolidiert.upper().startswith("FEHLER") or final_umsatz_str_konsolidiert.lower() == 'k.a.' or \
final_ma_str_konsolidiert.upper().startswith("FEHLER") or final_ma_str_konsolidiert.lower() == 'k.a.':
# Wenn einer der Hauptwerte schon "k.A." oder Fehler ist, sind viele Plausi-Checks nicht sinnvoll
# Wir setzen die Flags auf NICHT_PRUEFBAR oder spezifische Fehler und die Begründung
plausi_results = {
"plaus_umsatz_flag": "NICHT_PRUEFBAR" if final_umsatz_str_konsolidiert.lower() == 'k.a.' else "FEHLER_INPUT",
"plaus_ma_flag": "NICHT_PRUEFBAR" if final_ma_str_konsolidiert.lower() == 'k.a.' else "FEHLER_INPUT",
"plaus_ratio_flag": "NICHT_PRUEFBAR",
"abweichung_umsatz_flag": "N/A",
"abweichung_ma_flag": "N/A",
"plausi_begruendung_final": f"Input für Plausi-Check unvollständig/fehlerhaft (U: {final_umsatz_str_konsolidiert}, MA: {final_ma_str_konsolidiert})."
}
valid_input_for_plausi_check = False # Für das Zählen
if valid_input_for_plausi_check:
processed_rows_count +=1 # Zähle nur, wenn Plausi-Check tatsächlich durchgeführt wird
try:
plausi_input_data = {
"Finaler Umsatz (Wiki>CRM)": final_umsatz_str_konsolidiert,
"Finaler Mitarbeiter (Wiki>CRM)": final_ma_str_konsolidiert,
"CRM Umsatz": crm_umsatz_val_str, # Originalwerte für Abweichungscheck
"Wiki Umsatz": wiki_umsatz_val_str,
"CRM Anzahl Mitarbeiter": crm_ma_val_str,
"Wiki Mitarbeiter": wiki_ma_val_str
}
plausi_results = self._check_financial_plausibility(plausi_input_data)
except Exception as e_plausi_run:
self.logger.error(f"Fehler im Plausi-Check Lauf für Zeile {row_num_sheet}: {e_plausi_run}")
plausi_results = { # Fehler-Defaults
"plaus_umsatz_flag": "FEHLER_CHECK_RUNTIME", "plaus_ma_flag": "FEHLER_CHECK_RUNTIME",
"plaus_ratio_flag": "FEHLER_CHECK_RUNTIME", "abweichung_umsatz_flag": "FEHLER_CHECK_RUNTIME",
"abweichung_ma_flag": "FEHLER_CHECK_RUNTIME",
"plausi_begruendung_final": f"Systemfehler Plausi-Check: {str(e_plausi_run)[:100]}"
}
# Plausi-Ergebnisse zu Updates hinzufügen
current_row_updates.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["Plausibilität Umsatz"] + 1)}{row_num_sheet}', 'values': [[plausi_results.get("plaus_umsatz_flag", "ERR_FLAG")]]})
current_row_updates.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["Plausibilität Mitarbeiter"] + 1)}{row_num_sheet}', 'values': [[plausi_results.get("plaus_ma_flag", "ERR_FLAG")]]})
current_row_updates.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["Plausibilität Umsatz/MA Ratio"] + 1)}{row_num_sheet}', 'values': [[plausi_results.get("plaus_ratio_flag", "ERR_FLAG")]]})
current_row_updates.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["Abweichung Umsatz CRM/Wiki"] + 1)}{row_num_sheet}', 'values': [[plausi_results.get("abweichung_umsatz_flag", "ERR_FLAG")]]})
current_row_updates.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["Abweichung MA CRM/Wiki"] + 1)}{row_num_sheet}', 'values': [[plausi_results.get("abweichung_ma_flag", "ERR_FLAG")]]})
current_row_updates.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP["Plausibilität Begründung"] + 1)}{row_num_sheet}', 'values': [[plausi_results.get("plausi_begruendung_final", "Fehler Begr.")]]})
current_row_updates.append({'range': f'{self.sheet_handler._get_col_letter(COLUMN_MAP[plausi_ts_key] + 1)}{row_num_sheet}', 'values': [[now_timestamp_str]]})
updates_fuer_sheet.extend(current_row_updates)
# Batch-Update Logik (Anzahl Spalten: 2 Konsolidierung + 6 Plausi + 1 TS = 9)
if len(updates_fuer_sheet) >= getattr(Config, 'UPDATE_BATCH_ROW_LIMIT', 50) * 9:
self.logger.info(f"Sende Plausi-Check & Konsolidierungs Batch-Update ({len(updates_fuer_sheet)//9} Zeilen)...")
self.sheet_handler.batch_update_cells(updates_fuer_sheet)
updates_fuer_sheet = []
if updates_fuer_sheet:
self.logger.info(f"Sende finalen Plausi-Check Batch-Update ({len(updates_fuer_sheet)//6} Zeilen)...")
self.logger.info(f"Sende finalen Plausi-Check & Konsolidierungs Batch-Update ({len(updates_fuer_sheet)//9} Zeilen)...")
self.sheet_handler.batch_update_cells(updates_fuer_sheet)
self.logger.info(f"Plausibilitäts-Check-Lauf beendet. {processed_rows_count} Zeilen geprüft.")
self.logger.info(f"Plausibilitäts-Check-Lauf (mit Konsolidierung) beendet. {processed_rows_count} Zeilen geprüft/konsolidiert.")
# ==========================================================================
# === Utility Methods (ML Data Prep & Training) ============================