diff --git a/backend/src/__pycache__/extraer_autorizacion_pdf.cpython-313.pyc b/backend/src/__pycache__/extraer_autorizacion_pdf.cpython-313.pyc index da10051..819570d 100644 Binary files a/backend/src/__pycache__/extraer_autorizacion_pdf.cpython-313.pyc and b/backend/src/__pycache__/extraer_autorizacion_pdf.cpython-313.pyc differ diff --git a/backend/src/extraer_autorizacion_pdf.py b/backend/src/extraer_autorizacion_pdf.py index a2eb93e..7735574 100644 --- a/backend/src/extraer_autorizacion_pdf.py +++ b/backend/src/extraer_autorizacion_pdf.py @@ -502,11 +502,12 @@ def extract_fecha_egreso(lines, norm_lines): "FECHA DE ALTA", "FECHA ALTA", ] + candidates = [] for i, nline in enumerate(norm_lines): if not any(key in nline for key in keys): continue match = re.search( - r"(EGRESO|EGRESA|ALTA)[^0-9]{0,20}(\d{1,2}[/-]\d{1,2}[/-]\d{2,4})", + r"(EGRESO|EGRESA|ALTA)[^0-9]{0,40}(\d{1,2}[/-]\d{1,2}[/-]\d{2,4})", nline, ) date = match.group(2) if match else None @@ -518,8 +519,8 @@ def extract_fecha_egreso(lines, norm_lines): time = extract_time_from_text(lines[i]) or ( extract_time_from_text(lines[i + 1]) if i + 1 < len(lines) else None ) - return f"{date} {time}" if time else date - return None + candidates.append(f"{date} {time}" if time else date) + return candidates[-1] if candidates else None def clean_ips_name(value): diff --git a/backend/src/plantilla_autorizacion_brigadas_ambulancias_hospitalarios.js b/backend/src/plantilla_autorizacion_brigadas_ambulancias_hospitalarios.js index 7d1a84d..31ed0e4 100644 --- a/backend/src/plantilla_autorizacion_brigadas_ambulancias_hospitalarios.js +++ b/backend/src/plantilla_autorizacion_brigadas_ambulancias_hospitalarios.js @@ -2496,6 +2496,8 @@ async function crearLibroAutorizacionBrigadasAmbulanciasHospitalarios(a) { if (cupDescripcion) cupInfoParts.push(cupDescripcion); if (nivelTexto) cupInfoParts.push(nivelTexto); const cupInfo = cupInfoParts.join(' - '); + const tipoServicio = String(a.tipo_servicio || '').toLowerCase(); + const esHospitalario = tipoServicio === 'hospitalarios'; const limpiarObservacion = (value) => { const partes = String(value || '') .split('|') @@ -2511,11 +2513,31 @@ async function crearLibroAutorizacionBrigadasAmbulanciasHospitalarios(a) { }); return partes.join(' | '); }; - const observacionBase = limpiarObservacion(a.observacion || ''); + const filtrarObservacionHospitalarios = (value) => { + const partes = String(value || '') + .split('|') + .map((parte) => parte.trim()) + .filter(Boolean) + .filter((parte) => { + const lower = parte.toLowerCase(); + return ( + !lower.includes('solicitante') && + !lower.includes('solicitado por') && + !lower.includes('traslado a departamento') + ); + }); + return partes.join(' | '); + }; + let observacionBase = limpiarObservacion(a.observacion || ''); + if (esHospitalario) { + observacionBase = filtrarObservacionHospitalarios(observacionBase); + } const solicitanteNombre = String(a.nombre_solicitante || '').trim(); const observacionLower = observacionBase.toLowerCase(); const solicitanteInfo = - solicitanteNombre && !observacionLower.includes('solicitante') + esHospitalario + ? '' + : solicitanteNombre && !observacionLower.includes('solicitante') ? 'Solicitante: ' + solicitanteNombre : ''; const observacion = [cupInfo, observacionBase, solicitanteInfo].filter(Boolean).join(' | '); @@ -2523,7 +2545,6 @@ async function crearLibroAutorizacionBrigadasAmbulanciasHospitalarios(a) { sheet.getCell(celda).value = observacion; }); - const tipoServicio = String(a.tipo_servicio || '').toLowerCase(); if (tipoServicio === 'brigadas') { sheet.getCell('H27').value = 'X'; } else if (tipoServicio === 'ambulancias') { diff --git a/saludut-inpec/src/app/components/autorizaciones/autorizaciones.ts b/saludut-inpec/src/app/components/autorizaciones/autorizaciones.ts index 3219cf7..6f02bb4 100644 --- a/saludut-inpec/src/app/components/autorizaciones/autorizaciones.ts +++ b/saludut-inpec/src/app/components/autorizaciones/autorizaciones.ts @@ -470,7 +470,9 @@ export class AutorizacionesComponent { } autorrellenarDesdePdf(): void { - const archivo = this.archivoAnexo || this.archivoHistorialClinico; + const archivoAnexo = this.archivoAnexo; + const archivoHistorial = this.archivoHistorialClinico; + const archivo = archivoAnexo || archivoHistorial; if (!archivo) { this.autorrellenoError = 'Adjunta un PDF para autorrellenar.'; return; @@ -483,6 +485,18 @@ export class AutorizacionesComponent { this.pacienteService .autorrellenarAutorizacionPdf(archivo) .pipe( + switchMap((respPrimario: any) => { + if (!archivoAnexo || !archivoHistorial) { + return of({ primary: respPrimario, secondary: null }); + } + if (!this.necesitaFallbackPdf(respPrimario)) { + return of({ primary: respPrimario, secondary: null }); + } + return this.pacienteService + .autorrellenarAutorizacionPdf(archivoHistorial) + .pipe(map((respSecundario: any) => ({ primary: respPrimario, secondary: respSecundario }))); + }), + map(({ primary, secondary }) => this.mergePdfResponses(primary, secondary)), finalize(() => { this.autorrellenandoPdf = false; this.cdr.markForCheck(); @@ -592,6 +606,100 @@ export class AutorizacionesComponent { }); } + private necesitaFallbackPdf(resp: any): boolean { + const tieneCie10 = Boolean( + (resp?.cie10_codigo && String(resp.cie10_codigo).trim()) || + (resp?.cie10_descripcion && String(resp.cie10_descripcion).trim()) || + (Array.isArray(resp?.cie10_codigos) && resp.cie10_codigos.length) + ); + const tieneEgreso = Boolean(resp?.fecha_egreso && String(resp.fecha_egreso).trim()); + const tieneIngreso = Boolean( + resp?.fecha_ingreso_urgencias && String(resp.fecha_ingreso_urgencias).trim() + ); + return !tieneCie10 || !tieneEgreso || !tieneIngreso; + } + + private mergePdfResponses(primary: any, secondary: any): any { + if (!secondary) { + return primary; + } + + const merged = { ...secondary, ...primary }; + + merged.cups_codigos = this.mergeUniqueList(primary?.cups_codigos, secondary?.cups_codigos); + merged.cups_descripciones = this.mergeUniqueList( + primary?.cups_descripciones, + secondary?.cups_descripciones + ); + merged.cie10_codigos = this.mergeUniqueList(primary?.cie10_codigos, secondary?.cie10_codigos); + merged.cie10_descripciones = this.mergeUniqueList( + primary?.cie10_descripciones, + secondary?.cie10_descripciones + ); + + if (!merged.cup_codigo && merged.cups_codigos.length) { + merged.cup_codigo = merged.cups_codigos[0]; + } + if (!merged.cie10_codigo && merged.cie10_codigos.length) { + merged.cie10_codigo = merged.cie10_codigos.join(', '); + } + if (!merged.cie10_descripcion && merged.cie10_descripciones.length) { + merged.cie10_descripcion = merged.cie10_descripciones.filter(Boolean).join(', '); + } + + if (!merged.fecha_ingreso_urgencias && secondary?.fecha_ingreso_urgencias) { + merged.fecha_ingreso_urgencias = secondary.fecha_ingreso_urgencias; + } + if (!merged.fecha_egreso && secondary?.fecha_egreso) { + merged.fecha_egreso = secondary.fecha_egreso; + } + + merged.ocr_usado = Boolean(primary?.ocr_usado || secondary?.ocr_usado); + merged.ocr_disponible = Boolean(primary?.ocr_disponible || secondary?.ocr_disponible); + merged.ocr_error = primary?.ocr_error || secondary?.ocr_error || null; + + const warnings = this.mergeUniqueList(primary?.warnings, secondary?.warnings); + merged.warnings = this.filterPdfWarnings(warnings, merged); + + if (!merged.formato && secondary?.formato) { + merged.formato = secondary.formato; + } + + return merged; + } + + private mergeUniqueList(base: any, extra: any): string[] { + const result = Array.isArray(base) ? [...base] : []; + const extras = Array.isArray(extra) ? extra : []; + extras.forEach((item) => { + if (item && !result.includes(item)) { + result.push(item); + } + }); + return result; + } + + private filterPdfWarnings(warnings: string[], resp: any): string[] { + const tieneCups = Boolean( + (resp?.cup_codigo && String(resp.cup_codigo).trim()) || + (Array.isArray(resp?.cups_codigos) && resp.cups_codigos.length) + ); + const tieneCie10 = Boolean( + (resp?.cie10_codigo && String(resp.cie10_codigo).trim()) || + (Array.isArray(resp?.cie10_codigos) && resp.cie10_codigos.length) + ); + const tieneIps = Boolean( + (resp?.ips_nombre && String(resp.ips_nombre).trim()) || + (resp?.ips_nit && String(resp.ips_nit).trim()) + ); + return warnings.filter((warning) => { + if (warning === 'cups_not_found' && tieneCups) return false; + if (warning === 'cie10_not_found' && tieneCie10) return false; + if (warning === 'ips_not_found' && tieneIps) return false; + return true; + }); + } + private setPdfFile(event: Event, tipo: 'historial' | 'anexo'): void { const input = event.target as HTMLInputElement | null; const file = input?.files?.[0] || null;