From 913d7581d443d60e637dd45042d774560a1cd038 Mon Sep 17 00:00:00 2001 From: nicolasarana <90768149+nicolasarana@users.noreply.github.com> Date: Wed, 7 Jan 2026 11:31:20 -0300 Subject: [PATCH 1/3] feat(RUP):"Guardar datos de auditoria por registro" --- modules/rup/routes/prestacion.ts | 141 +++++++++++++++++++++++++++++- modules/rup/schemas/prestacion.ts | 11 +++ 2 files changed, 149 insertions(+), 3 deletions(-) diff --git a/modules/rup/routes/prestacion.ts b/modules/rup/routes/prestacion.ts index 0a9d5d490a..bc3d034a1c 100755 --- a/modules/rup/routes/prestacion.ts +++ b/modules/rup/routes/prestacion.ts @@ -583,6 +583,111 @@ router.post('/prestaciones', async (req, res, next) => { } }); +/** + * Mergea registros nuevos con existentes, preservando datos de auditoría + * + * @param registrosExistentes - Registros actuales en la base de datos + * @param registrosNuevos - Registros que vienen en el request + * @returns Registros mergeados con auditoría preservada + */ +function mergeRegistrosPreservandoAuditoria(registrosExistentes: any[], registrosNuevos: any[]): any[] { + if (!registrosExistentes || registrosExistentes.length === 0) { + // Si no hay registros existentes, retornamos los nuevos tal cual + return registrosNuevos; + } + + if (!registrosNuevos || registrosNuevos.length === 0) { + // Si no hay registros nuevos, mantenemos los existentes + return registrosExistentes; + } + + // Crear un mapa de registros existentes por _id para búsqueda rápida + const registrosExistentesMap = new Map(); + registrosExistentes.forEach(reg => { + if (reg._id) { + registrosExistentesMap.set(reg._id.toString(), reg); + } + }); + + // Procesar los registros nuevos + const registrosMergeados = registrosNuevos.map(regNuevo => { + const idNuevo = regNuevo._id ? regNuevo._id.toString() : null; + + // Si el registro nuevo tiene _id y existe en los registros actuales + if (idNuevo && registrosExistentesMap.has(idNuevo)) { + const regExistente = registrosExistentesMap.get(idNuevo); + + // Preservar datos de auditoría del registro existente + const registroMergeado = { + ...regNuevo, + createdAt: regExistente.createdAt, + createdBy: regExistente.createdBy, + // updatedAt y updatedBy serán actualizados por el AuditPlugin automáticamente + }; + + // Si el registro tiene registros anidados (secciones), mergear recursivamente + if (regNuevo.registros && regNuevo.registros.length > 0) { + registroMergeado.registros = mergeRegistrosPreservandoAuditoria( + regExistente.registros || [], + regNuevo.registros + ); + } + + return registroMergeado; + } else { + // Es un registro completamente nuevo, no tiene datos de auditoría previos + // El AuditPlugin de Mongoose agregará createdAt/createdBy automáticamente + + // Si tiene registros anidados y alguno podría ser existente, procesarlos también + if (regNuevo.registros && regNuevo.registros.length > 0) { + const registrosAnidadosExistentes = []; + // Intentar encontrar registros anidados existentes en todos los registros existentes + registrosExistentes.forEach(regEx => { + if (regEx.registros && regEx.registros.length > 0) { + registrosAnidadosExistentes.push(...regEx.registros); + } + }); + + regNuevo.registros = mergeRegistrosPreservandoAuditoria( + registrosAnidadosExistentes, + regNuevo.registros + ); + } + + return regNuevo; + } + }); + + return registrosMergeados; +} + +/** + * Actualiza la lista de profesionales que han registrado en esta prestación + * + * @param prestacion - Prestación a actualizar + * @param profesional - Profesional actual que está registrando + */ +function actualizarProfesionalesQueRegistran(prestacion: any, profesional: any) { + if (!prestacion.profesionalesQueRegistran) { + prestacion.profesionalesQueRegistran = []; + } + + // Verificar si el profesional ya está en la lista + const yaExiste = prestacion.profesionalesQueRegistran.some( + (prof: any) => prof.id && prof.id.toString() === profesional.id.toString() + ); + + if (!yaExiste) { + prestacion.profesionalesQueRegistran.push({ + id: profesional.id, + nombreCompleto: profesional.nombreCompleto, + nombre: profesional.nombre, + apellido: profesional.apellido, + documento: profesional.documento + }); + } +} + router.patch('/prestaciones/:id', (req: Request, res, next) => { Prestacion.findById(req.params.id, async (err, data: any) => { if (err) { @@ -638,7 +743,17 @@ router.patch('/prestaciones/:id', (req: Request, res, next) => { } } if (req.body.registros) { - data.ejecucion.registros = req.body.registros; + // Usar merge para preservar datos de auditoría de registros existentes + data.ejecucion.registros = mergeRegistrosPreservandoAuditoria( + data.ejecucion.registros, + req.body.registros + ); + + // Actualizar lista de profesionales que registran + const profesionalQueRegistra = Auth.getProfesional(req); + if (profesionalQueRegistra) { + actualizarProfesionalesQueRegistran(data, profesionalQueRegistra); + } } if (req.body.ejecucion?.fecha) { data.ejecucion.fecha = req.body.ejecucion.fecha; @@ -677,7 +792,17 @@ router.patch('/prestaciones/:id', (req: Request, res, next) => { break; case 'registros': if (req.body.registros && data.estadoActual.tipo !== 'validada') { - data.ejecucion.registros = req.body.registros; + // Usar merge para preservar datos de auditoría de registros existentes + data.ejecucion.registros = mergeRegistrosPreservandoAuditoria( + data.ejecucion.registros, + req.body.registros + ); + + // Actualizar lista de profesionales que registran + const profesionalQueRegistra = Auth.getProfesional(req); + if (profesionalQueRegistra) { + actualizarProfesionalesQueRegistran(data, profesionalQueRegistra); + } if (req.body.solicitud) { data.solicitud = req.body.solicitud; @@ -754,7 +879,17 @@ router.patch('/prestaciones/:id', (req: Request, res, next) => { break; case 'periodosCensables': data.periodosCensables = req.body.periodosCensables; - data.ejecucion.registros = req.body.registros; + // Usar merge para preservar datos de auditoría de registros existentes + data.ejecucion.registros = mergeRegistrosPreservandoAuditoria( + data.ejecucion.registros, + req.body.registros + ); + + // Actualizar lista de profesionales que registran + const profesionalActual = Auth.getProfesional(req); + if (profesionalActual) { + actualizarProfesionalesQueRegistran(data, profesionalActual); + } break; default: return next(500); diff --git a/modules/rup/schemas/prestacion.ts b/modules/rup/schemas/prestacion.ts index 4b45a514a4..4b247ea171 100644 --- a/modules/rup/schemas/prestacion.ts +++ b/modules/rup/schemas/prestacion.ts @@ -167,6 +167,17 @@ export const PrestacionSchema = new Schema({ elementoRUP: SchemaTypes.ObjectId }, + + profesionalesQueRegistran: [ + { + _id: false, + id: Schema.Types.ObjectId, + nombreCompleto: String, + nombre: String, + apellido: String, + documento: Number + } + ], tags: Schema.Types.Mixed, // Historia de estado de la prestación estados: [PrestacionEstadoSchema], From 3f0145c6c1e22b8fb21a4d3e8ba2b37395b88022 Mon Sep 17 00:00:00 2001 From: nicolasarana <90768149+nicolasarana@users.noreply.github.com> Date: Wed, 7 Jan 2026 11:31:20 -0300 Subject: [PATCH 2/3] feat(RUP):"Guardar datos de auditoria por registro" --- modules/rup/routes/prestacion.ts | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/modules/rup/routes/prestacion.ts b/modules/rup/routes/prestacion.ts index bc3d034a1c..e0bd632dbc 100755 --- a/modules/rup/routes/prestacion.ts +++ b/modules/rup/routes/prestacion.ts @@ -592,16 +592,13 @@ router.post('/prestaciones', async (req, res, next) => { */ function mergeRegistrosPreservandoAuditoria(registrosExistentes: any[], registrosNuevos: any[]): any[] { if (!registrosExistentes || registrosExistentes.length === 0) { - // Si no hay registros existentes, retornamos los nuevos tal cual return registrosNuevos; } if (!registrosNuevos || registrosNuevos.length === 0) { - // Si no hay registros nuevos, mantenemos los existentes return registrosExistentes; } - // Crear un mapa de registros existentes por _id para búsqueda rápida const registrosExistentesMap = new Map(); registrosExistentes.forEach(reg => { if (reg._id) { @@ -609,23 +606,18 @@ function mergeRegistrosPreservandoAuditoria(registrosExistentes: any[], registro } }); - // Procesar los registros nuevos const registrosMergeados = registrosNuevos.map(regNuevo => { const idNuevo = regNuevo._id ? regNuevo._id.toString() : null; - // Si el registro nuevo tiene _id y existe en los registros actuales if (idNuevo && registrosExistentesMap.has(idNuevo)) { const regExistente = registrosExistentesMap.get(idNuevo); - // Preservar datos de auditoría del registro existente const registroMergeado = { ...regNuevo, createdAt: regExistente.createdAt, createdBy: regExistente.createdBy, - // updatedAt y updatedBy serán actualizados por el AuditPlugin automáticamente }; - // Si el registro tiene registros anidados (secciones), mergear recursivamente if (regNuevo.registros && regNuevo.registros.length > 0) { registroMergeado.registros = mergeRegistrosPreservandoAuditoria( regExistente.registros || [], @@ -635,13 +627,8 @@ function mergeRegistrosPreservandoAuditoria(registrosExistentes: any[], registro return registroMergeado; } else { - // Es un registro completamente nuevo, no tiene datos de auditoría previos - // El AuditPlugin de Mongoose agregará createdAt/createdBy automáticamente - - // Si tiene registros anidados y alguno podría ser existente, procesarlos también if (regNuevo.registros && regNuevo.registros.length > 0) { const registrosAnidadosExistentes = []; - // Intentar encontrar registros anidados existentes en todos los registros existentes registrosExistentes.forEach(regEx => { if (regEx.registros && regEx.registros.length > 0) { registrosAnidadosExistentes.push(...regEx.registros); @@ -672,7 +659,6 @@ function actualizarProfesionalesQueRegistran(prestacion: any, profesional: any) prestacion.profesionalesQueRegistran = []; } - // Verificar si el profesional ya está en la lista const yaExiste = prestacion.profesionalesQueRegistran.some( (prof: any) => prof.id && prof.id.toString() === profesional.id.toString() ); From 19ce95aa1224c7b11eb55bde99f28af0399d240f Mon Sep 17 00:00:00 2001 From: nicolasarana <90768149+nicolasarana@users.noreply.github.com> Date: Wed, 28 Jan 2026 11:04:50 -0300 Subject: [PATCH 3/3] feat(RUP):"Arreglos en la funcionalidad" --- modules/rup/routes/prestacion.ts | 101 +++++++++++++++--------------- modules/rup/schemas/prestacion.ts | 2 +- 2 files changed, 52 insertions(+), 51 deletions(-) diff --git a/modules/rup/routes/prestacion.ts b/modules/rup/routes/prestacion.ts index e0bd632dbc..626eb96664 100755 --- a/modules/rup/routes/prestacion.ts +++ b/modules/rup/routes/prestacion.ts @@ -590,62 +590,63 @@ router.post('/prestaciones', async (req, res, next) => { * @param registrosNuevos - Registros que vienen en el request * @returns Registros mergeados con auditoría preservada */ -function mergeRegistrosPreservandoAuditoria(registrosExistentes: any[], registrosNuevos: any[]): any[] { - if (!registrosExistentes || registrosExistentes.length === 0) { + +function mergeRegistrosPreservandoAuditoria( + registrosExistentes: any[], + registrosNuevos: any[] +): any[] { + if (!registrosExistentes?.length) { return registrosNuevos; } - - if (!registrosNuevos || registrosNuevos.length === 0) { + if (!registrosNuevos?.length) { return registrosExistentes; } - const registrosExistentesMap = new Map(); - registrosExistentes.forEach(reg => { - if (reg._id) { - registrosExistentesMap.set(reg._id.toString(), reg); - } - }); + const existentesMap = new Map( + registrosExistentes + .filter(r => r._id) + .map(r => [r._id.toString(), r]) + ); - const registrosMergeados = registrosNuevos.map(regNuevo => { - const idNuevo = regNuevo._id ? regNuevo._id.toString() : null; + return registrosNuevos.map(regNuevo => { + const idNuevo = regNuevo._id?.toString() || regNuevo.id?.toString(); + const regExistente = idNuevo ? existentesMap.get(idNuevo) : null; - if (idNuevo && registrosExistentesMap.has(idNuevo)) { - const regExistente = registrosExistentesMap.get(idNuevo); + // 🔹 Registro completamente nuevo + if (!regExistente) { + return regNuevo; + } - const registroMergeado = { - ...regNuevo, - createdAt: regExistente.createdAt, - createdBy: regExistente.createdBy, - }; + // 🔹 Comparación profunda para detectar si hubo cambios reales + const valorIgual = + JSON.stringify(regExistente.valor) === JSON.stringify(regNuevo.valor); - if (regNuevo.registros && regNuevo.registros.length > 0) { - registroMergeado.registros = mergeRegistrosPreservandoAuditoria( - regExistente.registros || [], - regNuevo.registros - ); - } + const subRegistrosIguales = + JSON.stringify(regExistente.registros || []) === + JSON.stringify(regNuevo.registros || []); - return registroMergeado; - } else { - if (regNuevo.registros && regNuevo.registros.length > 0) { - const registrosAnidadosExistentes = []; - registrosExistentes.forEach(regEx => { - if (regEx.registros && regEx.registros.length > 0) { - registrosAnidadosExistentes.push(...regEx.registros); - } - }); + // 🔹 No hubo cambios → devolver registro original (preserva auditoría) + if (valorIgual && subRegistrosIguales) { + return regExistente; + } - regNuevo.registros = mergeRegistrosPreservandoAuditoria( - registrosAnidadosExistentes, - regNuevo.registros - ); - } + // 🔹 Hubo cambios → merge preservando auditoría original + const registroMergeado: any = { + ...regNuevo, + createdAt: regExistente.createdAt, + createdBy: regExistente.createdBy + }; - return regNuevo; + // 🔹 Merge recursivo de subregistros + if (regNuevo.registros?.length && regExistente.registros?.length) { + registroMergeado.registros = mergeRegistrosPreservandoAuditoria( + regExistente.registros, + regNuevo.registros + ); } - }); - return registrosMergeados; + return registroMergeado; + }); } /** @@ -654,17 +655,17 @@ function mergeRegistrosPreservandoAuditoria(registrosExistentes: any[], registro * @param prestacion - Prestación a actualizar * @param profesional - Profesional actual que está registrando */ -function actualizarProfesionalesQueRegistran(prestacion: any, profesional: any) { - if (!prestacion.profesionalesQueRegistran) { - prestacion.profesionalesQueRegistran = []; +function actualizarProfesionalesRegistrantes(prestacion: any, profesional: any) { + if (!prestacion.profesionalesRegistrantes) { + prestacion.profesionalesRegistrantes = []; } - const yaExiste = prestacion.profesionalesQueRegistran.some( + const yaExiste = prestacion.profesionalesRegistrantes.some( (prof: any) => prof.id && prof.id.toString() === profesional.id.toString() ); if (!yaExiste) { - prestacion.profesionalesQueRegistran.push({ + prestacion.profesionalesRegistrantes.push({ id: profesional.id, nombreCompleto: profesional.nombreCompleto, nombre: profesional.nombre, @@ -738,7 +739,7 @@ router.patch('/prestaciones/:id', (req: Request, res, next) => { // Actualizar lista de profesionales que registran const profesionalQueRegistra = Auth.getProfesional(req); if (profesionalQueRegistra) { - actualizarProfesionalesQueRegistran(data, profesionalQueRegistra); + actualizarProfesionalesRegistrantes(data, profesionalQueRegistra); } } if (req.body.ejecucion?.fecha) { @@ -787,7 +788,7 @@ router.patch('/prestaciones/:id', (req: Request, res, next) => { // Actualizar lista de profesionales que registran const profesionalQueRegistra = Auth.getProfesional(req); if (profesionalQueRegistra) { - actualizarProfesionalesQueRegistran(data, profesionalQueRegistra); + actualizarProfesionalesRegistrantes(data, profesionalQueRegistra); } if (req.body.solicitud) { @@ -874,7 +875,7 @@ router.patch('/prestaciones/:id', (req: Request, res, next) => { // Actualizar lista de profesionales que registran const profesionalActual = Auth.getProfesional(req); if (profesionalActual) { - actualizarProfesionalesQueRegistran(data, profesionalActual); + actualizarProfesionalesRegistrantes(data, profesionalActual); } break; default: diff --git a/modules/rup/schemas/prestacion.ts b/modules/rup/schemas/prestacion.ts index 4b247ea171..9af2d12ebb 100644 --- a/modules/rup/schemas/prestacion.ts +++ b/modules/rup/schemas/prestacion.ts @@ -168,7 +168,7 @@ export const PrestacionSchema = new Schema({ }, - profesionalesQueRegistran: [ + profesionalesRegistrantes: [ { _id: false, id: Schema.Types.ObjectId,