Egresos
Egresos
Prefijo: /api/egresos
Requiere Auth: Sí
Permiso requerido: egresos, *
Módulo de egresos (gastos) para registrar y consultar salidas de dinero del negocio.
GET /api/egresos/
Descripción: Lista todos los egresos/ingresos del tenant con paginación y filtros por rango de fechas. Incluye ambos tipo_movimiento: EGRESO (gastos) e INGRESO (entradas de caja no ventas). Para control de gastos, conciliación de caja y reporte de flujo de caja.
Requiere Auth: Sí
Permiso requerido: egresos, leer
Parámetros query:
| Parámetro | Tipo | Obligatorio | Descripción |
|---|---|---|---|
skip | int | ❌ | Registros a saltar (default 0) |
limit | int | ❌ | Máximo registros (default 100) |
fecha_desde | date | ❌ | Fecha inicio inclusive (YYYY-MM-DD) |
fecha_hasta | date | ❌ | Fecha fin inclusive (YYYY-MM-DD) |
Comportamiento / Casos de uso:
- Sin filtros: últimos 100 movimientos (egresos + ingresos) ordenados por fecha desc
- Con rango: reporte de gastos del mes para contabilidad
- Filtrar por
tipo_movimientoen frontend:EGRESO= gastos,INGRESO= entradas varias
Respuesta exitosa: 200 OK
Response:
[ { "id": 1, "categoria": "Servicios", "descripcionPago": "Pago de luz", "fechaPago": "2025-01-15", "metodoPago": "Efectivo", "montoPagado": 150000, "recibePago": "Empresa Eléctrica", "responsablePago": "Juan Pérez", "jornada_id": 1, "tipo_movimiento": "EGRESO", "tenant_id": "uuid-tenant" }, { "id": 2, "categoria": "Varios", "descripcionPago": "Préstamo socio", "fechaPago": "2025-01-15", "metodoPago": "Transferencia", "montoPagado": 500000, "recibePago": "Caja", "responsablePago": "Admin", "jornada_id": 1, "tipo_movimiento": "INGRESO", "tenant_id": "uuid-tenant" }]cURL:
# Todos (últimos 100)curl "http://localhost/api/egresos/?skip=0&limit=10" -H "Authorization: Bearer <token>"
# Rango enero 2025curl "http://localhost/api/egresos/?fecha_desde=2025-01-01&fecha_hasta=2025-01-31" -H "Authorization: Bearer <token>"Python:
import httpxresp = httpx.get("http://localhost/api/egresos/", params={"fecha_desde": "2025-01-01", "fecha_hasta": "2025-01-31"}, headers={"Authorization": f"Bearer :token"})egresos = resp.json()JavaScript:
const resp = await fetch('http://localhost/api/egresos/?fecha_desde=2025-01-01&fecha_hasta=2025-01-31', { headers: {'Authorization': `Bearer $:token`}});const egresos = await resp.json();GET /api/egresos/total-dia
Descripción: Obtiene el total de egresos del día
Requiere Auth: Sí
Permiso requerido: egresos, leer
Parámetros query:
| Parámetro | Tipo | Obligatorio | Descripción |
|---|---|---|---|
fecha | date | ✅ | Fecha a consultar |
Respuesta exitosa: 200 OK
cURL:
curl "http://localhost/api/egresos/total-dia?fecha=2025-01-15" -H "Authorization: Bearer <token>"GET /api/egresos/total-mensual
Descripción: Obtiene el total de egresos del mes
Requiere Auth: Sí
Permiso requerido: egresos, leer
Parámetros query:
| Parámetro | Tipo | Obligatorio | Descripción |
|---|---|---|---|
anio | int | ✅ | Año |
mes | int | ✅ | Mes (1-12) |
Respuesta exitosa: 200 OK
cURL:
curl "http://localhost/api/egresos/total-mensual?anio=2025&mes=1" -H "Authorization: Bearer <token>"GET /api/egresos/total-rango
Descripción: Suma montoPagado de TODOS los movimientos (EGRESO + INGRESO) en un rango. Diferencia con /total-gastos-rango: este incluye ambos tipos. Para flujo neto de caja: total_ingresos - total_egresos = flujo_neto.
Requiere Auth: Sí
Permiso requerido: egresos, leer
Parámetros query:
| Parámetro | Tipo | Obligatorio | Descripción |
|---|---|---|---|
fecha_inicio | date | ✅ | Fecha inicial inclusive (YYYY-MM-DD) |
fecha_fin | date | ✅ | Fecha final inclusive (YYYY-MM-DD) |
Comportamiento / Casos de uso:
- Flujo de caja neto: combinar con
/total-gastos-rangoy/total-ingresos-rango total-rango= suma absoluta de todo (no distingue signo)- Para saber si hay superávit/déficit: restar egresos de ingresos por separado
Respuesta exitosa: 200 OK
Response:
{"total": 650000.0}cURL:
curl "http://localhost/api/egresos/total-rango?fecha_inicio=2025-01-01&fecha_fin=2025-01-31" -H "Authorization: Bearer <token>"GET /api/egresos/total-gastos-rango [NUEVO]
Descripción: Suma montoPagado solo de movimientos con tipo_movimiento = 'EGRESO' en un rango. Contexto de uso: gastos operativos del negocio (servicios, insumos, nómina, alquiler, impuestos). Para deducibles de renta, control de presupuesto y análisis de costos fijos vs variables.
Requiere Auth: Sí
Permiso requerido: egresos, leer
Parámetros query:
| Parámetro | Tipo | Obligatorio | Descripción |
|---|---|---|---|
desde | date (YYYY-MM-DD) | ✅ | Fecha inicio inclusive |
hasta | date (YYYY-MM-DD) | ✅ | Fecha fin inclusive |
Comportamiento / Casos de uso:
- Gastos deducibles renta: filtrar categoría + rango → exportar a Excel
- Presupuesto mensual: comparar
total-gastos-rangomes actual vs anterior - Análisis por categoría: traer lista completa
/egresos/y agrupar en frontend
Respuesta exitosa: 200 OK
Response:
{"total": 10000.0}cURL:
curl "http://localhost/api/egresos/total-gastos-rango?desde=2026-07-24&hasta=2026-07-24" -H "Authorization: Bearer <token>"GET /api/egresos/total-ingresos-rango [NUEVO]
Descripción: Suma montoPagado solo de movimientos con tipo_movimiento = 'INGRESO' en un rango. Cuándo usar: entradas de caja que NO son ventas (préstamos socios, aportes capital, devoluciones proveedores, caja menor). No incluye ventas — para eso usar reportes de ventas.
Requiere Auth: Sí
Permiso requerido: egresos, leer
Parámetros query:
| Parámetro | Tipo | Obligatorio | Descripción |
|---|---|---|---|
desde | date (YYYY-MM-DD) | ✅ | Fecha inicio inclusive |
hasta | date (YYYY-MM-DD) | ✅ | Fecha fin inclusive |
Comportamiento / Casos de uso:
- Control de entradas no operativas: ¿cuánto entró por préstamos/aportes?
- Conciliación:
ingresos_rango + ventas_rango - egresos_rango = flujo_caja_total - Diferencia con
total-rango: este solo suma INGRESO;total-rangosuma EGRESO+INGRESO
Respuesta exitosa: 200 OK
Response:
{"total": 50000.0}cURL:
curl "http://localhost/api/egresos/total-ingresos-rango?desde=2026-07-24&hasta=2026-07-24" -H "Authorization: Bearer <token>"POST /api/egresos/
Descripción: Crea un nuevo egreso
Requiere Auth: Sí
Permiso requerido: egresos, crear
Request:
{ "categoria": "Servicios", "descripcionPago": "Pago de agua", "fechaPago": "2025-01-15", "metodoPago": "Transferencia", "montoPagado": 80000, "recibePago": "Empresa de Acueducto", "responsablePago": "Juan Pérez", "tipo_movimiento": "EGRESO"}Respuesta exitosa: 201 Created
cURL:
curl -X POST http://localhost/api/egresos/ \ -H "Content-Type: application/json" \ -H "Authorization: Bearer <token>" \ -d '{"categoria":"Servicios","descripcionPago":"Pago de agua","fechaPago":"2025-01-15","metodoPago":"Transferencia","montoPagado":80000,"recibePago":"Empresa de Acueducto","responsablePago":"Juan Pérez","tipo_movimiento":"EGRESO"}'Python:
import httpxresp = httpx.post("http://localhost/api/egresos/", json={"categoria": "Servicios", "descripcionPago": "Pago de agua", "fechaPago": "2025-01-15", "metodoPago": "Transferencia", "montoPagado": 80000, "recibePago": "Empresa de Acueducto", "responsablePago": "Juan Pérez", "tipo_movimiento": "EGRESO"}, headers={"Authorization": f"Bearer :token"})egreso = resp.json()JavaScript:
const resp = await fetch('http://localhost/api/egresos/', { method: 'POST', headers: {'Content-Type': 'application/json', 'Authorization': `Bearer $:token`}, body: JSON.stringify({categoria: 'Servicios', descripcionPago: 'Pago de agua', fechaPago: '2025-01-15', metodoPago: 'Transferencia', montoPagado: 80000, recibePago: 'Empresa de Acueducto', responsablePago: 'Juan Pérez', tipo_movimiento: 'EGRESO'})});GET /api/egresos/:egreso_id
Descripción: Obtiene el detalle completo de un egreso/ingreso por ID. Incluye categoría, descripción, fecha, método de pago, monto, proveedor/beneficiario, responsable y tipo de movimiento. Para auditoría, verificación de comprobante o edición.
Requiere Auth: Sí
Permiso requerido: egresos, leer
Parámetros path:
| Parámetro | Tipo | Obligatorio | Descripción |
|---|---|---|---|
egreso_id | int | ✅ | ID del movimiento |
Comportamiento / Casos de uso:
- Verificar comprobante antes de anular
- Ver detalle para conciliar con extracto bancario
- Pre-cargar formulario de edición
Respuesta exitosa: 200 OK
Response:
{ "id": 1, "categoria": "Servicios", "descripcionPago": "Pago de luz", "fechaPago": "2025-01-15", "metodoPago": "Efectivo", "montoPagado": 150000, "recibePago": "Empresa Eléctrica", "responsablePago": "Juan Pérez", "jornada_id": 1, "tipo_movimiento": "EGRESO", "tenant_id": "uuid-tenant"}Errores:
| Código | Causa | Solución |
|---|---|---|
| 404 | No encontrado | Verificar egreso_id |
| 403 | Sin permiso egresos, leer | Solicitar a admin |
cURL:
curl http://localhost/api/egresos/1 -H "Authorization: Bearer <token>"Python:
import httpxresp = httpx.get("http://localhost/api/egresos/1", headers={"Authorization": f"Bearer :token"})egreso = resp.json()JavaScript:
const resp = await fetch('http://localhost/api/egresos/1', { headers: {'Authorization': `Bearer $:token`}});const egreso = await resp.json();PUT /api/egresos/:egreso_id
Descripción: Actualiza campos de un egreso/ingreso existente. Solo campos enviados (partial update). Para corregir errores de digitación: monto, categoría, descripción, método de pago. No permite cambiar tipo_movimiento (EGRESO ↔ INGRESO) — crear uno nuevo y anular el anterior.
Requiere Auth: Sí
Permiso requerido: egresos, actualizar
Parámetros path:
| Parámetro | Tipo | Obligatorio | Descripción |
|---|---|---|---|
egreso_id | int | ✅ | ID del movimiento |
Request (campos opcionales):
{ "categoria": "Servicios Públicos", "descripcionPago": "Pago de energía enero", "fechaPago": "2025-01-15", "metodoPago": "Transferencia", "montoPagado": 160000, "recibePago": "EPM", "responsablePago": "Juan Pérez"}Campos actualizables:
| Campo | Tipo | Descripción |
|---|---|---|
categoria | string | Clasificación gasto |
descripcionPago | string | Detalle |
fechaPago | date | Fecha (YYYY-MM-DD) |
metodoPago | string | Efectivo, Transferencia, Credito, VARIOS |
montoPagado | int | Valor en COP |
recibePago | string | Proveedor/beneficiario |
responsablePago | string | Quién autorizó/registró |
Respuesta exitosa: 200 OK — retorna EgresoResponse actualizado
Response:
{ "id": 1, "categoria": "Servicios Públicos", "descripcionPago": "Pago de energía enero", "fechaPago": "2025-01-15", "metodoPago": "Transferencia", "montoPagado": 160000, "recibePago": "EPM", "responsablePago": "Juan Pérez", "jornada_id": 1, "tipo_movimiento": "EGRESO", "tenant_id": "uuid-tenant"}Errores:
| Código | Causa | Solución |
|---|---|---|
| 404 | No encontrado | Verificar egreso_id |
| 400 | Fecha inválida o monto ≤ 0 | Validar datos |
| 403 | Sin permiso egresos, actualizar | Solo admin |
cURL:
curl -X PUT http://localhost/api/egresos/1 \ -H "Content-Type: application/json" \ -H "Authorization: Bearer <token>" \ -d '{"montoPagado":90000,"descripcionPago":"Pago de luz actualizado"}'Python:
import httpxresp = httpx.put("http://localhost/api/egresos/1", json={"montoPagado": 90000, "descripcionPago": "Pago de luz actualizado"}, headers={"Authorization": f"Bearer :token"})egreso = resp.json()JavaScript:
const resp = await fetch('http://localhost/api/egresos/1', { method: 'PUT', headers: {'Content-Type': 'application/json', 'Authorization': `Bearer $:token`}, body: JSON.stringify({montoPagado: 90000, descripcionPago: 'Pago de luz actualizado'})});const egreso = await resp.json();DELETE /api/egresos/:egreso_id
Descripción: Elimina (hard delete) un movimiento de egreso/ingreso. Solo para errores de registro (duplicado, monto cero, prueba). Para anular gasto real contablemente: crear egreso inverso (INGRESO mismo monto) o usar nota de crédito.
Requiere Auth: Sí
Permiso requerido: egresos, eliminar
Parámetros path:
| Parámetro | Tipo | Obligatorio | Descripción |
|---|---|---|---|
egreso_id | int | ✅ | ID del movimiento |
Comportamiento / Casos de uso:
- Registro duplicado por doble click
- Prueba en desarrollo
- Error de sistema que creó movimiento fantasma
- NO usar para anular gasto real — rompería trazabilidad contable
Respuesta exitosa: 204 No Content
Errores:
| Código | Causa | Solución |
|---|---|---|
| 404 | No encontrado | Verificar egreso_id |
| 403 | Sin permiso egresos, eliminar | Solo admin/superadmin |
| 409 | Tiene dependencias (conciliado) | No eliminar, crear inverso |
cURL:
curl -X DELETE http://localhost/api/egresos/1 -H "Authorization: Bearer <token>"Python:
import httpxresp = httpx.delete("http://localhost/api/egresos/1", headers={"Authorization": f"Bearer :token"})assert resp.status_code == 204JavaScript:
const resp = await fetch('http://localhost/api/egresos/1', { method: 'DELETE', headers: {'Authorization': `Bearer $:token`}});// 204 = éxito