Spaces:
Sleeping
Sleeping
| """ | |
| Export API - Data Export Endpoints | |
| Endpoints for exporting entity data to CSV/Excel. | |
| Available entities: tickets, customers, subscriptions, field_agents, sales_orders | |
| Authorization: | |
| - platform_admin, client_admin, contractor_admin: Full access | |
| - project_manager, sales_manager, dispatcher: Project-scoped access | |
| - field_agent, sales_agent: No access | |
| """ | |
| from fastapi import APIRouter, Depends, HTTPException, status | |
| from fastapi.responses import StreamingResponse | |
| from sqlalchemy.orm import Session | |
| from typing import List | |
| import logging | |
| from datetime import datetime | |
| from app.api.deps import get_db, get_current_user | |
| from app.models.user import User | |
| from app.schemas.export import ( | |
| ExportRequest, | |
| AvailableColumnsResponse, | |
| ColumnMetadata | |
| ) | |
| from app.services.export_service import ExportService | |
| from app.config.export_columns import get_available_columns | |
| router = APIRouter() | |
| logger = logging.getLogger(__name__) | |
| # ============================================ | |
| # GET AVAILABLE COLUMNS | |
| # ============================================ | |
| async def get_available_export_columns( | |
| entity: str, | |
| current_user: User = Depends(get_current_user) | |
| ): | |
| """ | |
| Get list of available columns for export. | |
| Returns column metadata including: | |
| - key: Column identifier for API requests | |
| - label: Human-readable header | |
| - requires_join: Whether column needs database join (affects performance) | |
| Available entities: | |
| - tickets: Work orders/tickets | |
| - customers: Customer records | |
| - subscriptions: Active service subscriptions | |
| - field_agents: Field agent users | |
| - sales_orders: Sales orders | |
| Authorization: project_manager+, dispatcher+, admins | |
| """ | |
| # Check authorization | |
| if not ExportService.can_user_export(current_user): | |
| raise HTTPException( | |
| status_code=status.HTTP_403_FORBIDDEN, | |
| detail="You do not have permission to export data" | |
| ) | |
| # Get columns for entity | |
| columns_data = get_available_columns(entity) | |
| if not columns_data: | |
| raise HTTPException( | |
| status_code=status.HTTP_404_NOT_FOUND, | |
| detail=f"Entity '{entity}' not found or has no exportable columns" | |
| ) | |
| # Convert to schema | |
| columns = [ColumnMetadata(**col_data) for col_data in columns_data] | |
| return AvailableColumnsResponse( | |
| entity=entity, | |
| columns=columns | |
| ) | |
| # ============================================ | |
| # EXPORT DATA | |
| # ============================================ | |
| async def export_entity_data( | |
| entity: str, | |
| request: ExportRequest, | |
| db: Session = Depends(get_db), | |
| current_user: User = Depends(get_current_user) | |
| ): | |
| """ | |
| Export entity data to CSV/Excel. | |
| Request body: | |
| - columns: List of column keys to export (get from /columns endpoint) | |
| - filters: Optional filters to apply (project_id, status, etc.) | |
| - format: Export format ('csv' or 'excel') | |
| Response: File download | |
| Limits: | |
| - Max file size: 1MB | |
| - If file exceeds limit, reduce columns or add filters | |
| Example filters: | |
| - tickets: project_id, status, priority, ticket_type, region_id | |
| - customers: client_id, is_active, region_id | |
| - subscriptions: project_id, status, service_type, region_id | |
| - field_agents: contractor_id, is_active, status | |
| - sales_orders: project_id, status, is_processed, region_id | |
| Authorization: project_manager+, dispatcher+, admins | |
| """ | |
| try: | |
| # Ensure entity in request matches path parameter | |
| if request.entity != entity: | |
| raise HTTPException( | |
| status_code=status.HTTP_400_BAD_REQUEST, | |
| detail=f"Entity mismatch: path='{entity}', body='{request.entity}'" | |
| ) | |
| # Call export service | |
| file_buffer = ExportService.export_entity( | |
| db=db, | |
| entity=request.entity, | |
| columns=request.columns, | |
| filters=request.filters, | |
| format=request.format, | |
| current_user=current_user, | |
| calculated_fields=request.calculated_fields, | |
| aggregations=request.aggregations, | |
| group_by=request.group_by | |
| ) | |
| # Prepare filename | |
| timestamp = datetime.utcnow().strftime('%Y%m%d_%H%M%S') | |
| filename = f"{entity}_export_{timestamp}.{request.format}" | |
| # Determine media type | |
| if request.format == 'csv': | |
| media_type = 'text/csv' | |
| elif request.format == 'excel': | |
| media_type = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' | |
| else: | |
| media_type = 'application/octet-stream' | |
| # Return file as streaming response | |
| return StreamingResponse( | |
| file_buffer, | |
| media_type=media_type, | |
| headers={ | |
| 'Content-Disposition': f'attachment; filename="{filename}"', | |
| 'Content-Length': str(file_buffer.getbuffer().nbytes) | |
| } | |
| ) | |
| except HTTPException: | |
| raise | |
| except Exception as e: | |
| logger.error(f"Export failed: {str(e)}") | |
| raise HTTPException( | |
| status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, | |
| detail=f"Export failed: {str(e)}" | |
| ) | |
| # ============================================ | |
| # EXPORT PRESETS (Future Feature) | |
| # ============================================ | |
| async def get_export_presets( | |
| entity: str, | |
| current_user: User = Depends(get_current_user) | |
| ): | |
| """ | |
| Get saved export presets for entity. | |
| Presets are pre-configured column selections for common export scenarios. | |
| Example presets for tickets: | |
| - basic: id, ticket_name, status, priority, customer_name | |
| - detailed: All fields | |
| - analytics: status, priority, created_at, completed_at, sla_violated | |
| Future feature: Currently returns empty list. | |
| Authorization: project_manager+, dispatcher+, admins | |
| """ | |
| # Check authorization | |
| if not ExportService.can_user_export(current_user): | |
| raise HTTPException( | |
| status_code=status.HTTP_403_FORBIDDEN, | |
| detail="You do not have permission to export data" | |
| ) | |
| # TODO: Implement saved presets (future feature) | |
| return { | |
| "entity": entity, | |
| "presets": [] | |
| } | |