MCP_server_Odoo / config.py
Aktraiser
🚀 MCP Server Odoo prêt pour déploiement
0cb8341
import os
import json
import logging
import pandas as pd
import xmlrpc.client
from typing import Dict, List, Any
from dotenv import load_dotenv
load_dotenv()
# Configuration logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
# Configuration Odoo simplifiée
ODOO_URL = os.getenv("ODOO_URL", "")
ODOO_DB = os.getenv("ODOO_DB", "")
ODOO_USERNAME = os.getenv("ODOO_USERNAME", "")
ODOO_PASSWORD = os.getenv("ODOO_PASSWORD", "")
# Configuration optionnelle
ODOO_TIMEOUT = int(os.getenv("ODOO_TIMEOUT", "30"))
ODOO_VERIFY_SSL = os.getenv("ODOO_VERIFY_SSL", "true").lower() == "true"
# Configuration MCP pour Gradio
GRADIO_MCP_SERVER = os.getenv("GRADIO_MCP_SERVER", "True")
# =============================================================================
# CLIENT ODOO ET GESTION DE CONNEXION
# =============================================================================
class SimpleOdooClient:
"""Client Odoo simplifié pour les opérations de base"""
def __init__(self):
self.url = None
self.db = None
self.username = None
self.password = None
self.uid = None
self.models = None
def connect(self, url: str, db: str, username: str, password: str) -> Dict[str, Any]:
"""Connexion à Odoo"""
try:
# Connexion d'authentification
common = xmlrpc.client.ServerProxy(f'{url}/xmlrpc/2/common')
# Test de version (connexion)
version = common.version()
# Authentification
uid = common.authenticate(db, username, password, {})
if not uid:
return {"success": False, "error": "Échec d'authentification"}
# Connexion aux modèles
models = xmlrpc.client.ServerProxy(f'{url}/xmlrpc/2/object')
# Stockage des informations de connexion
self.url = url
self.db = db
self.username = username
self.password = password
self.uid = uid
self.models = models
return {
"success": True,
"message": f"Connecté en tant que {username}",
"version": version.get('server_version', 'Inconnue')
}
except Exception as e:
return {"success": False, "error": str(e)}
def is_connected(self) -> bool:
"""Vérifie si connecté"""
return self.uid is not None
def search_read(self, model: str, domain: List = None, fields: List = None, limit: int = 10) -> List[Dict]:
"""Recherche et lecture d'enregistrements"""
if not self.is_connected():
raise Exception("Non connecté à Odoo")
domain = domain or []
fields = fields or []
return self.models.execute_kw(
self.db, self.uid, self.password,
model, 'search_read',
[domain],
{'fields': fields, 'limit': limit}
)
def search_count(self, model: str, domain: List = None) -> int:
"""Compte les enregistrements"""
if not self.is_connected():
raise Exception("Non connecté à Odoo")
domain = domain or []
return self.models.execute_kw(
self.db, self.uid, self.password,
model, 'search_count',
[domain]
)
def read_group(self, model: str, domain: List = None, fields: List = None, groupby: List = None) -> List[Dict]:
"""Groupe et agrège les données"""
if not self.is_connected():
raise Exception("Non connecté à Odoo")
domain = domain or []
fields = fields or []
groupby = groupby or []
return self.models.execute_kw(
self.db, self.uid, self.password,
model, 'read_group',
[domain, fields, groupby]
)
def search(self, model: str, domain: List = None, limit: int = None) -> List[int]:
"""Recherche des IDs d'enregistrements"""
if not self.is_connected():
raise Exception("Non connecté à Odoo")
domain = domain or []
options = {}
if limit:
options['limit'] = limit
return self.models.execute_kw(
self.db, self.uid, self.password,
model, 'search',
[domain],
options
)
def create(self, model: str, values: Dict) -> int:
"""Crée un enregistrement"""
if not self.is_connected():
raise Exception("Non connecté à Odoo")
return self.models.execute_kw(
self.db, self.uid, self.password,
model, 'create',
[values]
)
def write(self, model: str, record_id: int, values: Dict) -> bool:
"""Met à jour un enregistrement"""
if not self.is_connected():
raise Exception("Non connecté à Odoo")
return self.models.execute_kw(
self.db, self.uid, self.password,
model, 'write',
[[record_id], values]
)
def unlink(self, model: str, record_id: int) -> bool:
"""Supprime un enregistrement"""
if not self.is_connected():
raise Exception("Non connecté à Odoo")
return self.models.execute_kw(
self.db, self.uid, self.password,
model, 'unlink',
[[record_id]]
)
# =============================================================================
# PERSISTANCE DES CREDENTIALS
# =============================================================================
def save_credentials_to_file(url: str, database: str, username: str, password: str):
"""Sauvegarde les credentials dans odoo_config.json"""
config = {
"url": url,
"db": database,
"username": username,
"password": password,
"timestamp": pd.Timestamp.now().isoformat()
}
try:
with open('odoo_config.json', 'w') as f:
json.dump(config, f, indent=2)
return True
except Exception as e:
logger.error(f"Erreur sauvegarde credentials: {e}")
return False
def load_credentials_from_file() -> Dict[str, str]:
"""Charge les credentials depuis odoo_config.json"""
try:
if os.path.exists('odoo_config.json'):
with open('odoo_config.json', 'r') as f:
config = json.load(f)
return {
"url": config.get('url', ''),
"database": config.get('db', ''),
"username": config.get('username', ''),
"password": config.get('password', '')
}
except Exception as e:
logger.error(f"Erreur chargement credentials: {e}")
return {"url": "", "database": "", "username": "", "password": ""}
# =============================================================================
# CLIENT GLOBAL ET AUTO-CONNEXION
# =============================================================================
# Client global - utilisé par GRADIO ET MCP
client = SimpleOdooClient()
# Variables globales pour stocker les credentials (+ persistance fichier)
stored_credentials = load_credentials_from_file()
def auto_connect_if_needed() -> bool:
"""Tente une auto-connexion si nécessaire, retourne True si connecté"""
if client.is_connected():
return True
# ✅ CHARGEMENT AUTOMATIQUE DEPUIS FICHIER SI NÉCESSAIRE
global stored_credentials
if not all(stored_credentials.values()):
stored_credentials = load_credentials_from_file()
# Tentative de connexion si credentials disponibles
if all(stored_credentials.values()):
result = client.connect(
stored_credentials["url"],
stored_credentials["database"],
stored_credentials["username"],
stored_credentials["password"]
)
return result["success"]
return False