Spaces:
Sleeping
Sleeping
File size: 6,197 Bytes
dad7dc2 44ca2cd dad7dc2 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 |
"""
Progress Report API Endpoints
Handles:
- Creating progress reports with location verification
- Listing reports with filters
- Updating and deleting reports
- Image management via polymorphic linking
- Statistics aggregation
"""
from fastapi import APIRouter, Depends, Query, status
from sqlalchemy.orm import Session
from typing import List, Optional
from uuid import UUID
from app.api.deps import get_db, get_current_user
from app.models.user import User
from app.schemas.ticket_progress import (
TicketProgressReportCreate,
TicketProgressReportUpdate,
TicketProgressReportResponse,
TicketProgressReportListResponse,
ProgressReportStats,
)
from app.services.progress_report_service import ProgressReportService
router = APIRouter(prefix="/progress-reports", tags=["Progress Reports"])
@router.post(
"",
response_model=TicketProgressReportResponse,
status_code=status.HTTP_201_CREATED,
summary="Create progress report",
description="""
Create a new progress report for a task ticket.
**Features:**
- Describes work completed and remaining
- Tracks issues encountered and resolved
- Captures team size and hours worked
- Optional GPS location verification
**Location Verification:**
If latitude/longitude provided, automatically checks if within 100m of ticket location.
**Image Upload:**
After creating the report, upload images using POST /progress-reports/{report_id}/images
and link them with linked_entity_type='progress_report'
""",
)
def create_progress_report(
data: TicketProgressReportCreate,
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user),
):
"""Create a new progress report"""
return ProgressReportService.create_progress_report(
db=db,
data=data,
reported_by_user_id=current_user.id
)
@router.get(
"",
response_model=TicketProgressReportListResponse,
summary="List progress reports",
description="""
List progress reports with optional filters.
**Filters:**
- ticket_id: Show reports for specific ticket
- reported_by_user_id: Show reports from specific user
- with_issues_only: Show only reports with issues_encountered
**Sorting:**
Always sorted by newest first (created_at DESC)
""",
)
def list_progress_reports(
ticket_id: Optional[UUID] = Query(None, description="Filter by ticket ID"),
reported_by_user_id: Optional[UUID] = Query(None, description="Filter by reporter"),
with_issues_only: bool = Query(False, description="Show only reports with issues"),
skip: int = Query(0, ge=0, description="Pagination offset"),
limit: int = Query(100, ge=1, le=500, description="Pagination limit"),
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user),
):
"""List progress reports"""
reports, total = ProgressReportService.list_progress_reports(
db=db,
ticket_id=ticket_id,
reported_by_user_id=reported_by_user_id,
with_issues_only=with_issues_only,
skip=skip,
limit=limit
)
return {
"items": reports,
"total": total,
"skip": skip,
"limit": limit,
}
@router.get(
"/stats",
response_model=ProgressReportStats,
summary="Get progress report statistics",
description="""
Get aggregated statistics for progress reports.
**Includes:**
- Total reports count
- Unique tickets with reports
- Average team size on site
- Total hours worked across all reports
- Reports with issues encountered
- Reports with location verification
""",
)
def get_progress_stats(
ticket_id: Optional[UUID] = Query(None, description="Filter by ticket ID"),
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user),
):
"""Get progress report statistics"""
return ProgressReportService.get_progress_stats(db=db, ticket_id=ticket_id)
@router.get(
"/{report_id}",
response_model=TicketProgressReportResponse,
summary="Get progress report by ID",
description="""
Retrieve a specific progress report with all details.
**Includes:**
- All report fields
- Reporter user information
- Ticket information
**To get images:**
Use the ticket_images endpoint with filters:
- linked_entity_type = 'progress_report'
- linked_entity_id = {report_id}
""",
)
def get_progress_report(
report_id: UUID,
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user),
):
"""Get progress report by ID"""
return ProgressReportService.get_progress_report(db=db, report_id=report_id)
@router.patch(
"/{report_id}",
response_model=TicketProgressReportResponse,
summary="Update progress report",
description="""
Update a progress report.
**Permissions:**
Only the original reporter can update their report.
**Update Strategy:**
Partial updates supported - only include fields you want to change.
""",
)
def update_progress_report(
report_id: UUID,
data: TicketProgressReportUpdate,
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user),
):
"""Update progress report"""
return ProgressReportService.update_progress_report(
db=db,
report_id=report_id,
data=data,
current_user_id=current_user.id
)
@router.delete(
"/{report_id}",
status_code=status.HTTP_204_NO_CONTENT,
summary="Delete progress report",
description="""
Soft delete a progress report.
**Permissions:**
Only the original reporter can delete their report.
**Cascade Behavior:**
Linked images remain but lose their link (linked_entity_id set to null).
""",
)
def delete_progress_report(
report_id: UUID,
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user),
):
"""Delete progress report"""
ProgressReportService.delete_progress_report(
db=db,
report_id=report_id,
current_user_id=current_user.id
)
return None
|