swiftops-backend / src /app /api /v1 /incidents.py
kamau1's picture
Fix dependency imports: use app.api.deps instead of app.dependencies
c345382
"""
INCIDENTS API - Support Request Management
Endpoints for:
1. Create incidents (customer reports issue)
2. List/get incidents with filters
3. Update/resolve/cancel incidents
4. Incident statistics
Authorization:
- platform_admin: Full access
- project_manager: Their projects only
- dispatcher: Their contractor's projects
- client_admin: View only
"""
from fastapi import APIRouter, Depends, status, Query
from sqlalchemy.orm import Session
from typing import List, Optional
from uuid import UUID
from math import ceil
from app.api.deps import get_db, get_current_user
from app.models.user import User
from app.services.incident_service import IncidentService
from app.schemas.incident import *
router = APIRouter()
# ============================================
# CREATE INCIDENTS
# ============================================
@router.post(
"",
response_model=IncidentResponse,
status_code=status.HTTP_201_CREATED,
summary="Create incident (support request)"
)
def create_incident(
data: IncidentCreate,
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user)
):
"""
Create incident (support request from customer).
**Authorization:** PM, Dispatcher, Platform Admin
**Workflow:**
1. Customer reports problem with existing service
2. Support creates incident with status='open'
3. Can be promoted to ticket for field technician dispatch
**Example:**
```json
{
"customer_id": "uuid-here",
"subscription_id": "uuid-here",
"project_id": "uuid-here",
"incident_type": "no_service",
"issue_description": "Customer reports no internet for 2 days",
"priority": "urgent"
}
```
"""
incident = IncidentService.create_incident(
db=db,
data=data,
current_user=current_user
)
# Populate response
response = IncidentResponse.from_orm(incident)
if incident.customer:
response.customer_name = incident.customer.customer_name
if incident.project:
response.project_name = incident.project.title
return response
# ============================================
# GET INCIDENTS
# ============================================
@router.get(
"/{incident_id}",
response_model=IncidentResponse,
summary="Get incident by ID"
)
def get_incident(
incident_id: UUID,
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user)
):
"""
Get incident details by ID.
**Authorization:** PM, Dispatcher, Client Admin, Platform Admin
"""
incident = IncidentService.get_incident(
db=db,
incident_id=incident_id,
current_user=current_user
)
# Populate response
response = IncidentResponse.from_orm(incident)
if incident.customer:
response.customer_name = incident.customer.customer_name
if incident.project:
response.project_name = incident.project.title
return response
@router.get(
"",
response_model=IncidentListResponse,
summary="List incidents"
)
def list_incidents(
project_id: Optional[UUID] = Query(None, description="Filter by project"),
customer_id: Optional[UUID] = Query(None, description="Filter by customer"),
status: Optional[str] = Query(None, description="Filter by status (open, ticket_created, resolved, closed, cancelled)"),
priority: Optional[str] = Query(None, description="Filter by priority (low, normal, high, urgent)"),
incident_type: Optional[str] = Query(None, description="Filter by incident type"),
page: int = Query(1, ge=1, description="Page number"),
page_size: int = Query(50, ge=1, le=100, description="Items per page"),
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user)
):
"""
List incidents with filters and pagination.
**Authorization:** PM, Dispatcher, Client Admin, Platform Admin
**Filters:**
- project_id: Filter by project
- customer_id: Filter by customer
- status: open, ticket_created, resolved, closed, cancelled
- priority: low, normal, high, urgent
- incident_type: no_service, slow_speed, equipment_fault, etc.
"""
incidents, total = IncidentService.list_incidents(
db=db,
current_user=current_user,
project_id=project_id,
customer_id=customer_id,
status=status,
priority=priority,
incident_type=incident_type,
page=page,
page_size=page_size
)
# Populate responses
incident_responses = []
for incident in incidents:
response = IncidentResponse.from_orm(incident)
if incident.customer:
response.customer_name = incident.customer.customer_name
if incident.project:
response.project_name = incident.project.title
incident_responses.append(response)
return IncidentListResponse(
incidents=incident_responses,
total=total,
page=page,
page_size=page_size,
total_pages=ceil(total / page_size)
)
# ============================================
# UPDATE INCIDENTS
# ============================================
@router.put(
"/{incident_id}",
response_model=IncidentResponse,
summary="Update incident"
)
def update_incident(
incident_id: UUID,
data: IncidentUpdate,
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user)
):
"""
Update incident details (open incidents only).
**Authorization:** PM, Dispatcher, Platform Admin
"""
incident = IncidentService.update_incident(
db=db,
incident_id=incident_id,
data=data,
current_user=current_user
)
# Populate response
response = IncidentResponse.from_orm(incident)
if incident.customer:
response.customer_name = incident.customer.customer_name
if incident.project:
response.project_name = incident.project.title
return response
# ============================================
# INCIDENT RESOLUTION
# ============================================
@router.post(
"/{incident_id}/resolve",
response_model=IncidentResponse,
summary="Resolve incident"
)
def resolve_incident(
incident_id: UUID,
data: IncidentResolve,
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user)
):
"""
Mark incident as resolved.
**Authorization:** PM, Dispatcher, Platform Admin
Typically called when support ticket completes.
"""
incident = IncidentService.resolve_incident(
db=db,
incident_id=incident_id,
data=data,
current_user=current_user
)
# Populate response
response = IncidentResponse.from_orm(incident)
if incident.customer:
response.customer_name = incident.customer.customer_name
if incident.project:
response.project_name = incident.project.title
return response
@router.post(
"/{incident_id}/cancel",
response_model=IncidentResponse,
summary="Cancel incident"
)
def cancel_incident(
incident_id: UUID,
data: IncidentCancel,
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user)
):
"""
Cancel incident (false alarm or customer withdrew complaint).
**Authorization:** PM, Dispatcher, Platform Admin
"""
incident = IncidentService.cancel_incident(
db=db,
incident_id=incident_id,
data=data,
current_user=current_user
)
# Populate response
response = IncidentResponse.from_orm(incident)
if incident.customer:
response.customer_name = incident.customer.customer_name
if incident.project:
response.project_name = incident.project.title
return response