mas cambios
This commit is contained in:
parent
a4cf0f84c3
commit
b8c258a963
BIN
CC 1016076860 -- EDISON ANDRES GOMEZ JULIO ANEXO.pdf
Normal file
BIN
CC 1016076860 -- EDISON ANDRES GOMEZ JULIO ANEXO.pdf
Normal file
Binary file not shown.
BIN
CC 1016076860 -- EDISON ANDRES GOMEZ JULIO HC.pdf
Normal file
BIN
CC 1016076860 -- EDISON ANDRES GOMEZ JULIO HC.pdf
Normal file
Binary file not shown.
BIN
backend/src/__pycache__/extraer_autorizacion_pdf.cpython-313.pyc
Normal file
BIN
backend/src/__pycache__/extraer_autorizacion_pdf.cpython-313.pyc
Normal file
Binary file not shown.
@ -27,6 +27,27 @@ def extract_digits_from_text(text, min_len=6, max_len=20):
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def extract_date_from_text(text):
|
||||||
|
if not text:
|
||||||
|
return None
|
||||||
|
match = re.search(
|
||||||
|
r"\b(\d{1,2}[/-]\d{1,2}[/-]\d{2,4}|\d{4}[/-]\d{1,2}[/-]\d{1,2})\b",
|
||||||
|
text,
|
||||||
|
)
|
||||||
|
if match:
|
||||||
|
return match.group(1)
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def extract_time_from_text(text):
|
||||||
|
if not text:
|
||||||
|
return None
|
||||||
|
match = re.search(r"\b(\d{1,2}:\d{2})\b", text)
|
||||||
|
if match:
|
||||||
|
return match.group(1)
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
def extract_text_pdfplumber(path):
|
def extract_text_pdfplumber(path):
|
||||||
try:
|
try:
|
||||||
import pdfplumber # type: ignore
|
import pdfplumber # type: ignore
|
||||||
@ -214,7 +235,9 @@ def extract_document(lines, norm_lines):
|
|||||||
def extract_cups_code(text):
|
def extract_cups_code(text):
|
||||||
if not text:
|
if not text:
|
||||||
return None
|
return None
|
||||||
match = re.search(r"\b[A-Z0-9]{4,10}\b", text, re.IGNORECASE)
|
match = re.search(
|
||||||
|
r"\b(?=[A-Z0-9]{4,10}\b)[A-Z]*\d[A-Z0-9]*\b", text, re.IGNORECASE
|
||||||
|
)
|
||||||
if match:
|
if match:
|
||||||
return match.group(0)
|
return match.group(0)
|
||||||
digits = extract_digits_from_text(text, min_len=4, max_len=10)
|
digits = extract_digits_from_text(text, min_len=4, max_len=10)
|
||||||
@ -223,25 +246,84 @@ def extract_cups_code(text):
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def extract_cups(lines, norm_lines):
|
def extract_cups_list(lines, norm_lines):
|
||||||
|
cups = []
|
||||||
|
header_idx = -1
|
||||||
|
for i, nline in enumerate(norm_lines):
|
||||||
|
if "CUPS" in nline and "CODIGO" in nline:
|
||||||
|
header_idx = i
|
||||||
|
break
|
||||||
|
|
||||||
|
stop_tokens = [
|
||||||
|
"JUSTIFICACION",
|
||||||
|
"IMPRESION",
|
||||||
|
"DIAGNOSTICO",
|
||||||
|
"INFORMACION",
|
||||||
|
"NOMBRE",
|
||||||
|
"RESPONSABLE",
|
||||||
|
"SOLICITA",
|
||||||
|
"SOLICITANTE",
|
||||||
|
"FIRMA",
|
||||||
|
]
|
||||||
|
|
||||||
|
def add_cup(code, desc):
|
||||||
|
if not code:
|
||||||
|
return
|
||||||
|
for existing, _ in cups:
|
||||||
|
if existing == code:
|
||||||
|
return
|
||||||
|
cups.append((code, desc or None))
|
||||||
|
|
||||||
|
if header_idx != -1:
|
||||||
|
for j in range(header_idx + 1, min(header_idx + 20, len(lines))):
|
||||||
|
nline = norm_lines[j]
|
||||||
|
if any(token in nline for token in stop_tokens):
|
||||||
|
break
|
||||||
|
code = extract_cups_code(lines[j])
|
||||||
|
if not code:
|
||||||
|
continue
|
||||||
|
raw = lines[j]
|
||||||
|
desc = ""
|
||||||
|
if code in raw:
|
||||||
|
desc = raw.split(code, 1)[-1].strip(" -:")
|
||||||
|
desc = re.sub(r"^\d+[.,]\d{1,2}(?:\s+|$)", "", desc)
|
||||||
|
desc = re.sub(r"^\d+(?:\s+|$)", "", desc)
|
||||||
|
if not desc and j + 1 < len(lines):
|
||||||
|
desc = lines[j + 1].strip()
|
||||||
|
add_cup(code, desc)
|
||||||
|
|
||||||
|
if not cups:
|
||||||
for i, line in enumerate(norm_lines):
|
for i, line in enumerate(norm_lines):
|
||||||
if (
|
if (
|
||||||
"CUPS" in line
|
"CUPS" in line
|
||||||
or re.search(r"C\s*[\.\-]?\s*U\s*[\.\-]?\s*P\s*[\.\-]?\s*S", line, re.IGNORECASE)
|
or re.search(
|
||||||
|
r"C\s*[\.\-]?\s*U\s*[\.\-]?\s*P\s*[\.\-]?\s*S",
|
||||||
|
line,
|
||||||
|
re.IGNORECASE,
|
||||||
|
)
|
||||||
or re.search(r"\bCUP\b", line, re.IGNORECASE)
|
or re.search(r"\bCUP\b", line, re.IGNORECASE)
|
||||||
):
|
):
|
||||||
for j in range(i, min(i + 8, len(lines))):
|
for j in range(i, min(i + 8, len(lines))):
|
||||||
code = extract_cups_code(lines[j])
|
code = extract_cups_code(lines[j])
|
||||||
if not code:
|
if not code:
|
||||||
continue
|
continue
|
||||||
desc = ""
|
|
||||||
raw = lines[j]
|
raw = lines[j]
|
||||||
|
desc = ""
|
||||||
if code in raw:
|
if code in raw:
|
||||||
desc = raw.split(code, 1)[-1].strip(" -:")
|
desc = raw.split(code, 1)[-1].strip(" -:")
|
||||||
if not desc and j + 1 < len(lines):
|
if not desc and j + 1 < len(lines):
|
||||||
desc = lines[j + 1].strip()
|
desc = lines[j + 1].strip()
|
||||||
return code, desc or None
|
add_cup(code, desc)
|
||||||
|
if cups:
|
||||||
|
break
|
||||||
|
|
||||||
|
return cups
|
||||||
|
|
||||||
|
|
||||||
|
def extract_cups(lines, norm_lines):
|
||||||
|
cups = extract_cups_list(lines, norm_lines)
|
||||||
|
if cups:
|
||||||
|
return cups[0]
|
||||||
return None, None
|
return None, None
|
||||||
|
|
||||||
|
|
||||||
@ -305,26 +387,62 @@ def extract_cups_hint(lines, norm_lines):
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def extract_cie10(lines, norm_lines):
|
def extract_cie10_list(lines, norm_lines):
|
||||||
|
results = []
|
||||||
|
seen = set()
|
||||||
for i, nline in enumerate(norm_lines):
|
for i, nline in enumerate(norm_lines):
|
||||||
if (
|
if (
|
||||||
"DIAGNOSTICO PRINCIPAL" in nline
|
"DIAGNOSTICO" in nline
|
||||||
or "IMPRESION DIAGNOSTICA" in nline
|
or "IMPRESION DIAGNOSTICA" in nline
|
||||||
or "DIAGNOSTICO" in nline
|
or "CIE10" in nline
|
||||||
):
|
):
|
||||||
candidate = lines[i]
|
for j in range(i, min(i + 6, len(lines))):
|
||||||
if i + 1 < len(lines) and len(lines[i + 1].split()) > 1:
|
code, desc = parse_cie10_from_line(lines[j])
|
||||||
candidate = candidate + " " + lines[i + 1]
|
if not code:
|
||||||
code, desc = parse_cie10_from_line(candidate)
|
continue
|
||||||
if code:
|
if code in seen:
|
||||||
return code, desc or None
|
continue
|
||||||
for line in lines:
|
seen.add(code)
|
||||||
code, desc = parse_cie10_from_line(line)
|
results.append((code, desc))
|
||||||
if code:
|
return results
|
||||||
return code, desc or None
|
|
||||||
|
|
||||||
|
def extract_cie10(lines, norm_lines):
|
||||||
|
cie_list = extract_cie10_list(lines, norm_lines)
|
||||||
|
if cie_list:
|
||||||
|
return cie_list[0]
|
||||||
return None, None
|
return None, None
|
||||||
|
|
||||||
|
|
||||||
|
def extract_fecha_ingreso_urgencias(lines, norm_lines):
|
||||||
|
keys = [
|
||||||
|
"INGRESO A URGENCIAS",
|
||||||
|
"INGRESO URGENCIAS",
|
||||||
|
"FECHA DE INGRESO",
|
||||||
|
"FECHA INGRESO",
|
||||||
|
"INGRESA",
|
||||||
|
"INGRESO",
|
||||||
|
]
|
||||||
|
for i, nline in enumerate(norm_lines):
|
||||||
|
if not any(key in nline for key in keys):
|
||||||
|
continue
|
||||||
|
match = re.search(
|
||||||
|
r"INGRES[AO][^0-9]{0,20}(\d{1,2}[/-]\d{1,2}[/-]\d{2,4})",
|
||||||
|
nline,
|
||||||
|
)
|
||||||
|
if match:
|
||||||
|
return match.group(1)
|
||||||
|
date = extract_date_from_text(lines[i])
|
||||||
|
if not date and i + 1 < len(lines):
|
||||||
|
date = extract_date_from_text(lines[i + 1])
|
||||||
|
if date:
|
||||||
|
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
|
||||||
|
|
||||||
|
|
||||||
def clean_ips_name(value):
|
def clean_ips_name(value):
|
||||||
if not value:
|
if not value:
|
||||||
return ""
|
return ""
|
||||||
@ -387,6 +505,76 @@ def detect_format(norm_text, norm_lines):
|
|||||||
return "DESCONOCIDO"
|
return "DESCONOCIDO"
|
||||||
|
|
||||||
|
|
||||||
|
def merge_unique(base_list, extra_list):
|
||||||
|
result = list(base_list or [])
|
||||||
|
for item in extra_list or []:
|
||||||
|
if item not in result:
|
||||||
|
result.append(item)
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def merge_response(base, extra):
|
||||||
|
result = dict(base)
|
||||||
|
|
||||||
|
if base.get("cups_codigos"):
|
||||||
|
result["cups_codigos"] = list(base.get("cups_codigos") or [])
|
||||||
|
result["cups_descripciones"] = list(base.get("cups_descripciones") or [])
|
||||||
|
else:
|
||||||
|
result["cups_codigos"] = merge_unique(
|
||||||
|
base.get("cups_codigos"), extra.get("cups_codigos")
|
||||||
|
)
|
||||||
|
result["cups_descripciones"] = merge_unique(
|
||||||
|
base.get("cups_descripciones"), extra.get("cups_descripciones")
|
||||||
|
)
|
||||||
|
result["cie10_codigos"] = merge_unique(
|
||||||
|
base.get("cie10_codigos"), extra.get("cie10_codigos")
|
||||||
|
)
|
||||||
|
result["cie10_descripciones"] = merge_unique(
|
||||||
|
base.get("cie10_descripciones"), extra.get("cie10_descripciones")
|
||||||
|
)
|
||||||
|
|
||||||
|
if not result.get("cup_codigo") and extra.get("cup_codigo"):
|
||||||
|
result["cup_codigo"] = extra.get("cup_codigo")
|
||||||
|
result["cup_descripcion"] = extra.get("cup_descripcion")
|
||||||
|
|
||||||
|
if not result.get("cie10_codigo") and extra.get("cie10_codigo"):
|
||||||
|
result["cie10_codigo"] = extra.get("cie10_codigo")
|
||||||
|
result["cie10_descripcion"] = extra.get("cie10_descripcion")
|
||||||
|
|
||||||
|
if not result.get("ips_nombre") and extra.get("ips_nombre"):
|
||||||
|
result["ips_nombre"] = extra.get("ips_nombre")
|
||||||
|
if not result.get("ips_nit") and extra.get("ips_nit"):
|
||||||
|
result["ips_nit"] = extra.get("ips_nit")
|
||||||
|
if not result.get("fecha_ingreso_urgencias") and extra.get(
|
||||||
|
"fecha_ingreso_urgencias"
|
||||||
|
):
|
||||||
|
result["fecha_ingreso_urgencias"] = extra.get("fecha_ingreso_urgencias")
|
||||||
|
if not result.get("cups_busqueda") and extra.get("cups_busqueda"):
|
||||||
|
result["cups_busqueda"] = extra.get("cups_busqueda")
|
||||||
|
if result.get("formato") == "DESCONOCIDO" and extra.get("formato"):
|
||||||
|
result["formato"] = extra.get("formato")
|
||||||
|
|
||||||
|
if not result.get("cup_codigo") and result.get("cups_codigos"):
|
||||||
|
result["cup_codigo"] = result["cups_codigos"][0]
|
||||||
|
if not result.get("cie10_codigo") and result.get("cie10_codigos"):
|
||||||
|
result["cie10_codigo"] = ", ".join(result["cie10_codigos"])
|
||||||
|
if not result.get("cie10_descripcion") and result.get("cie10_descripciones"):
|
||||||
|
result["cie10_descripcion"] = ", ".join(
|
||||||
|
[d for d in result["cie10_descripciones"] if d]
|
||||||
|
)
|
||||||
|
|
||||||
|
warnings = list(result.get("warnings") or [])
|
||||||
|
if result.get("cup_codigo") or result.get("cups_codigos"):
|
||||||
|
warnings = [w for w in warnings if w != "cups_not_found"]
|
||||||
|
if result.get("cie10_codigo") or result.get("cie10_codigos"):
|
||||||
|
warnings = [w for w in warnings if w != "cie10_not_found"]
|
||||||
|
if result.get("ips_nombre") or result.get("ips_nit"):
|
||||||
|
warnings = [w for w in warnings if w != "ips_not_found"]
|
||||||
|
result["warnings"] = warnings
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
def build_response(text, ocr_used, ocr_available, ocr_error):
|
def build_response(text, ocr_used, ocr_available, ocr_error):
|
||||||
lines = [line.strip() for line in (text or "").split("\n") if line.strip()]
|
lines = [line.strip() for line in (text or "").split("\n") if line.strip()]
|
||||||
norm_lines = [normalize(line) for line in lines]
|
norm_lines = [normalize(line) for line in lines]
|
||||||
@ -394,18 +582,26 @@ def build_response(text, ocr_used, ocr_available, ocr_error):
|
|||||||
|
|
||||||
nombre = extract_name(lines, norm_lines)
|
nombre = extract_name(lines, norm_lines)
|
||||||
documento = extract_document(lines, norm_lines)
|
documento = extract_document(lines, norm_lines)
|
||||||
cup_codigo, cup_desc = extract_cups(lines, norm_lines)
|
cups_list = extract_cups_list(lines, norm_lines)
|
||||||
|
cup_codigo, cup_desc = (cups_list[0] if cups_list else (None, None))
|
||||||
|
cups_codigos = [item[0] for item in cups_list]
|
||||||
|
cups_descripciones = [item[1] for item in cups_list]
|
||||||
cups_busqueda = extract_cups_hint(lines, norm_lines)
|
cups_busqueda = extract_cups_hint(lines, norm_lines)
|
||||||
cie_codigo, cie_desc = extract_cie10(lines, norm_lines)
|
cie_list = extract_cie10_list(lines, norm_lines)
|
||||||
|
cie_codigos = [item[0] for item in cie_list]
|
||||||
|
cie_descs = [item[1] for item in cie_list]
|
||||||
|
cie_codigo = ", ".join(cie_codigos) if cie_codigos else None
|
||||||
|
cie_desc = ", ".join([d for d in cie_descs if d]) if any(cie_descs) else None
|
||||||
ips_nombre, ips_nit = extract_ips(lines, norm_lines)
|
ips_nombre, ips_nit = extract_ips(lines, norm_lines)
|
||||||
|
fecha_ingreso = extract_fecha_ingreso_urgencias(lines, norm_lines)
|
||||||
formato = detect_format(norm_text, norm_lines)
|
formato = detect_format(norm_text, norm_lines)
|
||||||
|
|
||||||
warnings = []
|
warnings = []
|
||||||
if not text:
|
if not text:
|
||||||
warnings.append("no_text_extracted")
|
warnings.append("no_text_extracted")
|
||||||
if not cup_codigo:
|
if not cup_codigo and not cups_codigos:
|
||||||
warnings.append("cups_not_found")
|
warnings.append("cups_not_found")
|
||||||
if not cie_codigo:
|
if not cie_codigo and not cie_codigos:
|
||||||
warnings.append("cie10_not_found")
|
warnings.append("cie10_not_found")
|
||||||
if not ips_nombre and not ips_nit:
|
if not ips_nombre and not ips_nit:
|
||||||
warnings.append("ips_not_found")
|
warnings.append("ips_not_found")
|
||||||
@ -421,11 +617,16 @@ def build_response(text, ocr_used, ocr_available, ocr_error):
|
|||||||
"numero_documento": documento,
|
"numero_documento": documento,
|
||||||
"cup_codigo": cup_codigo,
|
"cup_codigo": cup_codigo,
|
||||||
"cup_descripcion": cup_desc,
|
"cup_descripcion": cup_desc,
|
||||||
|
"cups_codigos": cups_codigos,
|
||||||
|
"cups_descripciones": cups_descripciones,
|
||||||
"cups_busqueda": cups_busqueda,
|
"cups_busqueda": cups_busqueda,
|
||||||
"cie10_codigo": cie_codigo,
|
"cie10_codigo": cie_codigo,
|
||||||
"cie10_descripcion": cie_desc,
|
"cie10_descripcion": cie_desc,
|
||||||
|
"cie10_codigos": cie_codigos,
|
||||||
|
"cie10_descripciones": cie_descs,
|
||||||
"ips_nombre": ips_nombre,
|
"ips_nombre": ips_nombre,
|
||||||
"ips_nit": ips_nit,
|
"ips_nit": ips_nit,
|
||||||
|
"fecha_ingreso_urgencias": fecha_ingreso,
|
||||||
"warnings": warnings,
|
"warnings": warnings,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -441,18 +642,29 @@ def main():
|
|||||||
if not text:
|
if not text:
|
||||||
text = extract_text_fitz(path)
|
text = extract_text_fitz(path)
|
||||||
|
|
||||||
normalized_len = len(normalize(text))
|
|
||||||
ocr_used = False
|
ocr_used = False
|
||||||
ocr_error = ""
|
ocr_error = ""
|
||||||
ocr_available = is_tesseract_available()
|
ocr_available = is_tesseract_available()
|
||||||
|
|
||||||
if normalized_len < 50 and ocr_available:
|
response = build_response(text, False, ocr_available, None)
|
||||||
|
needs_ocr = ocr_available and (
|
||||||
|
not response.get("cup_codigo") or not response.get("cie10_codigo")
|
||||||
|
)
|
||||||
|
|
||||||
|
if needs_ocr:
|
||||||
ocr_text, ocr_error = extract_text_ocr(path)
|
ocr_text, ocr_error = extract_text_ocr(path)
|
||||||
if ocr_text:
|
if ocr_text:
|
||||||
text = ocr_text
|
|
||||||
ocr_used = True
|
ocr_used = True
|
||||||
|
ocr_response = build_response(ocr_text, True, ocr_available, ocr_error)
|
||||||
|
response = merge_response(response, ocr_response)
|
||||||
|
if ocr_error:
|
||||||
|
response["ocr_error"] = ocr_error
|
||||||
|
|
||||||
|
response["ocr_usado"] = bool(ocr_used)
|
||||||
|
response["ocr_disponible"] = bool(ocr_available)
|
||||||
|
if "ocr_error" not in response:
|
||||||
|
response["ocr_error"] = ocr_error or None
|
||||||
|
|
||||||
response = build_response(text, ocr_used, ocr_available, ocr_error)
|
|
||||||
print(json.dumps(response, ensure_ascii=True))
|
print(json.dumps(response, ensure_ascii=True))
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -184,7 +184,7 @@ CREATE TABLE IF NOT EXISTS autorizacion (
|
|||||||
fecha_autorizacion date NOT NULL DEFAULT current_date,
|
fecha_autorizacion date NOT NULL DEFAULT current_date,
|
||||||
observacion text,
|
observacion text,
|
||||||
cup_codigo varchar(20),
|
cup_codigo varchar(20),
|
||||||
cie10_codigo varchar(20),
|
cie10_codigo text,
|
||||||
cie10_descripcion text,
|
cie10_descripcion text,
|
||||||
tipo_autorizacion varchar(50) NOT NULL DEFAULT 'consultas_externas',
|
tipo_autorizacion varchar(50) NOT NULL DEFAULT 'consultas_externas',
|
||||||
tipo_servicio varchar(50),
|
tipo_servicio varchar(50),
|
||||||
@ -331,7 +331,7 @@ CREATE TABLE IF NOT EXISTS autorizacion_version (
|
|||||||
fecha_autorizacion DATE,
|
fecha_autorizacion DATE,
|
||||||
observacion TEXT,
|
observacion TEXT,
|
||||||
cup_codigo VARCHAR(20),
|
cup_codigo VARCHAR(20),
|
||||||
cie10_codigo VARCHAR(20),
|
cie10_codigo TEXT,
|
||||||
cie10_descripcion TEXT,
|
cie10_descripcion TEXT,
|
||||||
tipo_autorizacion VARCHAR(50),
|
tipo_autorizacion VARCHAR(50),
|
||||||
tipo_servicio VARCHAR(50),
|
tipo_servicio VARCHAR(50),
|
||||||
|
|||||||
@ -385,6 +385,11 @@ const ensureAutorizacionExtras = async () => {
|
|||||||
ADD COLUMN IF NOT EXISTS cie10_codigo VARCHAR(20);
|
ADD COLUMN IF NOT EXISTS cie10_codigo VARCHAR(20);
|
||||||
`);
|
`);
|
||||||
|
|
||||||
|
await pool.query(`
|
||||||
|
ALTER TABLE autorizacion
|
||||||
|
ALTER COLUMN cie10_codigo TYPE TEXT;
|
||||||
|
`);
|
||||||
|
|
||||||
await pool.query(`
|
await pool.query(`
|
||||||
ALTER TABLE autorizacion
|
ALTER TABLE autorizacion
|
||||||
ADD COLUMN IF NOT EXISTS cie10_descripcion TEXT;
|
ADD COLUMN IF NOT EXISTS cie10_descripcion TEXT;
|
||||||
@ -474,6 +479,11 @@ const ensureAutorizacionExtras = async () => {
|
|||||||
ADD COLUMN IF NOT EXISTS cie10_codigo VARCHAR(20);
|
ADD COLUMN IF NOT EXISTS cie10_codigo VARCHAR(20);
|
||||||
`);
|
`);
|
||||||
|
|
||||||
|
await pool.query(`
|
||||||
|
ALTER TABLE autorizacion_version
|
||||||
|
ALTER COLUMN cie10_codigo TYPE TEXT;
|
||||||
|
`);
|
||||||
|
|
||||||
await pool.query(`
|
await pool.query(`
|
||||||
ALTER TABLE autorizacion_version
|
ALTER TABLE autorizacion_version
|
||||||
ADD COLUMN IF NOT EXISTS cie10_descripcion TEXT;
|
ADD COLUMN IF NOT EXISTS cie10_descripcion TEXT;
|
||||||
@ -1641,14 +1651,35 @@ async function procesarExcelIps(inputFilePath) {
|
|||||||
const codigoKeys = new Set();
|
const codigoKeys = new Set();
|
||||||
const nombreKeys = new Set();
|
const nombreKeys = new Set();
|
||||||
|
|
||||||
|
const registerDigits = (set, value) => {
|
||||||
|
const digits = normalizeDigits(value);
|
||||||
|
if (!digits) return '';
|
||||||
|
set.add(digits);
|
||||||
|
if (digits.length >= 10) {
|
||||||
|
set.add(digits.slice(0, -1));
|
||||||
|
}
|
||||||
|
return digits;
|
||||||
|
};
|
||||||
|
|
||||||
const client = await pool.connect();
|
const client = await pool.connect();
|
||||||
try {
|
try {
|
||||||
await client.query('BEGIN');
|
await client.query('BEGIN');
|
||||||
|
|
||||||
for (let i = 2; i <= sheet.rowCount; i++) {
|
for (let i = 2; i <= sheet.rowCount; i++) {
|
||||||
const row = sheet.getRow(i);
|
const row = sheet.getRow(i);
|
||||||
const nit = getValue(row, 'NIT');
|
const nit = getValueMulti(row, [
|
||||||
const nombre = getValue(row, 'PRESTADOR');
|
'NIT',
|
||||||
|
'NITIPS',
|
||||||
|
'NITPRESTADOR',
|
||||||
|
'NITPRESTADORIPS',
|
||||||
|
]);
|
||||||
|
const nombre = getValueMulti(row, [
|
||||||
|
'PRESTADOR',
|
||||||
|
'PRESTADORDELSERVICIO',
|
||||||
|
'PRESTADORDESERVICIO',
|
||||||
|
'NOMBREPRESTADOR',
|
||||||
|
'NOMBREIPS',
|
||||||
|
]);
|
||||||
|
|
||||||
if (!nit && !nombre) {
|
if (!nit && !nombre) {
|
||||||
continue;
|
continue;
|
||||||
@ -1660,28 +1691,66 @@ async function procesarExcelIps(inputFilePath) {
|
|||||||
const departamento = getValue(row, 'DEPARTAMENTO');
|
const departamento = getValue(row, 'DEPARTAMENTO');
|
||||||
const municipio = getValue(row, 'MUNICIPIO');
|
const municipio = getValue(row, 'MUNICIPIO');
|
||||||
const telefono = getValue(row, 'TELEFONO');
|
const telefono = getValue(row, 'TELEFONO');
|
||||||
const codigoIps = getValue(row, 'CODIGOIPS');
|
const codigoIps = getValueMulti(row, [
|
||||||
|
'CODIGOIPS',
|
||||||
|
'CODIGOPRESTADOR',
|
||||||
|
'CODIGOHABILITACION',
|
||||||
|
]);
|
||||||
|
|
||||||
|
const nitDigits = registerDigits(nitKeys, nit);
|
||||||
|
const codigoDigits = registerDigits(codigoKeys, codigoIps);
|
||||||
|
const lookupKeys = [];
|
||||||
|
if (nitDigits) {
|
||||||
|
lookupKeys.push(nitDigits);
|
||||||
|
if (nitDigits.length >= 10) lookupKeys.push(nitDigits.slice(0, -1));
|
||||||
|
}
|
||||||
|
if (codigoDigits) {
|
||||||
|
lookupKeys.push(codigoDigits);
|
||||||
|
if (codigoDigits.length >= 10) lookupKeys.push(codigoDigits.slice(0, -1));
|
||||||
|
}
|
||||||
|
|
||||||
const nitDigits = normalizeDigits(nit);
|
|
||||||
const codigoDigits = normalizeDigits(codigoIps);
|
|
||||||
const lookupKey = nitDigits || codigoDigits;
|
|
||||||
const nombreKey = normalizeNameKey(nombre);
|
const nombreKey = normalizeNameKey(nombre);
|
||||||
|
|
||||||
if (nitDigits) nitKeys.add(nitDigits);
|
|
||||||
if (codigoDigits) codigoKeys.add(codigoDigits);
|
|
||||||
if (nombreKey) nombreKeys.add(nombreKey);
|
if (nombreKey) nombreKeys.add(nombreKey);
|
||||||
|
|
||||||
let existente = null;
|
let existente = null;
|
||||||
if (lookupKey) {
|
if (lookupKeys.length > 0) {
|
||||||
const res = await client.query(
|
const res = await client.query(
|
||||||
`
|
`
|
||||||
SELECT id_ips
|
SELECT id_ips
|
||||||
FROM ips
|
FROM ips
|
||||||
WHERE regexp_replace(nit, '\\D', '', 'g') = $1
|
WHERE regexp_replace(nit, '\\D', '', 'g') = ANY($1::text[])
|
||||||
OR regexp_replace(codigo_ips, '\\D', '', 'g') = $1
|
OR regexp_replace(codigo_ips, '\\D', '', 'g') = ANY($1::text[])
|
||||||
LIMIT 1
|
LIMIT 1
|
||||||
`,
|
`,
|
||||||
[lookupKey]
|
[lookupKeys]
|
||||||
|
);
|
||||||
|
existente = res.rows[0] || null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!existente && nitDigits && nitDigits.length >= 8) {
|
||||||
|
const res = await client.query(
|
||||||
|
`
|
||||||
|
SELECT id_ips
|
||||||
|
FROM ips
|
||||||
|
WHERE regexp_replace(nit, '\\D', '', 'g') LIKE $1
|
||||||
|
AND length(regexp_replace(nit, '\\D', '', 'g')) = $2
|
||||||
|
LIMIT 1
|
||||||
|
`,
|
||||||
|
[`${nitDigits}%`, nitDigits.length + 1]
|
||||||
|
);
|
||||||
|
existente = res.rows[0] || null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!existente && codigoDigits && codigoDigits.length >= 8) {
|
||||||
|
const res = await client.query(
|
||||||
|
`
|
||||||
|
SELECT id_ips
|
||||||
|
FROM ips
|
||||||
|
WHERE regexp_replace(codigo_ips, '\\D', '', 'g') LIKE $1
|
||||||
|
AND length(regexp_replace(codigo_ips, '\\D', '', 'g')) = $2
|
||||||
|
LIMIT 1
|
||||||
|
`,
|
||||||
|
[`${codigoDigits}%`, codigoDigits.length + 1]
|
||||||
);
|
);
|
||||||
existente = res.rows[0] || null;
|
existente = res.rows[0] || null;
|
||||||
}
|
}
|
||||||
@ -1753,6 +1822,26 @@ async function procesarExcelIps(inputFilePath) {
|
|||||||
const nitList = Array.from(nitKeys);
|
const nitList = Array.from(nitKeys);
|
||||||
const codigoList = Array.from(codigoKeys);
|
const codigoList = Array.from(codigoKeys);
|
||||||
const nombreList = Array.from(nombreKeys);
|
const nombreList = Array.from(nombreKeys);
|
||||||
|
const nitPrefixList = nitList.filter((nit) => nit.length >= 8 && nit.length <= 9);
|
||||||
|
const codigoPrefixList = codigoList.filter(
|
||||||
|
(codigo) => codigo.length >= 8 && codigo.length <= 9
|
||||||
|
);
|
||||||
|
|
||||||
|
if (nombreList.length > 0) {
|
||||||
|
await client.query(
|
||||||
|
`
|
||||||
|
UPDATE ips
|
||||||
|
SET tiene_convenio = true
|
||||||
|
WHERE regexp_replace(
|
||||||
|
translate(UPPER(nombre_ips), 'ÁÉÍÓÚÜÑ', 'AEIOUUN'),
|
||||||
|
'[^A-Z0-9]',
|
||||||
|
'',
|
||||||
|
'g'
|
||||||
|
) = ANY($1::text[])
|
||||||
|
`,
|
||||||
|
[nombreList]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
const desactRes = await client.query(
|
const desactRes = await client.query(
|
||||||
`
|
`
|
||||||
@ -1761,6 +1850,24 @@ async function procesarExcelIps(inputFilePath) {
|
|||||||
WHERE NOT (
|
WHERE NOT (
|
||||||
(regexp_replace(nit, '\\D', '', 'g') <> '' AND regexp_replace(nit, '\\D', '', 'g') = ANY($1::text[]))
|
(regexp_replace(nit, '\\D', '', 'g') <> '' AND regexp_replace(nit, '\\D', '', 'g') = ANY($1::text[]))
|
||||||
OR (regexp_replace(codigo_ips, '\\D', '', 'g') <> '' AND regexp_replace(codigo_ips, '\\D', '', 'g') = ANY($2::text[]))
|
OR (regexp_replace(codigo_ips, '\\D', '', 'g') <> '' AND regexp_replace(codigo_ips, '\\D', '', 'g') = ANY($2::text[]))
|
||||||
|
OR (
|
||||||
|
regexp_replace(nit, '\\D', '', 'g') <> ''
|
||||||
|
AND EXISTS (
|
||||||
|
SELECT 1
|
||||||
|
FROM unnest($3::text[]) AS k
|
||||||
|
WHERE regexp_replace(nit, '\\D', '', 'g') LIKE k || '%'
|
||||||
|
AND length(regexp_replace(nit, '\\D', '', 'g')) = length(k) + 1
|
||||||
|
)
|
||||||
|
)
|
||||||
|
OR (
|
||||||
|
regexp_replace(codigo_ips, '\\D', '', 'g') <> ''
|
||||||
|
AND EXISTS (
|
||||||
|
SELECT 1
|
||||||
|
FROM unnest($4::text[]) AS k
|
||||||
|
WHERE regexp_replace(codigo_ips, '\\D', '', 'g') LIKE k || '%'
|
||||||
|
AND length(regexp_replace(codigo_ips, '\\D', '', 'g')) = length(k) + 1
|
||||||
|
)
|
||||||
|
)
|
||||||
OR (
|
OR (
|
||||||
regexp_replace(
|
regexp_replace(
|
||||||
translate(UPPER(nombre_ips), 'ÁÉÍÓÚÜÑ', 'AEIOUUN'),
|
translate(UPPER(nombre_ips), 'ÁÉÍÓÚÜÑ', 'AEIOUUN'),
|
||||||
@ -1773,12 +1880,12 @@ async function procesarExcelIps(inputFilePath) {
|
|||||||
'[^A-Z0-9]',
|
'[^A-Z0-9]',
|
||||||
'',
|
'',
|
||||||
'g'
|
'g'
|
||||||
) = ANY($3::text[])
|
) = ANY($5::text[])
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
AND tiene_convenio IS DISTINCT FROM false
|
AND tiene_convenio IS DISTINCT FROM false
|
||||||
`,
|
`,
|
||||||
[nitList, codigoList, nombreList]
|
[nitList, codigoList, nitPrefixList, codigoPrefixList, nombreList]
|
||||||
);
|
);
|
||||||
|
|
||||||
resumen.desactivados = desactRes.rowCount || 0;
|
resumen.desactivados = desactRes.rowCount || 0;
|
||||||
@ -2143,7 +2250,12 @@ async function procesarExcelAutorizacionesMasivas(inputFilePath, usuario) {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const servicioExcel = getValue(row, 'SERVICIO');
|
const servicioExcel = getValueMulti(row, [
|
||||||
|
'SERVICIO',
|
||||||
|
'TIPOSERVICIO',
|
||||||
|
'TIPODESERVICIO',
|
||||||
|
'SERVICIOAUTORIZACION',
|
||||||
|
]);
|
||||||
const servicioInfo = parseServicio(servicioExcel);
|
const servicioInfo = parseServicio(servicioExcel);
|
||||||
|
|
||||||
const ambitoRaw = getValueMulti(row, [
|
const ambitoRaw = getValueMulti(row, [
|
||||||
@ -2248,35 +2360,63 @@ async function procesarExcelAutorizacionesMasivas(inputFilePath, usuario) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const ipsKey = normalizeDigits(nitIps) || normalizeSearch(hospital);
|
const nitKeyRaw = normalizeDigits(nitIps);
|
||||||
|
const nitKey = nitKeyRaw.length >= 10 ? nitKeyRaw.slice(0, -1) : nitKeyRaw;
|
||||||
|
const hospitalKey = normalizeNameKey(hospital);
|
||||||
|
const ipsKey = nitKey || hospitalKey;
|
||||||
let ipsInfo = ipsCache.get(ipsKey);
|
let ipsInfo = ipsCache.get(ipsKey);
|
||||||
|
|
||||||
if (!ipsInfo) {
|
if (!ipsInfo) {
|
||||||
const nitDigits = normalizeDigits(nitIps);
|
const nitDigits = normalizeDigits(nitIps);
|
||||||
let ipsRes = null;
|
const lookupKeys = [];
|
||||||
if (nitDigits) {
|
if (nitDigits) {
|
||||||
|
lookupKeys.push(nitDigits);
|
||||||
|
if (nitDigits.length >= 10) lookupKeys.push(nitDigits.slice(0, -1));
|
||||||
|
}
|
||||||
|
let ipsRes = null;
|
||||||
|
if (lookupKeys.length > 0) {
|
||||||
ipsRes = await client.query(
|
ipsRes = await client.query(
|
||||||
`
|
`
|
||||||
SELECT id_ips, nombre_ips, tiene_convenio, departamento, municipio
|
SELECT id_ips, nombre_ips, tiene_convenio, departamento, municipio
|
||||||
FROM ips
|
FROM ips
|
||||||
WHERE regexp_replace(nit, '\\D', '', 'g') = $1
|
WHERE regexp_replace(nit, '\\D', '', 'g') = ANY($1::text[])
|
||||||
OR regexp_replace(codigo_ips, '\\D', '', 'g') = $1
|
OR regexp_replace(codigo_ips, '\\D', '', 'g') = ANY($1::text[])
|
||||||
LIMIT 1
|
LIMIT 1
|
||||||
`,
|
`,
|
||||||
[nitDigits]
|
[lookupKeys]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ipsRes || ipsRes.rows.length === 0) {
|
if (!ipsRes || ipsRes.rows.length === 0) {
|
||||||
if (hospital) {
|
if (nitDigits && nitDigits.length >= 8) {
|
||||||
ipsRes = await client.query(
|
ipsRes = await client.query(
|
||||||
`
|
`
|
||||||
SELECT id_ips, nombre_ips, tiene_convenio, departamento, municipio
|
SELECT id_ips, nombre_ips, tiene_convenio, departamento, municipio
|
||||||
FROM ips
|
FROM ips
|
||||||
WHERE UPPER(nombre_ips) = $1
|
WHERE regexp_replace(nit, '\\D', '', 'g') LIKE $1
|
||||||
|
AND length(regexp_replace(nit, '\\D', '', 'g')) = $2
|
||||||
LIMIT 1
|
LIMIT 1
|
||||||
`,
|
`,
|
||||||
[normalizeSearch(hospital)]
|
[`${nitDigits}%`, nitDigits.length + 1]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ipsRes || ipsRes.rows.length === 0) {
|
||||||
|
if (hospitalKey) {
|
||||||
|
ipsRes = await client.query(
|
||||||
|
`
|
||||||
|
SELECT id_ips, nombre_ips, tiene_convenio, departamento, municipio
|
||||||
|
FROM ips
|
||||||
|
WHERE regexp_replace(
|
||||||
|
translate(UPPER(nombre_ips), 'ÁÉÍÓÚÜÑ', 'AEIOUUN'),
|
||||||
|
'[^A-Z0-9]',
|
||||||
|
'',
|
||||||
|
'g'
|
||||||
|
) = $1
|
||||||
|
LIMIT 1
|
||||||
|
`,
|
||||||
|
[hospitalKey]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2363,7 +2503,7 @@ async function procesarExcelAutorizacionesMasivas(inputFilePath, usuario) {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const dupRes = await client.query(
|
let dupRes = await client.query(
|
||||||
`
|
`
|
||||||
SELECT 1
|
SELECT 1
|
||||||
FROM autorizacion
|
FROM autorizacion
|
||||||
@ -2383,6 +2523,34 @@ async function procesarExcelAutorizacionesMasivas(inputFilePath, usuario) {
|
|||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (dupRes.rows.length === 0 && hospitalKey) {
|
||||||
|
dupRes = await client.query(
|
||||||
|
`
|
||||||
|
SELECT 1
|
||||||
|
FROM autorizacion a
|
||||||
|
JOIN ips i ON a.id_ips = i.id_ips
|
||||||
|
WHERE a.interno = $1
|
||||||
|
AND a.cup_codigo = $2
|
||||||
|
AND a.tipo_autorizacion = $3
|
||||||
|
AND COALESCE(a.tipo_servicio, '') = $4
|
||||||
|
AND regexp_replace(
|
||||||
|
translate(UPPER(i.nombre_ips), 'ÁÉÍÓÚÜÑ', 'AEIOUUN'),
|
||||||
|
'[^A-Z0-9]',
|
||||||
|
'',
|
||||||
|
'g'
|
||||||
|
) = $5
|
||||||
|
LIMIT 1
|
||||||
|
`,
|
||||||
|
[
|
||||||
|
interno,
|
||||||
|
cupCodigo,
|
||||||
|
servicioInfo.tipo_autorizacion,
|
||||||
|
servicioInfo.tipo_servicio || '',
|
||||||
|
hospitalKey,
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
if (dupRes.rows.length > 0) {
|
if (dupRes.rows.length > 0) {
|
||||||
resumen.omitidas += 1;
|
resumen.omitidas += 1;
|
||||||
resumen.duplicados += 1;
|
resumen.duplicados += 1;
|
||||||
@ -4709,7 +4877,7 @@ app.get('/api/autorizaciones-por-fecha', verificarToken, async (req, res) => {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const esAdmin = req.usuario?.nombre_rol === 'administrador';
|
const esAdmin = req.usuario?.nombre_rol === 'administrador';
|
||||||
const limit = Math.min(Number(req.query.limit) || 500, 2000);
|
const limit = Math.min(Number(req.query.limit) || 100000, 100000);
|
||||||
const offset = Math.max(Number(req.query.offset) || 0, 0);
|
const offset = Math.max(Number(req.query.offset) || 0, 0);
|
||||||
const ambitosPermitidos = ['intramural', 'extramural'];
|
const ambitosPermitidos = ['intramural', 'extramural'];
|
||||||
if (ambito && !ambitosPermitidos.includes(ambito)) {
|
if (ambito && !ambitosPermitidos.includes(ambito)) {
|
||||||
|
|||||||
@ -20,7 +20,7 @@ export class AutorizacionesPorFechaComponent implements OnInit {
|
|||||||
isLoading = false;
|
isLoading = false;
|
||||||
errorMessage: string | null = null;
|
errorMessage: string | null = null;
|
||||||
successMessage: string | null = null;
|
successMessage: string | null = null;
|
||||||
limiteAutorizaciones = 500;
|
limiteAutorizaciones = 100000;
|
||||||
avisoAutorizaciones = false;
|
avisoAutorizaciones = false;
|
||||||
descargandoZip = false;
|
descargandoZip = false;
|
||||||
descargandoPdf = false;
|
descargandoPdf = false;
|
||||||
|
|||||||
@ -429,6 +429,34 @@ export class AutorizacionesComponent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const observacionExtras: string[] = [];
|
||||||
|
const cupsCodigos = Array.isArray(resp?.cups_codigos)
|
||||||
|
? resp.cups_codigos
|
||||||
|
: [];
|
||||||
|
const cupsDescripciones = Array.isArray(resp?.cups_descripciones)
|
||||||
|
? resp.cups_descripciones
|
||||||
|
: [];
|
||||||
|
if (cupsCodigos.length > 1) {
|
||||||
|
const extras = cupsCodigos.slice(1).map((codigo: string, idx: number) => {
|
||||||
|
const desc = cupsDescripciones[idx + 1];
|
||||||
|
return desc ? `${codigo} ${desc}` : codigo;
|
||||||
|
});
|
||||||
|
if (extras.length) {
|
||||||
|
observacionExtras.push(`CUPS adicionales: ${extras.join(', ')}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (resp?.fecha_ingreso_urgencias) {
|
||||||
|
observacionExtras.push(`Ingreso a urgencias: ${resp.fecha_ingreso_urgencias}`);
|
||||||
|
}
|
||||||
|
if (observacionExtras.length) {
|
||||||
|
const actual = String(this.formAutorizacion.observacion || '').trim();
|
||||||
|
const nuevos = observacionExtras.filter(
|
||||||
|
(parte) => !actual.toLowerCase().includes(parte.toLowerCase())
|
||||||
|
);
|
||||||
|
this.formAutorizacion.observacion =
|
||||||
|
[actual, ...nuevos].filter(Boolean).join(' | ');
|
||||||
|
}
|
||||||
|
|
||||||
const infoParts = [];
|
const infoParts = [];
|
||||||
if (resp?.nombre_paciente) {
|
if (resp?.nombre_paciente) {
|
||||||
infoParts.push(`Paciente: ${resp.nombre_paciente}`);
|
infoParts.push(`Paciente: ${resp.nombre_paciente}`);
|
||||||
|
|||||||
@ -312,7 +312,7 @@ export class AuthService {
|
|||||||
getAutorizacionesPorFecha(
|
getAutorizacionesPorFecha(
|
||||||
fechaInicio: string,
|
fechaInicio: string,
|
||||||
fechaFin: string,
|
fechaFin: string,
|
||||||
limit = 500,
|
limit = 100000,
|
||||||
offset = 0,
|
offset = 0,
|
||||||
establecimiento?: string,
|
establecimiento?: string,
|
||||||
ambito?: string,
|
ambito?: string,
|
||||||
|
|||||||
BIN
yopal rx.xlsx
Normal file
BIN
yopal rx.xlsx
Normal file
Binary file not shown.
Loading…
Reference in New Issue
Block a user