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:
@@ -0,0 +1,466 @@
|
||||
#!/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())
|
||||
Reference in New Issue
Block a user