feat(calllog): Tags einer Gesprächsnotiz zuordnen (n:m)
Backend: - Neues CallLogTag-Model (Tabelle call_logs_tags) mit Relationship auf CallLog (cascade delete-orphan); to_dict liefert 'tags'. - Migration _db_V01_11 (idempotent via create_all). - _set_call_log_tags in create/update_call_log: ersetzt Tag-Zuordnungen, filtert is_parent-Tags, eliminiert Duplikate. - _parse_date wandelt ISO-Strings in date-Objekte (fixt autoflush- Crash bei Date-Spalten). Frontend: - iCallLog um tags (Lesen) und tag_ids (Schreiben) ergänzt. - Neues generisches MultiSelect-Widget (widgets/select.ts): Badges + Edit-Button, inline Modal mit Suchfeld, Checkbox-Liste, OK-Button; konfigurierbare Texte (placeholder, modalTitle, editTooltip). - Call_Log-Formular: Tag-Auswahl via MultiSelect, Submit via FormData.getAll; Tag-Badges in der Listenansicht hinter dem Betreff. Generated by Mistral Vibe. Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
This commit is contained in:
1 parent
5abcb2d96c
commit
d30adf1579
6 files changed
+421
-9
No files matched your search
@@ -9,14 +9,68 @@ dort über den Decorator authorisation_required.
|
||||
:date: 2026-09-04
|
||||
:version: 1.0
|
||||
"""
|
||||
from datetime import date
|
||||
|
||||
from db import dbapp
|
||||
from crm.model import CallLog, Projekt, ProjektUser
|
||||
from crm.model import CallLog, CallLogTag, Projekt, ProjektUser, Tag
|
||||
|
||||
from auth.model.errors import ApplicationError, HtmlStatusCode
|
||||
|
||||
session = dbapp.session
|
||||
|
||||
|
||||
def _parse_date(value: str | None) -> date | None:
|
||||
"""
|
||||
Wandelt einen ISO-Datum-String (yyyy-MM-dd) in ein date-Objekt um.
|
||||
Leere Strings und None werden zu None konvertiert (Spalte ist nullable).
|
||||
"""
|
||||
if not value:
|
||||
return None
|
||||
value = value.strip()
|
||||
if not value:
|
||||
return None
|
||||
try:
|
||||
return date.fromisoformat(value)
|
||||
except ValueError:
|
||||
return None
|
||||
|
||||
|
||||
|
||||
def _set_call_log_tags(call_log: CallLog, tag_ids: list) -> None:
|
||||
"""
|
||||
Ersetzt die Tag-Zuordnungen einer Gesprächsnotiz durch die übergebene
|
||||
Liste von Tag-IDs. Bestehende Zuordnungen werden gelöscht, danach werden
|
||||
die neuen Zuordnungen angelegt.
|
||||
|
||||
Nur Tags, die existieren und nicht reine Gruppierungsknoten
|
||||
(is_parent=True) sind, werden zugeordnet. Duplikate in der Liste
|
||||
werden durch ein Set eliminiert.
|
||||
"""
|
||||
# Bestehende Zuordnungen entfernen.
|
||||
for clt in list(call_log.tags_rel):
|
||||
session.delete(clt)
|
||||
call_log.tags_rel = []
|
||||
# Neue Zuordnungen anlegen.
|
||||
seen = set()
|
||||
for tag_id in tag_ids or []:
|
||||
try:
|
||||
tag_id = int(tag_id)
|
||||
except (TypeError, ValueError):
|
||||
continue
|
||||
if tag_id in seen:
|
||||
continue
|
||||
seen.add(tag_id)
|
||||
tag = Tag.query.get(tag_id)
|
||||
if tag is None or tag.is_parent:
|
||||
# Nicht zuordenbar — überspringen.
|
||||
continue
|
||||
clt = CallLogTag()
|
||||
clt.call_log = call_log
|
||||
clt.tag = tag
|
||||
session.add(clt)
|
||||
|
||||
|
||||
|
||||
def get_call_logs(projekt_id: int | None = None, user_id: int | None = None):
|
||||
"""
|
||||
Liefert Gesprächsnotizen, sortiert nach Datum absteigend.
|
||||
@@ -94,15 +148,16 @@ def create_call_log(data: dict) -> CallLog:
|
||||
)
|
||||
call_log = CallLog()
|
||||
call_log.projekt_id = int(projekt_id)
|
||||
call_log.datum = (data.get("datum") or "").strip() or None
|
||||
call_log.datum = _parse_date(data.get("datum"))
|
||||
call_log.uhrzeit_beginn = (data.get("uhrzeit_beginn") or "").strip() or None
|
||||
call_log.dauer = (data.get("dauer") or "").strip() or None
|
||||
call_log.betreff = (data.get("betreff") or "").strip() or None
|
||||
call_log.name_ansprechpartner = (data.get("name_ansprechpartner") or "").strip() or None
|
||||
call_log.telefon = (data.get("telefon") or "").strip() or None
|
||||
call_log.notiz = (data.get("notiz") or "").strip() or None
|
||||
call_log.wiedervorlage_datum = (data.get("wiedervorlage_datum") or "").strip() or None
|
||||
call_log.wiedervorlage_datum = _parse_date(data.get("wiedervorlage_datum"))
|
||||
call_log.erledigt = bool(data.get("erledigt", False))
|
||||
_set_call_log_tags(call_log, data.get("tag_ids"))
|
||||
session.add(call_log)
|
||||
session.commit()
|
||||
return call_log
|
||||
@@ -127,15 +182,16 @@ def update_call_log(data: dict) -> CallLog:
|
||||
htmlstatus=HtmlStatusCode.Bad_Request,
|
||||
)
|
||||
call_log.projekt_id = int(projekt_id)
|
||||
call_log.datum = (data.get("datum") or "").strip() or None
|
||||
call_log.datum = _parse_date(data.get("datum"))
|
||||
call_log.uhrzeit_beginn = (data.get("uhrzeit_beginn") or "").strip() or None
|
||||
call_log.dauer = (data.get("dauer") or "").strip() or None
|
||||
call_log.betreff = (data.get("betreff") or "").strip() or None
|
||||
call_log.name_ansprechpartner = (data.get("name_ansprechpartner") or "").strip() or None
|
||||
call_log.telefon = (data.get("telefon") or "").strip() or None
|
||||
call_log.notiz = (data.get("notiz") or "").strip() or None
|
||||
call_log.wiedervorlage_datum = (data.get("wiedervorlage_datum") or "").strip() or None
|
||||
call_log.wiedervorlage_datum = _parse_date(data.get("wiedervorlage_datum"))
|
||||
call_log.erledigt = bool(data.get("erledigt", False))
|
||||
_set_call_log_tags(call_log, data.get("tag_ids"))
|
||||
session.commit()
|
||||
return call_log
|
||||
|
||||
|
||||
Reference in new issue
Block a user