Saldo Inicial
Saldo Inicial
Prefijo: /api/saldo-inicial
Requiere Auth: Sí
Permiso requerido: saldo_inicial, *
Módulo para registrar el saldo inicial de efectivo por terminal al iniciar la jornada.
GET /api/saldo-inicial/
Descripción: Lista los saldos iniciales registrados
Requiere Auth: Sí
Permiso requerido: saldo_inicial, leer
Respuesta exitosa: 200 OK
Response:
[ { "id": 1, "terminal_id": "TERM-001", "fecha": "2025-01-15", "usuario": "Juan Pérez", "monto": 500000, "jornada_id": 19, "tenant_id": "uuid-tenant", "created_at": "2025-01-15T06:00:00" }]cURL:
curl http://localhost/api/saldo-inicial/ -H "Authorization: Bearer <token>"Python:
import httpxresp = httpx.get("http://localhost/api/saldo-inicial/", headers={"Authorization": f"Bearer :token"})saldos = resp.json()JavaScript:
const resp = await fetch('http://localhost/api/saldo-inicial/', { headers: {'Authorization': `Bearer $:token`}});const saldos = await resp.json();GET /api/saldo-inicial/existe
Descripción: Verifica si ya existe un saldo inicial para una terminal/fecha. La consulta es global por terminal_id + fecha (no depende del tenant actual), alineada con el UniqueConstraint(terminal_id, fecha) global: devuelve true aunque el registro haya sido creado bajo otro tenant.
Requiere Auth: Sí
Permiso requerido: saldo_inicial, leer
Parámetros query:
| Parámetro | Tipo | Obligatorio | Descripción |
|---|---|---|---|
terminal_id | string | ✅ | Identificador de terminal |
fecha | date | ✅ | Fecha a verificar |
Respuesta exitosa: 200 OK
Response:
{ "existe": true}cURL:
curl "http://localhost/api/saldo-inicial/existe?terminal_id=TERM-001&fecha=2025-01-15" -H "Authorization: Bearer <token>"POST /api/saldo-inicial/
Descripción: Crea un nuevo saldo inicial. Idempotente: si ya existe un saldo con la misma terminal_id + fecha, retorna el registro existente re-amarrado a la jornada (en vez de violar el UniqueConstraint(terminal_id, fecha) y devolver 500). Al crear o re-amarrar, sincroniza la base de la jornada: actualiza jornada_caja.base_inicial de la jornada activa del usuario (o la indicada en jornada_id) y caja.base de la última caja del tenant, de modo que el cierre cuadre contra la base correcta.
Requiere Auth: Sí
Permiso requerido: saldo_inicial, crear
Request:
{ "terminal_id": "TERM-001", "fecha": "2025-01-15", "usuario": "Juan Pérez", "monto": 500000, "jornada_id": 19}jornada_id(opcional): ID de la jornada a la que se amarra el saldo. Si no se envía, se resuelve automáticamente la jornadaABIERTAmás reciente delusuario.
Respuesta exitosa: 201 Created (creado) / 200 OK (ya existía, retorna el registro actualizado con su id, monto y jornada_id)
cURL:
curl -X POST http://localhost/api/saldo-inicial/ \ -H "Content-Type: application/json" \ -H "Authorization: Bearer <token>" \ -d '{"terminal_id":"TERM-001","fecha":"2025-01-15","usuario":"Juan Pérez","monto":500000,"jornada_id":19}'Python:
import httpxresp = httpx.post("http://localhost/api/saldo-inicial/", json={"terminal_id": "TERM-001", "fecha": "2025-01-15", "usuario": "Juan Pérez", "monto": 500000, "jornada_id": 19}, headers={"Authorization": f"Bearer :token"})saldo = resp.json()JavaScript:
const resp = await fetch('http://localhost/api/saldo-inicial/', { method: 'POST', headers: {'Content-Type': 'application/json', 'Authorization': `Bearer $:token`}, body: JSON.stringify({terminal_id: 'TERM-001', fecha: '2025-01-15', usuario: 'Juan Pérez', monto: 500000, jornada_id: 19})});GET /api/saldo-inicial/:saldo_id
Descripción: Obtiene el detalle de un saldo inicial por ID. Incluye terminal, fecha, usuario, monto, jornada asociada y timestamp de creación. Para verificar registro, auditoría o pre-cargar edición.
Requiere Auth: Sí
Permiso requerido: saldo_inicial, leer
Parámetros path:
| Parámetro | Tipo | Obligatorio | Descripción |
|---|---|---|---|
saldo_id | int | ✅ | ID del saldo inicial |
Comportamiento / Casos de uso:
- Verificar monto registrado vs arqueo físico
- Confirmar a qué jornada está amarrado el saldo
- Auditoría: quién y cuándo registró la base
Respuesta exitosa: 200 OK
Response:
{ "id": 1, "terminal_id": "TERM-001", "fecha": "2025-01-15", "usuario": "Juan Pérez", "monto": 500000, "jornada_id": 19, "tenant_id": "uuid-tenant", "created_at": "2025-01-15T06:00:00"}Errores:
| Código | Causa | Solución |
|---|---|---|
| 404 | No encontrado | Verificar saldo_id |
| 403 | Sin permiso saldo_inicial, leer | Solicitar a admin |
cURL:
curl http://localhost/api/saldo-inicial/1 -H "Authorization: Bearer <token>"Python:
import httpxresp = httpx.get("http://localhost/api/saldo-inicial/1", headers={"Authorization": f"Bearer :token"})saldo = resp.json()JavaScript:
const resp = await fetch('http://localhost/api/saldo-inicial/1', { headers: {'Authorization': `Bearer $:token`}});const saldo = await resp.json();PUT /api/saldo-inicial/:saldo_id
Descripción: Actualiza campos de un saldo inicial (partial update). Importante: al cambiar monto o jornada_id, sincroniza automáticamente jornada_caja.base_inicial de la jornada vinculada y caja.base del último cierre del tenant, para que el cuadre de cierre sea correcto.
Requiere Auth: Sí
Permiso requerido: saldo_inicial, actualizar
Parámetros path:
| Parámetro | Tipo | Obligatorio | Descripción |
|---|---|---|---|
saldo_id | int | ✅ | ID del saldo inicial |
Request (campos opcionales, solo los enviados):
{ "usuario": "Juan Pérez", "monto": 550000, "jornada_id": 20}Campos actualizables:
| Campo | Tipo | Descripción |
|---|---|---|
usuario | string | Cajero responsable |
monto | int | Nuevo monto base (sincroniza jornada.caja.base_inicial y caja.base) |
jornada_id | int | Re-asignar a otra jornada (debe ser del mismo usuario y fecha) |
Comportamiento / Casos de uso:
- Corrección de monto: cajero digitó mal la base inicial
- Re-asignación: saldo se creó en jornada equivocada
- Sincronización automática: al cambiar monto → actualiza
jornada.base_inicialycaja.basedel tenant
Respuesta exitosa: 200 OK — retorna SaldoInicialResponse actualizado
Response:
{ "id": 1, "terminal_id": "TERM-001", "fecha": "2025-01-15", "usuario": "Juan Pérez", "monto": 550000, "jornada_id": 20, "tenant_id": "uuid-tenant", "created_at": "2025-01-15T06:00:00"}Errores:
| Código | Causa | Solución |
|---|---|---|
| 404 | No encontrado | Verificar saldo_id |
| 400 | Jornada_id no pertenece al usuario/fecha | Validar jornada |
| 403 | Sin permiso saldo_inicial, actualizar | Solo admin |
| 409 | Conflicto unique (terminal_id + fecha) | No se puede duplicar |
cURL:
curl -X PUT http://localhost/api/saldo-inicial/1 \ -H "Content-Type: application/json" \ -H "Authorization: Bearer <token>" \ -d '{"monto":550000}'Python:
import httpxresp = httpx.put("http://localhost/api/saldo-inicial/1", json={"monto": 550000}, headers={"Authorization": f"Bearer :token"})saldo = resp.json()JavaScript:
const resp = await fetch('http://localhost/api/saldo-inicial/1', { method: 'PUT', headers: {'Content-Type': 'application/json', 'Authorization': `Bearer $:token`}, body: JSON.stringify({monto: 550000})});const saldo = await resp.json();DELETE /api/saldo-inicial/:saldo_id
Descripción: Elimina (hard delete) un saldo inicial. Solo para errores de registro (duplicado por bug, monto cero, prueba). NO usar para anular saldo real — eso des-sincroniza jornada.base_inicial y caja.base, rompiendo el cuadre de cierre. Para corregir: editar monto (PUT) o crear nuevo saldo en jornada correcta.
Requiere Auth: Sí
Permiso requerido: saldo_inicial, eliminar
Parámetros path:
| Parámetro | Tipo | Obligatorio | Descripción |
|---|---|---|---|
saldo_id | int | ✅ | ID del saldo inicial |
Comportamiento / Casos de uso:
- Saldo duplicado por doble envío (idempotencia falló)
- Registro de prueba en desarrollo
- Error de sistema (monto = 0)
- ADVERTENCIA: No hace rollback de sincronización —
jornada.base_inicialycaja.basequedan con valor viejo.
Respuesta exitosa: 204 No Content
Errores:
| Código | Causa | Solución |
|---|---|---|
| 404 | No encontrado | Verificar saldo_id |
| 403 | Sin permiso saldo_inicial, eliminar | Solo superadmin |
| 409 | Tiene dependencias (jornada/caja sincronizadas) | No eliminar, usar PUT para corregir |
cURL:
curl -X DELETE http://localhost/api/saldo-inicial/1 -H "Authorization: Bearer <token>"Python:
import httpxresp = httpx.delete("http://localhost/api/saldo-inicial/1", headers={"Authorization": f"Bearer :token"})assert resp.status_code == 204JavaScript:
const resp = await fetch('http://localhost/api/saldo-inicial/1', { method: 'DELETE', headers: {'Authorization': `Bearer $:token`}});// 204 = éxito