- Updated index.html to extend base template and improve structure. - Added new styles and search/filter functionality in the Sager list view. - Created a backup of the old index.html as index_old.html. - Updated navigation links in base.html for consistency. - Included new dashboard API router in main.py. - Added test scripts for customer and sag queries to validate database interactions.
178 lines
6.9 KiB
Python
178 lines
6.9 KiB
Python
import logging
|
|
from fastapi import APIRouter, HTTPException, Query, Request
|
|
from fastapi.responses import HTMLResponse
|
|
from fastapi.templating import Jinja2Templates
|
|
from pathlib import Path
|
|
from app.core.database import execute_query
|
|
|
|
logger = logging.getLogger(__name__)
|
|
router = APIRouter()
|
|
|
|
# Setup template directory
|
|
templates = Jinja2Templates(directory="app")
|
|
|
|
@router.get("/sag", response_class=HTMLResponse)
|
|
async def sager_liste(
|
|
request: Request,
|
|
status: str = Query(None),
|
|
tag: str = Query(None),
|
|
customer_id: int = Query(None),
|
|
):
|
|
"""Display list of all cases."""
|
|
try:
|
|
query = """
|
|
SELECT s.*,
|
|
c.name as customer_name,
|
|
CONCAT(COALESCE(cont.first_name, ''), ' ', COALESCE(cont.last_name, '')) as kontakt_navn
|
|
FROM sag_sager s
|
|
LEFT JOIN customers c ON s.customer_id = c.id
|
|
LEFT JOIN LATERAL (
|
|
SELECT cc.contact_id
|
|
FROM contact_companies cc
|
|
WHERE cc.customer_id = c.id
|
|
ORDER BY cc.is_primary DESC NULLS LAST, cc.id ASC
|
|
LIMIT 1
|
|
) cc_first ON true
|
|
LEFT JOIN contacts cont ON cc_first.contact_id = cont.id
|
|
WHERE s.deleted_at IS NULL
|
|
"""
|
|
params = []
|
|
|
|
if status:
|
|
query += " AND s.status = %s"
|
|
params.append(status)
|
|
if customer_id:
|
|
query += " AND s.customer_id = %s"
|
|
params.append(customer_id)
|
|
|
|
query += " ORDER BY s.created_at DESC"
|
|
sager = execute_query(query, tuple(params))
|
|
|
|
# Fetch relations for all cases
|
|
relations_query = """
|
|
SELECT
|
|
sr.kilde_sag_id,
|
|
sr.målsag_id,
|
|
sr.relationstype,
|
|
sr.id as relation_id
|
|
FROM sag_relationer sr
|
|
WHERE sr.deleted_at IS NULL
|
|
"""
|
|
all_relations = execute_query(relations_query, ())
|
|
child_ids = set()
|
|
|
|
# Build relations map: {sag_id: [list of related sag_ids]}
|
|
relations_map = {}
|
|
for rel in all_relations or []:
|
|
if rel.get('målsag_id') is not None:
|
|
child_ids.add(rel['målsag_id'])
|
|
# Add forward relation
|
|
if rel['kilde_sag_id'] not in relations_map:
|
|
relations_map[rel['kilde_sag_id']] = []
|
|
relations_map[rel['kilde_sag_id']].append({
|
|
'target_id': rel['målsag_id'],
|
|
'type': rel['relationstype'],
|
|
'direction': 'forward'
|
|
})
|
|
# Add backward relation
|
|
if rel['målsag_id'] not in relations_map:
|
|
relations_map[rel['målsag_id']] = []
|
|
relations_map[rel['målsag_id']].append({
|
|
'target_id': rel['kilde_sag_id'],
|
|
'type': rel['relationstype'],
|
|
'direction': 'backward'
|
|
})
|
|
|
|
# Filter by tag if provided
|
|
if tag and sager:
|
|
sag_ids = [s['id'] for s in sager]
|
|
tag_query = "SELECT sag_id FROM sag_tags WHERE tag_navn = %s AND deleted_at IS NULL"
|
|
tagged = execute_query(tag_query, (tag,))
|
|
tagged_ids = set(t['sag_id'] for t in tagged)
|
|
sager = [s for s in sager if s['id'] in tagged_ids]
|
|
|
|
# Fetch all distinct statuses and tags for filters
|
|
statuses = execute_query("SELECT DISTINCT status FROM sag_sager WHERE deleted_at IS NULL ORDER BY status", ())
|
|
all_tags = execute_query("SELECT DISTINCT tag_navn FROM sag_tags WHERE deleted_at IS NULL ORDER BY tag_navn", ())
|
|
|
|
return templates.TemplateResponse("modules/sag/templates/index.html", {
|
|
"request": request,
|
|
"sager": sager,
|
|
"relations_map": relations_map,
|
|
"child_ids": list(child_ids),
|
|
"statuses": [s['status'] for s in statuses],
|
|
"all_tags": [t['tag_navn'] for t in all_tags],
|
|
"current_status": status,
|
|
"current_tag": tag,
|
|
})
|
|
except Exception as e:
|
|
logger.error("❌ Error displaying case list: %s", e)
|
|
raise HTTPException(status_code=500, detail="Failed to load case list")
|
|
|
|
@router.get("/sag/{sag_id}", response_class=HTMLResponse)
|
|
async def sag_detaljer(request: Request, sag_id: int):
|
|
"""Display case details."""
|
|
try:
|
|
# Fetch main case
|
|
sag_query = "SELECT * FROM sag_sager WHERE id = %s AND deleted_at IS NULL"
|
|
sag_result = execute_query(sag_query, (sag_id,))
|
|
|
|
if not sag_result:
|
|
raise HTTPException(status_code=404, detail="Case not found")
|
|
|
|
sag = sag_result[0]
|
|
|
|
# Fetch tags
|
|
tags_query = "SELECT * FROM sag_tags WHERE sag_id = %s AND deleted_at IS NULL ORDER BY created_at DESC"
|
|
tags = execute_query(tags_query, (sag_id,))
|
|
|
|
# Fetch relations
|
|
relationer_query = """
|
|
SELECT sr.*,
|
|
ss_kilde.titel as kilde_titel,
|
|
ss_mål.titel as mål_titel
|
|
FROM sag_relationer sr
|
|
JOIN sag_sager ss_kilde ON sr.kilde_sag_id = ss_kilde.id
|
|
JOIN sag_sager ss_mål ON sr.målsag_id = ss_mål.id
|
|
WHERE (sr.kilde_sag_id = %s OR sr.målsag_id = %s)
|
|
AND sr.deleted_at IS NULL
|
|
ORDER BY sr.created_at DESC
|
|
"""
|
|
relationer = execute_query(relationer_query, (sag_id, sag_id))
|
|
|
|
# Fetch customer info if customer_id exists
|
|
customer = None
|
|
hovedkontakt = None
|
|
if sag.get('customer_id'):
|
|
customer_query = "SELECT * FROM customers WHERE id = %s"
|
|
customer_result = execute_query(customer_query, (sag['customer_id'],))
|
|
if customer_result:
|
|
customer = customer_result[0]
|
|
|
|
# Fetch hovedkontakt (primary contact) for customer via contact_companies
|
|
kontakt_query = """
|
|
SELECT c.*
|
|
FROM contacts c
|
|
JOIN contact_companies cc ON c.id = cc.contact_id
|
|
WHERE cc.customer_id = %s
|
|
ORDER BY cc.is_primary DESC, c.id ASC
|
|
LIMIT 1
|
|
"""
|
|
kontakt_result = execute_query(kontakt_query, (sag['customer_id'],))
|
|
if kontakt_result:
|
|
hovedkontakt = kontakt_result[0]
|
|
|
|
return templates.TemplateResponse("modules/sag/templates/detail.html", {
|
|
"request": request,
|
|
"case": sag,
|
|
"customer": customer,
|
|
"hovedkontakt": hovedkontakt,
|
|
"tags": tags,
|
|
"relationer": relationer,
|
|
})
|
|
except HTTPException:
|
|
raise
|
|
except Exception as e:
|
|
logger.error("❌ Error displaying case details: %s", e)
|
|
raise HTTPException(status_code=500, detail="Failed to load case details")
|