From 6ace09ec6cc6829a929e2c5fe817f702938bd597 Mon Sep 17 00:00:00 2001 From: Jhonathan Guevara Date: Tue, 6 Jan 2026 14:05:05 -0500 Subject: [PATCH] mas cambios 2 --- backend/src/plantilla_autorizacion.js | 100 ++++++++-- ...cion_brigadas_ambulancias_hospitalarios.js | 37 +++- backend/src/server.js | 171 +++++++++++++++--- .../autorizaciones-por-fecha.css | 50 ++++- .../autorizaciones-por-fecha.html | 26 +++ .../autorizaciones-por-fecha.ts | 102 +++++++++++ .../autorizaciones/autorizaciones.html | 5 +- .../autorizaciones/autorizaciones.ts | 17 +- saludut-inpec/src/app/services/paciente.ts | 31 ++++ 9 files changed, 491 insertions(+), 48 deletions(-) diff --git a/backend/src/plantilla_autorizacion.js b/backend/src/plantilla_autorizacion.js index 27c983c..7cd1fe1 100644 --- a/backend/src/plantilla_autorizacion.js +++ b/backend/src/plantilla_autorizacion.js @@ -2539,7 +2539,11 @@ async function crearLibroAutorizacion(a) { sheet.mergeCells('O35:R35'); sheet.mergeCells('B24:R24'); sheet.mergeCells('B25:G30'); - sheet.mergeCells('H25:R29'); + sheet.mergeCells('H25:R25'); + sheet.mergeCells('H26:R26'); + sheet.mergeCells('H27:R27'); + sheet.mergeCells('H28:R28'); + sheet.mergeCells('H29:R29'); sheet.mergeCells('H30:R30'); sheet.mergeCells('B31:G32'); sheet.mergeCells('H31:R31'); @@ -2658,6 +2662,32 @@ async function crearLibroAutorizacion(a) { .replace(/\s+/g, ' ') .trim(); + const emptyIpsValues = new Set([ + 'NA', + 'SD', + 'SINDATO', + 'SINDATOS', + 'SININFO', + 'SININFORMACION', + 'NOAPLICA', + 'NONE', + 'NULL', + ]); + + const cleanIpsValue = (value) => { + const raw = String(value || '').trim(); + if (!raw) return ''; + const normalized = raw + .normalize('NFD') + .replace(/[\u0300-\u036f]/g, '') + .toUpperCase() + .replace(/[^A-Z0-9]/g, ''); + if (!normalized || emptyIpsValues.has(normalized)) { + return ''; + } + return raw; + }; + // 1) Número de autorización (F8:I8) ['F8', 'G8', 'H8', 'I8'].forEach(celda => { sheet.getCell(celda).value = a.numero_autorizacion || ''; @@ -2692,12 +2722,12 @@ async function crearLibroAutorizacion(a) { sheet.getCell(celda).value = nombreIps; }); - const nitIps = a.nit || ''; + const nitIps = cleanIpsValue(a.nit); ['D13', 'E13', 'F13', 'G13'].forEach(celda => { sheet.getCell(celda).value = nitIps; }); - const telefonoIps = a.telefono_ips || ''; + const telefonoIps = cleanIpsValue(a.telefono_ips); ['D14', 'E14', 'F14', 'G14', 'D15', 'E15', 'F15', 'G15', 'D16', 'E16', 'F16', 'G16'].forEach(celda => { sheet.getCell(celda).value = telefonoIps; }); @@ -2710,8 +2740,9 @@ async function crearLibroAutorizacion(a) { }); // 5) Dirección IPS (M16:N16) + const direccionIps = cleanIpsValue(a.direccion); ['M13', 'N13','O13', 'P13','Q13', 'R13'].forEach(celda => { - sheet.getCell(celda).value = a.direccion || ''; + sheet.getCell(celda).value = direccionIps; }); ['M23', 'N23','O23', 'P23','Q23', 'R23'].forEach(celda => { @@ -2719,12 +2750,12 @@ async function crearLibroAutorizacion(a) { }); ['M16', 'N16'].forEach(celda => { - sheet.getCell(celda).value = a.municipio || ''; + sheet.getCell(celda).value = cleanIpsValue(a.municipio); }); // 6) Departamento IPS (Q16:R16) ['Q16', 'R16'].forEach(celda => { - sheet.getCell(celda).value = a.departamento || ''; + sheet.getCell(celda).value = cleanIpsValue(a.departamento); }); // 7) Nombre completo paciente (H18:R18) @@ -2742,10 +2773,36 @@ async function crearLibroAutorizacion(a) { sheet.getCell(celda).value = a.numero_documento || ''; }); - ['H27','R27'].forEach(celda => { + ['H29','R29'].forEach(celda => { sheet.getCell(celda).value = a.nombre_establecimiento || ''; }); + // Tipo de servicio (consulta externa) + const servicioCols = ['H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R']; + const addBottomBorder = (row, style = 'thin') => { + servicioCols.forEach((col) => { + const cell = sheet.getCell(`${col}${row}`); + const border = cell.border || {}; + cell.border = { + ...border, + bottom: { style, color: { argb: 'FF000000' } }, + }; + }); + }; + + sheet.getCell('B25').value = 'TIPO DE SERVICIO'; + sheet.getCell('B25').alignment = {"horizontal":"center","vertical":"middle"}; + sheet.getCell('H25').value = 'CONSULTA EXTERNA'; + sheet.getCell('H25').alignment = {"horizontal":"center","vertical":"middle"}; + sheet.getCell('H26').value = 'X'; + sheet.getCell('H26').alignment = {"horizontal":"center","vertical":"middle"}; + sheet.getCell('H27').value = ''; + sheet.getCell('H27').alignment = {"horizontal":"center","vertical":"middle"}; + sheet.getCell('H28').value = ''; + sheet.getCell('H28').alignment = {"horizontal":"center","vertical":"middle"}; + addBottomBorder(25); + addBottomBorder(26); + // 10) Observacion / servicios autorizados (H25:R25) const cupCodigo = a.cup_codigo || ''; const cupDescripcion = a.cup_descripcion || ''; @@ -2773,13 +2830,34 @@ async function crearLibroAutorizacion(a) { }); return partes.join(' | '); }; - const observacionBase = limpiarObservacion(a.observacion || ''); + const filtrarObservacionConsulta = (value) => { + const partes = String(value || '') + .split('|') + .map((parte) => parte.trim()) + .filter(Boolean) + .filter((parte) => { + const lower = parte.toLowerCase(); + return ( + !lower.includes('solicitante') && + !lower.includes('traslado a departamento') + ); + }); + return partes.join(' | '); + }; + const esConsultaExterna = + String(a.tipo_autorizacion || '').toLowerCase() === 'consultas_externas'; + let observacionBase = limpiarObservacion(a.observacion || ''); + if (esConsultaExterna) { + observacionBase = filtrarObservacionConsulta(observacionBase); + } const solicitanteNombre = String(a.nombre_solicitante || '').trim(); const observacionLower = observacionBase.toLowerCase(); const solicitanteInfo = - solicitanteNombre && !observacionLower.includes('solicitante') - ? `Solicitante: ${solicitanteNombre}` - : ''; + esConsultaExterna + ? '' + : solicitanteNombre && !observacionLower.includes('solicitante') + ? `Solicitante: ${solicitanteNombre}` + : ''; const observacion = [cupInfo, observacionBase, solicitanteInfo] .filter(Boolean) .join(' | '); diff --git a/backend/src/plantilla_autorizacion_brigadas_ambulancias_hospitalarios.js b/backend/src/plantilla_autorizacion_brigadas_ambulancias_hospitalarios.js index 9b0190e..6a93375 100644 --- a/backend/src/plantilla_autorizacion_brigadas_ambulancias_hospitalarios.js +++ b/backend/src/plantilla_autorizacion_brigadas_ambulancias_hospitalarios.js @@ -2338,6 +2338,32 @@ async function crearLibroAutorizacionBrigadasAmbulanciasHospitalarios(a) { .replace(/\s+/g, ' ') .trim(); + const emptyIpsValues = new Set([ + 'NA', + 'SD', + 'SINDATO', + 'SINDATOS', + 'SININFO', + 'SININFORMACION', + 'NOAPLICA', + 'NONE', + 'NULL', + ]); + + const cleanIpsValue = (value) => { + const raw = String(value || '').trim(); + if (!raw) return ''; + const normalized = raw + .normalize('NFD') + .replace(/[\u0300-\u036f]/g, '') + .toUpperCase() + .replace(/[^A-Z0-9]/g, ''); + if (!normalized || emptyIpsValues.has(normalized)) { + return ''; + } + return raw; + }; + ['F8', 'G8', 'H8', 'I8'].forEach((celda) => { sheet.getCell(celda).value = a.numero_autorizacion || ''; }); @@ -2368,12 +2394,12 @@ async function crearLibroAutorizacionBrigadasAmbulanciasHospitalarios(a) { sheet.getCell(celda).value = nombreIps; }); - const nitIps = a.nit || ''; + const nitIps = cleanIpsValue(a.nit); ['D13', 'E13', 'F13', 'G13'].forEach((celda) => { sheet.getCell(celda).value = nitIps; }); - const telefonoIps = a.telefono_ips || ''; + const telefonoIps = cleanIpsValue(a.telefono_ips); ['D14', 'E14', 'F14', 'G14', 'D15', 'E15', 'F15', 'G15', 'D16', 'E16', 'F16', 'G16'].forEach((celda) => { sheet.getCell(celda).value = telefonoIps; }); @@ -2385,8 +2411,9 @@ async function crearLibroAutorizacionBrigadasAmbulanciasHospitalarios(a) { sheet.getCell(celda).value = a.sexo || ''; }); + const direccionIps = cleanIpsValue(a.direccion); ['M13', 'N13', 'O13', 'P13', 'Q13', 'R13'].forEach((celda) => { - sheet.getCell(celda).value = a.direccion || ''; + sheet.getCell(celda).value = direccionIps; }); ['M23', 'N23', 'O23', 'P23', 'Q23', 'R23'].forEach((celda) => { @@ -2394,11 +2421,11 @@ async function crearLibroAutorizacionBrigadasAmbulanciasHospitalarios(a) { }); ['M16', 'N16'].forEach((celda) => { - sheet.getCell(celda).value = a.municipio || ''; + sheet.getCell(celda).value = cleanIpsValue(a.municipio); }); ['Q16', 'R16'].forEach((celda) => { - sheet.getCell(celda).value = a.departamento || ''; + sheet.getCell(celda).value = cleanIpsValue(a.departamento); }); ['H18', 'I18', 'J18', 'K18', 'L18', 'M18', 'N18', 'O18', 'P18', 'Q18', 'R18'].forEach((celda) => { diff --git a/backend/src/server.js b/backend/src/server.js index 5207074..3828100 100644 --- a/backend/src/server.js +++ b/backend/src/server.js @@ -1507,6 +1507,28 @@ const normalizeDigits = (value) => String(value || '').replace(/\D/g, ''); const normalizeNameKey = (value) => normalizeSearch(value).replace(/[^A-Z0-9]/g, ''); +const IPS_EMPTY_MARKERS = new Set([ + 'NA', + 'SD', + 'SINDATO', + 'SINDATOS', + 'SININFO', + 'SININFORMACION', + 'NOAPLICA', + 'NONE', + 'NULL', +]); + +const cleanIpsField = (value) => { + const raw = String(value || '').trim(); + if (!raw) return ''; + const normalized = normalizeSearch(raw).replace(/[^A-Z0-9]/g, ''); + if (!normalized || IPS_EMPTY_MARKERS.has(normalized)) { + return ''; + } + return raw; +}; + const extractCupCodigo = (value) => { const text = String(value || '').trim(); if (!text) return ''; @@ -1667,19 +1689,18 @@ async function procesarExcelIps(inputFilePath) { for (let i = 2; i <= sheet.rowCount; i++) { const row = sheet.getRow(i); - const nit = getValueMulti(row, [ - 'NIT', - 'NITIPS', - 'NITPRESTADOR', - 'NITPRESTADORIPS', - ]); - const nombre = getValueMulti(row, [ - 'PRESTADOR', - 'PRESTADORDELSERVICIO', - 'PRESTADORDESERVICIO', - 'NOMBREPRESTADOR', - 'NOMBREIPS', - ]); + const nit = cleanIpsField( + getValueMulti(row, ['NIT', 'NITIPS', 'NITPRESTADOR', 'NITPRESTADORIPS']) + ); + const nombre = cleanIpsField( + getValueMulti(row, [ + 'PRESTADOR', + 'PRESTADORDELSERVICIO', + 'PRESTADORDESERVICIO', + 'NOMBREPRESTADOR', + 'NOMBREIPS', + ]) + ); if (!nit && !nombre) { continue; @@ -1687,15 +1708,13 @@ async function procesarExcelIps(inputFilePath) { resumen.total += 1; - const direccion = getValue(row, 'DIRECCION'); - const departamento = getValue(row, 'DEPARTAMENTO'); - const municipio = getValue(row, 'MUNICIPIO'); - const telefono = getValue(row, 'TELEFONO'); - const codigoIps = getValueMulti(row, [ - 'CODIGOIPS', - 'CODIGOPRESTADOR', - 'CODIGOHABILITACION', - ]); + const direccion = cleanIpsField(getValue(row, 'DIRECCION')); + const departamento = cleanIpsField(getValue(row, 'DEPARTAMENTO')); + const municipio = cleanIpsField(getValue(row, 'MUNICIPIO')); + const telefono = cleanIpsField(getValue(row, 'TELEFONO')); + const codigoIps = cleanIpsField( + getValueMulti(row, ['CODIGOIPS', 'CODIGOPRESTADOR', 'CODIGOHABILITACION']) + ); const nitDigits = registerDigits(nitKeys, nit); const codigoDigits = registerDigits(codigoKeys, codigoIps); @@ -1777,16 +1796,18 @@ async function procesarExcelIps(inputFilePath) { await client.query( ` UPDATE ips - SET nombre_ips = COALESCE($1, nombre_ips), - codigo_ips = COALESCE($2, codigo_ips), - direccion = COALESCE($3, direccion), - telefono = COALESCE($4, telefono), - departamento = COALESCE($5, departamento), - municipio = COALESCE($6, municipio), + SET nit = COALESCE($1, nit), + nombre_ips = COALESCE($2, nombre_ips), + codigo_ips = COALESCE($3, codigo_ips), + direccion = COALESCE($4, direccion), + telefono = COALESCE($5, telefono), + departamento = COALESCE($6, departamento), + municipio = COALESCE($7, municipio), tiene_convenio = true - WHERE id_ips = $7 + WHERE id_ips = $8 `, [ + nit || null, nombre || null, codigoIps || null, direccion || null, @@ -5082,6 +5103,98 @@ app.patch('/api/autorizaciones/estado-masivo', verificarToken, esAdministrador, } }); +/** + * PATCH /api/autorizaciones/autorizante-masivo + * Body: { fecha_inicio, fecha_fin, numero_documento_autorizante, establecimiento?, ambito?, ips? } + * Solo administrador + */ +app.patch('/api/autorizaciones/autorizante-masivo', verificarToken, esAdministrador, async (req, res) => { + const fecha_inicio = req.body?.fecha_inicio || req.query?.fecha_inicio; + const fecha_fin = req.body?.fecha_fin || req.query?.fecha_fin; + const numeroDocumento = + req.body?.numero_documento_autorizante || req.query?.numero_documento_autorizante; + const establecimiento = String( + req.body?.establecimiento || req.query?.establecimiento || '' + ).trim(); + const ambito = String(req.body?.ambito || req.query?.ambito || '') + .trim() + .toLowerCase(); + const ips = String(req.body?.ips || req.query?.ips || '').trim(); + + if (!fecha_inicio || !fecha_fin) { + return res.status(400).json({ error: 'fecha_inicio y fecha_fin son requeridos' }); + } + + const numeroAutorizante = Number(numeroDocumento); + if (!Number.isFinite(numeroAutorizante)) { + return res.status(400).json({ error: 'numero_documento_autorizante invalido' }); + } + + const ambitosPermitidos = ['intramural', 'extramural']; + if (ambito && !ambitosPermitidos.includes(ambito)) { + return res.status(400).json({ error: 'ambito invalido' }); + } + + try { + const autorizanteRes = await pool.query( + 'SELECT 1 FROM autorizante WHERE numero_documento = $1 LIMIT 1', + [numeroAutorizante] + ); + if (autorizanteRes.rows.length === 0) { + return res.status(404).json({ error: 'Autorizante no encontrado' }); + } + + const whereParts = ['a.fecha_autorizacion BETWEEN $2::date AND $3::date']; + const params = [numeroAutorizante, fecha_inicio, fecha_fin]; + + if (establecimiento) { + params.push(`%${establecimiento}%`); + whereParts.push( + `EXISTS ( + SELECT 1 + FROM ingreso i + JOIN establecimiento e ON i.codigo_establecimiento = e.codigo_establecimiento + WHERE i.interno = a.interno + AND (e.codigo_establecimiento ILIKE $${params.length} OR e.nombre_establecimiento ILIKE $${params.length}) + )` + ); + } + + if (ambito) { + params.push(ambito); + whereParts.push(`a.ambito_atencion = $${params.length}`); + } + + if (ips) { + params.push(`%${ips}%`); + whereParts.push( + `EXISTS ( + SELECT 1 + FROM ips i + WHERE i.id_ips = a.id_ips + AND (i.nombre_ips ILIKE $${params.length} OR i.nit ILIKE $${params.length} OR i.codigo_ips ILIKE $${params.length}) + )` + ); + } + + const sql = ` + UPDATE autorizacion a + SET numero_documento_autorizante = $1 + WHERE ${whereParts.join('\n AND ')} + RETURNING a.numero_autorizacion; + `; + + const result = await pool.query(sql, params); + return res.json({ + mensaje: 'Autorizantes actualizados', + actualizados: result.rowCount || 0, + }); + } catch (error) { + console.error('Error en autorizante masivo:', error.message); + return res.status(500).json({ error: 'Error actualizando autorizantes' }); + } +}); + /** * GET /api/autorizaciones-por-fecha/zip * Query params: fecha_inicio, fecha_fin diff --git a/saludut-inpec/src/app/components/autorizaciones-por-fecha/autorizaciones-por-fecha.css b/saludut-inpec/src/app/components/autorizaciones-por-fecha/autorizaciones-por-fecha.css index 72cc828..60d6a2c 100644 --- a/saludut-inpec/src/app/components/autorizaciones-por-fecha/autorizaciones-por-fecha.css +++ b/saludut-inpec/src/app/components/autorizaciones-por-fecha/autorizaciones-por-fecha.css @@ -242,6 +242,36 @@ min-width: 180px; } +.autorizante-masivo { + display: flex; + align-items: center; + gap: 8px; + padding: 6px 10px; + border-radius: 8px; + background: var(--color-surface); + border: 1px solid var(--color-border); +} + +.autorizante-masivo label { + font-size: 0.85rem; + color: var(--color-text-muted); + font-weight: 600; +} + +.autorizante-masivo select { + min-width: 200px; + padding: 8px 10px; + border-radius: 6px; + border: 1px solid var(--color-input-border); + background: var(--color-input-bg); + font-size: 0.85rem; + color: var(--color-text-main); +} + +.autorizante-masivo button { + min-width: 180px; +} + /* Table */ .table-container { overflow-x: auto; @@ -503,6 +533,11 @@ justify-content: space-between; } + .autorizante-masivo { + width: 100%; + justify-content: space-between; + } + .autorizaciones-table th, .autorizaciones-table td { padding: 8px 12px; @@ -527,7 +562,9 @@ .btn-exportar, .btn-descargar-todos, .estado-masivo, - .estado-masivo button { + .estado-masivo button, + .autorizante-masivo, + .autorizante-masivo button { justify-content: center; } @@ -537,11 +574,22 @@ align-items: stretch; } + .autorizante-masivo { + width: 100%; + flex-direction: column; + align-items: stretch; + } + .estado-masivo select, .estado-masivo button { width: 100%; } + .autorizante-masivo select, + .autorizante-masivo button { + width: 100%; + } + .empty-state { padding: 40px 16px; } diff --git a/saludut-inpec/src/app/components/autorizaciones-por-fecha/autorizaciones-por-fecha.html b/saludut-inpec/src/app/components/autorizaciones-por-fecha/autorizaciones-por-fecha.html index cfbb64e..6bfdbc2 100644 --- a/saludut-inpec/src/app/components/autorizaciones-por-fecha/autorizaciones-por-fecha.html +++ b/saludut-inpec/src/app/components/autorizaciones-por-fecha/autorizaciones-por-fecha.html @@ -149,6 +149,32 @@ {{ actualizandoMasivo ? 'Actualizando...' : 'Aplicar a todo el rango' }} +
+ + + +