from datetime import datetime, timezone from pathlib import Path from fastapi import APIRouter, Depends, File, HTTPException, UploadFile, status from fastapi.responses import FileResponse from sqlalchemy.orm import Session from .auth import current_user from .config import settings from .database import get_db from .dlt_constants import DLT_DOCUMENT_TYPES, DLT_UPLOAD_DOCUMENT_TYPES, PE_TM_CHAIN_BINDING_ID from .dlt_service import ensure_dlt_application, serialize_dlt from .kyc_constants import ALLOWED_UPLOAD_EXTENSIONS from .kyc_service import upload_root from .models import UserAccount router = APIRouter(prefix="/api/v1/dlt", tags=["dlt"]) @router.get("/me") def get_my_dlt(db: Session = Depends(get_db), user: UserAccount = Depends(current_user)) -> dict: application = ensure_dlt_application(db, user) return serialize_dlt(application) @router.get("/loa") def download_loa(_: UserAccount = Depends(current_user)) -> FileResponse: template = Path(settings.dlt_loa_template_path) if not template.is_file(): raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="LOA template not found") return FileResponse( template, media_type="application/vnd.openxmlformats-officedocument.wordprocessingml.document", filename="Updated LOA.docx", ) @router.post("/chain-binding/confirm") def confirm_chain_binding( db: Session = Depends(get_db), user: UserAccount = Depends(current_user), ) -> dict: application = ensure_dlt_application(db, user) if application.status == "approved": raise HTTPException(status_code=status.HTTP_409_CONFLICT, detail="Approved DLT cannot be edited") document = next(doc for doc in application.documents if doc.document_type == "pe_tm_chain_binding") if document.status == "approved": raise HTTPException(status_code=status.HTTP_409_CONFLICT, detail="Chain binding already approved") document.original_filename = f"Chain binding {PE_TM_CHAIN_BINDING_ID}" document.stored_path = None document.status = "pending" document.review_note = None document.uploaded_at = datetime.now(timezone.utc) document.reviewed_at = None if application.status in {"not_started", "in_progress", "rejected"}: application.status = "in_progress" db.commit() db.refresh(application) return serialize_dlt(application) @router.post("/documents/{document_type}") async def upload_document( document_type: str, file: UploadFile = File(...), db: Session = Depends(get_db), user: UserAccount = Depends(current_user), ) -> dict: if document_type not in DLT_DOCUMENT_TYPES: raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="Invalid document type") if document_type not in DLT_UPLOAD_DOCUMENT_TYPES: raise HTTPException( status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, detail="This item uses chain binding confirmation instead of file upload", ) application = ensure_dlt_application(db, user) if application.status == "approved": raise HTTPException(status_code=status.HTTP_409_CONFLICT, detail="Approved DLT cannot be edited") filename = file.filename or "" extension = Path(filename).suffix.lower() if extension not in ALLOWED_UPLOAD_EXTENSIONS: raise HTTPException( status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, detail="Allowed file types: PDF, PNG, JPG, DOC, DOCX", ) content = await file.read() if not content: raise HTTPException(status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, detail="File is empty") if len(content) > settings.max_upload_bytes: raise HTTPException(status_code=status.HTTP_413_REQUEST_ENTITY_TOO_LARGE, detail="File exceeds 10 MB limit") document = next(doc for doc in application.documents if doc.document_type == document_type) root = upload_root(settings.upload_dir) stored_name = f"{application.id}_{document_type}{extension}" stored_path = root / stored_name stored_path.write_bytes(content) document.original_filename = filename document.stored_path = str(stored_path) document.status = "pending" document.review_note = None document.uploaded_at = datetime.now(timezone.utc) document.reviewed_at = None if application.status in {"not_started", "in_progress", "rejected"}: application.status = "in_progress" db.commit() db.refresh(application) return serialize_dlt(application) @router.post("/submit") def submit_dlt(db: Session = Depends(get_db), user: UserAccount = Depends(current_user)) -> dict: application = ensure_dlt_application(db, user) if application.status == "approved": return serialize_dlt(application) missing = [doc.document_type for doc in application.documents if doc.status == "missing"] if missing: raise HTTPException( status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, detail="Complete all required DLT items before submitting", ) application.status = "submitted" application.submitted_at = datetime.now(timezone.utc) db.commit() db.refresh(application) return serialize_dlt(application)