Incidentes
Incidentes
Prefijo: /api/incidentes
Requiere Auth: Sí
Permiso requerido: incidentes, *
Módulo de gestión de incidentes del sistema. Cada incidente representa un evento anómalo o error ocurrido durante la operación del POS (ej: error de sincronización, fallo de integración DIAN, producto sin stock crítico, etc.).
Arquitectura: Los incidentes se almacenan en la tabla movimientos_log con tipo_movimiento = 'INCIDENTE', extendiendo el modelo de auditoría existente con campos adicionales (severidad, resuelto, resuelto_por, resuelto_at, notas_resolucion, accion, datos_extra).
Severidades válidas: CRITICO, ALTO, MEDIO (default), BAJO
Contexto de uso: Los incidentes pueden ser generados automáticamente por el sistema (sync errors, fallos de conexión) o manualmente desde el panel de administración. El equipo de soporte puede consultarlos, filtrarlos por severidad/módulo, resolverlos individualmente o en批量, y agruparlos por módulo para identificar patrones.
CRUD Incidentes
<MethodBadge method="GET" /> /api/incidentes/ [NUEVO]
Descripción: Lista todos los incidentes del tenant con paginación y filtros
Requiere Auth: Sí
Permiso requerido: incidentes, leer
Parámetros query:
| Parámetro | Tipo | Obligatorio | Descripción |
|---|---|---|---|
skip | int | ❌ | Número de registros a saltar (default 0) |
limit | int | ❌ | Máximo de registros a retornar (default 100) |
resuelto | bool | ❌ | Filtrar por estado: true (solo resueltos), false (solo abiertos) |
severidad | string | ❌ | Filtrar por severidad: CRITICO, ALTO, MEDIO, BAJO |
modulo | string | ❌ | Filtrar por módulo del sistema (ej: sync, ventas, dian) |
Respuesta exitosa: 200 OK
Response:
[ { "id": 1, "tenant_id": "uuid-tenant", "tipo_movimiento": "INCIDENTE", "tabla_afectada": "sync", "id_referencia": null, "descripcion": "Error de sincronización con el cloud: timeout", "usuario": "sistema", "origen": "API", "fecha": "2026-07-29", "hora": "10:30:00", "severidad": "ALTO", "resuelto": true, "resuelto_por": "admin@neoapp.com", "resuelto_at": "2026-07-29T11:00:00Z", "notas_resolucion": "Se restableció la conexión manualmente", "accion": "sync_error", "datos_extra": { "codigo_error": "ETIMEOUT", "intentos": 3 } }, { "id": 2, "tenant_id": "uuid-tenant", "tipo_movimiento": "INCIDENTE", "tabla_afectada": "dian", "id_referencia": 42, "descripcion": "Falló la facturación electrónica para la venta #42", "usuario": "sistema", "origen": "API", "fecha": "2026-07-29", "hora": "09:15:00", "severidad": "CRITICO", "resuelto": false, "resuelto_por": null, "resuelto_at": null, "notas_resolucion": null, "accion": "dian_error", "datos_extra": { "venta_id": 42, "cufe": "", "codigo_error": "HOST_RESPONSE_ERROR" } }]cURL:
curl "http://localhost/api/incidentes/?skip=0&limit=20&severidad=ALTO" \ -H "Authorization: Bearer <token>"Python:
import httpxresp = httpx.get("http://localhost/api/incidentes/", params={"skip": 0, "limit": 20, "severidad": "ALTO"}, headers={"Authorization": f"Bearer :token"})incidentes = resp.json()JavaScript:
const resp = await fetch('http://localhost/api/incidentes/?skip=0&limit=20&severidad=ALTO', { headers: {'Authorization': `Bearer $:token`}});const incidentes = await resp.json();<MethodBadge method="GET" /> /api/incidentes/count [NUEVO]
Descripción: Obtiene el conteo de incidentes, con opción de filtrar por estado o severidad
Requiere Auth: Sí
Permiso requerido: incidentes, leer
Parámetros query:
| Parámetro | Tipo | Obligatorio | Descripción |
|---|---|---|---|
resuelto | bool | ❌ | Si se envía, retorna solo el total filtrado (sin desglose) |
severidad | string | ❌ | Filtrar por severidad antes de contar |
Comportamiento:
- Sin filtros: Retorna desglose completo (
total,abiertos,resueltos) - Con
resuelto: Retorna solo el total de ese estado (los otros campos en 0) - Con
severidad: Cuenta solo los de esa severidad
Respuesta exitosa: 200 OK
Response (sin filtros):
{ "total": 15, "abiertos": 8, "resueltos": 7}Response (con resuelto=false):
{ "total": 8, "abiertos": 0, "resueltos": 0}cURL:
curl "http://localhost/api/incidentes/count" -H "Authorization: Bearer <token>"curl "http://localhost/api/incidentes/count?resuelto=false" -H "Authorization: Bearer <token>"curl "http://localhost/api/incidentes/count?severidad=CRITICO" -H "Authorization: Bearer <token>"<MethodBadge method="GET" /> /api/incidentes/por-modulo [NUEVO]
Descripción: Retorna los incidentes agrupados por módulo (tabla_afectada). Útil para dashboards que muestran incidentes por área del sistema.
Requiere Auth: Sí
Permiso requerido: incidentes, leer
Respuesta exitosa: 200 OK
Response:
{ "sync": [ { "id": 1, "descripcion": "Error de sincronización con el cloud: timeout", "severidad": "ALTO", "resuelto": true, ... } ], "dian": [ { "id": 2, "descripcion": "Falló la facturación electrónica para la venta #42", "severidad": "CRITICO", "resuelto": false, ... } ], "ventas": [ ... ]}cURL:
curl "http://localhost/api/incidentes/por-modulo" -H "Authorization: Bearer <token>"<MethodBadge method="GET" /> /api/incidentes/:incident_id [NUEVO]
Descripción: Obtiene un incidente por ID
Requiere Auth: Sí
Permiso requerido: incidentes, leer
Respuesta exitosa: 200 OK
Errores: 404 (no encontrado)
cURL:
curl http://localhost/api/incidentes/1 -H "Authorization: Bearer <token>"<MethodBadge method="POST" /> /api/incidentes/ [NUEVO]
Descripción: Crea un nuevo incidente. Puede ser usado tanto por el sistema (auto-reporte) como por usuarios del panel de administración.
Requiere Auth: Sí
Permiso requerido: incidentes, crear
Request:
{ "modulo": "sync", "accion": "sync_error", "mensaje": "Error de sincronización con el cloud: timeout después de 30s", "severidad": "ALTO", "id_referencia": null, "datos_extra": { "codigo_error": "ETIMEOUT", "intentos": 3, "ultimo_exito": "2026-07-29T08:00:00Z" }}| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
modulo | string | ✅ | Módulo del sistema donde ocurrió (ej: sync, dian, ventas) |
accion | string | ✅ | Acción específica que falló (ej: sync_error, dian_error) |
mensaje | string | ✅ | Descripción legible del incidente |
severidad | string | ❌ | Severidad: CRITICO, ALTO, MEDIO (default), BAJO |
id_referencia | int | ❌ | ID opcional del registro relacionado (ej: venta_id) |
datos_extra | object | ❌ | Metadatos adicionales en JSON para debugging |
Respuesta exitosa: 201 Created
Response: (objeto IncidentResponse completo con resuelto: false)
cURL:
curl -X POST http://localhost/api/incidentes/ \ -H "Content-Type: application/json" \ -H "Authorization: Bearer <token>" \ -d '{"modulo":"sync","accion":"sync_error","mensaje":"Error de sincronización: timeout","severidad":"ALTO","datos_extra":{"codigo_error":"ETIMEOUT","intentos":3}}'Python:
import httpxresp = httpx.post("http://localhost/api/incidentes/", json={"modulo": "sync", "accion": "sync_error", "mensaje": "Error de sincronización: timeout", "severidad": "ALTO"}, headers={"Authorization": f"Bearer :token"})incidente = resp.json()JavaScript:
const resp = await fetch('http://localhost/api/incidentes/', { method: 'POST', headers: {'Content-Type': 'application/json', 'Authorization': `Bearer $:token`}, body: JSON.stringify({modulo: 'sync', accion: 'sync_error', mensaje: 'Error de sincronización: timeout', severidad: 'ALTO'})});const incidente = await resp.json();<MethodBadge method="PATCH" /> /api/incidentes/:incident_id/resolver [NUEVO]
Descripción: Marca un incidente como resuelto. Requiere indicar quién lo resolvió y opcionalmente notas de la resolución.
Requiere Auth: Sí
Permiso requerido: incidentes, actualizar
Request:
{ "resuelto_por": "admin@neoapp.com", "notas_resolucion": "Se restableció la conexión VPN y se re-intentó la sincronización exitosamente"}| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
resuelto_por | string | ✅ | Email o nombre de usuario que resolvió el incidente |
notas_resolucion | string | ❌ | Notas opcionales sobre cómo se resolvió |
Respuesta exitosa: 200 OK
Errores: 404 (incidente no encontrado)
Response:
{ "id": 1, "descripcion": "Error de sincronización con el cloud: timeout", "severidad": "ALTO", "resuelto": true, "resuelto_por": "admin@neoapp.com", "resuelto_at": "2026-07-29T11:00:00Z", "notas_resolucion": "Se restableció la conexión VPN y se re-intentó la sincronización exitosamente", ...}cURL:
curl -X PATCH http://localhost/api/incidentes/1/resolver \ -H "Content-Type: application/json" \ -H "Authorization: Bearer <token>" \ -d '{"resuelto_por":"admin@neoapp.com","notas_resolucion":"Conexión restablecida"}'Python:
import httpxresp = httpx.patch("http://localhost/api/incidentes/1/resolver", json={"resuelto_por": "admin@neoapp.com", "notas_resolucion": "Conexión restablecida"}, headers={"Authorization": f"Bearer :token"})incidente = resp.json()JavaScript:
const resp = await fetch('http://localhost/api/incidentes/1/resolver', { method: 'PATCH', headers: {'Content-Type': 'application/json', 'Authorization': `Bearer $:token`}, body: JSON.stringify({resuelto_por: 'admin@neoapp.com', notas_resolucion: 'Conexión restablecida'})});