Visión General
El módulo de Caja permite gestionar el efectivo y otros métodos de pago en punto de venta, con flujos completos de apertura, movimientos, arqueo y cierre de caja.
El sistema soporta múltiples cajas por empresa con control granular de permisos por usuario.
Arquitectura del Módulo
Servicios Core
El módulo de caja utiliza tres servicios principales con interfaces:
public function __construct (
private readonly CajaServiceInterface $cajaService ,
private readonly CajaSesionServiceInterface $sesionService ,
private readonly CajaArqueoServiceInterface $arqueoService ,
) {}
CajaService CRUD de cajas
Validaciones
Activación/Desactivación
CajaSesionService Apertura de sesión
Cierre de sesión
Validación de estados
CajaArqueoService Cálculo de arqueo
Resumen por método de pago
Diferencias teoría vs real
Modelo de Datos
Tabla cajas
protected $fillable = [
'id_empresa' ,
'nombre' ,
'descripcion' ,
'id_responsable' , // Usuario responsable de la caja
'id_usuario' , // Usuario que abrió la sesión actual
'id_usuario_cierre' , // Usuario que cerró
'id_usuario_validacion' , // Usuario que validó el cierre
'fecha_apertura' ,
'fecha_cierre' ,
'fecha_autorizacion_cierre' ,
'saldo_inicial' , // Monto inicial al abrir
'tipo_apertura' , // normal, especial, etc.
'total_teorico' , // Calculado: inicial + ingresos - egresos
'total_real' , // Conteo físico al cerrar
'diferencia' , // total_real - total_teorico
'tipo_cierre' ,
'tipo_diferencia' , // sobrante, faltante, exacto
'estado' , // activa, inactiva, cerrada
'observaciones' ,
'observaciones_cierre' ,
];
Estados de Caja
enum CajaEstadoEnum : string
{
case Activa = 'activa' ; // Caja abierta y operativa
case Inactiva = 'inactiva' ; // Caja cerrada temporalmente
case Cerrada = 'cerrada' ; // Sesión cerrada (requiere nueva apertura)
}
API Endpoints
Crear Caja
Request:
{
"nombre" : "Caja Principal" ,
"descripcion" : "Caja para ventas mostrador" ,
"id_responsable" : 5 ,
"metodos_pago" : [ 1 , 2 , 3 , 7 ] // IDs de métodos de pago habilitados
}
Apertura de Caja
POST / api / cajas / { id } / abrir
Request:
{
"saldo_inicial" : 200.00 ,
"tipo_apertura" : "normal" ,
"observaciones" : "Apertura turno mañana" ,
"billetes" : [
{ "denominacion" : 200 , "cantidad" : 1 },
{ "denominacion" : 100 , "cantidad" : 0 },
{ "denominacion" : 50 , "cantidad" : 0 },
{ "denominacion" : 20 , "cantidad" : 0 },
{ "denominacion" : 10 , "cantidad" : 0 }
]
}
No se puede abrir una caja que ya tiene una sesión activa. Debe cerrarse primero.
Registrar Movimiento
POST / api / cajas / { id } / movimientos
Request:
{
"tipo" : "Ingreso" , // Ingreso | Egreso
"monto" : 50.00 ,
"concepto" : "Gastos varios" ,
"descripcion" : "Compra de útiles de oficina"
}
Validación:
if ( $caja -> estado !== CajaEstadoEnum :: Activa -> value ) {
return $this -> unprocessable ( 'La caja no está activa.' );
}
Obtener Resumen de Arqueo
GET / api / cajas / { id } / resumen
Respuesta:
{
"saldo_inicial" : "200.00" ,
"total_ingresos" : "1850.00" ,
"total_egresos" : "120.00" ,
"saldo_teorico" : "1930.00" ,
"saldo_real" : "1925.00" ,
"diferencia" : "-5.00" ,
"ventas_por_metodo" : [
{
"metodo" : "Efectivo" ,
"cantidad" : 15 ,
"monto_total" : "850.00"
},
{
"metodo" : "Yape" ,
"cantidad" : 8 ,
"monto_total" : "450.00"
},
{
"metodo" : "POS Visa" ,
"cantidad" : 12 ,
"monto_total" : "550.00"
}
]
}
Obtener Caja Activa
Retorna la caja activa de la empresa del usuario autenticado.
Cálculo de Saldo Teórico
El saldo teórico se calcula dinámicamente:
public function calcularSaldoTeorico () : float
{
$ingresos = $this -> movimientos () -> where ( 'tipo' , 'Ingreso' ) -> sum ( 'monto' );
$egresos = $this -> movimientos () -> where ( 'tipo' , 'Egreso' ) -> sum ( 'monto' );
return ( float ) $this -> saldo_inicial + $ingresos - $egresos ;
}
Los ingresos por ventas se registran automáticamente al confirmar una venta en el sistema.
Relaciones de Base de Datos
Relación con Métodos de Pago
public function metodosPago ()
{
return $this -> belongsToMany (
MetodoPago :: class ,
'caja_metodos_pago' ,
'id_caja' ,
'id_metodo_pago'
)
-> withPivot ( 'activo' )
-> withTimestamps ();
}
Permite definir qué métodos de pago acepta cada caja (Efectivo, Yape, POS, Transferencia, etc.).
Permisos Granulares
La tabla permisos_caja define permisos específicos por usuario:
GET / api / cajas / permisos / { usuario_id }
Permisos disponibles:
puede_abrir_caja
puede_cerrar_caja
puede_autorizar_cierre
puede_rechazar_cierre
puede_registrar_movimientos
puede_ver_reportes
Estos permisos son independientes del sistema de roles general. Permiten control fino sobre quién puede hacer qué en las cajas.
Actualizar permisos:
PUT / api / cajas / permisos / { usuario_id }
{
"puede_abrir_caja" : true ,
"puede_cerrar_caja" : false ,
"puede_autorizar_cierre" : false ,
"puede_rechazar_cierre" : false ,
"puede_registrar_movimientos" : true ,
"puede_ver_reportes" : true
}
Auditoría
Todos los eventos importantes se registran en auditorias_caja:
GET / api / cajas / { id } / auditoria
Eventos auditados:
Apertura de caja
Cierre de caja
Modificación de saldo inicial
Autorización/Rechazo de cierre
Cambios de estado
Integración con Frontend
Componentes ubicados en:
resources/js/components/Finanzas/Caja/
├── page.jsx # Vista principal
├── AperturaCajaModal.jsx # Modal de apertura
├── CierreModal.jsx # Modal de cierre
├── ArqueoModal.jsx # Modal de arqueo
└── hooks/
├── useCajaActiva.js
├── useAbrirCaja.js
└── useArqueo.js
Ejemplo de uso:
import { useCajaActiva , useAbrirCaja } from './hooks' ;
const { data : cajaActiva } = useCajaActiva ();
const abrirMutation = useAbrirCaja ();
const handleAbrir = ( datos ) => {
abrirMutation . mutate ({
id: cajaId ,
saldo_inicial: datos . saldo_inicial ,
billetes: datos . billetes ,
});
};
Flujo de Trabajo Típico
Crear Caja
Administrador crea una nueva caja y asigna un responsable
Configurar Permisos
Definir qué usuarios pueden abrir, cerrar y operar la caja
Apertura Diaria
Usuario con permiso abre la caja, registra saldo inicial y billetes
Operaciones
Registro de ventas automático, movimientos manuales (ingresos/egresos)
Arqueo
Consultar resumen en tiempo real: saldo teórico vs ventas por método
Cierre
Contar efectivo real, registrar diferencias, solicitar autorización si aplica
Use GET /api/cajas/denominaciones para obtener la lista de billetes y monedas peruanas para el conteo de apertura/cierre.