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
|
||||
|
||||
|
||||
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):
|
||||
try:
|
||||
import pdfplumber # type: ignore
|
||||
@ -214,7 +235,9 @@ def extract_document(lines, norm_lines):
|
||||
def extract_cups_code(text):
|
||||
if not text:
|
||||
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:
|
||||
return match.group(0)
|
||||
digits = extract_digits_from_text(text, min_len=4, max_len=10)
|
||||
@ -223,25 +246,84 @@ def extract_cups_code(text):
|
||||
return None
|
||||
|
||||
|
||||
def extract_cups(lines, norm_lines):
|
||||
for i, line in enumerate(norm_lines):
|
||||
if (
|
||||
"CUPS" in line
|
||||
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)
|
||||
):
|
||||
for j in range(i, min(i + 8, len(lines))):
|
||||
code = extract_cups_code(lines[j])
|
||||
if not code:
|
||||
continue
|
||||
desc = ""
|
||||
raw = lines[j]
|
||||
if code in raw:
|
||||
desc = raw.split(code, 1)[-1].strip(" -:")
|
||||
if not desc and j + 1 < len(lines):
|
||||
desc = lines[j + 1].strip()
|
||||
return code, desc or None
|
||||
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):
|
||||
if (
|
||||
"CUPS" in line
|
||||
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)
|
||||
):
|
||||
for j in range(i, min(i + 8, len(lines))):
|
||||
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(" -:")
|
||||
if not desc and j + 1 < len(lines):
|
||||
desc = lines[j + 1].strip()
|
||||
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
|
||||
|
||||
|
||||
@ -305,26 +387,62 @@ def extract_cups_hint(lines, norm_lines):
|
||||
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):
|
||||
if (
|
||||
"DIAGNOSTICO PRINCIPAL" in nline
|
||||
"DIAGNOSTICO" in nline
|
||||
or "IMPRESION DIAGNOSTICA" in nline
|
||||
or "DIAGNOSTICO" in nline
|
||||
or "CIE10" in nline
|
||||
):
|
||||
candidate = lines[i]
|
||||
if i + 1 < len(lines) and len(lines[i + 1].split()) > 1:
|
||||
candidate = candidate + " " + lines[i + 1]
|
||||
code, desc = parse_cie10_from_line(candidate)
|
||||
if code:
|
||||
return code, desc or None
|
||||
for line in lines:
|
||||
code, desc = parse_cie10_from_line(line)
|
||||
if code:
|
||||
return code, desc or None
|
||||
for j in range(i, min(i + 6, len(lines))):
|
||||
code, desc = parse_cie10_from_line(lines[j])
|
||||
if not code:
|
||||
continue
|
||||
if code in seen:
|
||||
continue
|
||||
seen.add(code)
|
||||
results.append((code, desc))
|
||||
return results
|
||||
|
||||
|
||||
def extract_cie10(lines, norm_lines):
|
||||
cie_list = extract_cie10_list(lines, norm_lines)
|
||||
if cie_list:
|
||||
return cie_list[0]
|
||||
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):
|
||||
if not value:
|
||||
return ""
|
||||
@ -387,6 +505,76 @@ def detect_format(norm_text, norm_lines):
|
||||
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):
|
||||
lines = [line.strip() for line in (text or "").split("\n") if line.strip()]
|
||||
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)
|
||||
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)
|
||||
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)
|
||||
fecha_ingreso = extract_fecha_ingreso_urgencias(lines, norm_lines)
|
||||
formato = detect_format(norm_text, norm_lines)
|
||||
|
||||
warnings = []
|
||||
if not text:
|
||||
warnings.append("no_text_extracted")
|
||||
if not cup_codigo:
|
||||
if not cup_codigo and not cups_codigos:
|
||||
warnings.append("cups_not_found")
|
||||
if not cie_codigo:
|
||||
if not cie_codigo and not cie_codigos:
|
||||
warnings.append("cie10_not_found")
|
||||
if not ips_nombre and not ips_nit:
|
||||
warnings.append("ips_not_found")
|
||||
@ -421,11 +617,16 @@ def build_response(text, ocr_used, ocr_available, ocr_error):
|
||||
"numero_documento": documento,
|
||||
"cup_codigo": cup_codigo,
|
||||
"cup_descripcion": cup_desc,
|
||||
"cups_codigos": cups_codigos,
|
||||
"cups_descripciones": cups_descripciones,
|
||||
"cups_busqueda": cups_busqueda,
|
||||
"cie10_codigo": cie_codigo,
|
||||
"cie10_descripcion": cie_desc,
|
||||
"cie10_codigos": cie_codigos,
|
||||
"cie10_descripciones": cie_descs,
|
||||
"ips_nombre": ips_nombre,
|
||||
"ips_nit": ips_nit,
|
||||
"fecha_ingreso_urgencias": fecha_ingreso,
|
||||
"warnings": warnings,
|
||||
}
|
||||
|
||||
@ -441,18 +642,29 @@ def main():
|
||||
if not text:
|
||||
text = extract_text_fitz(path)
|
||||
|
||||
normalized_len = len(normalize(text))
|
||||
ocr_used = False
|
||||
ocr_error = ""
|
||||
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)
|
||||
if ocr_text:
|
||||
text = ocr_text
|
||||
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))
|
||||
|
||||
|
||||
|
||||
@ -184,7 +184,7 @@ CREATE TABLE IF NOT EXISTS autorizacion (
|
||||
fecha_autorizacion date NOT NULL DEFAULT current_date,
|
||||
observacion text,
|
||||
cup_codigo varchar(20),
|
||||
cie10_codigo varchar(20),
|
||||
cie10_codigo text,
|
||||
cie10_descripcion text,
|
||||
tipo_autorizacion varchar(50) NOT NULL DEFAULT 'consultas_externas',
|
||||
tipo_servicio varchar(50),
|
||||
@ -331,7 +331,7 @@ CREATE TABLE IF NOT EXISTS autorizacion_version (
|
||||
fecha_autorizacion DATE,
|
||||
observacion TEXT,
|
||||
cup_codigo VARCHAR(20),
|
||||
cie10_codigo VARCHAR(20),
|
||||
cie10_codigo TEXT,
|
||||
cie10_descripcion TEXT,
|
||||
tipo_autorizacion VARCHAR(50),
|
||||
tipo_servicio VARCHAR(50),
|
||||
|
||||
@ -385,6 +385,11 @@ const ensureAutorizacionExtras = async () => {
|
||||
ADD COLUMN IF NOT EXISTS cie10_codigo VARCHAR(20);
|
||||
`);
|
||||
|
||||
await pool.query(`
|
||||
ALTER TABLE autorizacion
|
||||
ALTER COLUMN cie10_codigo TYPE TEXT;
|
||||
`);
|
||||
|
||||
await pool.query(`
|
||||
ALTER TABLE autorizacion
|
||||
ADD COLUMN IF NOT EXISTS cie10_descripcion TEXT;
|
||||
@ -474,6 +479,11 @@ const ensureAutorizacionExtras = async () => {
|
||||
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(`
|
||||
ALTER TABLE autorizacion_version
|
||||
ADD COLUMN IF NOT EXISTS cie10_descripcion TEXT;
|
||||
@ -1641,14 +1651,35 @@ async function procesarExcelIps(inputFilePath) {
|
||||
const codigoKeys = 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();
|
||||
try {
|
||||
await client.query('BEGIN');
|
||||
|
||||
for (let i = 2; i <= sheet.rowCount; i++) {
|
||||
const row = sheet.getRow(i);
|
||||
const nit = getValue(row, 'NIT');
|
||||
const nombre = getValue(row, 'PRESTADOR');
|
||||
const nit = getValueMulti(row, [
|
||||
'NIT',
|
||||
'NITIPS',
|
||||
'NITPRESTADOR',
|
||||
'NITPRESTADORIPS',
|
||||
]);
|
||||
const nombre = getValueMulti(row, [
|
||||
'PRESTADOR',
|
||||
'PRESTADORDELSERVICIO',
|
||||
'PRESTADORDESERVICIO',
|
||||
'NOMBREPRESTADOR',
|
||||
'NOMBREIPS',
|
||||
]);
|
||||
|
||||
if (!nit && !nombre) {
|
||||
continue;
|
||||
@ -1660,28 +1691,66 @@ async function procesarExcelIps(inputFilePath) {
|
||||
const departamento = getValue(row, 'DEPARTAMENTO');
|
||||
const municipio = getValue(row, 'MUNICIPIO');
|
||||
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);
|
||||
|
||||
if (nitDigits) nitKeys.add(nitDigits);
|
||||
if (codigoDigits) codigoKeys.add(codigoDigits);
|
||||
if (nombreKey) nombreKeys.add(nombreKey);
|
||||
|
||||
let existente = null;
|
||||
if (lookupKey) {
|
||||
if (lookupKeys.length > 0) {
|
||||
const res = await client.query(
|
||||
`
|
||||
SELECT id_ips
|
||||
FROM ips
|
||||
WHERE regexp_replace(nit, '\\D', '', 'g') = $1
|
||||
OR regexp_replace(codigo_ips, '\\D', '', 'g') = $1
|
||||
WHERE regexp_replace(nit, '\\D', '', 'g') = ANY($1::text[])
|
||||
OR regexp_replace(codigo_ips, '\\D', '', 'g') = ANY($1::text[])
|
||||
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;
|
||||
}
|
||||
@ -1753,6 +1822,26 @@ async function procesarExcelIps(inputFilePath) {
|
||||
const nitList = Array.from(nitKeys);
|
||||
const codigoList = Array.from(codigoKeys);
|
||||
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(
|
||||
`
|
||||
@ -1761,6 +1850,24 @@ async function procesarExcelIps(inputFilePath) {
|
||||
WHERE NOT (
|
||||
(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(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 (
|
||||
regexp_replace(
|
||||
translate(UPPER(nombre_ips), 'ÁÉÍÓÚÜÑ', 'AEIOUUN'),
|
||||
@ -1773,12 +1880,12 @@ async function procesarExcelIps(inputFilePath) {
|
||||
'[^A-Z0-9]',
|
||||
'',
|
||||
'g'
|
||||
) = ANY($3::text[])
|
||||
) = ANY($5::text[])
|
||||
)
|
||||
)
|
||||
AND tiene_convenio IS DISTINCT FROM false
|
||||
`,
|
||||
[nitList, codigoList, nombreList]
|
||||
[nitList, codigoList, nitPrefixList, codigoPrefixList, nombreList]
|
||||
);
|
||||
|
||||
resumen.desactivados = desactRes.rowCount || 0;
|
||||
@ -2143,7 +2250,12 @@ async function procesarExcelAutorizacionesMasivas(inputFilePath, usuario) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const servicioExcel = getValue(row, 'SERVICIO');
|
||||
const servicioExcel = getValueMulti(row, [
|
||||
'SERVICIO',
|
||||
'TIPOSERVICIO',
|
||||
'TIPODESERVICIO',
|
||||
'SERVICIOAUTORIZACION',
|
||||
]);
|
||||
const servicioInfo = parseServicio(servicioExcel);
|
||||
|
||||
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);
|
||||
|
||||
if (!ipsInfo) {
|
||||
const nitDigits = normalizeDigits(nitIps);
|
||||
let ipsRes = null;
|
||||
const lookupKeys = [];
|
||||
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(
|
||||
`
|
||||
SELECT id_ips, nombre_ips, tiene_convenio, departamento, municipio
|
||||
FROM ips
|
||||
WHERE regexp_replace(nit, '\\D', '', 'g') = $1
|
||||
OR regexp_replace(codigo_ips, '\\D', '', 'g') = $1
|
||||
WHERE regexp_replace(nit, '\\D', '', 'g') = ANY($1::text[])
|
||||
OR regexp_replace(codigo_ips, '\\D', '', 'g') = ANY($1::text[])
|
||||
LIMIT 1
|
||||
`,
|
||||
[nitDigits]
|
||||
[lookupKeys]
|
||||
);
|
||||
}
|
||||
|
||||
if (!ipsRes || ipsRes.rows.length === 0) {
|
||||
if (hospital) {
|
||||
if (nitDigits && nitDigits.length >= 8) {
|
||||
ipsRes = await client.query(
|
||||
`
|
||||
SELECT id_ips, nombre_ips, tiene_convenio, departamento, municipio
|
||||
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
|
||||
`,
|
||||
[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;
|
||||
}
|
||||
|
||||
const dupRes = await client.query(
|
||||
let dupRes = await client.query(
|
||||
`
|
||||
SELECT 1
|
||||
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) {
|
||||
resumen.omitidas += 1;
|
||||
resumen.duplicados += 1;
|
||||
@ -4709,7 +4877,7 @@ app.get('/api/autorizaciones-por-fecha', verificarToken, async (req, res) => {
|
||||
|
||||
try {
|
||||
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 ambitosPermitidos = ['intramural', 'extramural'];
|
||||
if (ambito && !ambitosPermitidos.includes(ambito)) {
|
||||
|
||||
@ -20,7 +20,7 @@ export class AutorizacionesPorFechaComponent implements OnInit {
|
||||
isLoading = false;
|
||||
errorMessage: string | null = null;
|
||||
successMessage: string | null = null;
|
||||
limiteAutorizaciones = 500;
|
||||
limiteAutorizaciones = 100000;
|
||||
avisoAutorizaciones = false;
|
||||
descargandoZip = 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 = [];
|
||||
if (resp?.nombre_paciente) {
|
||||
infoParts.push(`Paciente: ${resp.nombre_paciente}`);
|
||||
|
||||
@ -312,7 +312,7 @@ export class AuthService {
|
||||
getAutorizacionesPorFecha(
|
||||
fechaInicio: string,
|
||||
fechaFin: string,
|
||||
limit = 500,
|
||||
limit = 100000,
|
||||
offset = 0,
|
||||
establecimiento?: 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