diff --git a/app/main.py b/app/main.py index ac2a87c..d291338 100644 --- a/app/main.py +++ b/app/main.py @@ -15,7 +15,7 @@ from starlette.middleware.sessions import SessionMiddleware from fastapi.middleware.cors import CORSMiddleware from fastapi.staticfiles import StaticFiles from fastapi.templating import Jinja2Templates -from sqlalchemy.orm import Session +from sqlalchemy.orm import Session, joinedload from sqlalchemy import or_ from dotenv import load_dotenv from starlette.middleware.base import BaseHTTPMiddleware @@ -314,3 +314,58 @@ async def admin_panel(request: Request, db: Session = Depends(get_db)): "request": request, "user": user }) + + +@app.get("/case/{case_id}") +async def case_detail( + request: Request, + case_id: int, + db: Session = Depends(get_db), +): + """ + Case detail view. + + Displays detailed information for a single case and its related client and + associated records (transactions, documents, payments). + """ + # Check authentication + user = get_current_user_from_session(request.session) + if not user: + return RedirectResponse(url="/login", status_code=302) + + # Fetch case with related entities eagerly loaded to avoid lazy-load issues + case_obj = ( + db.query(Case) + .options( + joinedload(Case.client), + joinedload(Case.transactions), + joinedload(Case.documents), + joinedload(Case.payments), + ) + .filter(Case.id == case_id) + .first() + ) + + if not case_obj: + logger.warning("Case not found: id=%s", case_id) + return templates.TemplateResponse( + "case.html", + { + "request": request, + "user": user, + "case": None, + "error": "Case not found", + }, + status_code=404, + ) + + logger.info("Rendering case detail: id=%s, file_no='%s'", case_obj.id, case_obj.file_no) + + return templates.TemplateResponse( + "case.html", + { + "request": request, + "user": user, + "case": case_obj, + }, + ) diff --git a/app/templates/case.html b/app/templates/case.html index ec139a7..5c3b4b7 100644 --- a/app/templates/case.html +++ b/app/templates/case.html @@ -1 +1,183 @@ - +{% extends "base.html" %} + +{% block title %} +Case {{ case.file_no if case else '' }} ยท Delphi Database +{% endblock %} + +{% block content %} +
+
+ + + Back + +

Case Details

+
+ + {% if error %} +
+ +
+ {% endif %} + + {% if case %} +
+
+
+
+
+
File #
+
{{ case.file_no }}
+
+
+
Status
+
+ {% if case.status == 'active' %} + Active + {% elif case.status == 'closed' %} + Closed + {% else %} + {{ case.status or 'n/a' }} + {% endif %} +
+
+
+
Type
+
{{ case.case_type or '' }}
+
+
+
Opened
+
{{ case.open_date.strftime('%Y-%m-%d') if case.open_date else '' }}
+
+
+ +
+ {% set client = case.client %} +
+
Client
+
+ {% if client %} + {{ client.last_name }}, {{ client.first_name }} + {% else %} + Unknown + {% endif %} +
+
+
+
Company
+
{{ client.company if client else '' }}
+
+
+
City/State
+
+ {% if client %} + {{ client.city or '' }}{% if client.state %}, {{ client.state }}{% endif %} + {% endif %} +
+
+
+ +
Description
+

{{ case.description or '' }}

+
+
+
+ +
+
+
Transactions
+
+
+ + + + + + + + + + {% if case.transactions and case.transactions|length > 0 %} + {% for t in case.transactions %} + + + + + + {% endfor %} + {% else %} + + {% endif %} + +
DateTypeAmount
{{ t.transaction_date.strftime('%Y-%m-%d') if t.transaction_date else '' }}{{ t.transaction_type or '' }}{{ '%.2f'|format(t.amount) if t.amount is not none else '' }}
No transactions.
+
+
+
+
+ +
+
+
Documents
+
+
+ + + + + + + + + + {% if case.documents and case.documents|length > 0 %} + {% for d in case.documents %} + + + + + + {% endfor %} + {% else %} + + {% endif %} + +
TypeFileUploaded
{{ d.document_type or '' }}{{ d.file_name or '' }}{{ d.uploaded_date.strftime('%Y-%m-%d') if d.uploaded_date else '' }}
No documents.
+
+
+
+
+ +
+
+
Payments
+
+
+ + + + + + + + + + {% if case.payments and case.payments|length > 0 %} + {% for p in case.payments %} + + + + + + {% endfor %} + {% else %} + + {% endif %} + +
DateTypeAmount
{{ p.payment_date.strftime('%Y-%m-%d') if p.payment_date else '' }}{{ p.payment_type or '' }}{{ '%.2f'|format(p.amount) if p.amount is not none else '' }}
No payments.
+
+
+
+
+ {% endif %} +
+{% endblock %}