From 9c58a21007d3b15a7c57410b6ce0e57bb1bc5baa 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/4] 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 937629cbfe..36f0413ba0 100755 --- a/modules/rup/routes/prestacion.ts +++ b/modules/rup/routes/prestacion.ts @@ -620,6 +620,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) { @@ -675,7 +780,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; @@ -714,7 +829,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; @@ -791,7 +916,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 573068731b..376ef61f0a 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 de656212ddc6db5041f257471e526408729dd985 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/4] 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 36f0413ba0..bf15d1fa96 100755 --- a/modules/rup/routes/prestacion.ts +++ b/modules/rup/routes/prestacion.ts @@ -629,16 +629,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) { @@ -646,23 +643,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 || [], @@ -672,13 +664,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); @@ -709,7 +696,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 37f19d4870170df9706522b73fc3c33506617ef6 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/4] 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 bf15d1fa96..c8acde4335 100755 --- a/modules/rup/routes/prestacion.ts +++ b/modules/rup/routes/prestacion.ts @@ -627,62 +627,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; + }); } /** @@ -691,17 +692,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, @@ -775,7 +776,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) { @@ -824,7 +825,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) { @@ -911,7 +912,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 376ef61f0a..69d4b84a02 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, From 72bfb3b98b003c8d1a7308886f982233c214be85 Mon Sep 17 00:00:00 2001 From: nicolasarana <90768149+nicolasarana@users.noreply.github.com> Date: Thu, 10 Sep 2026 11:26:59 -0300 Subject: [PATCH 4/4] =?UTF-8?q?RUP=20-554=20:=20Quitar=20restriccion=20de?= =?UTF-8?q?=20edici=C3=B3n=20de=20registros?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- modules/rup/routes/prestacion.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/rup/routes/prestacion.ts b/modules/rup/routes/prestacion.ts index c8acde4335..c128f5948b 100755 --- a/modules/rup/routes/prestacion.ts +++ b/modules/rup/routes/prestacion.ts @@ -800,8 +800,8 @@ router.patch('/prestaciones/:id', (req: Request, res, next) => { } if (!req.body.desdeInternacion) { const puedeValidar = Auth.check(req, 'rup:validacion:' + data.solicitud.tipoPrestacion.id); - if ((req as any).user.usuario.username !== data.estadoActual.createdBy.documento && !puedeValidar) { - return next('Solo puede romper la validación el usuario que haya creado.'); + if (!puedeValidar) { + return next('No tiene permisos para romper la validación de esta prestación.'); } } const estadoModificada = {