Appearance
Implementación Multi-Schema para Movimientos de Caja y Caja (Tesorería)
Módulo: Tesorería Tipo: Process Estado: ✅ Implementado Fecha: 2025-12-29 Fecha de Implementación: 2025-12-30
📋 Documento Arquitectural General: Sistema de Búsqueda Multi-Schema para Operaciones Transaccionales
Este documento describe la aplicación específica del sistema multi-schema al módulo de Tesorería para operaciones de consulta, eliminación y modificación en tablas transaccionales. Para entender el problema general del search_path de PostgreSQL, la solución basada en ConfigurableMigration, y los patrones arquitecturales, consulte el documento general.
Resumen
Esta es la primera implementación del sistema de búsqueda multi-schema para operaciones transaccionales (consulta, eliminación, modificación), aplicada a las tablas transaccionales del módulo de Tesorería:
- ✅
movimi(movimientos de caja) - ✅
caja(registros de apertura/cierre de caja)
El objetivo es resolver los problemas operativos cuando se necesita consultar, modificar o eliminar registros (comprobantes, movimientos) que están distribuidos en diferentes schemas según la configuración de niveles de la empresa.
Problema Específico en Tesorería
Configuración de Tablas
Tabla movimi (movimientos de caja):
- Niveles por defecto: [1, 2, 3] (Empresa, Sucursal, Caja)
- Configuración típica: [2, 3] (Sucursal y Caja)
- Descripción: Registros de entradas y salidas de efectivo
Tabla caja (registros de caja):
- Niveles por defecto: [1, 2, 3] (Empresa, Sucursal, Caja)
- Configuración típica: [3] (solo Caja)
- Descripción: Registros de apertura y cierre de caja
Escenarios Problemáticos en Tesorería
Escenario 1: Eliminación de Orden de Pago
Situación:
- Se registra una orden de pago en
suc0001caja0001 - Los movimientos de caja se guardan en
suc0001caja0001 - Un usuario de
suc0001caja0002intenta eliminar la orden de pago
Problema actual:
Usuario en: suc0001caja0002
search_path: suc0001caja0002, suc0001, public
Al buscar movimientos relacionados:
- Busca solo en suc0001caja0002 (schema actual)
- NO encuentra movimientos en suc0001caja0001
- Solo elimina la orden, dejando movimientos huérfanos ❌Solución con multi-schema:
Usuario en: suc0001caja0002
Configuración movimi: [2, 3]
Al buscar movimientos relacionados:
- Busca en: suc0001, suc0001caja0001, suc0001caja0002
- Encuentra movimientos en suc0001caja0001
- Elimina orden y TODOS los movimientos ✅Escenario 2: Registro Manual de Comprobante
Situación:
- Se registra manualmente un comprobante en
suc0001caja0001 - Los movimientos se guardan en
suc0001caja0001 - Un usuario de
suc0001caja0002necesita dar de baja el comprobante
Problema actual:
- Sistema busca movimientos solo en
suc0001caja0002 - NO encuentra movimientos en
suc0001caja0001 - Eliminación parcial (comprobante sí, movimientos no)
Solución con multi-schema:
- Sistema busca en todos los schemas de caja de la sucursal
- Encuentra y elimina todos los movimientos
- Eliminación completa sin huérfanos
Escenario 3: Comprobante a Nivel Sucursal con Movimientos a Nivel Caja
Situación:
- Empresa configura movimi con niveles [2, 3]
- Un comprobante se registra a nivel sucursal (suc0001)
- Los movimientos se registran a nivel caja (suc0001caja0001)
- Se intenta eliminar el comprobante
Problema actual:
Comprobante en: suc0001 (nivel sucursal)
search_path: suc0001, public
Al buscar movimientos:
- Busca en suc0001 y public
- NO busca en suc0001caja0001 (nivel inferior)
- Movimientos quedan huérfanos ❌Solución con multi-schema:
Comprobante en: suc0001
Configuración movimi: [2, 3]
Al buscar movimientos:
- Busca en: suc0001 Y suc0001caja0001, suc0001caja0002, etc.
- Encuentra movimientos en todos los niveles
- Eliminación completa ✅Aplicación del Sistema Multi-Schema
Tablas Involucradas
Movimiento de Caja (movimi)
Relaciones críticas:
id_comprobante+id_tipo_comprobante→ Comprobantes de venta/compra/ctacteid_ctacte→ Movimientos de cuenta corrientenrocaj/nro_caja→ Caja donde se registró
Operaciones afectadas:
- ✅ Eliminación: Al eliminar comprobante, eliminar movimientos de todos los schemas
- ✅ Consulta: Al consultar comprobante, obtener movimientos de todos los schemas
- ⚠️ Modificación: Futuro (puede agregarse posteriormente)
Caja
Relación con movimi:
- Controla el estado (abierta/cerrada) de la caja
- Si caja está cerrada → movimientos son de solo lectura
- Consistencia de schema: Si movimiento está en
suc0001caja0002, la caja debe consultarse ensuc0001caja0002
Validaciones:
- Antes de eliminar movimiento → verificar que caja esté abierta
- Si caja está cerrada → rechazar eliminación con mensaje descriptivo
Reglas de Negocio Específicas de Tesorería
RN-TES-001: Validación de estado de caja
Descripción: Antes de eliminar un movimiento de caja, verificar que la caja correspondiente esté abierta (fecha_cierre IS NULL).
Condición: Se intenta eliminar un movimiento de caja encontrado mediante búsqueda multi-schema.
Acción:
- Para cada movimiento encontrado, identificar su schema de origen
- Consultar el estado de la caja EN EL MISMO SCHEMA (RA-003)
- Si la caja está cerrada → rechazar eliminación completa
- Si todas las cajas están abiertas → proceder con eliminación
Mensaje de error:
"No se puede eliminar: existen movimientos en caja cerrada (caja {nrocaj} del schema {schema})"RN-TES-002: Consistencia movimiento-caja
Descripción: Un movimiento y su caja siempre deben consultarse del mismo schema para garantizar consistencia.
Ejemplo:
sql
-- Movimiento encontrado en suc0001caja0002
-- ✅ CORRECTO - consultar caja en el mismo schema
SET search_path TO suc0001caja0002, suc0001, public;
SELECT * FROM caja WHERE fecha_cierre IS NULL;
-- ❌ INCORRECTO - consultar caja en schema actual del usuario
SET search_path TO suc0001caja0001, suc0001, public;
SELECT * FROM caja WHERE fecha_cierre IS NULL;RN-TES-003: Alcance de búsqueda por sucursal
Descripción: La búsqueda de movimientos de caja solo incluye schemas de la sucursal actual del usuario.
Ejemplo:
Usuario en: suc0001caja0001
Configuración movimi: [2, 3]
Schemas a buscar:
- suc0001 (nivel sucursal)
- suc0001caja0001, suc0001caja0002, suc0001caja0003, ... (nivel caja)
NO buscar en:
- suc0002, suc0003 (otras sucursales)
- suc0002caja0001, etc. (cajas de otras sucursales)Casos de Uso Específicos
UC-TES-001: Eliminar orden de pago con movimientos en otra caja
Actor: Usuario de tesorería desde caja0002
Objetivo: Eliminar una orden de pago registrada en caja0001
Precondiciones:
- Usuario autenticado con permisos de eliminación en la sucursal
- Orden de pago registrada en suc0001caja0001 con movimientos
- Tabla
movimiconfigurada con niveles [2, 3] - Caja0001 está abierta
Flujo principal:
- Usuario busca la orden de pago por número
- Sistema ejecuta búsqueda multi-schema (RA-001):
- Consulta configuración de movimi → [2, 3]
- Genera schemas: suc0001, suc0001caja0001, suc0001caja0002
- Sistema encuentra orden en suc0001caja0001
- Usuario selecciona eliminar
- Sistema busca movimientos relacionados en todos los schemas
- Sistema encuentra movimientos en suc0001caja0001
- Sistema consulta estado de caja en suc0001caja0001 (RN-TES-001, RA-003)
- Caja está abierta → validación OK
- Sistema inicia transacción atómica
- Sistema elimina movimientos de suc0001caja0001
- Sistema elimina orden de pago
- Sistema confirma transacción
- Sistema audita operación con schemas afectados
Postcondiciones:
- Orden de pago eliminada
- Movimientos eliminados de todos los schemas
- Sin datos huérfanos
- Operación auditada
Flujos alternativos:
- Caja cerrada: Sistema muestra error y cancela operación
- Error en eliminación: Rollback completo de todos los schemas
UC-TES-002: Eliminar comprobante manual con validación de caja
Actor: Usuario de caja0001
Objetivo: Eliminar comprobante registrado manualmente que tiene movimientos en múltiples schemas
Precondiciones:
- Comprobante registrado con movimientos en suc0001 y suc0001caja0001
- Configuración movimi: [2, 3]
Flujo principal:
- Usuario selecciona comprobante a eliminar
- Sistema confirma eliminación
- Sistema determina schemas relevantes (RA-001):
- suc0001 (nivel sucursal)
- suc0001caja0001, suc0001caja0002 (nivel caja)
- Sistema busca movimientos en todos los schemas
- Sistema encuentra:
- 2 movimientos en suc0001
- 1 movimiento en suc0001caja0001
- Para movimiento en suc0001caja0001:
- Consulta caja en suc0001caja0001 (RN-TES-002)
- Verifica estado → abierta
- Sistema inicia transacción
- Elimina movimientos de suc0001
- Elimina movimiento de suc0001caja0001
- Elimina comprobante
- Confirma transacción
Postcondiciones:
- Comprobante y todos los movimientos eliminados
- Sin registros huérfanos
- Auditoría completa
UC-TES-003: Rechazo por caja cerrada en otro schema
Actor: Usuario de caja0002
Objetivo: Intentar eliminar comprobante con movimientos en caja cerrada de otro schema
Precondiciones:
- Comprobante con movimientos en suc0001caja0001
- Caja0001 está cerrada (fecha_cierre NOT NULL)
- Usuario opera desde caja0002
Flujo principal:
- Usuario selecciona comprobante a eliminar
- Sistema busca movimientos en todos los schemas
- Sistema encuentra movimiento en suc0001caja0001
- Sistema consulta caja en suc0001caja0001 (RN-TES-002)
- Detecta fecha_cierre NOT NULL → caja cerrada
- Sistema rechaza operación (RN-TES-001)
- Sistema muestra mensaje: "No se puede eliminar: existen movimientos en caja cerrada (caja 1 del schema suc0001caja0001)"
Postcondiciones:
- Operación cancelada
- Datos sin cambios
- Intento registrado en auditoría
Configuración Recomendada
Configuración Típica por Tipo de Empresa
Empresa con operación centralizada:
json
{
"movimi": [2], // Solo nivel sucursal
"caja": [2] // Solo nivel sucursal
}Una caja por sucursal, datos consolidados
Empresa con múltiples cajas por sucursal:
json
{
"movimi": [3], // Solo nivel caja
"caja": [3] // Solo nivel caja
}Control granular por caja, segregación máxima
Empresa mixta (recomendado):
json
{
"movimi": [2, 3], // Sucursal y caja
"caja": [3] // Solo caja
}Flexibilidad para movimientos a nivel sucursal y caja
Comando de Configuración
bash
# Ver configuración actual
php manage-table-levels.php --show --database=mi_empresa
# Configurar movimi en niveles Sucursal y Caja
php manage-table-levels.php --set --database=mi_empresa --table=movimi --levels=2,3
# Configurar caja solo en nivel Caja
php manage-table-levels.php --set --database=mi_empresa --table=caja --levels=3Criterios de Aceptación Específicos
Movimientos de Caja
- [x] AC-TES-001: Al eliminar un comprobante, se eliminan todos los movimientos de caja relacionados de todos los schemas según configuración de niveles ✅
- [x] AC-TES-002: La eliminación valida que todas las cajas donde hay movimientos estén abiertas ✅
- [x] AC-TES-003: Si alguna caja está cerrada, la eliminación se rechaza con mensaje descriptivo indicando el schema ✅
- [x] AC-TES-004: Al consultar un movimiento en un schema, la caja se consulta en el mismo schema (consistencia) ✅
Caja
- [x] AC-TES-005: El estado de la caja (abierta/cerrada) se verifica en el schema correcto del movimiento ✅
- [x] AC-TES-006: Los movimientos de cajas cerradas son de solo lectura (no se pueden eliminar) ✅
Transaccionalidad
- [x] AC-TES-007: Las eliminaciones que afectan múltiples schemas son atómicas ✅
- [x] AC-TES-008: Si falla la eliminación en algún schema, se revierten todos los cambios ✅
Auditoría
- [x] AC-TES-009: Las operaciones multi-schema registran todos los schemas consultados y afectados ✅
- [x] AC-TES-010: Los rechazos por caja cerrada quedan registrados en auditoría ✅
Impacto en Frontend
IMPORTANTE: La implementación multi-schema es completamente transparente para el frontend de tesorería. No requiere cambios visuales, de componentes, ni de interfaz de usuario.
Sin Cambios Requeridos
- Formularios de órdenes de pago: Sin cambios
- Gestión de comprobantes: Sin cambios
- Botones de eliminación: Sin cambios
- Confirmaciones: Sin cambios
- Mensajes de éxito: Sin cambios
Mensajes Mejorados (Opcional)
Mensaje de error mejorado:
Antes: "No se puede eliminar el comprobante"
Ahora: "No se puede eliminar: existen movimientos en caja cerrada (caja 1 del schema suc0001caja0001)"Proporciona más contexto para el usuario sin requerir cambios de interfaz
Extensión Futura
Tabla iteban (Movimientos Bancarios)
Estado: Pendiente
Configuración esperada:
json
{
"iteban": [1, 2] // Niveles Empresa y Sucursal
}Casos de uso similares:
- Eliminar comprobante con movimientos bancarios en múltiples schemas
- Validar estado de cuenta bancaria
Implementación:
- Seguir mismo patrón que movimi
- Agregar reglas de negocio específicas para cuentas bancarias
- No requiere cambios en infraestructura base (RA-005)
Referencias
Documentación Arquitectural
- Sistema Multi-Schema para Operaciones Transaccionales - Documento arquitectural completo
Documentación Técnica
- ConfigurableMigration:
/server/migrations/migrations/ConfigurableMigration.php - Migración movimi:
/server/migrations/migrations/tenancy/20240823200758_new_table_movimi.php - Migración caja:
/server/migrations/migrations/tenancy/20240917132424_newtable_caja.php
Código Relacionado
- MovimientoCaja Model:
/server/models/modulo-tesoreria/MovimientoCaja.php - MovimientoCajaService:
/server/service/Tesoreria/MovimientoCajaService.php - Caja Model:
/server/models/modulo-tesoreria/Caja.php
Historial de Cambios
| Fecha | Versión | Autor | Descripción |
|---|---|---|---|
| 2025-12-30 | 3.0 | Sistema | Implementación completa con tests comprehensivos. Actualización de estado a Implementado. |
| 2025-12-29 | 2.1 | Sistema | Corrección de enfoque: el sistema es para TODAS las operaciones transaccionales (consulta, eliminación, modificación), no solo eliminación. Consulta es tan prioritaria como eliminación. |
| 2025-12-29 | 2.0 | Sistema | Reestructuración como documento específico de tesorería. Referencia al documento arquitectural general. Enfoque en aplicación concreta a movimi y caja con casos de uso específicos del módulo. |
| 2025-12-29 | 1.0 | Sistema | Versión inicial combinada (general + específica). |