Jornadas
Jornadas
Prefijo: /api/jornada
Requiere Auth: Sí
Permiso requerido: jornadas, *
Módulo de jornadas de caja. Cada usuario puede tener una jornada activa que registra apertura, operaciones diarias y cierre.
GET /api/jornada/
Descripción: Lista las jornadas de caja con paginación
Requiere Auth: Sí
Permiso requerido: jornadas, leer
Respuesta exitosa: 200 OK
Response:
[ { "id": 1, "usuario": "Juan Pérez", "apertura": "2025-01-15T06:00:00", "base_inicial": 500000, "cierre": "2025-01-15T18:00:00", "estado": "CERRADA", "tenant_id": "uuid-tenant" }]cURL:
curl "http://localhost/api/jornada/?skip=0&limit=10" -H "Authorization: Bearer <token>"Python:
import httpxresp = httpx.get("http://localhost/api/jornada/", headers={"Authorization": f"Bearer :token"})jornadas = resp.json()JavaScript:
const resp = await fetch('http://localhost/api/jornada/', { headers: {'Authorization': `Bearer $:token`}});const jornadas = await resp.json();GET /api/jornada/pendientes-cierre [NUEVO]
Descripción: Jornadas ABIERTAS de días anteriores que quedaron sin cierre de caja. El POS lo consulta a primera hora del día siguiente para avisar al cajero que debe cerrar la jornada anterior con conexión habilitada. El cierre de caja es online obligatorio; si no se hizo el día anterior, al día siguiente el POS muestra un aviso y bloquea nuevas ventas hasta que se realice el cierre.
Caso de uso típico:
- El cajero cierra el POS el lunes sin internet (modo offline). La jornada queda ABIERTA en la BD local.
- El martes, el POS arranca y llama
GET /api/jornada/pendientes-cierre?usuario=Juliana+Leon. - Si la API retorna la jornada del lunes, el POS muestra un modal: “Debe cerrar la jornada del lunes antes de continuar. Conéctese a internet para cerrar.”
- El cajero conecta a internet, el POS llama
POST /api/jornada/cerrarpara cerrar la jornada pendiente. - Una vez cerrada, el POS crea la nueva jornada del martes.
Requiere Auth: Sí
Permiso requerido: jornadas, leer
Parámetros query:
| Parámetro | Tipo | Obligatorio | Descripción |
|---|---|---|---|
usuario | string | ✅ | Nombre del usuario/cajero |
Comportamiento:
- Solo retorna jornadas con
estado = "ABIERTA"cuya apertura fue anterior al inicio de hoy (es decir, jornadas de días anteriores que no se cerraron). - Si el usuario cerró todas sus jornadas anteriores, retorna un array vacío
[]. - Las jornadas se ordenan por apertura ascendente (la más antigua primero).
Respuesta exitosa: 200 OK
Response (jornadas pendientes):
[ { "id": 39, "usuario": "Juliana Leon", "apertura": "2026-08-24T07:00:00", "base_inicial": 200000, "cierre": null, "estado": "ABIERTA", "tenant_id": "uuid-tenant" }]Response (sin jornadas pendientes):
[]Errores:
403— El usuario autenticado no tiene permiso para acceder a la caja de otro usuario (asistente intentando ver cierre de admin).404— No se encontró jornada activa para el usuario (este endpoint retorna 404 solo sirequire_acceso_cajafalla; un array vacío NO es error).
cURL:
curl "http://localhost/api/jornada/pendientes-cierre?usuario=Juliana%20Leon" \ -H "Authorization: Bearer <token>"Python:
import httpxresp = httpx.get("http://localhost/api/jornada/pendientes-cierre", params={"usuario": "Juliana Leon"}, headers={"Authorization": f"Bearer <token}"})pendientes = resp.json()if pendientes: print(f"Hay {len(pendientes)} jornada(s) sin cerrar")JavaScript:
const resp = await fetch('http://localhost/api/jornada/pendientes-cierre?usuario=Juliana%20Leon', { headers: {'Authorization': `Bearer $:token`}});const pendientes = await resp.json();if (pendientes.length > 0) { alert(`Hay ${pendientes.length} jornada(s) sin cerrar`);}GET /api/jornada/:jornada_id
Descripción: Obtiene el detalle completo de una jornada por ID. Incluye usuario, fecha/hora de apertura, base inicial, fecha/hora de cierre (si aplica), estado (ABIERTA/CERRADA). Para auditoría, verificación de cuadre o reimpresión.
Requiere Auth: Sí
Permiso requerido: jornadas, leer
Parámetros path:
| Parámetro | Tipo | Obligatorio | Descripción |
|---|---|---|---|
jornada_id | int | ✅ | ID de la jornada |
Comportamiento / Casos de uso:
- Admin revisa jornada específica por discrepancia en cierre
- Verificar si una jornada está ABIERTA o CERRADA
- Obtener base_inicial para conciliar con caja
Respuesta exitosa: 200 OK
Response:
{ "id": 1, "usuario": "Juan Pérez", "apertura": "2025-01-15T06:00:00", "base_inicial": 500000, "cierre": "2025-01-15T18:00:00", "estado": "CERRADA", "tenant_id": "uuid-tenant"}Errores:
| Código | Causa | Solución |
|---|---|---|
| 404 | Jornada no encontrada | Verificar jornada_id |
| 403 | Sin permiso jornadas, leer | Solicitar a admin |
cURL:
curl http://localhost/api/jornada/1 -H "Authorization: Bearer <token>"Python:
import httpxresp = httpx.get("http://localhost/api/jornada/1", headers={"Authorization": f"Bearer :token"})jornada = resp.json()JavaScript:
const resp = await fetch('http://localhost/api/jornada/1', { headers: {'Authorization': `Bearer $:token`}});const jornada = await resp.json();POST /api/jornada/
Descripción: Crea una nueva jornada de caja
Requiere Auth: Sí
Permiso requerido: jornadas, crear
Request:
{ "usuario": "Juan Pérez", "apertura": "2025-01-15T06:00:00", "base_inicial": 500000, "estado": "ABIERTA"}Respuesta exitosa: 201 Created
cURL:
curl -X POST http://localhost/api/jornada/ \ -H "Content-Type: application/json" \ -H "Authorization: Bearer <token>" \ -d '{"usuario":"Juan Pérez","apertura":"2025-01-15T06:00:00","base_inicial":500000,"estado":"ABIERTA"}'Python:
import httpxresp = httpx.post("http://localhost/api/jornada/", json={"usuario": "Juan Pérez", "apertura": "2025-01-15T06:00:00", "base_inicial": 500000, "estado": "ABIERTA"}, headers={"Authorization": f"Bearer :token"})jornada = resp.json()JavaScript:
const resp = await fetch('http://localhost/api/jornada/', { method: 'POST', headers: {'Content-Type': 'application/json', 'Authorization': `Bearer $:token`}, body: JSON.stringify({usuario: 'Juan Pérez', apertura: '2025-01-15T06:00:00', base_inicial: 500000, estado: 'ABIERTA'})});PUT /api/jornada/:jornada_id
Descripción: Actualiza una jornada — principalmente para cerrarla (setear cierre timestamp y estado: "CERRADA"). Validación de acceso a caja: solo el usuario dueño de la jornada (o admin) puede cerrarla. Para reapertura usar DELETE + POST nuevo (no recomendado).
Requiere Auth: Sí
Permiso requerido: jornadas, actualizar
Parámetros path:
| Parámetro | Tipo | Obligatorio | Descripción |
|---|---|---|---|
jornada_id | int | ✅ | ID de la jornada |
Request:
{ "cierre": "2025-01-15T18:00:00", "estado": "CERRADA"}Campos:
| Campo | Tipo | Obligatorio | Descripción | Valores |
|---|---|---|---|---|
cierre | datetime | ✅ | Timestamp de cierre | ISO 8601 (ej: 2025-01-15T18:00:00) |
estado | string | ✅ | Estado final | CERRADA (único válido para cierre) |
Comportamiento / Casos de uso:
- Cierre manual: admin cierra jornada de cajero que olvidó cerrar
- Corrección: ajustar hora de cierre si se registró mal
- Validación: verifica
require_acceso_caja— el usuario autenticado debe ser dueño de la jornada o tener rol admin
Respuesta exitosa: 200 OK — retorna JornadaCajaResponse actualizado
Response:
{ "id": 1, "usuario": "Juan Pérez", "apertura": "2025-01-15T06:00:00", "base_inicial": 500000, "cierre": "2025-01-15T18:00:00", "estado": "CERRADA", "tenant_id": "uuid-tenant"}Errores:
| Código | Causa | Solución |
|---|---|---|
| 404 | Jornada no encontrada | Verificar jornada_id |
| 403 | Sin acceso a caja del usuario | Solo dueño o admin |
| 400 | Estado inválido (no ABIERTA) | Solo jornadas ABIERTA se pueden cerrar |
| 409 | Jornada ya cerrada | No se puede cerrar dos veces |
cURL:
curl -X PUT http://localhost/api/jornada/1 \ -H "Content-Type: application/json" \ -H "Authorization: Bearer <token>" \ -d '{"cierre":"2025-01-15T18:00:00","estado":"CERRADA"}'Python:
import httpxresp = httpx.put("http://localhost/api/jornada/1", json={"cierre": "2025-01-15T18:00:00", "estado": "CERRADA"}, headers={"Authorization": f"Bearer :token"})jornada = resp.json()JavaScript:
const resp = await fetch('http://localhost/api/jornada/1', { method: 'PUT', headers: {'Content-Type': 'application/json', 'Authorization': `Bearer $:token`}, body: JSON.stringify({cierre: '2025-01-15T18:00:00', estado: 'CERRADA'})});const jornada = await resp.json();DELETE /api/jornada/:jornada_id
Descripción: Elimina (hard delete) una jornada de caja. Solo para jornadas de prueba o error de sistema (duplicada, creada por bug). NO usar para anular jornada real — eso rompe la trazabilidad de caja y cuadre. Para corregir: cerrar correctamente y registrar ajuste en egresos/ingresos.
Requiere Auth: Sí
Permiso requerido: jornadas, eliminar
Parámetros path:
| Parámetro | Tipo | Obligatorio | Descripción |
|---|---|---|---|
jornada_id | int | ✅ | ID de la jornada |
Comportamiento / Casos de uso:
- Jornada duplicada por bug de frontend (doble click apertura)
- Jornada de prueba en desarrollo
- Error de sistema que creó jornada sin base_inicial
- ADVERTENCIA: Elimina permanentemente. Si la jornada tenía caja asociada, queda huérfana.
Respuesta exitosa: 204 No Content
Errores:
| Código | Causa | Solución |
|---|---|---|
| 404 | Jornada no encontrada | Verificar jornada_id |
| 403 | Sin permiso jornadas, eliminar | Solo superadmin |
| 409 | Tiene caja asociada (cierre registrado) | No eliminar, cerrar correctamente |
cURL:
curl -X DELETE http://localhost/api/jornada/1 -H "Authorization: Bearer <token>"Python:
import httpxresp = httpx.delete("http://localhost/api/jornada/1", headers={"Authorization": f"Bearer :token"})assert resp.status_code == 204JavaScript:
const resp = await fetch('http://localhost/api/jornada/1', { method: 'DELETE', headers: {'Authorization': `Bearer $:token`}});// 204 = éxitoGET /api/jornada/activa/detalle
Descripción: Obtiene la jornada activa de un usuario
Requiere Auth: Sí
Permiso requerido: jornadas, leer
Parámetros query:
| Parámetro | Tipo | Obligatorio | Descripción |
|---|---|---|---|
usuario | string | ✅ | Nombre del usuario |
Respuesta exitosa: 200 OK
Errores: 404 (no hay jornada activa)
cURL:
curl "http://localhost/api/jornada/activa/detalle?usuario=Juan%20P%C3%A9rez" -H "Authorization: Bearer <token>"GET /api/jornada/activas/usuarios
Descripción: Lista los usuarios con jornada activa
Requiere Auth: Sí
Permiso requerido: jornadas, leer
Respuesta exitosa: 200 OK
Response:
["Juan Pérez", "María López"]cURL:
curl http://localhost/api/jornada/activas/usuarios -H "Authorization: Bearer <token>"POST /api/jornada/cerrar [NUEVO]
Descripción: Cierra la jornada activa del usuario (setea estado: "CERRADA" y cierre con timestamp actual).
Requiere Auth: Sí
Permiso requerido: jornadas, actualizar
Request:
{ "usuario": "Juan Pérez"}Respuesta exitosa: 200 OK
Errores: 404 (no hay jornada activa para el usuario)
Response:
{ "id": 1, "usuario": "Juan Pérez", "apertura": "2026-07-24T06:00:00", "base_inicial": 500000, "cierre": "2026-07-24T18:00:00", "estado": "CERRADA", "tenant_id": "uuid-tenant"}cURL:
curl -X POST http://localhost/api/jornada/cerrar \ -H "Content-Type: application/json" \ -H "Authorization: Bearer <token>" \ -d '{"usuario":"Juan Pérez"}'