Spaces:
Sleeping
Sleeping
| """ | |
| Ticket Completion API - Runtime checklist validation with photo upload | |
| NO DATABASE PERSISTENCE OF CHECKLISTS! | |
| Checklist generated on-the-fly from project.activation_requirements and project.photo_requirements | |
| """ | |
| from fastapi import APIRouter, Depends, File, UploadFile, Form, HTTPException | |
| from sqlalchemy.orm import Session | |
| from typing import List, Dict, Optional | |
| from uuid import UUID | |
| import json | |
| import logging | |
| from app.api.deps import get_db, get_current_user | |
| from app.models.user import User | |
| from app.models.ticket import Ticket | |
| from app.services.ticket_completion_service import TicketCompletionService | |
| from app.schemas.ticket_completion import ( | |
| TicketCompletionChecklist, | |
| TicketActivationDataUpdate, | |
| TicketCompleteRequest, | |
| TicketCompletionResponse, | |
| ValidationErrorResponse | |
| ) | |
| router = APIRouter() | |
| logger = logging.getLogger(__name__) | |
| def get_completion_checklist( | |
| ticket_id: UUID, | |
| db: Session = Depends(get_db), | |
| current_user: User = Depends(get_current_user) | |
| ): | |
| """Get or generate completion checklist (runtime only)""" | |
| from sqlalchemy.orm import joinedload | |
| from app.models.ticket_image import TicketImage | |
| # Load ticket with images and their documents for checklist generation | |
| ticket = db.query(Ticket).options( | |
| joinedload(Ticket.images).joinedload(TicketImage.document) | |
| ).filter(Ticket.id == ticket_id).first() | |
| if not ticket: | |
| raise HTTPException(status_code=404, detail="Ticket not found") | |
| # Generate checklist from project requirements (runtime) | |
| checklist = TicketCompletionService.generate_checklist(ticket, db) | |
| return checklist | |
| async def upload_photos( | |
| ticket_id: UUID, | |
| photo_type: str = Form(..., description="Type of photo (e.g., 'before_installation', 'after_installation')"), | |
| files: List[UploadFile] = File(..., description="Photo files to upload"), | |
| db: Session = Depends(get_db), | |
| current_user: User = Depends(get_current_user) | |
| ): | |
| """Upload photos for ticket (routes to Cloudinary via media_service.py)""" | |
| ticket = db.query(Ticket).filter(Ticket.id == ticket_id).first() | |
| if not ticket: | |
| raise HTTPException(status_code=404, detail="Ticket not found") | |
| # Organize photos by type | |
| photos = {photo_type: files} | |
| # Upload and validate | |
| result = await TicketCompletionService.update_photos( | |
| ticket=ticket, | |
| photos=photos, | |
| uploaded_by_user_id=current_user.id, | |
| db=db | |
| ) | |
| return result | |
| def set_completion_data( | |
| ticket_id: UUID, | |
| request: TicketActivationDataUpdate, | |
| db: Session = Depends(get_db), | |
| current_user: User = Depends(get_current_user) | |
| ): | |
| """Set/replace completion data (replaces entire object)""" | |
| ticket = db.query(Ticket).filter(Ticket.id == ticket_id).first() | |
| if not ticket: | |
| raise HTTPException(status_code=404, detail="Ticket not found") | |
| # Validate and store (replaces entire object) | |
| result = TicketCompletionService.set_completion_data( | |
| ticket=ticket, | |
| completion_data=request.activation_data, | |
| replace=True, | |
| db=db | |
| ) | |
| return result | |
| def update_completion_data( | |
| ticket_id: UUID, | |
| request: TicketActivationDataUpdate, | |
| db: Session = Depends(get_db), | |
| current_user: User = Depends(get_current_user) | |
| ): | |
| """Update completion data (merges with existing)""" | |
| ticket = db.query(Ticket).filter(Ticket.id == ticket_id).first() | |
| if not ticket: | |
| raise HTTPException(status_code=404, detail="Ticket not found") | |
| # Validate and merge with existing data | |
| result = TicketCompletionService.set_completion_data( | |
| ticket=ticket, | |
| completion_data=request.activation_data, | |
| replace=False, # Merge mode | |
| db=db | |
| ) | |
| return result | |
| def complete_ticket( | |
| ticket_id: UUID, | |
| request: TicketCompleteRequest, | |
| db: Session = Depends(get_db), | |
| current_user: User = Depends(get_current_user) | |
| ): | |
| """Complete ticket (final validation + subscription creation)""" | |
| ticket = db.query(Ticket).filter(Ticket.id == ticket_id).first() | |
| if not ticket: | |
| raise HTTPException(status_code=404, detail="Ticket not found") | |
| # Complete ticket with validation | |
| result = TicketCompletionService.complete_ticket( | |
| ticket=ticket, | |
| work_notes=request.work_notes, | |
| force_complete=request.force_complete, | |
| completed_by_user_id=current_user.id, | |
| location_lat=request.location_latitude, | |
| location_lng=request.location_longitude, | |
| location_accuracy=request.location_accuracy, | |
| db=db | |
| ) | |
| return result | |