All checks were successful
Build & Deploy / deploy (push) Successful in 10m41s
Vier Funktionen: - Anlass: ein Feld auf der Startseite gilt für alle folgenden Scans und wird im Browser gemerkt. Ordnet den Bestand verlässlicher als der Ortsname aus den Koordinaten. Durchsuchbar, nachträglich änderbar. - Dubletten: die Detailansicht zeigt Karten, die dieselbe Person meinen könnten - gleiche E-Mail, gleiche Telefonnummer (verglichen werden die letzten acht Ziffern, damit +49 511 123456 und 0511/123456 aufeinander passen) oder gleicher Nachname bei gleicher Firma. - Rückseite: nachträglich ein zweites Bild zur Karte. Es füllt nur Felder, die die Vorderseite offen gelassen hat. - Schnellwahl bei Erinnerungen: in 3 Tagen / 1 Woche / 2 Wochen / 1 Monat, jeweils 9 Uhr. Das Datumsfeld braucht man damit selten. Teilen als vCard über das System-Teilenblatt, mit Download als Rückfallebene, wo es kein Teilenblatt gibt. Oberfläche: - Startseite führt jetzt: Anlass, große Aufnahmefläche mit Symbol statt Textzeile, leise Alternative, darunter die zuletzt erfassten Karten. Vorher stand dort eine Überschrift mit Zahlen und man musste raten. - Weniger Webseite, mehr App: kein Seitenrahmen auf dem Telefon, Symbole in der Tableiste mit Zählerblasen, kein Tap-Highlight, keine Textmarkierung auf Bedienelementen, Safe-Area oben, Einblendung beim Ansichtswechsel, Mindesthöhe 54 px für Schaltflächen. - Die Marken "exportiert" / "nicht exportiert" sind aus der Liste raus; dafür gibt es den Filter. Neue Spalten occasion und back_image_file kommen per ALTER TABLE in bestehende Datenbanken - CREATE TABLE IF NOT EXISTS rührt eine vorhandene Tabelle nicht an. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
89 lines
2.4 KiB
Python
89 lines
2.4 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(full_name="Anna Berg", email="A.Berg@Firma.de")
|
|
neu = _card(full_name="A. 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(full_name="Anna Berg", phone="+49 511 1234560")
|
|
neu = _card(full_name="Anna 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(full_name="Anna Berg", phone="123")
|
|
neu = _card(full_name="Bea Kurz", phone="123")
|
|
|
|
assert duplicates.find(neu) == []
|
|
|
|
|
|
def test_leere_felder_erzeugen_keine_treffer():
|
|
_card(full_name="Anna Berg")
|
|
neu = _card(full_name="Bea Kurz")
|
|
|
|
assert duplicates.find(neu) == []
|
|
|
|
|
|
def test_die_karte_selbst_ist_keine_dublette():
|
|
karte = _card(full_name="Anna Berg", email="a@b.de")
|
|
|
|
assert duplicates.find(karte) == []
|
|
|
|
|
|
def test_noch_nicht_gelesene_karten_bleiben_aussen_vor():
|
|
_card(full_name="Anna Berg", email="a@b.de", extract_status="offen")
|
|
neu = _card(full_name="Anna Berg", email="a@b.de")
|
|
|
|
assert duplicates.find(neu) == []
|