# Arquitectura de Hoja de Distribución

El controlador conserva las rutas históricas, valida request, sesión, CSRF y
permisos. Las reglas nuevas están separadas:

- `HojaConfiguracionService`: tipos, movimiento, tiendas y columnas dinámicas.
- `HojaService`: maestro, resumen, fechas, gastos y operaciones comunes.
- `HojaValeService`: selección, precios y documento de vales por solicitud.
- `HojaVentasService`: consulta base, cuatro modalidades, periodos y EXPLAIN.
- `HojaAuditoriaService`: auditoría agrupada, detallada, individual y valores.
- `HojaExportacionService`: estado por tienda, idempotencia por token de lote,
  envío y confirmación. Sin tabla de outbox: el estado autoritativo es
  `maedoc.exportado` y el historial se lee de la bitácora.
- `HojaPermisoService`: autorización específica con denegación predeterminada.
- `DocumentoAnulacionService`: anulación no destructiva e inversos por saldo.

## Flujo de escritura

`POST → autenticación → permiso → CSRF → validación → transacción → bitácora → respuesta`.

Las columnas `Txx/Fxx` se obtienen de tiendas configuradas y se validan contra
el esquema; nunca se aceptan nombres arbitrarios del navegador. Aplicar,
reaplicar y desaplicar bloquean los registros relevantes. La reversión conserva
originales, registra `maedoc_anulado` e inserta sólo el inverso del saldo aún
activo, evitando crecimiento exponencial al repetir ciclos.

## Concurrencia

La creación usa un correlativo global de `hoja`, protegido por un bloqueo
compartido por todos los tipos de documento. `tipodoc` identifica el maestro y
la carga de productos, pero no separa la numeración. La edición usa `hoja.version`. Vales no usan
`hoja_impresion`; ventas y auditoría son consultas por solicitud. La exportación
usa una clave SHA-256 única por lote.

## Compatibilidad

El código evita sintaxis posterior a PHP 5.6 y mantiene Symfony 2.7, Doctrine
DBAL 2.5, Twig 1.x, jQuery y Bootstrap existentes. No introduce frameworks ni
dependencias nuevas.
