#!/usr/bin/env python3 """ Test: Deaktivierung via gueltigBis + reihenfolgeIndex-Verhalten ================================================================ Ziele: 1. Teste ob abgelaufene Adressen (gueltigBis < heute) ausgeblendet werden 2. Teste ob man reihenfolgeIndex beim POST setzen kann 3. Teste ob neue Adressen automatisch ans Ende rutschen 4. Teste ob man reihenfolgeIndex via PUT ändern kann (Sortierung) """ import asyncio import sys import os from datetime import datetime, timedelta # Add parent directory to path sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..')) from services.advoware import AdvowareAPI # Test-Konfiguration TEST_BETNR = 104860 # ANSI Color codes BOLD = '\033[1m' RED = '\033[91m' GREEN = '\033[92m' YELLOW = '\033[93m' BLUE = '\033[94m' RESET = '\033[0m' def print_header(text): print(f"\n{BOLD}{'='*80}{RESET}") print(f"{BOLD}{text}{RESET}") print(f"{BOLD}{'='*80}{RESET}\n") def print_success(text): print(f"{GREEN}✓ {text}{RESET}") def print_error(text): print(f"{RED}✗ {text}{RESET}") def print_warning(text): print(f"{YELLOW}⚠ {text}{RESET}") def print_info(text): print(f"{BLUE}ℹ {text}{RESET}") class SimpleLogger: """Minimal logger für AdvowareAPI""" def info(self, msg): pass def error(self, msg): print_error(msg) def debug(self, msg): pass def warning(self, msg): pass class SimpleContext: """Minimal context für AdvowareAPI""" def __init__(self): self.logger = SimpleLogger() def log_info(self, msg): pass def log_error(self, msg): print_error(msg) def log_debug(self, msg): pass async def test_1_create_expired_address(): """Test 1: Erstelle Adresse mit gueltigBis in der Vergangenheit""" print_header("TEST 1: Adresse mit gueltigBis in Vergangenheit (abgelaufen)") context = SimpleContext() advo = AdvowareAPI(context=context) # Datum in der Vergangenheit expired_date = "2023-12-31T23:59:59" address_data = { "strasse": "Abgelaufene Straße 99", "plz": "99999", "ort": "Vergangenheit", "land": "DE", "bemerkung": "TEST-ABGELAUFEN: Diese Adresse ist seit 2023 ungültig", "gueltigVon": "2020-01-01T00:00:00", "gueltigBis": expired_date # ← In der Vergangenheit! } print_info(f"Erstelle Adresse mit gueltigBis: {expired_date} (vor 2+ Jahren)") try: result = await advo.api_call( f'/api/v1/advonet/Beteiligte/{TEST_BETNR}/Adressen', method='POST', json_data=address_data ) if result and len(result) > 0: addr = result[0] print_success(f"✓ Adresse erstellt: rowId={addr.get('rowId')}") print_info(f" gueltigBis: {addr.get('gueltigBis')}") print_info(f" reihenfolgeIndex: {addr.get('reihenfolgeIndex')}") return addr.get('bemerkung') else: print_error("POST lieferte keine Response") return None except Exception as e: print_error(f"Fehler: {e}") import traceback traceback.print_exc() return None async def test_2_check_if_expired_address_visible(): """Test 2: Prüfe ob abgelaufene Adresse in GET sichtbar ist""" print_header("TEST 2: Ist abgelaufene Adresse in GET sichtbar?") context = SimpleContext() advo = AdvowareAPI(context=context) try: all_addresses = await advo.api_call( f'/api/v1/advonet/Beteiligte/{TEST_BETNR}/Adressen', method='GET' ) print_info(f"Gesamtanzahl Adressen: {len(all_addresses)}") # Suche abgelaufene Adresse expired_found = None active_count = 0 expired_count = 0 today = datetime.now() for addr in all_addresses: bemerkung = addr.get('bemerkung') or '' gueltig_bis = addr.get('gueltigBis') if 'TEST-ABGELAUFEN' in bemerkung: expired_found = addr print_success(f"\n✓ Abgelaufene Test-Adresse gefunden!") print_info(f" Index: {addr.get('reihenfolgeIndex')}") print_info(f" gueltigBis: {gueltig_bis}") print_info(f" Straße: {addr.get('strasse')}") # Zähle aktive vs. abgelaufene if gueltig_bis: try: bis_date = datetime.fromisoformat(gueltig_bis.replace('Z', '+00:00')) if bis_date < today: expired_count += 1 else: active_count += 1 except: pass print(f"\n{BOLD}Statistik:{RESET}") print(f" Aktive Adressen (gueltigBis > heute): {active_count}") print(f" Abgelaufene Adressen (gueltigBis < heute): {expired_count}") print(f" Ohne gueltigBis: {len(all_addresses) - active_count - expired_count}") if expired_found: print_error("\n❌ WICHTIG: Abgelaufene Adressen werden NICHT gefiltert!") print_warning("⚠ GET /Adressen zeigt ALLE Adressen, auch abgelaufene") print_info("💡 Filtern nach gueltigBis muss CLIENT-seitig erfolgen") return True else: print_success("\n✓ Abgelaufene Adresse nicht sichtbar (wird gefiltert)") return False except Exception as e: print_error(f"Fehler: {e}") import traceback traceback.print_exc() return None async def test_3_create_with_explicit_reihenfolgeIndex(): """Test 3: Versuche reihenfolgeIndex beim POST zu setzen""" print_header("TEST 3: Kann man reihenfolgeIndex beim POST setzen?") context = SimpleContext() advo = AdvowareAPI(context=context) # Versuche mit explizitem Index address_data = { "reihenfolgeIndex": 999, # ← Versuche expliziten Index "strasse": "Test Index 999", "plz": "88888", "ort": "Indextest", "land": "DE", "bemerkung": "TEST-INDEX: Versuch mit explizitem reihenfolgeIndex=999" } print_info("Versuche POST mit reihenfolgeIndex=999...") try: result = await advo.api_call( f'/api/v1/advonet/Beteiligte/{TEST_BETNR}/Adressen', method='POST', json_data=address_data ) if result and len(result) > 0: addr = result[0] actual_index = addr.get('reihenfolgeIndex') print_info(f"Response reihenfolgeIndex: {actual_index}") # Hole alle Adressen und prüfe wo sie gelandet ist all_addresses = await advo.api_call( f'/api/v1/advonet/Beteiligte/{TEST_BETNR}/Adressen', method='GET' ) found = None for a in all_addresses: if (a.get('bemerkung') or '').startswith('TEST-INDEX'): found = a break if found: real_index = found.get('reihenfolgeIndex') print_info(f"GET zeigt reihenfolgeIndex: {real_index}") if real_index == 999: print_success("\n✓ reihenfolgeIndex kann explizit gesetzt werden!") print_warning("⚠ ABER: Das könnte bestehende Adressen verschieben!") elif real_index == 0: print_warning("\n⚠ POST gibt reihenfolgeIndex=0 zurück") print_info("→ Echter Index wird erst nach GET sichtbar") else: print_error(f"\n❌ reihenfolgeIndex={real_index} ignoriert Vorgabe (999)") print_success("✓ Index wird automatisch vergeben (ans Ende)") return real_index except Exception as e: print_error(f"Fehler: {e}") import traceback traceback.print_exc() return None async def test_4_create_multiple_check_ordering(): """Test 4: Erstelle mehrere Adressen und prüfe Reihenfolge""" print_header("TEST 4: Mehrere neue Adressen - werden sie ans Ende gereiht?") context = SimpleContext() advo = AdvowareAPI(context=context) print_info("Hole aktuelle Adressen...") all_before = await advo.api_call( f'/api/v1/advonet/Beteiligte/{TEST_BETNR}/Adressen', method='GET' ) max_index_before = max([a.get('reihenfolgeIndex', 0) for a in all_before]) count_before = len(all_before) print_info(f" Anzahl vorher: {count_before}") print_info(f" Höchster Index: {max_index_before}") # Erstelle 3 neue Adressen print_info("\nErstelle 3 neue Adressen...") created_ids = [] for i in range(1, 4): address_data = { "strasse": f"Reihenfolge-Test {i}", "plz": f"7777{i}", "ort": f"Stadt-{i}", "land": "DE", "bemerkung": f"TEST-REIHENFOLGE-{i}" } try: result = await advo.api_call( f'/api/v1/advonet/Beteiligte/{TEST_BETNR}/Adressen', method='POST', json_data=address_data ) if result and len(result) > 0: created_ids.append(f"TEST-REIHENFOLGE-{i}") print_success(f" ✓ Adresse {i} erstellt") except Exception as e: print_error(f" ✗ Fehler bei Adresse {i}: {e}") # Hole alle Adressen erneut print_info("\nHole Adressen erneut...") all_after = await advo.api_call( f'/api/v1/advonet/Beteiligte/{TEST_BETNR}/Adressen', method='GET' ) count_after = len(all_after) print_info(f" Anzahl nachher: {count_after}") print_info(f" Neue Adressen: {count_after - count_before}") # Finde unsere Test-Adressen print(f"\n{BOLD}Reihenfolge der neuen Test-Adressen:{RESET}") test_addresses = [] for addr in all_after: bemerkung = addr.get('bemerkung') or '' if 'TEST-REIHENFOLGE-' in bemerkung: test_addresses.append({ 'bemerkung': bemerkung, 'index': addr.get('reihenfolgeIndex'), 'strasse': addr.get('strasse') }) test_addresses.sort(key=lambda x: x['index']) for t in test_addresses: print(f" Index {t['index']:2d}: {t['bemerkung']} ({t['strasse']})") # Analyse if len(test_addresses) >= 3: indices = [t['index'] for t in test_addresses[-3:]] # Letzten 3 if indices == sorted(indices) and indices[-1] > max_index_before: print_success("\n✓✓✓ Neue Adressen werden automatisch ANS ENDE gereiht!") print_success("✓ Indices sind aufsteigend und fortlaufend") print_info(f" Neue Indices: {indices}") else: print_warning(f"\n⚠ Unerwartete Reihenfolge: {indices}") return test_addresses async def test_5_try_change_reihenfolgeIndex_via_put(): """Test 5: Versuche reihenfolgeIndex via PUT zu ändern""" print_header("TEST 5: Kann man reihenfolgeIndex via PUT ändern?") context = SimpleContext() advo = AdvowareAPI(context=context) try: # Finde Test-Adresse all_addresses = await advo.api_call( f'/api/v1/advonet/Beteiligte/{TEST_BETNR}/Adressen', method='GET' ) test_addr = None for addr in all_addresses: bemerkung = addr.get('bemerkung') or '' if 'TEST-REIHENFOLGE-1' in bemerkung: test_addr = addr break if not test_addr: print_error("Test-Adresse nicht gefunden") return False current_index = test_addr.get('reihenfolgeIndex') new_index = 1 # Versuche an erste Position zu setzen print_info(f"Aktueller Index: {current_index}") print_info(f"Versuche Index zu ändern auf: {new_index}") # PUT mit neuem reihenfolgeIndex update_data = { "reihenfolgeIndex": new_index, "strasse": test_addr.get('strasse'), "plz": test_addr.get('plz'), "ort": test_addr.get('ort'), "land": test_addr.get('land') } await advo.api_call( f'/api/v1/advonet/Beteiligte/{TEST_BETNR}/Adressen/{current_index}', method='PUT', json_data=update_data ) print_success("✓ PUT erfolgreich") # Prüfe Ergebnis print_info("\nPrüfe neuen Index...") all_after = await advo.api_call( f'/api/v1/advonet/Beteiligte/{TEST_BETNR}/Adressen', method='GET' ) for addr in all_after: bemerkung = addr.get('bemerkung') or '' if 'TEST-REIHENFOLGE-1' in bemerkung: result_index = addr.get('reihenfolgeIndex') print_info(f"Index nach PUT: {result_index}") if result_index == new_index: print_success("\n✓✓✓ reihenfolgeIndex KANN via PUT geändert werden!") print_warning("⚠ Das könnte andere Adressen verschieben!") else: print_error(f"\n❌ reihenfolgeIndex NICHT änderbar (bleibt {result_index})") print_success("✓ Index ist READ-ONLY bei PUT") return result_index == new_index except Exception as e: print_error(f"Fehler: {e}") import traceback traceback.print_exc() return None async def main(): print(f"\n{BOLD}╔══════════════════════════════════════════════════════════════╗{RESET}") print(f"{BOLD}║ Deaktivierung + reihenfolgeIndex Tests für Adressen ║{RESET}") print(f"{BOLD}╚══════════════════════════════════════════════════════════════╝{RESET}\n") print(f"Test-Konfiguration:") print(f" BetNr: {TEST_BETNR}") print(f" Datum: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}") # Test 1: Abgelaufene Adresse erstellen await test_1_create_expired_address() # Test 2: Ist abgelaufene Adresse sichtbar? visible = await test_2_check_if_expired_address_visible() # Test 3: Expliziter reihenfolgeIndex await test_3_create_with_explicit_reihenfolgeIndex() # Test 4: Mehrere Adressen - Reihenfolge await test_4_create_multiple_check_ordering() # Test 5: reihenfolgeIndex ändern via PUT changeable = await test_5_try_change_reihenfolgeIndex_via_put() # Finale Zusammenfassung print(f"\n{BOLD}╔══════════════════════════════════════════════════════════════╗{RESET}") print(f"{BOLD}║ FINALE ERKENNTNISSE ║{RESET}") print(f"{BOLD}╚══════════════════════════════════════════════════════════════╝{RESET}\n") print(f"{BOLD}1. Deaktivierung via gueltigBis:{RESET}") if visible: print_error(" ❌ Abgelaufene Adressen werden NICHT automatisch gefiltert") print_warning(" ⚠ GET /Adressen zeigt alle Adressen (auch abgelaufen)") print_info(" 💡 Soft-Delete via gueltigBis ist möglich") print_info(" 💡 Aber: Filtern muss CLIENT-seitig erfolgen") print_info(" 💡 Strategie: In EspoCRM als 'inactive' markieren wenn gueltigBis < heute") else: print_success(" ✓ Abgelaufene Adressen werden automatisch ausgeblendet") print_success(" ✓ gueltigBis eignet sich perfekt für Soft-Delete") print(f"\n{BOLD}2. reihenfolgeIndex Verhalten:{RESET}") print_info(" • Neue Adressen werden automatisch ans Ende gereiht") print_info(" • Index wird vom System vergeben (fortlaufend)") if changeable: print_warning(" ⚠ reihenfolgeIndex kann via PUT geändert werden") print_warning(" ⚠ Vorsicht: Könnte andere Adressen verschieben") else: print_success(" ✓ reihenfolgeIndex ist READ-ONLY bei PUT (stabil)") print(f"\n{BOLD}3. Sync-Empfehlungen:{RESET}") print_success(" ✓ Nutze 'bemerkung' für EspoCRM-ID Matching (stabil)") print_success(" ✓ Nutze 'gueltigBis' für Soft-Delete (setze auf gestern)") print_success(" ✓ Nutze 'reihenfolgeIndex' nur für PUT (nicht für Matching)") print_info(" 💡 Workflow: GET → parse bemerkung → match → PUT via Index") print(f"\n{YELLOW}⚠️ ACHTUNG: Test-Adressen mit 'TEST-' im bemerkung-Feld{RESET}") print(f"{YELLOW} sollten manuell bereinigt werden.{RESET}\n") if __name__ == "__main__": asyncio.run(main())