"""Pay-off endpoints.""" from datetime import date from decimal import Decimal from enum import Enum from typing import Optional from fastapi import APIRouter, Depends, HTTPException, status from pydantic import BaseModel, Field, field_validator from sqlalchemy.orm import Session from app.database import get_db, PO10DAY from app.logging import get_logger router = APIRouter() logger = get_logger(__name__) class PayoffStatus(str, Enum): """Enum for payoff status values.""" PROCESSED = "processed" PENDING = "pending" FAILED = "failed" CANCELLED = "cancelled" class PayoffRequest(BaseModel): """Request model for loan payoff.""" loan_id: str = Field(..., description="Loan identifier", min_length=1, max_length=50) payoff_amount: Decimal = Field(..., description="Payoff amount", gt=0, decimal_places=2) payoff_date: date = Field(..., description="Payoff date") borrower_name: Optional[str] = Field(None, description="Borrower name", max_length=100) payment_method: str = Field(..., description="Payment method", regex="^(check|wire|ach|cash)$") notes: Optional[str] = Field(None, description="Additional notes", max_length=500) @field_validator('payoff_date') def validate_payoff_date(cls, v): """Validate payoff date is not in the future.""" from datetime import date if v > date.today(): raise ValueError('Payoff date cannot be in the future') return v class PayoffResponse(BaseModel): """Response model for loan payoff.""" status: PayoffStatus loan_id: str payoff_amount: Decimal payoff_date: date transaction_id: str @router.post("/payoff", response_model=PayoffResponse, status_code=status.HTTP_201_CREATED) async def create_payoff(payoff_request: PayoffRequest, db: Session = Depends(get_db)) -> PayoffResponse: """Create a loan payoff record.""" logger.info(f"Processing payoff for loan {payoff_request.loan_id}") # Check if loan_id already exists existing_payoff = db.query(PO10DAY).filter(PO10DAY.loan_id == payoff_request.loan_id).first() if existing_payoff: logger.error(f"Payoff already exists for loan {payoff_request.loan_id}") raise HTTPException( status_code=status.HTTP_409_CONFLICT, detail=f"Payoff already exists for loan {payoff_request.loan_id}" ) import uuid transaction_id = str(uuid.uuid4()) # Create database entry try: po10day_record = PO10DAY( loan_id=payoff_request.loan_id, payoff_amount=payoff_request.payoff_amount, payoff_date=payoff_request.payoff_date, borrower_name=payoff_request.borrower_name, payment_method=payoff_request.payment_method, notes=payoff_request.notes, transaction_id=transaction_id ) db.add(po10day_record) db.commit() db.refresh(po10day_record) logger.info(f"Payoff created successfully for loan {payoff_request.loan_id}, transaction {transaction_id}") except Exception as e: db.rollback() logger.error(f"Failed to create payoff for loan {payoff_request.loan_id}", exc_info=e) raise e response = PayoffResponse( status=PayoffStatus.PROCESSED, loan_id=payoff_request.loan_id, payoff_amount=payoff_request.payoff_amount, payoff_date=payoff_request.payoff_date, transaction_id=transaction_id ) return response