All checks were successful
Build & Deploy / deploy (push) Successful in 1m29s
Bildbearbeitung im Nachgang: Drehen in 90-Grad-Schritten, Ausrichten per
Schieberegler, Zuschneiden per Rahmen mit anfassbaren Ecken. Der Server
rechnet jede Korrektur vom unbearbeiteten Original, das beim ersten
Eingriff daneben abgelegt wird - sonst summieren sich die Verluste über
mehrere Korrekturen, und Zurücksetzen wäre nicht möglich. Zwei
Zuschnitte hintereinander werden ineinander verrechnet.
Der Ort ließ sich nicht übernehmen, weil beide Quellen versagen können:
iOS entfernt beim Weitergeben an eine Webseite oft die GPS-Daten aus dem
Foto, und der Browserstandort scheiterte bisher stumm. Jetzt meldet er
seinen Grund ("Standortfreigabe fehlt"), die Detailansicht zeigt die
Herkunft des Ortes, und der Scan-Ort ist von Hand nachtragbar.
E-Mail, Web, Telefon und Mobil sind in der Tabelle jetzt Links; Straße,
PLZ, Ort und Land stehen als eine Adresszeile, die die eingestellte
Navigations-App öffnet.
Einstellungen als vierter Reiter: Navigations-App (Apple Karten, Google
Maps, OpenStreetMap), Statusübersicht und Abmelden - der Knopf saß
vorher in der Kopfzeile.
Die Kopfzeile ist weg. Sie kostete auf dem Telefon eine Bildschirmzeile
und wiederholte nur, was die Tableiste schon sagt.
Kein full_name mehr, nur Vor- und Nachname; akademische Titel gehören in
den Vornamen. Bestehende Datensätze werden bei der Migration am letzten
Leerzeichen aufgeteilt. Die Spalte bleibt ungenutzt stehen: SQLite baut
zum Löschen die ganze Tabelle neu, der Gewinn wären ein paar Byte.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
89 lines
2.6 KiB
Python
89 lines
2.6 KiB
Python
"""Dublettenerkennung. Auf Messen trifft man Leute wieder."""
|
|
import uuid
|
|
|
|
import pytest
|
|
|
|
from app import db, duplicates
|
|
|
|
|
|
def _card(**felder):
|
|
columns = {
|
|
"id": uuid.uuid4().hex,
|
|
"created_at": "2026-09-01T10:00:00+00:00",
|
|
"extract_status": "ok",
|
|
**felder,
|
|
}
|
|
names = ", ".join(columns)
|
|
db.execute(
|
|
f"INSERT INTO cards ({names}) VALUES ({', '.join('?' for _ in columns)})",
|
|
list(columns.values()),
|
|
)
|
|
return db.query_one("SELECT * FROM cards WHERE id = ?", (columns["id"],))
|
|
|
|
|
|
@pytest.fixture(autouse=True)
|
|
def leere_tabelle():
|
|
db.execute("DELETE FROM cards")
|
|
yield
|
|
db.execute("DELETE FROM cards")
|
|
|
|
|
|
def test_gleiche_email_wird_gefunden():
|
|
_card(first_name="Anna", last_name="Berg", email="A.Berg@Firma.de")
|
|
neu = _card(first_name="A.", last_name="Berg", email="a.berg@firma.de")
|
|
|
|
treffer = duplicates.find(neu)
|
|
|
|
assert [t["reason"] for t in treffer] == ["gleiche E-Mail"]
|
|
|
|
|
|
def test_telefonnummer_in_anderer_schreibweise():
|
|
_card(first_name="Anna", last_name="Berg", phone="+49 511 1234560")
|
|
neu = _card(first_name="Anna", last_name="B.", mobile="0511/1234560")
|
|
|
|
treffer = duplicates.find(neu)
|
|
|
|
assert [t["reason"] for t in treffer] == ["gleiche Telefonnummer"]
|
|
|
|
|
|
def test_name_und_firma_zusammen():
|
|
_card(last_name="Berg", company="Berg & Partner GmbH")
|
|
neu = _card(last_name="berg", company="berg & partner gmbh")
|
|
|
|
assert [t["reason"] for t in duplicates.find(neu)] == ["gleicher Name und dieselbe Firma"]
|
|
|
|
|
|
def test_gleicher_nachname_allein_reicht_nicht():
|
|
_card(last_name="Berg", company="Andere GmbH")
|
|
neu = _card(last_name="Berg", company="Berg & Partner GmbH")
|
|
|
|
assert duplicates.find(neu) == []
|
|
|
|
|
|
def test_kurze_nummern_werden_nicht_verglichen():
|
|
# Eine dreistellige Durchwahl darf keine Dublette erzeugen.
|
|
_card(first_name="Anna", last_name="Berg", phone="123")
|
|
neu = _card(first_name="Bea", last_name="Kurz", phone="123")
|
|
|
|
assert duplicates.find(neu) == []
|
|
|
|
|
|
def test_leere_felder_erzeugen_keine_treffer():
|
|
_card(first_name="Anna", last_name="Berg")
|
|
neu = _card(first_name="Bea", last_name="Kurz")
|
|
|
|
assert duplicates.find(neu) == []
|
|
|
|
|
|
def test_die_karte_selbst_ist_keine_dublette():
|
|
karte = _card(first_name="Anna", last_name="Berg", email="a@b.de")
|
|
|
|
assert duplicates.find(karte) == []
|
|
|
|
|
|
def test_noch_nicht_gelesene_karten_bleiben_aussen_vor():
|
|
_card(first_name="Anna", last_name="Berg", email="a@b.de", extract_status="offen")
|
|
neu = _card(first_name="Anna", last_name="Berg", email="a@b.de")
|
|
|
|
assert duplicates.find(neu) == []
|