From ccf91c472b67ace3d33be71bf13ca2d2d9393ea9 Mon Sep 17 00:00:00 2001 From: Floke Date: Mon, 12 May 2025 18:58:11 +0000 Subject: [PATCH] debug --- brancheneinstufung.py | 153 +++++++++++++++++++----------------------- 1 file changed, 70 insertions(+), 83 deletions(-) diff --git a/brancheneinstufung.py b/brancheneinstufung.py index ca816fef..551ac9f8 100644 --- a/brancheneinstufung.py +++ b/brancheneinstufung.py @@ -7959,90 +7959,87 @@ class DataProcessor: def _check_financial_plausibility(self, row_data_dict): - """ - Prüft die Plausibilität der finalen Umsatz- und Mitarbeiterzahlen - sowie deren Ratio und den Abgleich mit CRM-Daten. - - Args: - row_data_dict (dict): Ein Dictionary mit den relevanten Werten der Zeile, - z.B. {'Finaler Umsatz (Wiki>CRM)': '123', - 'Finaler Mitarbeiter (Wiki>CRM)': '10', - 'CRM Umsatz': '120', 'Wiki Umsatz': '123', ...} - Returns: - dict: Ein Dictionary mit Plausibilitäts-Flags und einer Begründung. - """ results = { - "plaus_umsatz_flag": "OK", - "plaus_ma_flag": "OK", - "plaus_ratio_flag": "OK", - "abweichung_umsatz_flag": "N/A", # N/A wenn nicht prüfbar - "abweichung_ma_flag": "N/A", # N/A wenn nicht prüfbar - "begruendungen": [] # Liste für mehrere Begründungen + "plaus_umsatz_flag": "NICHT_PRUEFBAR", # Default, wenn Wert NaN ist + "plaus_ma_flag": "NICHT_PRUEFBAR", # Default, wenn Wert NaN ist + "plaus_ratio_flag": "NICHT_PRUEFBAR",# Default + "abweichung_umsatz_flag": "N/A", + "abweichung_ma_flag": "N/A", + "begruendungen": [] } final_umsatz_str = row_data_dict.get("Finaler Umsatz (Wiki>CRM)", "k.A.") final_ma_str = row_data_dict.get("Finaler Mitarbeiter (Wiki>CRM)", "k.A.") + # DEBUG-Ausgabe für die Einganswerte der Funktion + self.logger.debug(f" _check_financial_plausibility Input: final_umsatz_str='{final_umsatz_str}', final_ma_str='{final_ma_str}'") + umsatz_num = self._get_numeric_value_for_plausi(final_umsatz_str, is_umsatz=True) ma_num = self._get_numeric_value_for_plausi(final_ma_str, is_umsatz=False) - # 1. Format-Plausibilität - # Wird gesetzt, wenn der Originalstring nicht k.A./leer/explizit "0" war, aber die Konvertierung trotzdem zu NaN führte. - if pd.isna(umsatz_num) and final_umsatz_str.lower().strip() not in ['k.a.', '', 'n/a', '-', '0', '0.0', '0,00', '0.000']: - results["plaus_umsatz_flag"] = "FEHLER_FORMAT" - results["begruendungen"].append(f"Finaler Umsatz ('{final_umsatz_str}') konnte nicht als gültige Zahl interpretiert werden.") - - if pd.isna(ma_num) and final_ma_str.lower().strip() not in ['k.a.', '', 'n/a', '-', '0', '0.0', '0,00', '0.000']: - results["plaus_ma_flag"] = "FEHLER_FORMAT" - results["begruendungen"].append(f"Finale MA-Zahl ('{final_ma_str}') konnte nicht als gültige Zahl interpretiert werden.") + self.logger.debug(f" _check_financial_plausibility Numerisch: umsatz_num={umsatz_num}, ma_num={ma_num}") - # Nur weiter prüfen, wenn Werte numerisch sind (nicht NaN) - if not pd.isna(umsatz_num): - if umsatz_num == 0 and final_umsatz_str.lower().strip() not in ['k.a.', '', 'n/a', '-', '0', '0.0', '0,00', '0.000']: # Gilt für Fälle, wo z.B. "0 Tsd" zu 0.0 wird + # 1. Plausibilität Umsatz + if pd.isna(umsatz_num): + # Wenn der Originalstring nicht schon 'k.A.' oder leer war (was bereits NaN ergibt), dann ist es ein Formatfehler + if final_umsatz_str.lower().strip() not in ['k.a.', '', 'n/a', '-']: + results["plaus_umsatz_flag"] = "FEHLER_FORMAT" + results["begruendungen"].append(f"Finaler Umsatz ('{final_umsatz_str}') konnte nicht als Zahl interpretiert werden.") + # else: Flag bleibt "NICHT_PRUEFBAR" + else: # umsatz_num ist eine gültige Zahl (kann auch 0 sein) + results["plaus_umsatz_flag"] = "OK" # Initialannahme für numerische Werte + if umsatz_num == 0: results["plaus_umsatz_flag"] = "WARNUNG_NULL_WERT" - results["begruendungen"].append(f"Finaler Umsatz ist numerisch 0 (ursprünglicher Wert: '{final_umsatz_str}').") - elif umsatz_num < getattr(Config, 'PLAUSI_UMSATZ_MIN_WARNUNG', 50000) and umsatz_num != 0: # 0 wurde oben behandelt + results["begruendungen"].append(f"Finaler Umsatz ist numerisch 0 (aus '{final_umsatz_str}').") + elif umsatz_num < getattr(Config, 'PLAUSI_UMSATZ_MIN_WARNUNG', 50000): results["plaus_umsatz_flag"] = "WARNUNG_NIEDRIG" - results["begruendungen"].append(f"Finaler Umsatz ({umsatz_num:,.0f} €) sehr niedrig (< {getattr(Config, 'PLAUSI_UMSATZ_MIN_WARNUNG', 50000):,.0f} €).") - elif umsatz_num > getattr(Config, 'PLAUSI_UMSATZ_MAX_WARNUNG', 200000000000): # Jetzt als elif oder separates if + results["begruendungen"].append(f"Finaler Umsatz ({umsatz_num:,.0f} €) < {getattr(Config, 'PLAUSI_UMSATZ_MIN_WARNUNG', 50000):,.0f} €.") + elif umsatz_num > getattr(Config, 'PLAUSI_UMSATZ_MAX_WARNUNG', 200000000000): results["plaus_umsatz_flag"] = "WARNUNG_HOCH" - results["begruendungen"].append(f"Finaler Umsatz ({umsatz_num:,.0f} €) sehr hoch (> {getattr(Config, 'PLAUSI_UMSATZ_MAX_WARNUNG', 200000000000):,.0f} €).") - # Wenn keine der obigen Bedingungen zutrifft und der Flag noch "OK" ist, bleibt er "OK". + results["begruendungen"].append(f"Finaler Umsatz ({umsatz_num:,.0f} €) > {getattr(Config, 'PLAUSI_UMSATZ_MAX_WARNUNG', 200000000000):,.0f} €.") - if not pd.isna(ma_num): - if ma_num == 0 and final_ma_str.lower().strip() not in ['k.a.', '', 'n/a', '-', '0', '0.0', '0,00', '0.000']: + # 2. Plausibilität Mitarbeiter + if pd.isna(ma_num): + if final_ma_str.lower().strip() not in ['k.a.', '', 'n/a', '-']: + results["plaus_ma_flag"] = "FEHLER_FORMAT" + results["begruendungen"].append(f"Finale MA-Zahl ('{final_ma_str}') konnte nicht als Zahl interpretiert werden.") + # else: Flag bleibt "NICHT_PRUEFBAR" + else: # ma_num ist eine gültige Zahl + results["plaus_ma_flag"] = "OK" # Initialannahme + if ma_num == 0: # Explizit numerisch 0 results["plaus_ma_flag"] = "WARNUNG_NULL_WERT" - results["begruendungen"].append(f"Finale MA-Zahl ist numerisch 0 (ursprünglicher Wert: '{final_ma_str}').") - elif ma_num < getattr(Config, 'PLAUSI_MA_MIN_WARNUNG_ABS', 1) and ma_num != 0: # 0 wurde oben behandelt + results["begruendungen"].append(f"Finale MA-Zahl ist numerisch 0 (aus '{final_ma_str}').") + elif ma_num < getattr(Config, 'PLAUSI_MA_MIN_WARNUNG_ABS', 1): results["plaus_ma_flag"] = "WARNUNG_NIEDRIG" results["begruendungen"].append(f"Finale MA-Zahl ({ma_num:.0f}) < {getattr(Config, 'PLAUSI_MA_MIN_WARNUNG_ABS', 1)}.") elif ma_num > getattr(Config, 'PLAUSI_MA_MAX_WARNUNG', 1000000): results["plaus_ma_flag"] = "WARNUNG_HOCH" - results["begruendungen"].append(f"Finale MA-Zahl ({ma_num:.0f}) sehr hoch (> {getattr(Config, 'PLAUSI_MA_MAX_WARNUNG', 1000000)}).") + results["begruendungen"].append(f"Finale MA-Zahl ({ma_num:.0f}) > {getattr(Config, 'PLAUSI_MA_MAX_WARNUNG', 1000000)}.") - # Spezifischer Check: Wenig MA bei signifikantem Umsatz if not pd.isna(umsatz_num) and umsatz_num > getattr(Config, 'PLAUSI_UMSATZ_MIN_SCHWELLE_FUER_MA_CHECK', 1000000) and \ - ma_num < getattr(Config, 'PLAUSI_MA_MIN_WARNUNG_BEI_UMSATZ', 3) and ma_num !=0 : # MA !=0 hier auch wichtig - # Flag könnte auch 'WARNUNG_NIEDRIG' sein, aber Begründung ist spezifischer + ma_num !=0 and ma_num < getattr(Config, 'PLAUSI_MA_MIN_WARNUNG_BEI_UMSATZ', 3) : if results["plaus_ma_flag"] == "OK": results["plaus_ma_flag"] = "WARNUNG_RATIO_IMPL" results["begruendungen"].append(f"Wenige MA ({ma_num:.0f}) bei signifikantem Umsatz ({umsatz_num:,.0f} €).") # 3. Umsatz/MA Ratio - if not pd.isna(umsatz_num) and not pd.isna(ma_num) and ma_num > 0: # Division durch Null vermeiden - ratio = umsatz_num / ma_num - if ratio < getattr(Config, 'PLAUSI_RATIO_UMSATZ_PRO_MA_MIN', 25000): - results["plaus_ratio_flag"] = "WARNUNG_RATIO_NIEDRIG" - results["begruendungen"].append(f"Umsatz/MA Ratio ({ratio:,.0f} €/MA) sehr niedrig (< {getattr(Config, 'PLAUSI_RATIO_UMSATZ_PRO_MA_MIN', 25000):,.0f}).") - if ratio > getattr(Config, 'PLAUSI_RATIO_UMSATZ_PRO_MA_MAX', 1500000): - results["plaus_ratio_flag"] = "WARNUNG_RATIO_HOCH" - results["begruendungen"].append(f"Umsatz/MA Ratio ({ratio:,.0f} €/MA) sehr hoch (> {getattr(Config, 'PLAUSI_RATIO_UMSATZ_PRO_MA_MAX', 1500000):,.0f}).") - elif not pd.isna(umsatz_num) and (pd.isna(ma_num) or ma_num == 0) and umsatz_num > 0 : # Umsatz vorhanden, aber keine MA - results["plaus_ratio_flag"] = "FEHLER_RATIO_MA_NULL" - results["begruendungen"].append("Ratio nicht berechenbar: Umsatz vorhanden, aber MA=0 oder nicht numerisch.") - if results["plaus_ma_flag"] == "OK": results["plaus_ma_flag"] = "WARNUNG_NULL_BEI_UMSATZ" - - - # 4. Abgleich CRM vs. Wiki + if not pd.isna(umsatz_num) and not pd.isna(ma_num): + if ma_num > 0: + ratio = umsatz_num / ma_num + results["plaus_ratio_flag"] = "OK" # Initialannahme + if ratio < getattr(Config, 'PLAUSI_RATIO_UMSATZ_PRO_MA_MIN', 25000): + results["plaus_ratio_flag"] = "WARNUNG_RATIO_NIEDRIG" + results["begruendungen"].append(f"Umsatz/MA Ratio ({ratio:,.0f} €/MA) < {getattr(Config, 'PLAUSI_RATIO_UMSATZ_PRO_MA_MIN', 25000):,.0f}.") + elif ratio > getattr(Config, 'PLAUSI_RATIO_UMSATZ_PRO_MA_MAX', 1500000): + results["plaus_ratio_flag"] = "WARNUNG_RATIO_HOCH" + results["begruendungen"].append(f"Umsatz/MA Ratio ({ratio:,.0f} €/MA) > {getattr(Config, 'PLAUSI_RATIO_UMSATZ_PRO_MA_MAX', 1500000):,.0f}.") + elif umsatz_num > 0 and ma_num == 0: # Umsatz da, aber MA ist numerisch 0 + results["plaus_ratio_flag"] = "FEHLER_RATIO_MA_NULL" + results["begruendungen"].append("Ratio nicht berechenbar: Umsatz > 0, aber MA=0.") + if results["plaus_ma_flag"] == "OK" or results["plaus_ma_flag"] == "WARNUNG_NULL_WERT": + results["plaus_ma_flag"] = "WARNUNG_NULL_BEI_UMSATZ" # Spezifischere Warnung + # Wenn ma_num NaN ist oder umsatz_num NaN ist, bleibt der Flag "NICHT_PRUEFBAR" + + # ... (Rest der Funktion für Abweichung CRM/Wiki bleibt gleich) ... crm_umsatz_str = row_data_dict.get("CRM Umsatz", "k.A.") wiki_umsatz_str = row_data_dict.get("Wiki Umsatz", "k.A.") crm_ma_str = row_data_dict.get("CRM Anzahl Mitarbeiter", "k.A.") @@ -8055,42 +8052,32 @@ class DataProcessor: abweichung_prozent = getattr(Config, 'PLAUSI_ABWEICHUNG_CRM_WIKI_PROZENT', 30) / 100.0 - # Umsatz Abweichung if not pd.isna(crm_u) and not pd.isna(wiki_u): - if crm_u > 0 and wiki_u > 0 : # Nur prüfen, wenn beide positiv sind - diff = abs(crm_u - wiki_u) - max_val = max(crm_u, wiki_u) + if crm_u == 0 and wiki_u == 0: results["abweichung_umsatz_flag"] = "OK_BEIDE_NULL" + elif crm_u > 0 and wiki_u > 0 : + diff = abs(crm_u - wiki_u); max_val = max(crm_u, wiki_u) if max_val > 0 and (diff / max_val) > abweichung_prozent: results["abweichung_umsatz_flag"] = "WARNUNG_SIGNIFIKANT" results["begruendungen"].append(f"Umsatz CRM ({crm_u:,.0f}) vs. Wiki ({wiki_u:,.0f}) weicht >{abweichung_prozent*100:.0f}% ab.") - else: - results["abweichung_umsatz_flag"] = "OK" - else: # Einer oder beide sind 0 oder negativ, was schon auffällig ist - results["abweichung_umsatz_flag"] = "INFO_NULL_WERT" - + else: results["abweichung_umsatz_flag"] = "OK" + else: results["abweichung_umsatz_flag"] = "INFO_EINER_NULL" elif pd.isna(crm_u) and not pd.isna(wiki_u): results["abweichung_umsatz_flag"] = "CRM_FEHLT" elif not pd.isna(crm_u) and pd.isna(wiki_u): results["abweichung_umsatz_flag"] = "WIKI_FEHLT" - # Mitarbeiter Abweichung if not pd.isna(crm_m) and not pd.isna(wiki_m): - if crm_m > 0 and wiki_m > 0: - diff = abs(crm_m - wiki_m) - max_val = max(crm_m, wiki_m) - if max_val > 0 and (diff / max_val) > abweichung_prozent: + if crm_m == 0 and wiki_m == 0: results["abweichung_ma_flag"] = "OK_BEIDE_NULL" + elif crm_m >= 0 and wiki_m >= 0: # Erlaube 0 MA für Vergleich, wenn nicht NaN + # Spezialfall: wenn einer 0 ist und der andere nicht, ist es eine große Abweichung, es sei denn beide sind sehr klein + if (crm_m == 0 and wiki_m > 5) or (wiki_m == 0 and crm_m > 5) or (crm_m > 0 and wiki_m > 0 and (abs(crm_m - wiki_m) / max(crm_m, wiki_m)) > abweichung_prozent): results["abweichung_ma_flag"] = "WARNUNG_SIGNIFIKANT" - results["begruendungen"].append(f"MA CRM ({crm_m:.0f}) vs. Wiki ({wiki_m:.0f}) weicht >{abweichung_prozent*100:.0f}% ab.") - else: - results["abweichung_ma_flag"] = "OK" - else: - results["abweichung_ma_flag"] = "INFO_NULL_WERT" + results["begruendungen"].append(f"MA CRM ({crm_m:.0f}) vs. Wiki ({wiki_m:.0f}) weicht signifikant ab.") + else: results["abweichung_ma_flag"] = "OK" + # else: bleibt N/A elif pd.isna(crm_m) and not pd.isna(wiki_m): results["abweichung_ma_flag"] = "CRM_FEHLT" elif not pd.isna(crm_m) and pd.isna(wiki_m): results["abweichung_ma_flag"] = "WIKI_FEHLT" - # Begründungen zusammenfassen - if not results["begruendungen"]: - results["plausi_begruendung_final"] = "Plausibilität OK" - else: - results["plausi_begruendung_final"] = "; ".join(results["begruendungen"]) + if not results["begruendungen"]: results["plausi_begruendung_final"] = "Plausibilität OK" + else: results["plausi_begruendung_final"] = "; ".join(results["begruendungen"]) return results