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>
56 lines
1.8 KiB
Python
56 lines
1.8 KiB
Python
"""Karten finden, die dieselbe Person meinen.
|
|
|
|
Auf Messen trifft man Leute wieder, und dieselbe Karte landet ein zweites Mal
|
|
im Stapel. Verglichen wird nicht der ganze Datensatz, sondern das, was eine
|
|
Person eindeutig macht - in dieser Reihenfolge, weil die Aussagekraft faellt.
|
|
"""
|
|
from . import db
|
|
|
|
|
|
def _phone_key(value) -> str:
|
|
"""Nur die letzten acht Ziffern. Damit passen +49 511 123456,
|
|
0049511123456 und 0511/123456 aufeinander."""
|
|
digits = "".join(character for character in (value or "") if character.isdigit())
|
|
return digits[-8:] if len(digits) >= 8 else ""
|
|
|
|
|
|
def _phone_keys(row) -> set:
|
|
return {_phone_key(row["phone"]), _phone_key(row["mobile"])} - {""}
|
|
|
|
|
|
def _clean(value) -> str:
|
|
return (value or "").strip().lower()
|
|
|
|
|
|
def _match(card, other) -> str:
|
|
email = _clean(card["email"])
|
|
if email and _clean(other["email"]) == email:
|
|
return "gleiche E-Mail"
|
|
if _phone_keys(card) & _phone_keys(other):
|
|
return "gleiche Telefonnummer"
|
|
last_name, company = _clean(card["last_name"]), _clean(card["company"])
|
|
if last_name and company:
|
|
if _clean(other["last_name"]) == last_name and _clean(other["company"]) == company:
|
|
return "gleicher Name und dieselbe Firma"
|
|
return ""
|
|
|
|
|
|
def find(card) -> list:
|
|
"""Aehnliche Karten, neueste zuerst."""
|
|
others = db.query(
|
|
"""
|
|
SELECT id, first_name, last_name, company, email, phone, mobile,
|
|
occasion, captured_at, created_at
|
|
FROM cards
|
|
WHERE id <> ? AND extract_status <> 'offen'
|
|
ORDER BY COALESCE(captured_at, created_at) DESC
|
|
""",
|
|
(card["id"],),
|
|
)
|
|
hits = []
|
|
for other in others:
|
|
reason = _match(card, other)
|
|
if reason:
|
|
hits.append({**dict(other), "reason": reason})
|
|
return hits
|