from fastapi import APIRouter, HTTPException from typing import Dict, Any import httpx from adapters.amocrm_client import AmoCRMClient router = APIRouter() @router.get("/fetch/all") async def fetch_all_amocrm_data() -> Dict[str, Any]: """Fetch all data from AMO CRM (limited amounts for testing)""" try: client = AmoCRMClient() return await client.fetch_all_data() except Exception as e: raise HTTPException(status_code=500, detail=f"Error fetching all data: {str(e)}") @router.get("/fetch/custom_fields/{entity_type}") async def fetch_custom_fields(entity_type: str) -> Dict[str, Any]: """Fetch custom fields metadata from AMO CRM""" valid_types = ["leads", "contacts", "companies"] if entity_type not in valid_types: raise HTTPException(status_code=400, detail=f"Entity type must be one of: {valid_types}") try: client = AmoCRMClient() return await client.get_custom_fields(entity_type) except Exception as e: raise HTTPException(status_code=500, detail=f"Error fetching custom fields: {str(e)}") @router.get("/fetch/{entity_type}") async def fetch_amocrm_entity( entity_type: str, limit: int = 10, page: int = 1 ) -> Dict[str, Any]: """Fetch data directly from AMO CRM API""" try: client = AmoCRMClient() if entity_type == "users": return await client.get_users(limit=limit) elif entity_type == "pipelines": return await client.get_pipelines() elif entity_type == "companies": return await client.get_companies(limit=limit, page=page) elif entity_type == "contacts": return await client.get_contacts(limit=limit, page=page) elif entity_type == "deals": return await client.get_deals(limit=limit, page=page) elif entity_type == "events": return await client.get_events(limit=limit, page=page) else: raise HTTPException(status_code=404, detail=f"Entity type '{entity_type}' not supported") except Exception as e: raise HTTPException(status_code=500, detail=f"Error fetching from AMO CRM: {str(e)}") @router.post("/sync/{entity_type}") async def sync_entity_from_amocrm( entity_type: str, limit: int = 250, page: int = 1 ) -> Dict[str, Any]: """Fetch data from AMO CRM and store it in database""" valid_entities = ["deals", "contacts", "companies", "pipelines", "users", "events"] if entity_type not in valid_entities: raise HTTPException( status_code=404, detail=f"Entity type '{entity_type}' not supported. Must be one of: {valid_entities}" ) try: # Fetch data from AMO CRM client = AmoCRMClient() entities = await client.fetch_entity_data( entity_type=entity_type, limit=limit, page=page ) if not entities: return { "message": f"No {entity_type} data found in AMO CRM", "records_fetched": 0, "records_synced": 0, "sync_status": "no_data" } # Store data in database using data ingestion endpoint from utils.config import settings data_url = f"{settings.API_BASE_URL}{settings.API_V1_STR}/data/{entity_type}" payload = { "data": entities, "sync_mode": "upsert" } async with httpx.AsyncClient(timeout=300.0) as http_client: response = await http_client.post(data_url, json=payload) response.raise_for_status() result = response.json() return { "message": f"Successfully synced {entity_type} from AMO CRM to database", "records_fetched": len(entities), "records_synced": result.get("processed_count", 0), "sync_status": "completed" } except httpx.HTTPError as e: raise HTTPException( status_code=500, detail=f"Error storing data in database: {str(e)}" ) except Exception as e: raise HTTPException(status_code=500, detail=f"Error syncing from AMO CRM: {str(e)}") @router.post("/sync/full/{entity_type}") async def full_sync_entity_from_amocrm( entity_type: str, batch_size: int = 250 ) -> Dict[str, Any]: """ Perform a complete full synchronization of an entity type from AMO CRM. This is an asynchronous operation that runs in the background. Use entity_type='all' to sync all entities sequentially. This fetches ALL records from AMO CRM in batches and stores them in the database. Use this for initial sync or to completely refresh data. Returns immediately with a job_id that can be used to track progress. """ import uuid from datetime import datetime valid_entities = ["deals", "contacts", "companies", "pipelines", "users", "events", "all"] if entity_type not in valid_entities: raise HTTPException( status_code=404, detail=f"Entity type '{entity_type}' not supported. Must be one of: {valid_entities}" ) try: # Generate unique job ID job_id = f"full-sync-{entity_type}-{uuid.uuid4().hex[:8]}" # Prepare job data job_data = { "job_id": job_id, "entity_type": entity_type, "batch_size": batch_size, "created_at": datetime.utcnow().isoformat(), "job_type": "full_sync" } # Publish job to broker for async processing from workers.broker import broker await broker.publish(job_data, channel="full-sync-jobs") return { "message": f"Full sync job created for {entity_type}", "job_id": job_id, "entity_type": entity_type, "batch_size": batch_size, "status": "queued", "note": "This is an async operation. Check job status or logs for progress." } except Exception as e: raise HTTPException( status_code=500, detail=f"Error creating full sync job for {entity_type}: {str(e)}" ) @router.get("/info") async def amocrm_info() -> Dict[str, Any]: """Get AMO CRM connection info""" from utils.config import settings return { "domain": settings.AMO_CRM_DOMAIN, "has_token": bool(settings.AMO_CRM_ACCESS_TOKEN), "base_url": f"https://{settings.AMO_CRM_DOMAIN}/api/v4", "supported_entities": [ "users", "pipelines", "companies", "contacts", "deals", "events" ], "full_sync_options": [ "users", "pipelines", "companies", "contacts", "deals", "events", "all" ], "endpoints": { "fetch": "GET /api/v1/amocrm/fetch/{entity_type}", "sync": "POST /api/v1/amocrm/sync/{entity_type}", "full_sync": "POST /api/v1/amocrm/sync/full/{entity_type} (async, supports 'all')" } }