This commit is contained in:
HotSwapp
2025-08-18 20:20:04 -05:00
parent 89b2bc0aa2
commit bac8cc4bd5
114 changed files with 30258 additions and 1341 deletions

View File

@@ -9,8 +9,8 @@ from pydantic import BaseModel, Field, ConfigDict
from app.database.base import get_db
from app.models import (
File, FileStatus, FileType, Employee, User, FileStatusHistory,
FileTransferHistory, FileArchiveInfo
File, FileStatus, FileType, Employee, User, FileStatusHistory,
FileTransferHistory, FileArchiveInfo, FileClosureChecklist, FileAlert
)
from app.services.file_management import FileManagementService, FileManagementError, FileStatusWorkflow
from app.auth.security import get_current_user
@@ -134,6 +134,10 @@ async def change_file_status(
"""Change file status with workflow validation"""
try:
service = FileManagementService(db)
# Get the old status before changing
old_file = db.query(File).filter(File.file_no == file_no).first()
old_status = old_file.status if old_file else None
file_obj = service.change_file_status(
file_no=file_no,
new_status=request.new_status,
@@ -142,6 +146,21 @@ async def change_file_status(
validate_transition=request.validate_transition
)
# Log workflow event for file status change
try:
from app.services.workflow_integration import log_file_status_change_sync
log_file_status_change_sync(
db=db,
file_no=file_no,
old_status=old_status,
new_status=request.new_status,
user_id=current_user.id,
notes=request.notes
)
except Exception as e:
# Don't fail the operation if workflow logging fails
logger.warning(f"Failed to log workflow event for file {file_no}: {str(e)}")
return {
"message": f"File {file_no} status changed to {request.new_status}",
"file_no": file_obj.file_no,
@@ -397,6 +416,302 @@ async def bulk_status_update(
)
# Checklist endpoints
class ChecklistItemRequest(BaseModel):
item_name: str
item_description: Optional[str] = None
is_required: bool = True
sort_order: int = 0
class ChecklistItemUpdateRequest(BaseModel):
item_name: Optional[str] = None
item_description: Optional[str] = None
is_required: Optional[bool] = None
is_completed: Optional[bool] = None
sort_order: Optional[int] = None
notes: Optional[str] = None
@router.get("/{file_no}/closure-checklist")
async def get_closure_checklist(
file_no: str,
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user),
):
service = FileManagementService(db)
return service.get_closure_checklist(file_no)
@router.post("/{file_no}/closure-checklist")
async def add_checklist_item(
file_no: str,
request: ChecklistItemRequest,
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user),
):
service = FileManagementService(db)
try:
item = service.add_checklist_item(
file_no=file_no,
item_name=request.item_name,
item_description=request.item_description,
is_required=request.is_required,
sort_order=request.sort_order,
)
return {
"id": item.id,
"file_no": item.file_no,
"item_name": item.item_name,
"item_description": item.item_description,
"is_required": item.is_required,
"is_completed": item.is_completed,
"sort_order": item.sort_order,
}
except FileManagementError as e:
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(e))
@router.put("/closure-checklist/{item_id}")
async def update_checklist_item(
item_id: int,
request: ChecklistItemUpdateRequest,
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user),
):
service = FileManagementService(db)
try:
item = service.update_checklist_item(
item_id=item_id,
item_name=request.item_name,
item_description=request.item_description,
is_required=request.is_required,
is_completed=request.is_completed,
sort_order=request.sort_order,
user_id=current_user.id,
notes=request.notes,
)
return {
"id": item.id,
"file_no": item.file_no,
"item_name": item.item_name,
"item_description": item.item_description,
"is_required": item.is_required,
"is_completed": item.is_completed,
"completed_date": item.completed_date,
"completed_by_name": item.completed_by_name,
"notes": item.notes,
"sort_order": item.sort_order,
}
except FileManagementError as e:
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(e))
@router.delete("/closure-checklist/{item_id}")
async def delete_checklist_item(
item_id: int,
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user),
):
service = FileManagementService(db)
try:
service.delete_checklist_item(item_id=item_id)
return {"message": "Checklist item deleted"}
except FileManagementError as e:
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(e))
# Alerts endpoints
class AlertCreateRequest(BaseModel):
alert_type: str
title: str
message: str
alert_date: date
notify_attorney: bool = True
notify_admin: bool = False
notification_days_advance: int = 7
class AlertUpdateRequest(BaseModel):
title: Optional[str] = None
message: Optional[str] = None
alert_date: Optional[date] = None
is_active: Optional[bool] = None
@router.post("/{file_no}/alerts")
async def create_alert(
file_no: str,
request: AlertCreateRequest,
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user),
):
service = FileManagementService(db)
try:
alert = service.create_alert(
file_no=file_no,
alert_type=request.alert_type,
title=request.title,
message=request.message,
alert_date=request.alert_date,
notify_attorney=request.notify_attorney,
notify_admin=request.notify_admin,
notification_days_advance=request.notification_days_advance,
)
return {
"id": alert.id,
"file_no": alert.file_no,
"alert_type": alert.alert_type,
"title": alert.title,
"message": alert.message,
"alert_date": alert.alert_date,
"is_active": alert.is_active,
}
except FileManagementError as e:
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(e))
@router.get("/{file_no}/alerts")
async def get_alerts(
file_no: str,
active_only: bool = Query(True),
upcoming_only: bool = Query(False),
limit: int = Query(100, ge=1, le=500),
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user),
):
service = FileManagementService(db)
alerts = service.get_alerts(
file_no=file_no,
active_only=active_only,
upcoming_only=upcoming_only,
limit=limit,
)
return [
{
"id": a.id,
"file_no": a.file_no,
"alert_type": a.alert_type,
"title": a.title,
"message": a.message,
"alert_date": a.alert_date,
"is_active": a.is_active,
"is_acknowledged": a.is_acknowledged,
}
for a in alerts
]
@router.post("/alerts/{alert_id}/acknowledge")
async def acknowledge_alert(
alert_id: int,
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user),
):
service = FileManagementService(db)
try:
alert = service.acknowledge_alert(alert_id=alert_id, user_id=current_user.id)
return {"message": "Alert acknowledged", "id": alert.id}
except FileManagementError as e:
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(e))
@router.put("/alerts/{alert_id}")
async def update_alert(
alert_id: int,
request: AlertUpdateRequest,
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user),
):
service = FileManagementService(db)
try:
alert = service.update_alert(
alert_id=alert_id,
title=request.title,
message=request.message,
alert_date=request.alert_date,
is_active=request.is_active,
)
return {"message": "Alert updated", "id": alert.id}
except FileManagementError as e:
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(e))
@router.delete("/alerts/{alert_id}")
async def delete_alert(
alert_id: int,
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user),
):
service = FileManagementService(db)
try:
service.delete_alert(alert_id=alert_id)
return {"message": "Alert deleted"}
except FileManagementError as e:
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(e))
# Relationships endpoints
class RelationshipCreateRequest(BaseModel):
target_file_no: str
relationship_type: str
notes: Optional[str] = None
@router.post("/{file_no}/relationships")
async def create_relationship(
file_no: str,
request: RelationshipCreateRequest,
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user),
):
service = FileManagementService(db)
try:
rel = service.create_relationship(
source_file_no=file_no,
target_file_no=request.target_file_no,
relationship_type=request.relationship_type,
user_id=current_user.id,
notes=request.notes,
)
return {
"id": rel.id,
"source_file_no": rel.source_file_no,
"target_file_no": rel.target_file_no,
"relationship_type": rel.relationship_type,
"notes": rel.notes,
}
except FileManagementError as e:
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(e))
@router.get("/{file_no}/relationships")
async def get_relationships(
file_no: str,
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user),
):
service = FileManagementService(db)
return service.get_relationships(file_no=file_no)
@router.delete("/relationships/{relationship_id}")
async def delete_relationship(
relationship_id: int,
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user),
):
service = FileManagementService(db)
try:
service.delete_relationship(relationship_id=relationship_id)
return {"message": "Relationship deleted"}
except FileManagementError as e:
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(e))
# File queries and reports
@router.get("/by-status/{status}")
async def get_files_by_status(