===== Documentación de Cambio: Control de Concurrencia y Duplicidad en Remisiones con el check de enviar a contabilidad ===== Objeto Modificado: w_remisiones_factura_ela.srw Fecha:19/03/2026 Tipo de Cambio: Mejora de Integridad de Datos / Corrección 1. Resumen del cambio Se implementó un mecanismo de validación robusto en el proceso de guardado y envío de remisiones de facturas. El objetivo es prevenir dos escenarios críticos: Duplicidad: Que un mismo documento sea incluido en múltiples remisiones activas. Colisión de Concurrencia: Que dos usuarios intenten procesar el mismo documento simultáneamente. 2. Descripción Funcional (Para Usuarios) Al momento de hacer clic en Guardar o procesar la remisión, el sistema realiza una verificación automática de cada documento en la lista: Bloqueo de Seguridad: El sistema verifica si alguien más está trabajando con alguno de los documentos seleccionados en ese preciso instante. Comportamiento: Si detecta uso simultáneo, mostrará el mensaje: "El documento [No. Factura] está siendo procesado por otro usuario en este momento. La operación será cancelada." Validación de Duplicados: El sistema busca en la base de datos si el documento ya pertenece a otra remisión que esté en proceso, enviada o aprobada (cualquier estado diferente a Rechazada o Anulada). Comportamiento: Si lo encuentra, mostrará el mensaje: "El documento [No. Factura] ya se encuentra incluido en la remisión No. [XXXX] y no puede ser agregado..." En ambos casos, la operación se detiene y no se guardan cambios hasta que se resuelva el conflicto (por ejemplo, eliminando el documento conflictivo de la lista). 3. Detalles Técnicos (Para Desarrolladores) 3.1. Estrategia de Implementación Se optó por realizar la validación en el evento ue_grabar (Commit time) en lugar de línea por línea durante la inserción. Esto garantiza que la validación sea atómica respecto a la transacción final y minimiza el tiempo de bloqueo de recursos. 3.2. Cambios en Código (w_remisiones_factura_ela.srw) Evento ue_grabar Se insertó un bloque de lógica al inicio del evento, antes de cualquier actualización de estado o commit. Lógica del Algoritmo: Iteración: Se recorre el DataWindow dw_remision_facturas_det. Identificación: Se obtiene IDENTIFICACION_FACTURA de MAE_RECEPCION_PEDIDOS para usar en mensajes de error (UX). Control de Concurrencia (FOR UPDATE NOWAIT): Se intenta bloquear el registro maestro del documento en MAE_RECEPCION_PEDIDOS. Si la BD retorna SQLDBCode = 54 (ORA-00054: resource busy), se asume concurrencia, se hace Rollback y se retorna. Control de Duplicidad: Se consulta DET_REMISION_FACTURA uniendo con MAESTRO_REMISION_FACTURA. Criterios de búsqueda: Mismo codigo_documento. Diferente codigo_remision (para excluir la actual). Estado activo (No 'J' - Rechazada, ni 'C' - Cancelada/Anulada). Si SQLCode = 0 (se encontró registro), se obtiene el consecutivo de la remisión externa, se muestra error, se hace Rollback y se retorna. Función f_inserte_documento Se mantuvo (o restauró) a su versión ligera. Solo realiza el INSERT en la tabla temporalmente sin COMMIT. La validación pesada se delega a ue_grabar. 3.3. Fragmento de Código Clave (Validación) // Control de Concurrencia: Intentar bloquear el documento origen iuo_context.of_sql_embedded_context(ts_transaccion, gd_cempresa) SELECT 1 INTO :li_dummy FROM MAE_RECEPCION_PEDIDOS WHERE CODIGO_RECEPCION = :ld_codigo_documento_actual FOR UPDATE NOWAIT USING ts_transaccion; If ts_transaccion.SQLDBCode = 54 Then // ORA-00054: recurso ocupado MessageBox("Aviso de Concurrencia", "El documento ...", Exclamation!) Rollback Using ts_transaccion; Return End If ===== Control de Duplicidad de Facturas en Elaboración de Remisiones ===== === 1. Descripción del Problema === En el módulo de presupuesto, específicamente en la ventana de Elaboración de Remisiones de Factura (w_remisiones_factura_ela), el sistema permitía seleccionar facturas que ya habían sido incluidas en remisiones previas que se encontraban en estado "Guardado" (Estado 'G' o 'Por Enviar'). Esto causaba confusión al usuario y posibles errores de integridad de datos al intentar procesar dos veces la misma factura antes de que esta fuera enviada a contabilidad. === 2. Causa Raíz (Análisis Técnico) === El objeto DataWindow g_lista_facturas_causadas.srd (utilizado por la ventana de búsqueda w_facturas_causadas) realizaba la consulta de facturas disponibles basándose únicamente en el estado del documento en la tabla DET_COMPROMISO_DOCUMENTOS (Estados 'C' o 'J'). Sin embargo, el motor de búsqueda no validaba la existencia de registros en la tabla DET_REMISION_FACTURA. Cuando un usuario guarda una remisión sin marcar la opción "Enviar a contabilidad", el registro se inserta en DET_REMISION_FACTURA, pero al no haber un filtro de exclusión en la búsqueda, la factura seguía apareciendo como "disponible". === 3. Solución Implementada === Se modificó la sentencia SQL del DataWindow g_lista_facturas_causadas.srd para incluir una cláusula NOT EXISTS. Esta cláusula excluye automáticamente cualquier factura que ya esté vinculada a una remisión activa (cualquier estado que no sea 'J' - Anulado/Rechazado). == Lógica de Filtrado: == Tablas afectadas: DET_COMPROMISO_DOCUMENTOS (A) y DET_REMISION_FACTURA (DRF). Condición de exclusión: Se excluye el documento si existe en DET_REMISION_FACTURA y su estado es distinto a 'J'. === 4. Cambios en el Código === AND NOT EXISTS ( SELECT 1 FROM DET_REMISION_FACTURA DRF WHERE DRF.CODIGO_DOCUMENTO = A.CODIGO_DOCUMENTO AND (DRF.ESTADO IS NULL OR DRF.ESTADO <> 'J') ) === Objetos Involucrados === g_lista_facturas_causadas.srd: Modificación del SQL de recuperación. w_facturas_causadas.srw: Ventana de selección que consume el DataWindow. w_remisiones_factura_ela.srw: Ventana principal de proceso ===== Resolución de Incidente: Remisiones de facturas sin detalle en pantalla de envío ===== === . Información General del Ticket === Módulo / Ruta: Presupuesto / Compromisos / Envío de remisión de facturas a contabilidad. === Falla Reportada: Remisiones de facturas sin facturas asociadas se siguen mostrando en la lista. === Impacto del Error: Las remisiones que quedaban registradas sin detalle de facturas no permitían ser enviadas, quedando bloqueadas en la pantalla de forma permanente (se evidenciaron registros estancados desde el año 2016). === 2. Análisis del Problema === En la ventana de Envío de remisión de facturas a contabilidad, la consulta principal estaba recuperando los registros directamente de la cabecera (MAESTRO_REMISION_FACTURA) basándose únicamente en los filtros de usuario, dependencia, fechas y estado. No existía una condición que verificara la integridad frente a la tabla de detalle (DET_REMISION_FACTURA). Aunque la solución esperada por la mesa de servicios sugería que el sistema "elimine" estas remisiones, a nivel de arquitectura y bases de datos es más seguro y eficiente modificar la capa de consulta para omitir estos registros huérfanos, protegiendo así la integridad referencial y el historial de la base de datos en Oracle. === 3. Solución Técnica Implementada (Desarrollo) === Se modificó la consulta principal SQL (Oracle 11g) del módulo. Para evitar la duplicidad de registros que generaría un INNER JOIN tradicional, se implementó una cláusula EXISTS en el bloque WHERE. Esta validación funciona como un semi-join, haciendo que el optimizador de Oracle evalúe si la remisión tiene al menos un registro en DET_REMISION_FACTURA. Si la remisión está vacía, simplemente se excluye del resultado que se muestra en pantalla. Fragmento del cambio en el código SQL: SQL -- (...) Consulta original WHERE B.CODIGO = '08' -- (...) Filtros de usuario y fechas AND C.CODIGO_ESTADO = A.ESTADO -- NUEVA VALIDACIÓN: Solo retorna la remisión si existe al menos un detalle asociado AND EXISTS ( SELECT 1 FROM PRESUP01.DET_REMISION_FACTURA DRF_VAL WHERE DRF_VAL.CODIGO_REMISION = A.CODIGO_REMISION ); === Desarrollado por: [Miguel Muñoz] Fecha: [28/04/2026] Versión de PB: 12.5 ===