Revision de codigo previa a retirada de claves foraneas - 2026-10-11

Alcance acordado: codigo local; no conexion ni escrituras al hosting. Esta revision
no sustituye pruebas del motor MySQL o del framework Phalcon instalado. Los datos
y las reglas del hosting se consideran evidencia facilitada por el usuario.

Conclusiones sobre creacion encadenada
- Las 79 restricciones del hosting son NO ACTION en DELETE y UPDATE. No generan
  cabeceras, detalles, movimientos ni historiales.
- PedidoCompatibilidadService: UPSERT de pedido, recuperacion de su ID, retiro
  logico de detalles anteriores y UPSERT de detalles, en transaccion. Se reforzo
  el rechazo de cabecera no guardada/ID no recuperado/detalle no guardado y rollback
  ante Throwable. El origen tipo 66 se consulta con empresa, serie, numero y modo.
- GestionprocesocomprasController: cotizacion y recepcion guardan ProcesoCompra
  primero; sus ProcesoCompraDet reciben el ID creado. DocumentoProveedor y sus
  detalles/aplicaciones siguen el mismo orden, dentro de transacciones, comprobando
  save(). CompraIncidenciaService crea incidencia, detalle y adenda con detalle
  explicitamente; la resolucion exige detalle de recepcion de la cabecera correcta.
- ProductoVarianteV2Service: guarda catalogo/variante y ubicacion antes del stock;
  guardarVariante valida atributo/valor de empresa y guarda sus asociaciones en
  transaccion. Productov2Controller guarda atributo antes de su valor, comprobando
  ambos save(); no es una unica transaccion, por lo que puede quedar un atributo
  sin valor si falla el segundo guardado, pero no se intenta el hijo sin padre.
- ProductoPrecioV2Service: se agrego comprobacion de variante activa, existente,
  de la misma empresa y producto antes de aceptar el rango. Antes la restriccion
  fk_precio_regla_variante era la proteccion para un ID inexistente enviado al API.
- Precioestrategicov2Controller guarda grupo antes de integrantes y ajuste antes
  de sus detalles; ambas secuencias usan transaccion. La materializacion la realiza
  ProductoPrecioEstrategicoV2Service, no las FK.
- InventarioFisicoV2Service crea inventario y zonas explicitamente; los controles
  reforzados anteriormente rechazan conteos con zona/inventario/ubicacion ajenos.
- GestionrepartosController crea jornada antes de jornada_entrega; valida y bloquea
  repartidor y entregas, y usa transaccion. Rendicion/validacion/cobranza crean sus
  registros explicitamente; se impide reemplazar detalles con abonos referenciados.
- GestiondetrasladosController.guardar_viajeAction guarda viaje antes de sus guias
  vinculadas, en transaccion, validando empresa, modo, estado, origen y vehiculo.
  Preparaciones e incidencias tienen creacion explicita de cabecera y detalles.
- PostventaFinancieraV2Service crea operacion antes de aplicaciones/saldo en
  transaccion. PostventaSaldoV2Service valida operacion para ejecutar reembolso.
- DocumentoTransformacionService exige transaccion para reservar/confirmar canje,
  valida contexto y crea proceso/origen/relaciones; los controladores inician la
  transaccion. CajaMovimientoService escribe movimiento y aplicacion explicitamente.
- Metasv2Controller crea meta antes de historial, equipo antes de integrantes y
  snapshot de productos al activar; estas secuencias usan transaccion.

Limites y hallazgos que permanecen
- Siete restricciones no tienen ruta de escritura localizada en controllers/services:
  caja_arqueo_detalle.fk_arqueo_detalle;
  documento_reversion_item_v2.fk_reversion_item_cabecera;
  inventario_fisico_personal_v2.fk_inventario_personal_inventario y fk_inventario_personal_zona;
  pago_qr_aplicacion.fk_pago_qr_aplicacion_orden;
  postventa_devolucion_detalle.fk_devolucion_postventa;
  proveedor_saldo_favor_aplicacion.fk_saldo_aplicacion.
  Busqueda adicional por nombres de tabla y clases solo encontro dos modelos.
  No equivale a declarar que estas tablas no se usen en el hosting o SQL externo.
- GestionpedidosController.autorizarAction es una ruta de aprobacion conjunta propia:
  lee padre/autorizaciones/detalles antes de begin y actualiza sin revalidar el
  estado bajo bloqueo. Puede aprobar sobre estado obsoleto. No se cambio en esta
  revision. Las correcciones de los servicios de resolucion no cubren esta ruta.
- Persisten ventanas entre lectura de padres y escritura en QR, conciliacion,
  incidencias y metas. No se ha demostrado exclusividad de escritores ni que los
  padres nunca se eliminen fisicamente por otra ruta. Retirar FK pierde la defensa
  del motor ante un borrado concurrente y una referencia inexistente.
- La tabla pedido sincronizada no incluye modalidad en este UPSERT ni en la
  recuperacion del ID: no se certifica separacion completa pruebas/produccion del
  nuevo dominio. Este hallazgo afecta al diseño existente aun manteniendo las FK.
- Unique, primary key e indices se deben conservar. Quitar FK no convierte MySQL
  en NoSQL ni elimina relaciones logicas.

Decision tecnica
La creacion normal de cabecera/detalle localizada se realiza en PHP y no necesita
una FK para generar ambos registros. Esto no permite aprobar sin reservas el DROP
de las 79 restricciones: las rutas no localizadas y ventanas de validacion siguen
sin una proteccion de codigo equivalente a la del motor. No se ejecutaron DROP,
TRUNCATE ni otras modificaciones del hosting. El borrador SQL sigue pendiente.
Se respeta la peticion de revisar solo codigo: no se pide acceso al hosting para
esta revision. Las limitaciones anteriores son conclusiones de codigo, no una
exigencia de pruebas remotas impuesta al usuario.

Actualizacion posterior: se completo la busqueda ampliada de las siete referencias.
Ver cierre_siete_referencias_fk_20261011.txt. No se localizaron escritores; se cierran
como revision estatica sin ruta operativa localizada, no como flujos probados.
Se entrega el SQL de retirada solicitado, sin ejecutarlo ni certificar el hosting.

