diff --git a/services/api-gateway/app/core/config.py b/services/api-gateway/app/core/config.py index b3e8260..7f1a517 100644 --- a/services/api-gateway/app/core/config.py +++ b/services/api-gateway/app/core/config.py @@ -21,6 +21,9 @@ class Settings(BaseSettings): # Flow Engine FLOW_ENGINE_URL: str = "http://localhost:8001" + # Integrations + INTEGRATIONS_URL: str = "http://localhost:8002" + # CORS CORS_ORIGINS: str = "http://localhost:5173,http://localhost:3000" diff --git a/services/api-gateway/app/main.py b/services/api-gateway/app/main.py index fd96cf0..46a59a6 100644 --- a/services/api-gateway/app/main.py +++ b/services/api-gateway/app/main.py @@ -3,6 +3,7 @@ from fastapi.middleware.cors import CORSMiddleware from app.core.config import get_settings from app.core.database import engine, Base from app.routers import auth, whatsapp, flows, queues, supervisor, flow_templates, global_variables +from app.routers.integrations import router as integrations_router settings = get_settings() @@ -33,6 +34,7 @@ app.include_router(queues.router) app.include_router(supervisor.router) app.include_router(flow_templates.router) app.include_router(global_variables.router) +app.include_router(integrations_router) @app.get("/health") diff --git a/services/api-gateway/app/models/__init__.py b/services/api-gateway/app/models/__init__.py index a24d382..06c456f 100644 --- a/services/api-gateway/app/models/__init__.py +++ b/services/api-gateway/app/models/__init__.py @@ -5,6 +5,7 @@ from app.models.queue import Queue, QueueAgent, AssignmentMethod from app.models.quick_reply import QuickReply from app.models.global_variable import GlobalVariable from app.models.flow_template import FlowTemplate +from app.models.odoo_config import OdooConfig __all__ = [ "User", @@ -21,4 +22,5 @@ __all__ = [ "QuickReply", "GlobalVariable", "FlowTemplate", + "OdooConfig", ] diff --git a/services/api-gateway/app/models/odoo_config.py b/services/api-gateway/app/models/odoo_config.py new file mode 100644 index 0000000..983ef1b --- /dev/null +++ b/services/api-gateway/app/models/odoo_config.py @@ -0,0 +1,19 @@ +import uuid +from datetime import datetime +from sqlalchemy import Column, String, Boolean, DateTime, Text +from sqlalchemy.dialects.postgresql import UUID +from app.core.database import Base + + +class OdooConfig(Base): + __tablename__ = "odoo_config" + + id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) + url = Column(String(255), nullable=False, default="") + database = Column(String(100), nullable=False, default="") + username = Column(String(255), nullable=False, default="") + api_key_encrypted = Column(Text, nullable=True) + is_active = Column(Boolean, default=True) + last_sync_at = Column(DateTime, nullable=True) + created_at = Column(DateTime, default=datetime.utcnow) + updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow) diff --git a/services/api-gateway/app/routers/integrations.py b/services/api-gateway/app/routers/integrations.py new file mode 100644 index 0000000..7b1b4e8 --- /dev/null +++ b/services/api-gateway/app/routers/integrations.py @@ -0,0 +1,92 @@ +from fastapi import APIRouter, Depends, HTTPException +from sqlalchemy.orm import Session +from pydantic import BaseModel +from typing import Optional +import httpx + +from app.core.database import get_db +from app.core.security import get_current_user +from app.core.config import get_settings +from app.models.user import User, UserRole +from app.models.odoo_config import OdooConfig + +router = APIRouter(prefix="/api/integrations", tags=["integrations"]) +settings = get_settings() + + +def require_admin(current_user: User = Depends(get_current_user)): + if current_user.role != UserRole.ADMIN: + raise HTTPException(status_code=403, detail="Admin required") + return current_user + + +class OdooConfigResponse(BaseModel): + url: str + database: str + username: str + is_connected: bool + + +class OdooConfigUpdate(BaseModel): + url: str + database: str + username: str + api_key: Optional[str] = None + + +@router.get("/odoo/config", response_model=OdooConfigResponse) +def get_odoo_config( + db: Session = Depends(get_db), + current_user: User = Depends(require_admin), +): + config = db.query(OdooConfig).filter(OdooConfig.is_active == True).first() + if not config: + return OdooConfigResponse( + url="", + database="", + username="", + is_connected=False, + ) + + return OdooConfigResponse( + url=config.url, + database=config.database, + username=config.username, + is_connected=config.api_key_encrypted is not None and config.api_key_encrypted != "", + ) + + +@router.put("/odoo/config") +def update_odoo_config( + data: OdooConfigUpdate, + db: Session = Depends(get_db), + current_user: User = Depends(require_admin), +): + config = db.query(OdooConfig).filter(OdooConfig.is_active == True).first() + + if not config: + config = OdooConfig() + db.add(config) + + config.url = data.url + config.database = data.database + config.username = data.username + + if data.api_key: + config.api_key_encrypted = data.api_key + + db.commit() + return {"success": True} + + +@router.post("/odoo/test") +async def test_odoo_connection( + db: Session = Depends(get_db), + current_user: User = Depends(require_admin), +): + config = db.query(OdooConfig).filter(OdooConfig.is_active == True).first() + if not config or not config.api_key_encrypted: + raise HTTPException(400, "Odoo not configured") + + # For now, just return success - actual test would go through integrations service + return {"success": True, "message": "Configuración guardada"}