Skip to content

Caja

Caja

Prefijo: /api/caja
Requiere Auth:
Permiso requerido: caja, *

Módulo de caja para gestión del dinero en efectivo y electrónico. El flujo típico es: apertura de caja → operaciones (ventas, gastos) → cierre con resumen.

GET /api/caja/

Descripción: Lista los registros de caja del tenant con paginación y filtros opcionales por rango de fechas y usuario/cajero. Ideal para el panel de administración que muestra el historial de cierres de caja con filtros por día y por cajero.
Requiere Auth:
Permiso requerido: caja, leer

Parámetros query:

ParámetroTipoObligatorioDescripción
skipintRegistros a saltar (default 0)
limitintMáximo de registros a retornar (default 100)
desdedateFecha inicio del filtro inclusiva (YYYY-MM-DD). Filtra por Caja.fecha >= desde
hastadateFecha fin del filtro inclusiva (YYYY-MM-DD). Filtra por Caja.fecha <= hasta
usuariostringFiltra por nombre exacto del usuario/cajero que registró el cierre

Comportamiento:

  • Sin filtros: retorna los 100 registros más recientes del tenant ordenados por fecha descendente.
  • Con desde y hasta: retorna solo los cierres dentro del rango (inclusive). Útil para reportes diarios/semanales.
  • Con usuario: retorna solo los cierres de ese cajero específico. Combinable con rango de fechas.
  • Los filtros se combinan con AND lógico.

Respuesta exitosa: 200 OK

Headers de respuesta:

HeaderTipoDescripción
X-Total-CountintegerTotal de cierres de caja que cumplen los filtros (desde, hasta, usuario). No considera skip/limit.

Response:

[
{
"id": 1,
"base": 500000,
"cierre": 850000,
"credito": 100000,
"efectivo": 700000,
"gastos": 50000,
"total": 750000,
"transferencia": 50000,
"fecha": "2025-01-15",
"hora": "18:00:00",
"usuario": "Juan Pérez",
"id_jornada": 1,
"tenant_id": "uuid-tenant"
}
]

cURL:

Terminal window
# Sin filtros
curl "http://localhost/api/caja/?skip=0&limit=10" -H "Authorization: Bearer <token>"
# Solo cierres del 15 al 20 de enero
curl "http://localhost/api/caja/?desde=2025-01-15&hasta=2025-01-20" -H "Authorization: Bearer <token>"
# Solo cierres de un cajero específico
curl "http://localhost/api/caja/?usuario=Juan%20Pérez&desde=2025-01-15" -H "Authorization: Bearer <token>"

Python:

import httpx
resp = httpx.get("http://localhost/api/caja/",
params={"desde": "2025-01-15", "hasta": "2025-01-20", "usuario": "Juan Pérez"},
headers={"Authorization": f"Bearer :token"})
caja = resp.json()
total = int(resp.headers.get("X-Total-Count", "0"))
total_pages = (total + 10 - 1) // 10 # ceil division

JavaScript:

const params = new URLSearchParams({desde: '2025-01-15', hasta: '2025-01-20', usuario: 'Juan Pérez'});
const resp = await fetch(`http://localhost/api/caja/?$:params`, {
headers: {'Authorization': `Bearer $:token`}
});
const caja = await resp.json();
const totalCount = parseInt(resp.headers.get('X-Total-Count') || '0', 10);
const totalPages = Math.ceil(totalCount / 10);

GET /api/caja/count [NUEVO]

Descripción: Cuenta el total de registros de caja del tenant con los mismos filtros opcionales que GET /api/caja/. Diseñado para paginación del frontend: primero se llama /count para saber cuántos registros hay, y luego se llama /api/caja/ con skip y limit para la página actual.
Requiere Auth:
Permiso requerido: caja, leer

Parámetros query:

ParámetroTipoObligatorioDescripción
desdedateFecha inicio del filtro inclusiva (YYYY-MM-DD)
hastadateFecha fin del filtro inclusiva (YYYY-MM-DD)
usuariostringFiltra por nombre exacto del usuario/cajero

Caso de uso típico:

  1. El admin abre la vista “Cierres de Caja” en NeoxAdminPanel.
  2. Frontend llama GET /api/caja/count?desde=2025-01-15&hasta=2025-01-20 para saber que hay 45 cierres en ese rango.
  3. Frontend renderiza paginator con 5 páginas (10 por página).
  4. Para cada página, llama GET /api/caja/?desde=2025-01-15&hasta=2025-01-20&skip=0&limit=10.

Respuesta exitosa: 200 OK

Response:

{
"total": 45
}

cURL:

Terminal window
# Contar todos los cierres del tenant
curl "http://localhost/api/caja/count" -H "Authorization: Bearer <token>"
# Contar cierres de un rango específico
curl "http://localhost/api/caja/count?desde=2025-01-15&hasta=2025-01-20" -H "Authorization: Bearer <token>"
# Contar cierres de un cajero en un rango
curl "http://localhost/api/caja/count?usuario=Juan%20Pérez&desde=2025-01-15&hasta=2025-01-20" -H "Authorization: Bearer <token>"

Python:

import httpx
resp = httpx.get("http://localhost/api/caja/count",
params={"desde": "2025-01-15", "hasta": "2025-01-20"},
headers={"Authorization": f"Bearer :token"})
total = resp.json()["total"] # 45

JavaScript:

const resp = await fetch('http://localhost/api/caja/count?desde=2025-01-15&hasta=2025-01-20', {
headers: {'Authorization': `Bearer $:token`}
});
const { total } = await resp.json(); // 45

GET /api/caja/resumen-cierre

Descripción: Obtiene el resumen de cierre de jornada para un usuario
Requiere Auth:
Permiso requerido: caja, leer

Parámetros query:

ParámetroTipoObligatorioDescripción
usuariostringNombre del usuario

Respuesta exitosa: 200 OK

Response:

{
"ventas_canal": {
"local": 450000,
"electronico": 150000
},
"ventas_medio": {
"efectivo": 400000,
"transferencia": 100000,
"credito": 100000
},
"creditos_jornada": {
"monto_total": 200000,
"abono_inicial": 0
},
"abonos": {
"efectivo": 50000,
"digital": 30000,
"total": 80000
},
"gastos": 50000,
"ingresos": 0,
"retiros": 0,
"base_inicial": 500000
}

cURL:

Terminal window
curl "http://localhost/api/caja/resumen-cierre?usuario=Juan%20P%C3%A9rez" -H "Authorization: Bearer <token>"

GET /api/caja/base-inicial

Descripción: Obtiene la base inicial de la jornada activa del usuario
Requiere Auth:
Permiso requerido: caja, leer

Parámetros query:

ParámetroTipoObligatorioDescripción
usuariostringNombre del usuario

Respuesta exitosa: 200 OK

Response:

500000

cURL:

Terminal window
curl "http://localhost/api/caja/base-inicial?usuario=Juan%20P%C3%A9rez" -H "Authorization: Bearer <token>"

GET /api/caja/gastos

Descripción: Obtiene el total de gastos en un rango de fechas
Requiere Auth:
Permiso requerido: caja, leer

Parámetros query:

ParámetroTipoObligatorioDescripción
desdedateFecha inicial
hastadateFecha final

Respuesta exitosa: 200 OK

Response:

{
"total": 150000,
"fecha": "2025-01-01"
}

cURL:

Terminal window
curl "http://localhost/api/caja/gastos?desde=2025-01-01&hasta=2025-01-15" -H "Authorization: Bearer <token>"

GET /api/caja/ultimo

Descripción: Obtiene el último ID de caja registrado
Requiere Auth:
Permiso requerido: caja, leer

Respuesta exitosa: 200 OK

Response:

42

cURL:

Terminal window
curl http://localhost/api/caja/ultimo -H "Authorization: Bearer <token>"

POST /api/caja/

Descripción: Registra el CIERRE de caja con todos los totales del día (base, cierre, efectivo, crédito, gastos, transferencia). Diferencia clave vs /apertura: este endpoint cierra la jornada contabilizando ventas, gastos y calculando el cuadratura. Usar al final del día cuando el cajero hace arqueo.
Requiere Auth:
Permiso requerido: caja, crear

Request:

{
"base": 500000,
"cierre": 1200000,
"efectivo": 800000,
"credito": 100000,
"gastos": 50000,
"transferencia": 50000,
"total": 1150000,
"usuario": "Juan Pérez",
"id_jornada": 5
}

Campos:

CampoTipoObligatorioDescripción
baseintBase inicial (debe coincidir con apertura)
cierreintTotal en caja al cerrar (efectivo + cheques)
efectivointEfectivo contado en arqueo
creditointVentas a crédito del día
gastosintEgresos/gastos del día
transferenciaintTransferencias recibidas
totalintefectivo + credito + transferencia - gastos (debe cuadrar con cierre)
usuariostringCajero que cierra
id_jornadaintJornada a cerrar

Comportamiento / Casos de uso:

  • Cierre diario: cajero cuenta efectivo, ingresa totales, sistema valida cuadratura
  • Si total != cierre → advertencia pero permite guardar (para ajustes manuales)
  • Crea registro en caja + actualiza jornada_caja.estado = CERRADA

Respuesta exitosa: 201 Created

Response:

{
"id": 10,
"base": 500000,
"cierre": 1200000,
"credito": 100000,
"efectivo": 800000,
"gastos": 50000,
"total": 1150000,
"transferencia": 50000,
"fecha": "2025-01-15",
"hora": "18:00:00",
"usuario": "Juan Pérez",
"id_jornada": 5,
"tenant_id": "uuid-tenant"
}

Errores:

CódigoCausaSolución
400Jornada no activa o datos inválidosVerificar id_jornada y usuario
403Sin permiso caja, crearSolicitar a admin
409Jornada ya cerradaNo se puede cerrar dos veces

cURL:

Terminal window
curl -X POST http://localhost/api/caja/ \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <token>" \
-d '{"base":500000,"cierre":1200000,"efectivo":800000,"credito":100000,"gastos":50000,"transferencia":50000,"total":1150000,"usuario":"Juan Pérez","id_jornada":5}'

Python:

import httpx
resp = httpx.post("http://localhost/api/caja/",
json={"base": 500000, "cierre": 1200000, "efectivo": 800000, "credito": 100000, "gastos": 50000, "transferencia": 50000, "total": 1150000, "usuario": "Juan Pérez", "id_jornada": 5},
headers={"Authorization": f"Bearer :token"})
cierre = resp.json()

JavaScript:

const resp = await fetch('http://localhost/api/caja/', {
method: 'POST',
headers: {'Content-Type': 'application/json', 'Authorization': `Bearer $:token`},
body: JSON.stringify({base: 500000, cierre: 1200000, efectivo: 800000, credito: 100000, gastos: 50000, transferencia: 50000, total: 1150000, usuario: 'Juan Pérez', id_jornada: 5})
});
const cierre = await resp.json();

POST /api/caja/apertura

Descripción: Registra la apertura de caja para un usuario
Requiere Auth:
Permiso requerido: caja, crear

Request:

{
"base": 500000,
"usuario": "Juan Pérez"
}

Respuesta exitosa: 201 Created

Response:

{
"id_caja": 10,
"id_jornada": 5,
"base": 500000,
"mensaje": "Apertura registrada exitosamente"
}

cURL:

Terminal window
curl -X POST http://localhost/api/caja/apertura \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <token>" \
-d '{"base":500000,"usuario":"Juan Pérez"}'

GET /api/caja/:caja_id

Descripción: Obtiene el detalle completo de un cierre de caja por ID. Incluye todos los totales (base, cierre, efectivo, crédito, gastos, transferencia) y metadatos (fecha, hora, usuario, jornada). Para auditoría, reimpresión de cierre o corrección de errores.
Requiere Auth:
Permiso requerido: caja, leer

Parámetros path:

ParámetroTipoObligatorioDescripción
caja_idintID del registro de caja (cierre)

Comportamiento / Casos de uso:

  • Admin revisa cierre específico por discrepancia en arqueo
  • Reimprimir comprobante de cierre
  • Verificar que un cierre tiene los datos correctos antes de anular

Respuesta exitosa: 200 OK

Response:

{
"id": 1,
"base": 500000,
"cierre": 850000,
"credito": 100000,
"efectivo": 700000,
"gastos": 50000,
"total": 750000,
"transferencia": 50000,
"fecha": "2025-01-15",
"hora": "18:00:00",
"usuario": "Juan Pérez",
"id_jornada": 1,
"tenant_id": "uuid-tenant"
}

Errores:

CódigoCausaSolución
404Cierre no encontradoVerificar caja_id
403Sin permiso caja, leerSolicitar a admin

cURL:

Terminal window
curl http://localhost/api/caja/1 -H "Authorization: Bearer <token>"

Python:

import httpx
resp = httpx.get("http://localhost/api/caja/1", headers={"Authorization": f"Bearer :token"})
caja = resp.json()

JavaScript:

const resp = await fetch('http://localhost/api/caja/1', {
headers: {'Authorization': `Bearer $:token`}
});
const caja = await resp.json();

PUT /api/caja/:caja_id

Descripción: Actualiza campos de un cierre de caja ya registrado. Solo admin para corregir errores de digitación en arqueo. No cambia el estado de la jornada (para reabrir usar jornadas).
Requiere Auth:
Permiso requerido: caja, actualizar

Parámetros path:

ParámetroTipoObligatorioDescripción
caja_idintID del registro de caja

Request (campos opcionales, solo los enviados):

{
"cierre": 900000,
"efectivo": 750000,
"total": 850000,
"gastos": 60000
}

Campos actualizables:

CampoTipoDescripción
cierreintTotal en caja al cerrar
efectivointEfectivo contado
creditointVentas a crédito
gastosintEgresos del día
transferenciaintTransferencias
totalintTotal calculado

Comportamiento / Casos de uso:

  • Corrección de error de digitación: cajero escribió mal el efectivo
  • Ajuste post-cierre: se detecta diferencia en conciliación bancaria
  • NO recalcula automáticamente — el admin debe asegurar que total = efectivo + credito + transferencia - gastos

Respuesta exitosa: 200 OK — retorna CajaResponse actualizado

Response:

{
"id": 1,
"base": 500000,
"cierre": 900000,
"credito": 100000,
"efectivo": 750000,
"gastos": 60000,
"total": 850000,
"transferencia": 50000,
"fecha": "2025-01-15",
"hora": "18:00:00",
"usuario": "Juan Pérez",
"id_jornada": 1,
"tenant_id": "uuid-tenant"
}

Errores:

CódigoCausaSolución
404Cierre no encontradoVerificar caja_id
403Sin permiso caja, actualizarSolo admin
400Datos inválidosValidar tipos numéricos

cURL:

Terminal window
curl -X PUT http://localhost/api/caja/1 \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <token>" \
-d '{"cierre":900000,"efectivo":750000,"total":850000,"gastos":60000}'

Python:

import httpx
resp = httpx.put("http://localhost/api/caja/1",
json={"cierre": 900000, "efectivo": 750000, "total": 850000, "gastos": 60000},
headers={"Authorization": f"Bearer :token"})
caja = resp.json()

JavaScript:

const resp = await fetch('http://localhost/api/caja/1', {
method: 'PUT',
headers: {'Content-Type': 'application/json', 'Authorization': `Bearer $:token`},
body: JSON.stringify({cierre: 900000, efectivo: 750000, total: 850000, gastos: 60000})
});
const caja = await resp.json();

DELETE /api/caja/:caja_id

Descripción: Elimina un registro de cierre de caja (hard delete). Solo para casos excepcionales: registro de prueba, cierre duplicado por error de sistema. NO usar para anular cierre real — eso requiere reabrir jornada y nuevo cierre.
Requiere Auth:
Permiso requerido: caja, eliminar

Parámetros path:

ParámetroTipoObligatorioDescripción
caja_idintID del registro de caja

Comportamiento / Casos de uso:

  • Cierre de prueba creado en desarrollo/testing
  • Doble cierre por bug de frontend (verificar que no haya movimientos posteriores)
  • ADVERTENCIA: Elimina el registro permanentemente. No hay soft delete en caja.

Respuesta exitosa: 204 No Content

Errores:

CódigoCausaSolución
404Cierre no encontradoVerificar caja_id
403Sin permiso caja, eliminarSolo superadmin
409Tiene dependencias (movimientos)No se puede eliminar

cURL:

Terminal window
curl -X DELETE http://localhost/api/caja/1 -H "Authorization: Bearer <token>"

Python:

import httpx
resp = httpx.delete("http://localhost/api/caja/1", headers={"Authorization": f"Bearer :token"})
assert resp.status_code == 204

JavaScript:

const resp = await fetch('http://localhost/api/caja/1', {
method: 'DELETE',
headers: {'Authorization': `Bearer $:token`}
});
// 204 = éxito sin body