106 lines
3.4 KiB
Python
106 lines
3.4 KiB
Python
from flask import Blueprint, request, jsonify, g
|
|
from pydantic import ValidationError
|
|
|
|
from app.schemas.optimizer_dto import OptimizerJobRequestDTO, SpringBootSyncPayloadDTO
|
|
from app.services.optimizer_service import OptimizerService
|
|
from app.utils.jwt_decorators import jwt_required
|
|
|
|
api_optimizer_bp = Blueprint('api_optimizer', __name__, url_prefix='/api/v1/optimizer')
|
|
|
|
|
|
@api_optimizer_bp.route('/jobs', methods=['POST'])
|
|
@jwt_required
|
|
def submit_optimization_job():
|
|
"""
|
|
Despacha un trabajo de optimización heurística asíncrono.
|
|
Retorna inmediatamente con HTTP 202 Accepted y el identificador de trabajo para sondeo.
|
|
"""
|
|
data = request.get_json(silent=True) or {}
|
|
try:
|
|
dto = OptimizerJobRequestDTO(**data)
|
|
except ValidationError as ex:
|
|
return jsonify({
|
|
'error': 'UnprocessableEntity',
|
|
'message': 'Error de validación en los parámetros del optimizador.',
|
|
'details': ex.errors()
|
|
}), 422
|
|
|
|
user_id = g.current_user.id if hasattr(g, 'current_user') and g.current_user else 1
|
|
|
|
job = OptimizerService.submit_job(
|
|
commission_ids=dto.commission_ids,
|
|
admin_user_id=user_id,
|
|
start_date=dto.start_date,
|
|
end_date=dto.end_date,
|
|
generations=dto.generations,
|
|
population_size=dto.population_size,
|
|
workers=dto.workers
|
|
)
|
|
|
|
return jsonify({
|
|
'job_id': job.job_id,
|
|
'status': job.status.value,
|
|
'poll_url': f'/api/v1/optimizer/jobs/{job.job_id}',
|
|
'message': 'Trabajo de optimización puesto en cola con éxito.'
|
|
}), 202
|
|
|
|
|
|
@api_optimizer_bp.route('/jobs/<string:job_id>', methods=['GET'])
|
|
@jwt_required
|
|
def get_optimization_job(job_id: str):
|
|
"""
|
|
Obtiene el estado, progreso y resultados de un trabajo de optimización en cola.
|
|
"""
|
|
job = OptimizerService.get_job(job_id)
|
|
if not job:
|
|
return jsonify({
|
|
'error': 'NotFound',
|
|
'message': f'Trabajo de optimización {job_id} no encontrado.'
|
|
}), 404
|
|
|
|
return jsonify(job.to_dict()), 200
|
|
|
|
|
|
@api_optimizer_bp.route('/jobs', methods=['GET'])
|
|
@jwt_required
|
|
def list_optimization_jobs():
|
|
"""
|
|
Lista los trabajos de optimización más recientes.
|
|
"""
|
|
limit = request.args.get('limit', default=20, type=int)
|
|
jobs = OptimizerService.list_jobs(limit=limit)
|
|
return jsonify({
|
|
'total': len(jobs),
|
|
'jobs': jobs
|
|
}), 200
|
|
|
|
|
|
@api_optimizer_bp.route('/spring-boot/sync', methods=['POST'])
|
|
@jwt_required
|
|
def sync_with_spring_boot():
|
|
"""
|
|
Endpoint interoperable para la sincronización y resolución de horarios con microservicios Spring Boot.
|
|
Recibe el payload en formato Spring Boot (camelCase) y retorna el cronograma optimizado.
|
|
"""
|
|
data = request.get_json(silent=True) or {}
|
|
try:
|
|
dto = SpringBootSyncPayloadDTO(**data)
|
|
except ValidationError as ex:
|
|
return jsonify({
|
|
'error': 'UnprocessableEntity',
|
|
'message': 'Error de validación en el payload Spring Boot.',
|
|
'details': ex.errors()
|
|
}), 422
|
|
|
|
user_id = g.current_user.id if hasattr(g, 'current_user') and g.current_user else 1
|
|
|
|
try:
|
|
result = OptimizerService.sync_with_spring_boot(dto, admin_user_id=user_id)
|
|
return jsonify(result), 200
|
|
except Exception as ex:
|
|
return jsonify({
|
|
'requestId': dto.requestId,
|
|
'status': 'ERROR',
|
|
'error': str(ex)
|
|
}), 500
|