fixes and refactor
This commit is contained in:
@@ -1,11 +1,11 @@
|
||||
"""
|
||||
Financial/Ledger API endpoints
|
||||
"""
|
||||
from typing import List, Optional, Dict, Any
|
||||
from typing import List, Optional, Dict, Any, Union
|
||||
from fastapi import APIRouter, Depends, HTTPException, status, Query
|
||||
from sqlalchemy.orm import Session, joinedload
|
||||
from sqlalchemy import or_, func, and_, desc, asc, text
|
||||
from datetime import date, datetime, timedelta
|
||||
from datetime import date, datetime, timedelta, timezone
|
||||
|
||||
from app.database.base import get_db
|
||||
from app.models.ledger import Ledger
|
||||
@@ -14,12 +14,14 @@ from app.models.rolodex import Rolodex
|
||||
from app.models.lookups import Employee, TransactionType, TransactionCode
|
||||
from app.models.user import User
|
||||
from app.auth.security import get_current_user
|
||||
from app.services.cache import invalidate_search_cache
|
||||
from app.services.query_utils import apply_sorting, paginate_with_total
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
# Pydantic schemas
|
||||
from pydantic import BaseModel
|
||||
from pydantic import BaseModel, ConfigDict
|
||||
|
||||
|
||||
class LedgerBase(BaseModel):
|
||||
@@ -57,8 +59,7 @@ class LedgerResponse(LedgerBase):
|
||||
id: int
|
||||
item_no: int
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
|
||||
class FinancialSummary(BaseModel):
|
||||
@@ -75,23 +76,46 @@ class FinancialSummary(BaseModel):
|
||||
billed_amount: float
|
||||
|
||||
|
||||
@router.get("/ledger/{file_no}", response_model=List[LedgerResponse])
|
||||
class PaginatedLedgerResponse(BaseModel):
|
||||
items: List[LedgerResponse]
|
||||
total: int
|
||||
|
||||
|
||||
@router.get("/ledger/{file_no}", response_model=Union[List[LedgerResponse], PaginatedLedgerResponse])
|
||||
async def get_file_ledger(
|
||||
file_no: str,
|
||||
skip: int = Query(0, ge=0),
|
||||
limit: int = Query(100, ge=1, le=500),
|
||||
billed_only: Optional[bool] = Query(None),
|
||||
skip: int = Query(0, ge=0, description="Offset for pagination"),
|
||||
limit: int = Query(100, ge=1, le=500, description="Page size"),
|
||||
billed_only: Optional[bool] = Query(None, description="Filter billed vs unbilled entries"),
|
||||
sort_by: Optional[str] = Query("date", description="Sort by: date, item_no, amount, billed"),
|
||||
sort_dir: Optional[str] = Query("desc", description="Sort direction: asc or desc"),
|
||||
include_total: bool = Query(False, description="When true, returns {items, total} instead of a plain list"),
|
||||
db: Session = Depends(get_db),
|
||||
current_user: User = Depends(get_current_user)
|
||||
):
|
||||
"""Get ledger entries for specific file"""
|
||||
query = db.query(Ledger).filter(Ledger.file_no == file_no).order_by(Ledger.date.desc())
|
||||
query = db.query(Ledger).filter(Ledger.file_no == file_no)
|
||||
|
||||
if billed_only is not None:
|
||||
billed_filter = "Y" if billed_only else "N"
|
||||
query = query.filter(Ledger.billed == billed_filter)
|
||||
|
||||
entries = query.offset(skip).limit(limit).all()
|
||||
|
||||
# Sorting (whitelisted)
|
||||
query = apply_sorting(
|
||||
query,
|
||||
sort_by,
|
||||
sort_dir,
|
||||
allowed={
|
||||
"date": [Ledger.date, Ledger.item_no],
|
||||
"item_no": [Ledger.item_no],
|
||||
"amount": [Ledger.amount],
|
||||
"billed": [Ledger.billed, Ledger.date],
|
||||
},
|
||||
)
|
||||
|
||||
entries, total = paginate_with_total(query, skip, limit, include_total)
|
||||
if include_total:
|
||||
return {"items": entries, "total": total or 0}
|
||||
return entries
|
||||
|
||||
|
||||
@@ -127,6 +151,10 @@ async def create_ledger_entry(
|
||||
# Update file balances (simplified version)
|
||||
await _update_file_balances(file_obj, db)
|
||||
|
||||
try:
|
||||
await invalidate_search_cache()
|
||||
except Exception:
|
||||
pass
|
||||
return entry
|
||||
|
||||
|
||||
@@ -158,6 +186,10 @@ async def update_ledger_entry(
|
||||
if file_obj:
|
||||
await _update_file_balances(file_obj, db)
|
||||
|
||||
try:
|
||||
await invalidate_search_cache()
|
||||
except Exception:
|
||||
pass
|
||||
return entry
|
||||
|
||||
|
||||
@@ -185,6 +217,10 @@ async def delete_ledger_entry(
|
||||
if file_obj:
|
||||
await _update_file_balances(file_obj, db)
|
||||
|
||||
try:
|
||||
await invalidate_search_cache()
|
||||
except Exception:
|
||||
pass
|
||||
return {"message": "Ledger entry deleted successfully"}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user