- Updated docs and inventory files - Added new architecture docs Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
14 KiB
API de Asignacion Inteligente
Modulo: MAI-005 (Despacho) Version: 1.0.0 Fecha: 2026-01-27
Descripcion General
API REST para el Centro de Despacho Inteligente. Permite sugerir, asignar y reasignar unidades a viajes usando el algoritmo de scoring ponderado.
Endpoints
POST /api/dispatch/suggest
Sugiere las mejores unidades disponibles para un viaje basandose en el algoritmo de scoring.
Request:
interface SuggestRequest {
tripId: string; // ID del viaje a asignar
maxResults?: number; // Maximo de sugerencias (default: 5)
maxDistanceKm?: number; // Radio maximo de busqueda (default: 50)
requiredSkills?: string[]; // Skills requeridos (ej: ['HAZMAT', 'refrigerado'])
preferredUnitTypes?: string[]; // Tipos de unidad preferidos
excludeUnitIds?: string[]; // Unidades a excluir
}
Response:
interface SuggestResponse {
tripId: string;
origin: {
latitude: number;
longitude: number;
address: string;
};
suggestions: AssignmentSuggestion[];
generatedAt: string; // ISO 8601 timestamp
algorithm: string; // 'weighted_score_v1'
}
interface AssignmentSuggestion {
rank: number; // 1-based ranking
unitId: string;
unitCode: string; // Ej: 'U-005'
unitType: string; // Ej: 'TRACTOCAMION'
operatorId: string;
operatorName: string;
totalScore: number; // 0-100
scoreBreakdown: {
distance: {
value: number; // Score 0-100
weight: number; // Peso aplicado (ej: 0.40)
weighted: number; // value * weight
distanceKm: number; // Distancia real en km
};
capacity: {
value: number;
weight: number;
weighted: number;
unitCapacity: number; // Capacidad de la unidad
requiredCapacity: number; // Capacidad requerida
};
availability: {
value: number;
weight: number;
weighted: number;
status: string; // Estado actual
shiftActive: boolean; // Turno activo
};
skills: {
value: number;
weight: number;
weighted: number;
matched: string[]; // Skills que coinciden
missing: string[]; // Skills faltantes
extra: string[]; // Skills adicionales
};
};
currentLocation: {
latitude: number;
longitude: number;
lastUpdate: string;
};
estimatedArrival: string; // ISO 8601 timestamp
estimatedTravelMinutes: number;
}
Ejemplo de Request:
{
"tripId": "550e8400-e29b-41d4-a716-446655440000",
"maxResults": 3,
"maxDistanceKm": 30,
"requiredSkills": ["HAZMAT"]
}
Ejemplo de Response:
{
"tripId": "550e8400-e29b-41d4-a716-446655440000",
"origin": {
"latitude": 19.4326,
"longitude": -99.1332,
"address": "Av. Insurgentes Sur 1234, CDMX"
},
"suggestions": [
{
"rank": 1,
"unitId": "unit-001",
"unitCode": "U-005",
"unitType": "TRACTOCAMION",
"operatorId": "op-001",
"operatorName": "Juan Perez Garcia",
"totalScore": 87.5,
"scoreBreakdown": {
"distance": {
"value": 95,
"weight": 0.40,
"weighted": 38,
"distanceKm": 7.2
},
"capacity": {
"value": 100,
"weight": 0.25,
"weighted": 25,
"unitCapacity": 25,
"requiredCapacity": 20
},
"availability": {
"value": 100,
"weight": 0.20,
"weighted": 20,
"status": "AVAILABLE",
"shiftActive": true
},
"skills": {
"value": 90,
"weight": 0.15,
"weighted": 13.5,
"matched": ["HAZMAT"],
"missing": [],
"extra": ["refrigerado"]
}
},
"currentLocation": {
"latitude": 19.4126,
"longitude": -99.1532,
"lastUpdate": "2026-01-27T10:30:00Z"
},
"estimatedArrival": "2026-01-27T10:45:00Z",
"estimatedTravelMinutes": 15
}
],
"generatedAt": "2026-01-27T10:30:15Z",
"algorithm": "weighted_score_v1"
}
POST /api/dispatch/assign
Asigna una unidad a un viaje.
Request:
interface AssignRequest {
tripId: string; // ID del viaje
unitId: string; // ID de la unidad a asignar
operatorId: string; // ID del operador
notes?: string; // Notas de asignacion
overrideValidation?: boolean; // Forzar asignacion (requiere permiso especial)
}
Response:
interface AssignResponse {
success: boolean;
assignmentId: string; // ID del registro de asignacion
tripId: string;
unitId: string;
operatorId: string;
assignedAt: string; // ISO 8601 timestamp
assignedBy: string; // Usuario que asigno
scoreAtAssignment: number | null; // Score si vino de sugerencia
warnings?: string[]; // Advertencias (ej: turno por terminar)
}
Ejemplo de Request:
{
"tripId": "550e8400-e29b-41d4-a716-446655440000",
"unitId": "unit-001",
"operatorId": "op-001",
"notes": "Asignacion prioritaria por cliente VIP"
}
Ejemplo de Response:
{
"success": true,
"assignmentId": "asgn-001",
"tripId": "550e8400-e29b-41d4-a716-446655440000",
"unitId": "unit-001",
"operatorId": "op-001",
"assignedAt": "2026-01-27T10:35:00Z",
"assignedBy": "admin@transportes.com",
"scoreAtAssignment": 87.5,
"warnings": ["Turno del operador termina en 2 horas"]
}
POST /api/dispatch/reassign
Reasigna un viaje a una unidad diferente, registrando el motivo.
Request:
interface ReassignRequest {
tripId: string; // ID del viaje
newUnitId: string; // Nueva unidad
newOperatorId: string; // Nuevo operador
reason: ReassignReason; // Motivo de reasignacion
reasonDetail?: string; // Detalle adicional
}
type ReassignReason =
| 'UNIT_BREAKDOWN' // Falla mecanica
| 'OPERATOR_UNAVAILABLE' // Operador no disponible
| 'CUSTOMER_REQUEST' // Solicitud del cliente
| 'OPTIMIZATION' // Optimizacion de rutas
| 'SKILL_MISMATCH' // Skills no coinciden
| 'CAPACITY_ISSUE' // Problema de capacidad
| 'OTHER'; // Otro motivo
Response:
interface ReassignResponse {
success: boolean;
reassignmentId: string;
tripId: string;
previousUnit: {
unitId: string;
unitCode: string;
operatorId: string;
operatorName: string;
};
newUnit: {
unitId: string;
unitCode: string;
operatorId: string;
operatorName: string;
};
reason: ReassignReason;
reasonDetail: string | null;
reassignedAt: string;
reassignedBy: string;
}
Ejemplo de Request:
{
"tripId": "550e8400-e29b-41d4-a716-446655440000",
"newUnitId": "unit-002",
"newOperatorId": "op-002",
"reason": "UNIT_BREAKDOWN",
"reasonDetail": "Falla en sistema de frenos detectada en checklist"
}
GET /api/dispatch/units/available
Obtiene todas las unidades disponibles para asignacion.
Query Parameters:
| Parametro | Tipo | Descripcion |
|---|---|---|
| latitude | number | Latitud del punto de referencia |
| longitude | number | Longitud del punto de referencia |
| maxDistanceKm | number | Radio maximo (default: 100) |
| unitType | string | Filtrar por tipo de unidad |
| skills | string | Skills requeridos (separados por coma) |
| minCapacity | number | Capacidad minima |
| page | number | Pagina (default: 1) |
| limit | number | Registros por pagina (default: 20) |
Response:
interface AvailableUnitsResponse {
units: AvailableUnit[];
pagination: {
page: number;
limit: number;
total: number;
totalPages: number;
};
referencePoint: {
latitude: number;
longitude: number;
} | null;
}
interface AvailableUnit {
unitId: string;
unitCode: string;
unitType: string;
plateNumber: string;
capacity: number;
capacityUnit: string; // 'TON', 'M3', etc.
status: string;
currentLocation: {
latitude: number;
longitude: number;
lastUpdate: string;
address: string | null;
};
distanceKm: number | null; // Distancia al punto de referencia
operator: {
id: string;
name: string;
shiftStart: string | null;
shiftEnd: string | null;
skills: string[];
};
features: string[]; // Caracteristicas (GPS, refrigeracion, etc.)
}
Ejemplo de Request:
GET /api/dispatch/units/available?latitude=19.4326&longitude=-99.1332&maxDistanceKm=30&skills=HAZMAT
GET /api/dispatch/logs
Obtiene el historial de acciones de despacho para auditoria.
Query Parameters:
| Parametro | Tipo | Descripcion |
|---|---|---|
| tripId | string | Filtrar por viaje |
| unitId | string | Filtrar por unidad |
| operatorId | string | Filtrar por operador |
| action | string | Filtrar por accion (SUGGESTED, ASSIGNED, REASSIGNED, CANCELLED) |
| performedBy | string | Filtrar por usuario |
| fromDate | string | Fecha inicio (ISO 8601) |
| toDate | string | Fecha fin (ISO 8601) |
| page | number | Pagina (default: 1) |
| limit | number | Registros por pagina (default: 50) |
Response:
interface DispatchLogsResponse {
logs: DispatchLogEntry[];
pagination: {
page: number;
limit: number;
total: number;
totalPages: number;
};
}
interface DispatchLogEntry {
id: string;
tripId: string;
tripCode: string; // Codigo legible del viaje
action: 'SUGGESTED' | 'ASSIGNED' | 'REASSIGNED' | 'CANCELLED';
unitId: string;
unitCode: string;
operatorId: string;
operatorName: string;
performedBy: string; // Usuario que realizo la accion
reason: string | null; // Motivo (para REASSIGNED/CANCELLED)
previousUnitId: string | null; // Unidad anterior (para REASSIGNED)
previousUnitCode: string | null;
scoreAtAssignment: number | null; // Score si aplica
timestamp: string; // ISO 8601
metadata: Record<string, any>; // Datos adicionales
}
Ejemplo de Request:
GET /api/dispatch/logs?tripId=550e8400-e29b-41d4-a716-446655440000&fromDate=2026-01-01T00:00:00Z
DTOs Comunes
TripSummary
interface TripSummary {
id: string;
code: string;
customer: {
id: string;
name: string;
};
origin: {
latitude: number;
longitude: number;
address: string;
scheduledTime: string;
};
destination: {
latitude: number;
longitude: number;
address: string;
scheduledTime: string;
};
requirements: {
capacity: number;
capacityUnit: string;
unitType: string;
skills: string[];
};
priority: 'LOW' | 'NORMAL' | 'HIGH' | 'URGENT';
status: string;
}
UnitSummary
interface UnitSummary {
id: string;
code: string;
type: string;
plateNumber: string;
capacity: number;
capacityUnit: string;
status: string;
operator: {
id: string;
name: string;
} | null;
location: {
latitude: number;
longitude: number;
lastUpdate: string;
} | null;
}
Codigos de Error
| Codigo | HTTP Status | Descripcion |
|---|---|---|
| DISPATCH_001 | 404 | Viaje no encontrado |
| DISPATCH_002 | 404 | Unidad no encontrada |
| DISPATCH_003 | 404 | Operador no encontrado |
| DISPATCH_004 | 400 | Viaje ya tiene unidad asignada |
| DISPATCH_005 | 400 | Unidad no disponible |
| DISPATCH_006 | 400 | Operador no disponible |
| DISPATCH_007 | 400 | Capacidad insuficiente |
| DISPATCH_008 | 400 | Skills requeridos no cumplidos |
| DISPATCH_009 | 400 | Unidad fuera de rango maximo |
| DISPATCH_010 | 400 | Viaje no esta en estado asignable |
| DISPATCH_011 | 400 | Motivo de reasignacion requerido |
| DISPATCH_012 | 403 | Sin permisos para forzar asignacion |
| DISPATCH_013 | 400 | Coordenadas invalidas |
| DISPATCH_014 | 400 | Rango de fechas invalido |
| DISPATCH_015 | 500 | Error calculando distancia |
Formato de Error:
interface ErrorResponse {
error: {
code: string; // Ej: 'DISPATCH_005'
message: string; // Mensaje legible
details?: Record<string, any>; // Detalles adicionales
timestamp: string;
};
}
Ejemplo de Error:
{
"error": {
"code": "DISPATCH_005",
"message": "La unidad U-005 no esta disponible para asignacion",
"details": {
"unitId": "unit-001",
"currentStatus": "EN_ROUTE",
"currentTripId": "trip-999"
},
"timestamp": "2026-01-27T10:40:00Z"
}
}
Autenticacion
Todos los endpoints requieren autenticacion via JWT Bearer token:
Authorization: Bearer <token>
Permisos Requeridos
| Endpoint | Permiso |
|---|---|
| POST /dispatch/suggest | dispatch:read |
| POST /dispatch/assign | dispatch:write |
| POST /dispatch/reassign | dispatch:write |
| GET /dispatch/units/available | dispatch:read |
| GET /dispatch/logs | dispatch:audit |
Rate Limiting
| Endpoint | Limite |
|---|---|
| POST /dispatch/suggest | 30 req/min |
| POST /dispatch/assign | 60 req/min |
| POST /dispatch/reassign | 30 req/min |
| GET /dispatch/units/available | 60 req/min |
| GET /dispatch/logs | 30 req/min |
API Asignacion Inteligente - MAI-005 - ERP Transportistas - Sistema SIMCO v4.0.0