Add tests for Kommunikation Sync implementation and verification scripts

- Implemented comprehensive tests for the Kommunikation Sync functionality, covering base64 encoding, marker parsing, creation, type detection, and integration scenarios.
- Added a verification script to check for unique IDs in Advoware communications, ensuring stability and integrity of the IDs.
- Created utility scripts for code validation, notification testing, and PUT response detail analysis to enhance development and testing processes.
- Updated README with details on new tools and their usage.
This commit is contained in:
2026-02-08 23:05:56 +00:00
parent a157d3fa1d
commit 7856dd1d68
37 changed files with 438 additions and 271 deletions

View File

@@ -0,0 +1,468 @@
#!/usr/bin/env python3
"""
Test: gueltigBis nachträglich setzen und entfernen (Soft-Delete)
==================================================================
Ziele:
1. Teste ob gueltigBis via PUT gesetzt werden kann (Deaktivierung)
2. Teste ob gueltigBis via PUT entfernt werden kann (Reaktivierung)
3. Teste ob gueltigBis auf null/None gesetzt werden kann
"""
import asyncio
import sys
import os
from datetime import datetime
# 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:
def info(self, msg): pass
def error(self, msg): print_error(msg)
def debug(self, msg): pass
def warning(self, msg): pass
class SimpleContext:
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_active_address():
"""Test 1: Erstelle aktive Adresse (ohne gueltigBis)"""
print_header("TEST 1: Erstelle aktive Adresse (OHNE gueltigBis)")
context = SimpleContext()
advo = AdvowareAPI(context=context)
address_data = {
"strasse": "Soft-Delete Test Straße",
"plz": "66666",
"ort": "Teststadt",
"land": "DE",
"bemerkung": "TEST-SOFTDELETE: Für gueltigBis Modifikation",
"gueltigVon": "2026-01-01T00:00:00"
# KEIN gueltigBis → unbegrenzt gültig
}
print_info("Erstelle Adresse OHNE gueltigBis (unbegrenzt aktiv)...")
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")
print_info(f" rowId: {addr.get('rowId')}")
print_info(f" gueltigVon: {addr.get('gueltigVon')}")
print_info(f" gueltigBis: {addr.get('gueltigBis')} (sollte None sein)")
# Hole echten Index via GET
all_addresses = await advo.api_call(
f'/api/v1/advonet/Beteiligte/{TEST_BETNR}/Adressen',
method='GET'
)
for a in all_addresses:
if (a.get('bemerkung') or '').startswith('TEST-SOFTDELETE'):
print_info(f" reihenfolgeIndex: {a.get('reihenfolgeIndex')}")
return a.get('reihenfolgeIndex')
return None
else:
print_error("POST fehlgeschlagen")
return None
except Exception as e:
print_error(f"Fehler: {e}")
import traceback
traceback.print_exc()
return None
async def test_2_deactivate_via_gueltigbis(index):
"""Test 2: Deaktiviere Adresse durch Setzen von gueltigBis"""
print_header("TEST 2: Deaktivierung - gueltigBis nachträglich setzen")
context = SimpleContext()
advo = AdvowareAPI(context=context)
try:
# Hole aktuelle Adresse
all_addresses = await advo.api_call(
f'/api/v1/advonet/Beteiligte/{TEST_BETNR}/Adressen',
method='GET'
)
test_addr = next((a for a in all_addresses if a.get('reihenfolgeIndex') == index), None)
if not test_addr:
print_error(f"Adresse mit Index {index} nicht gefunden")
return False
print_info("Status VORHER:")
print(f" gueltigVon: {test_addr.get('gueltigVon')}")
print(f" gueltigBis: {test_addr.get('gueltigBis')}")
# Setze gueltigBis auf gestern (= deaktiviert)
print_info("\nSetze gueltigBis auf 2024-12-31 (Vergangenheit = deaktiviert)...")
update_data = {
"strasse": test_addr.get('strasse'),
"plz": test_addr.get('plz'),
"ort": test_addr.get('ort'),
"land": test_addr.get('land'),
"gueltigVon": test_addr.get('gueltigVon'),
"gueltigBis": "2024-12-31T23:59:59" # ← Vergangenheit
}
result = await advo.api_call(
f'/api/v1/advonet/Beteiligte/{TEST_BETNR}/Adressen/{index}',
method='PUT',
json_data=update_data
)
print_success("✓ PUT erfolgreich")
# Prüfe Ergebnis
print_info("\nHole Adresse erneut und prüfe gueltigBis...")
all_addresses = await advo.api_call(
f'/api/v1/advonet/Beteiligte/{TEST_BETNR}/Adressen',
method='GET'
)
updated_addr = next((a for a in all_addresses if a.get('reihenfolgeIndex') == index), None)
if updated_addr:
print_info("Status NACHHER:")
print(f" gueltigVon: {updated_addr.get('gueltigVon')}")
print(f" gueltigBis: {updated_addr.get('gueltigBis')}")
if updated_addr.get('gueltigBis') == "2024-12-31T00:00:00":
print_success("\n✓✓✓ PERFEKT: gueltigBis wurde nachträglich gesetzt!")
print_success("✓ Adresse kann via PUT deaktiviert werden!")
return True
else:
print_error(f"\n❌ gueltigBis nicht korrekt: {updated_addr.get('gueltigBis')}")
return False
else:
print_error("Adresse nach PUT nicht gefunden")
return False
except Exception as e:
print_error(f"Fehler: {e}")
import traceback
traceback.print_exc()
return False
async def test_3_reactivate_set_far_future(index):
"""Test 3: Reaktivierung durch Setzen auf weit in Zukunft"""
print_header("TEST 3: Reaktivierung - gueltigBis auf fernes Datum setzen")
context = SimpleContext()
advo = AdvowareAPI(context=context)
try:
# Hole aktuelle Adresse
all_addresses = await advo.api_call(
f'/api/v1/advonet/Beteiligte/{TEST_BETNR}/Adressen',
method='GET'
)
test_addr = next((a for a in all_addresses if a.get('reihenfolgeIndex') == index), None)
if not test_addr:
print_error(f"Adresse mit Index {index} nicht gefunden")
return False
print_info("Status VORHER (deaktiviert):")
print(f" gueltigBis: {test_addr.get('gueltigBis')}")
# Setze gueltigBis auf weit in Zukunft
print_info("\nSetze gueltigBis auf 2099-12-31 (weit in Zukunft = aktiv)...")
update_data = {
"strasse": test_addr.get('strasse'),
"plz": test_addr.get('plz'),
"ort": test_addr.get('ort'),
"land": test_addr.get('land'),
"gueltigVon": test_addr.get('gueltigVon'),
"gueltigBis": "2099-12-31T23:59:59" # ← Weit in Zukunft
}
await advo.api_call(
f'/api/v1/advonet/Beteiligte/{TEST_BETNR}/Adressen/{index}',
method='PUT',
json_data=update_data
)
print_success("✓ PUT erfolgreich")
# Prüfe Ergebnis
print_info("\nHole Adresse erneut...")
all_addresses = await advo.api_call(
f'/api/v1/advonet/Beteiligte/{TEST_BETNR}/Adressen',
method='GET'
)
updated_addr = next((a for a in all_addresses if a.get('reihenfolgeIndex') == index), None)
if updated_addr:
print_info("Status NACHHER (reaktiviert):")
print(f" gueltigBis: {updated_addr.get('gueltigBis')}")
if updated_addr.get('gueltigBis') == "2099-12-31T00:00:00":
print_success("\n✓✓✓ PERFEKT: gueltigBis wurde auf Zukunft gesetzt!")
print_success("✓ Adresse ist jetzt wieder aktiv!")
return True
else:
print_error(f"\n❌ gueltigBis nicht korrekt: {updated_addr.get('gueltigBis')}")
return False
else:
print_error("Adresse nach PUT nicht gefunden")
return False
except Exception as e:
print_error(f"Fehler: {e}")
import traceback
traceback.print_exc()
return False
async def test_4_remove_gueltigbis_completely(index):
"""Test 4: Entferne gueltigBis komplett (null/None)"""
print_header("TEST 4: gueltigBis komplett entfernen (null/None)")
context = SimpleContext()
advo = AdvowareAPI(context=context)
try:
# Hole aktuelle Adresse
all_addresses = await advo.api_call(
f'/api/v1/advonet/Beteiligte/{TEST_BETNR}/Adressen',
method='GET'
)
test_addr = next((a for a in all_addresses if a.get('reihenfolgeIndex') == index), None)
if not test_addr:
print_error(f"Adresse mit Index {index} nicht gefunden")
return None
print_info("Status VORHER:")
print(f" gueltigBis: {test_addr.get('gueltigBis')}")
# Versuche 1: gueltigBis weglassen
print_info("\n=== Versuch 1: gueltigBis komplett weglassen ===")
update_data = {
"strasse": test_addr.get('strasse'),
"plz": test_addr.get('plz'),
"ort": test_addr.get('ort'),
"land": test_addr.get('land'),
"gueltigVon": test_addr.get('gueltigVon')
# gueltigBis absichtlich weggelassen
}
await advo.api_call(
f'/api/v1/advonet/Beteiligte/{TEST_BETNR}/Adressen/{index}',
method='PUT',
json_data=update_data
)
all_addresses = await advo.api_call(
f'/api/v1/advonet/Beteiligte/{TEST_BETNR}/Adressen',
method='GET'
)
updated_addr = next((a for a in all_addresses if a.get('reihenfolgeIndex') == index), None)
result_1 = updated_addr.get('gueltigBis') if updated_addr else "ERROR"
print_info(f"Ergebnis: gueltigBis = {result_1}")
if result_1 is None:
print_success("✓ Weglassen entfernt gueltigBis!")
return "omit"
# Versuche 2: gueltigBis = None/null
print_info("\n=== Versuch 2: gueltigBis explizit auf None setzen ===")
update_data['gueltigBis'] = None
await advo.api_call(
f'/api/v1/advonet/Beteiligte/{TEST_BETNR}/Adressen/{index}',
method='PUT',
json_data=update_data
)
all_addresses = await advo.api_call(
f'/api/v1/advonet/Beteiligte/{TEST_BETNR}/Adressen',
method='GET'
)
updated_addr = next((a for a in all_addresses if a.get('reihenfolgeIndex') == index), None)
result_2 = updated_addr.get('gueltigBis') if updated_addr else "ERROR"
print_info(f"Ergebnis: gueltigBis = {result_2}")
if result_2 is None:
print_success("✓ None entfernt gueltigBis!")
return "none"
# Versuche 3: gueltigBis = ""
print_info("\n=== Versuch 3: gueltigBis auf leeren String setzen ===")
update_data['gueltigBis'] = ""
try:
await advo.api_call(
f'/api/v1/advonet/Beteiligte/{TEST_BETNR}/Adressen/{index}',
method='PUT',
json_data=update_data
)
all_addresses = await advo.api_call(
f'/api/v1/advonet/Beteiligte/{TEST_BETNR}/Adressen',
method='GET'
)
updated_addr = next((a for a in all_addresses if a.get('reihenfolgeIndex') == index), None)
result_3 = updated_addr.get('gueltigBis') if updated_addr else "ERROR"
print_info(f"Ergebnis: gueltigBis = {result_3}")
if result_3 is None:
print_success("✓ Leerer String entfernt gueltigBis!")
return "empty"
except Exception as e:
print_warning(f"⚠ Leerer String wird abgelehnt: {e}")
print_warning("\n⚠ gueltigBis kann nicht komplett entfernt werden")
print_info("💡 Lösung: Setze auf weit in Zukunft (2099-12-31) für 'unbegrenzt aktiv'")
return "not_possible"
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}║ gueltigBis nachträglich ändern (Soft-Delete Tests) ║{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: Erstelle aktive Adresse
index = await test_1_create_active_address()
if not index:
print_error("\nTest abgebrochen: Konnte Adresse nicht erstellen")
return
# Test 2: Deaktiviere via gueltigBis
can_deactivate = await test_2_deactivate_via_gueltigbis(index)
# Test 3: Reaktiviere via gueltigBis auf Zukunft
can_reactivate = await test_3_reactivate_set_far_future(index)
# Test 4: Versuche gueltigBis zu entfernen
remove_method = await test_4_remove_gueltigbis_completely(index)
# Finale Zusammenfassung
print(f"\n{BOLD}╔══════════════════════════════════════════════════════════════╗{RESET}")
print(f"{BOLD}║ FINALE ERKENNTNISSE ║{RESET}")
print(f"{BOLD}╚══════════════════════════════════════════════════════════════╝{RESET}\n")
print(f"{BOLD}Soft-Delete Funktionalität:{RESET}\n")
if can_deactivate:
print_success("✓✓✓ DEAKTIVIERUNG funktioniert:")
print_success(" • gueltigBis kann via PUT auf Vergangenheit gesetzt werden")
print_success(" • Beispiel: gueltigBis = '2024-12-31T23:59:59'")
print_success(" • Adresse bleibt in GET sichtbar (Client-Filter nötig)")
else:
print_error("✗ DEAKTIVIERUNG funktioniert NICHT")
print()
if can_reactivate:
print_success("✓✓✓ REAKTIVIERUNG funktioniert:")
print_success(" • gueltigBis kann via PUT auf Zukunft gesetzt werden")
print_success(" • Beispiel: gueltigBis = '2099-12-31T23:59:59'")
print_success(" • Adresse ist damit wieder aktiv")
else:
print_error("✗ REAKTIVIERUNG funktioniert NICHT")
print()
if remove_method:
if remove_method in ["omit", "none", "empty"]:
print_success(f"✓ gueltigBis entfernen funktioniert (Methode: {remove_method})")
if remove_method == "omit":
print_success(" • Weglassen des Feldes entfernt gueltigBis")
elif remove_method == "none":
print_success(" • Setzen auf None/null entfernt gueltigBis")
elif remove_method == "empty":
print_success(" • Setzen auf '' entfernt gueltigBis")
else:
print_warning("⚠ gueltigBis kann NICHT komplett entfernt werden")
print_info(" • Lösung: Setze auf 2099-12-31 für 'unbegrenzt aktiv'")
print(f"\n{BOLD}Empfohlener Workflow:{RESET}\n")
print_info("1. AKTIV (Standard):")
print_info(" → gueltigBis = '2099-12-31T23:59:59' oder None")
print_info(" → In EspoCRM: isActive = True")
print()
print_info("2. DEAKTIVIEREN (Soft-Delete):")
print_info(" → PUT mit gueltigBis = '2024-01-01T00:00:00' (Vergangenheit)")
print_info(" → In EspoCRM: isActive = False")
print()
print_info("3. REAKTIVIEREN:")
print_info(" → PUT mit gueltigBis = '2099-12-31T23:59:59' (Zukunft)")
print_info(" → In EspoCRM: isActive = True")
print()
print_info("4. SYNC LOGIC:")
print_info(" → GET /Adressen → filter wo gueltigBis > heute")
print_info(" → Sync nur aktive Adressen nach EspoCRM")
print_info(" → Update isActive basierend auf gueltigBis")
print(f"\n{YELLOW}⚠️ ACHTUNG: Test-Adresse 'TEST-SOFTDELETE' sollte bereinigt werden.{RESET}\n")
if __name__ == "__main__":
asyncio.run(main())