# Interfaces de Inventario

Este modulo migra las opciones `codigosNuevos` y `cargarFacturas` de `frmMenu.frm` a Symfony 2.7/PHP 5.6.

## Puesta en marcha

1. Desplegar el codigo y limpiar la cache de Symfony con el PHP 5.6 de la instalacion.
2. Ejecutar `docs/sql/interfaz_inventario_log.sql` con un usuario autorizado. El servicio tambien intenta crear estas tablas de forma idempotente para conservar compatibilidad con instalaciones existentes.
3. En Usuarios > Accesos asignar, segun corresponda:
   - `interfaz_inventario_ver`
   - `interfaz_inventario_nuevos_plu`
   - `interfaz_inventario_cargar_factura`
   - `interfaz_inventario_configurar`
4. Abrir Procesos > Interfaces de Inventario > Configuracion, probar la conexion y guardarla.

La configuracion se guarda en `parametros_globales.ODBCCentral` con el formato completo esperado por VB6. La aplicacion web nunca devuelve la contrasena al navegador ni la incluye en la bitacora.

## Reglas operativas

- La consulta de PLU es una vista previa. Cada PLU nuevo se copia en su propia transaccion con sus filas completas de `maeplu`, `detuni`, `detplu` y catalogos relacionados. Los registros existentes no se reemplazan.
- La carga de factura se vuelve a consultar y se compara antes de confirmar. Cabecera, detalles, costos, `detuni`, `detpro` y `maeplu` se escriben en una sola transaccion remota. La bitacora local conserva por PLU los valores anteriores y posteriores de costo/proveedor.
- Antes de escribir se exige que las tablas modificadas sean InnoDB. Un error provoca rollback y queda registrado localmente.
- Las facturas repetidas se detectan por `facserie` y `facnumero`; un bloqueo MySQL breve serializa las importaciones para proteger en conjunto la referencia y la generacion de correlativos, incluso en versiones antiguas de MySQL con un solo bloqueo nombrado por conexion.
- La copia de cada PLU usa un bloqueo nombrado propio antes de volver a comprobar su existencia; solicitudes concurrentes se vuelven omisiones idempotentes en vez de duplicados o errores de llave.
- Los productos con series solicitan y validan exactamente una serie por unidad, rechazan duplicados y crean `detser` dentro de la misma transaccion. Las formulas se rechazan antes de escribir porque VB6 puede abrir una captura adicional de lotes y esa distribucion no se puede inferir de la factura.
- Como `clsDocumento.Nuevo`, la compra usa la fecha actual del servidor remoto para bloqueos, fisicos y cierres; la fecha de emision local se conserva sin sustituirla en `facfecha`.
- La validacion de fisicos incluye tanto el ultimo fisico total de la bodega como el ultimo fisico selectivo de cada PLU, equivalente a `revisarFechas` y `ultimoFisicoPLU`.

## Diferencias justificadas respecto de VB6

VB6 usa `REPLACE INTO` al copiar catalogos. En web se consulta la llave y se inserta solo si no existe, porque `REPLACE` elimina y recrea filas y puede sobrescribir cambios validos del inventario central. Los IDs autoincrementales se dejan generar en el destino; las demas columnas compatibles se copian completas.

La interfaz tampoco crea ni altera tablas operativas del inventario remoto. `sincronizarEstructuras` de VB6 solo intentaba crear `maepro`; en web la prueba de conexion exige toda la estructura antes de habilitar escrituras para evitar crear esquemas incompletos con credenciales de operacion.

VB6 puede dejar una compra parcial si falla una linea. La version web exige tablas transaccionales y revierte la compra completa.

## Verificacion rapida

La prueba independiente y compatible con PHP 5.6 para el parser ODBC, enmascaramiento y clasificacion de errores se ejecuta con:

```bash
php tests/legacy/interfaz_inventario_connection_test.php
php tests/legacy/interfaz_inventario_transaction_test.php
```

Para validar la integracion deben probarse en una base de ensayo: conexion incorrecta, tablas faltantes, PLU existente, PLU con catalogo faltante, factura con PLU faltante, factura repetida y un error inducido a mitad de transaccion.

## Flujo manual recomendado

1. Asignar solo `interfaz_inventario_ver` y comprobar que se muestre el resumen, pero no las acciones restringidas.
2. Asignar configuracion, probar credenciales incorrectas y verificar el error y la bitacora; luego probar y guardar una conexion valida.
3. Consultar Nuevos PLU desde ambos origenes. Confirmar que la vista previa no altere el destino y que identifique existentes e inconsistencias.
4. Procesar un lote pequeno y comparar las filas completas de las diez tablas. Inducir un error en `detuni` en una base de ensayo y confirmar que el PLU no quede en `maeplu`.
5. Consultar una factura con un PLU faltante y usar el enlace a Nuevos PLU. Reconsultar cuando el catalogo ya este completo.
6. Seleccionar proveedor local, bodega y documento remotos; validar y confirmar. Comparar `maedoc`, `detmov`, `detuni`, `detpro` y `maeplu`.
7. Reintentar la misma factura y confirmar que se rechace como duplicada. Revisar usuario, IP, destino, cantidades y errores en Historial.

## Mapeo de VB6

| VB6 | Equivalente web |
| --- | --- |
| `mnuInventarios_Click` | `InterfazInventarioController::indexAction` y tarjetas Twig |
| `codigosNuevos` | `InterfazInventario::previewNewProducts`, `copyProduct` y acciones AJAX por lote |
| `sincronizarEstructuras` | validacion previa de estructura en `InterfazInventarioConnection`; no ejecuta DDL remoto |
| `SQLCopiarSinRevisar` | `insertCompatibleRow` y `copyRows`, sin IDs autoincrementales ni reemplazos destructivos |
| `cargarFacturas` | `previewInvoice`, `validateInvoiceDestination` e `importInvoice` |
| `clsDocumento.Nuevo/getProximo` | `nextDocument`, cabecera remota y bloqueo nombrado de correlativo |
| `clsDocumento.grabarDetalle` | insercion de `detmov`, calculos, actualizaciones y verificacion dentro de una transaccion |

La captura de series de `frmSeries` se migro al formulario de validacion. La distribucion de lotes de formulas de `frmLotes` no puede inferirse de una factura; esos productos se detectan y bloquean antes de escribir y requieren una pantalla especializada con datos adicionales.

Los tipos de documento con `pidecliente='S'` tambien se bloquean antes de escribir. `clsDocumento.Nuevo` abre una captura interactiva de `maecli`, pero el flujo solicitado para esta interfaz solo define proveedor, bodega y tipo de compra; admitirlos sin seleccionar cliente crearia una cabecera incompleta.

La notificacion de disponibilidad de `nohayAvisar` no se envia desde este modulo. Esa rutina VB6 depende de `parametros_nohay` y de un servicio SAM externo (`api_sam_path`) cuya autenticacion y contrato no estan implementados en MBBackOffice. La compra y su bitacora quedan correctas, pero esa integracion de correo requiere un trabajo separado antes de actualizar estados de `nohay_detalle`.
