from fastapi import APIRouter, Depends, HTTPException, status from sqlmodel import Session, select from app.core.db import get_session from app.core.auth import require_any_access, require_write_access, require_admin from app.schemas.models import Credit, Partner, Transaction from app.schemas.schemas import ( CreditCreate, CreditUpdate, CreditResponse, UserResponse ) from typing import List router = APIRouter(prefix="/credit", tags=["credit"]) # Create Credit @router.post("/", response_model=CreditResponse, status_code=status.HTTP_201_CREATED) def create_credit( credit: CreditCreate, session: Session = Depends(get_session), current_user: UserResponse = Depends(require_write_access) ): """Create new credit account (requires write access).""" # Validate partner exists partner = session.get(Partner, credit.partner_id) if not partner: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail="Partner not found" ) # Validate transaction exists transaction = session.get(Transaction, credit.transaction_id) if not transaction: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail="Transaction not found" ) # Check if credit account already exists for this partner existing_credit = session.exec( select(Credit).where(Credit.partner_id == credit.partner_id) ).first() if existing_credit: raise HTTPException( status_code=status.HTTP_409_CONFLICT, detail="Credit account already exists for this partner" ) # Create credit with audit fields credit_data = credit.model_dump() credit_data["created_by"] = current_user.id credit_data["updated_by"] = current_user.id db_credit = Credit(**credit_data) session.add(db_credit) session.commit() session.refresh(db_credit) return db_credit # Read all Credit accounts @router.get("/", response_model=List[CreditResponse]) def read_credits( skip: int = 0, limit: int = 100, session: Session = Depends(get_session), current_user: UserResponse = Depends(require_any_access) ): """Get all credit accounts (requires authentication).""" credits = session.exec( select(Credit).offset(skip).limit(limit) ).all() return credits # Read Credit by partner @router.get("/partner/{partner_id}", response_model=CreditResponse) def read_credit_by_partner( partner_id: int, session: Session = Depends(get_session), current_user: UserResponse = Depends(require_any_access) ): """Get credit account for a specific partner (requires authentication).""" # Validate partner exists partner = session.get(Partner, partner_id) if not partner: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="Partner not found" ) credit = session.exec( select(Credit).where(Credit.partner_id == partner_id) ).first() if not credit: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="Credit account not found for this partner" ) return credit # Read single Credit by ID @router.get("/{credit_id}", response_model=CreditResponse) def read_credit_by_id( credit_id: int, session: Session = Depends(get_session), current_user: UserResponse = Depends(require_any_access) ): """Get specific credit account by ID (requires authentication).""" credit = session.get(Credit, credit_id) if not credit: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="Credit account not found" ) return credit # Update Credit @router.put("/{credit_id}", response_model=CreditResponse) def update_credit( credit_id: int, credit: CreditUpdate, session: Session = Depends(get_session), current_user: UserResponse = Depends(require_write_access) ): """Update specific credit account (requires write access).""" db_credit = session.get(Credit, credit_id) if not db_credit: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="Credit account not found" ) update_data = credit.model_dump(exclude_unset=True) # Validate partner if being updated if "partner_id" in update_data: partner = session.get(Partner, update_data["partner_id"]) if not partner: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail="Partner not found" ) # Check for duplicate partner (excluding current record) existing_credit = session.exec( select(Credit).where( Credit.partner_id == update_data["partner_id"], Credit.id != credit_id ) ).first() if existing_credit: raise HTTPException( status_code=status.HTTP_409_CONFLICT, detail="Credit account already exists for this partner" ) # Validate transaction if being updated if "transaction_id" in update_data: transaction = session.get(Transaction, update_data["transaction_id"]) if not transaction: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail="Transaction not found" ) # Track who updated update_data["updated_by"] = current_user.id # Update credit for key, value in update_data.items(): setattr(db_credit, key, value) session.add(db_credit) session.commit() session.refresh(db_credit) return db_credit # Delete Credit @router.delete("/{credit_id}", status_code=status.HTTP_204_NO_CONTENT) def delete_credit( credit_id: int, session: Session = Depends(get_session), current_user: UserResponse = Depends(require_admin) ): """Delete specific credit account (admin only).""" credit = session.get(Credit, credit_id) if not credit: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="Credit account not found" ) session.delete(credit) session.commit() return None