test-rda: add preview, ver más pagination, sent tracking, default contrato=011
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 4.6
parent
e477aa2bea
commit
ef71a1db56
@@ -39,6 +39,16 @@ def init_db():
|
|||||||
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
||||||
);
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS rda_test_log (
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
idrecepcion INTEGER NOT NULL,
|
||||||
|
factura TEXT,
|
||||||
|
contrato TEXT,
|
||||||
|
ok INTEGER NOT NULL DEFAULT 0,
|
||||||
|
mensaje TEXT,
|
||||||
|
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
||||||
|
);
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS envios (
|
CREATE TABLE IF NOT EXISTS envios (
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
user_id INTEGER,
|
user_id INTEGER,
|
||||||
|
|||||||
+49
-4
@@ -70,9 +70,21 @@ async def test_page(request: Request, user: dict = Depends(get_current_user)):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@router.get("/enviados")
|
||||||
|
async def get_enviados(request: Request, user: dict = Depends(get_current_user)):
|
||||||
|
db = get_connection()
|
||||||
|
rows = db.execute(
|
||||||
|
"SELECT idrecepcion, ok FROM rda_test_log ORDER BY created_at DESC"
|
||||||
|
).fetchall()
|
||||||
|
db.close()
|
||||||
|
enviados = {r["idrecepcion"]: bool(r["ok"]) for r in rows}
|
||||||
|
return JSONResponse({"enviados": enviados})
|
||||||
|
|
||||||
|
|
||||||
@router.get("/candidatos")
|
@router.get("/candidatos")
|
||||||
async def get_candidatos(request: Request, user: dict = Depends(get_current_user),
|
async def get_candidatos(request: Request, user: dict = Depends(get_current_user),
|
||||||
contrato: str = "", factura: str = "", articulos: str = ""):
|
contrato: str = "", factura: str = "", articulos: str = "",
|
||||||
|
offset: int = 0):
|
||||||
db = get_connection()
|
db = get_connection()
|
||||||
cfg = {r[0]: r[1] for r in db.execute("SELECT key, value FROM config").fetchall()}
|
cfg = {r[0]: r[1] for r in db.execute("SELECT key, value FROM config").fetchall()}
|
||||||
db.close()
|
db.close()
|
||||||
@@ -102,8 +114,8 @@ async def get_candidatos(request: Request, user: dict = Depends(get_current_user
|
|||||||
filtros.append("r.NUM_FACTURA = :factura")
|
filtros.append("r.NUM_FACTURA = :factura")
|
||||||
params["factura"] = int(factura)
|
params["factura"] = int(factura)
|
||||||
|
|
||||||
sql_final = """
|
sql_final = f"""
|
||||||
SELECT FIRST 10
|
SELECT FIRST 10 SKIP {int(offset)}
|
||||||
r.IDRECEPCION, r.NUM_FACTURA, r.FECHA_RECEPCION, r.COD_PACIENTE, r.NIT_EMPRESA,
|
r.IDRECEPCION, r.NUM_FACTURA, r.FECHA_RECEPCION, r.COD_PACIENTE, r.NIT_EMPRESA,
|
||||||
e.CODCONTRATO,
|
e.CODCONTRATO,
|
||||||
LIST(DISTINCT rel.COD_EXAMEN, ', ') AS EXAMENES,
|
LIST(DISTINCT rel.COD_EXAMEN, ', ') AS EXAMENES,
|
||||||
@@ -111,7 +123,7 @@ async def get_candidatos(request: Request, user: dict = Depends(get_current_user
|
|||||||
FROM RECEPCION r
|
FROM RECEPCION r
|
||||||
JOIN RELACION rel ON rel.IDRECEPCION = r.IDRECEPCION
|
JOIN RELACION rel ON rel.IDRECEPCION = r.IDRECEPCION
|
||||||
LEFT JOIN EMPRESA e ON e.NIT = r.NIT_EMPRESA
|
LEFT JOIN EMPRESA e ON e.NIT = r.NIT_EMPRESA
|
||||||
WHERE """ + " AND ".join(filtros) + """
|
WHERE {" AND ".join(filtros)}
|
||||||
GROUP BY r.IDRECEPCION, r.NUM_FACTURA, r.FECHA_RECEPCION, r.COD_PACIENTE, r.NIT_EMPRESA, e.CODCONTRATO
|
GROUP BY r.IDRECEPCION, r.NUM_FACTURA, r.FECHA_RECEPCION, r.COD_PACIENTE, r.NIT_EMPRESA, e.CODCONTRATO
|
||||||
ORDER BY r.IDRECEPCION DESC
|
ORDER BY r.IDRECEPCION DESC
|
||||||
"""
|
"""
|
||||||
@@ -138,6 +150,32 @@ async def get_candidatos(request: Request, user: dict = Depends(get_current_user
|
|||||||
return JSONResponse({"candidatos": candidatos})
|
return JSONResponse({"candidatos": candidatos})
|
||||||
|
|
||||||
|
|
||||||
|
@router.get("/preview")
|
||||||
|
async def preview_rda(request: Request, user: dict = Depends(get_current_user),
|
||||||
|
idrecepcion: int = 0):
|
||||||
|
if not idrecepcion:
|
||||||
|
return JSONResponse({"error": "Falta idrecepcion"})
|
||||||
|
db = get_connection()
|
||||||
|
cfg = {r[0]: r[1] for r in db.execute("SELECT key, value FROM config").fetchall()}
|
||||||
|
db.close()
|
||||||
|
prof_def = cfg.get("profesional_default", "XIMENA")
|
||||||
|
esp_def = cfg.get("especialidad_default", "02")
|
||||||
|
remis_def = cfg.get("remisionante_default", "00")
|
||||||
|
prefijo_def = cfg.get("prefijo_tns_default", "00")
|
||||||
|
fb, fb_ok, fb_msg = get_firebird_from_config(cfg)
|
||||||
|
if not fb_ok:
|
||||||
|
return JSONResponse({"error": fb_msg})
|
||||||
|
ok2, err2, rows_rda = fb.execute_query(
|
||||||
|
_SQL_RDA_BY_WHERE.format(where="r.IDRECEPCION = :val"), {"val": idrecepcion}
|
||||||
|
)
|
||||||
|
fb.disconnect()
|
||||||
|
if not ok2 or not rows_rda:
|
||||||
|
return JSONResponse({"error": err2 or "Sin registros"})
|
||||||
|
grupos = agrupar_por_recepcion(rows_rda)
|
||||||
|
rda_json = generar_rda_paciente(list(grupos.values())[0], prof_def, esp_def, remis_def, prefijo_def)
|
||||||
|
return JSONResponse({"json": rda_json})
|
||||||
|
|
||||||
|
|
||||||
@router.post("/enviar")
|
@router.post("/enviar")
|
||||||
async def test_enviar(request: Request, user: dict = Depends(get_current_user)):
|
async def test_enviar(request: Request, user: dict = Depends(get_current_user)):
|
||||||
form = await request.form()
|
form = await request.form()
|
||||||
@@ -259,6 +297,13 @@ async def test_enviar(request: Request, user: dict = Depends(get_current_user)):
|
|||||||
"respuesta_tns": raw_resp,
|
"respuesta_tns": raw_resp,
|
||||||
"json_enviado": rda_json,
|
"json_enviado": rda_json,
|
||||||
})
|
})
|
||||||
|
db_log = get_connection()
|
||||||
|
db_log.execute(
|
||||||
|
"INSERT OR REPLACE INTO rda_test_log (idrecepcion, factura, contrato, ok, mensaje) VALUES (?,?,?,?,?)",
|
||||||
|
(id_rec, rda_json.get("numero", ""), rda_json.get("numeroContrato", ""), 1 if ok_rda else 0, msg_rda)
|
||||||
|
)
|
||||||
|
db_log.commit()
|
||||||
|
db_log.close()
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
pasos.append({
|
pasos.append({
|
||||||
"tipo": "rda", "idrecepcion": id_rec, "ok": False,
|
"tipo": "rda", "idrecepcion": id_rec, "ok": False,
|
||||||
|
|||||||
+174
-43
@@ -6,15 +6,15 @@
|
|||||||
|
|
||||||
<!-- Filtros y candidatos -->
|
<!-- Filtros y candidatos -->
|
||||||
<div class="bg-white rounded-xl shadow-sm border border-gray-200">
|
<div class="bg-white rounded-xl shadow-sm border border-gray-200">
|
||||||
<div class="px-6 py-4 border-b border-gray-200 flex items-center justify-between">
|
<div class="px-6 py-4 border-b border-gray-200 flex items-center justify-between flex-wrap gap-2">
|
||||||
<h3 class="font-semibold text-gray-800"><i class="fas fa-list mr-2 text-blue-500"></i>Candidatos disponibles</h3>
|
<h3 class="font-semibold text-gray-800"><i class="fas fa-list mr-2 text-blue-500"></i>Candidatos disponibles</h3>
|
||||||
<div class="flex gap-2 items-center flex-wrap">
|
<div class="flex gap-2 items-center flex-wrap">
|
||||||
<input id="filtro-contrato" type="text" placeholder="Contrato (ej: 011)" value="011"
|
<input id="filtro-contrato" type="text" placeholder="Contrato (ej: 011)" value="011"
|
||||||
class="px-3 py-1.5 border border-gray-300 rounded-lg text-sm w-32">
|
class="px-3 py-1.5 border border-gray-300 rounded-lg text-sm w-28">
|
||||||
<input id="filtro-articulos" type="text" placeholder="Artículos (ej: CH4,TSH,GLI)"
|
<input id="filtro-articulos" type="text" placeholder="Artículos (vacío = lista TNS)"
|
||||||
class="px-3 py-1.5 border border-gray-300 rounded-lg text-sm w-56"
|
class="px-3 py-1.5 border border-gray-300 rounded-lg text-sm w-52"
|
||||||
title="Filtrar por artículos configurados en TNS. Vacío = lista predeterminada.">
|
title="Vacío = lista predeterminada de artículos configurados en TNS.">
|
||||||
<button onclick="cargarCandidatos()"
|
<button onclick="cargarCandidatos(true)"
|
||||||
class="px-4 py-1.5 bg-blue-600 text-white rounded-lg text-sm hover:bg-blue-700">
|
class="px-4 py-1.5 bg-blue-600 text-white rounded-lg text-sm hover:bg-blue-700">
|
||||||
<i class="fas fa-search mr-1"></i> Buscar
|
<i class="fas fa-search mr-1"></i> Buscar
|
||||||
</button>
|
</button>
|
||||||
@@ -35,23 +35,47 @@
|
|||||||
<th class="pb-2 pr-3">Paciente</th>
|
<th class="pb-2 pr-3">Paciente</th>
|
||||||
<th class="pb-2 pr-3">Contrato</th>
|
<th class="pb-2 pr-3">Contrato</th>
|
||||||
<th class="pb-2 pr-3">Exámenes</th>
|
<th class="pb-2 pr-3">Exámenes</th>
|
||||||
<th class="pb-2"></th>
|
<th class="pb-2 text-right">Acciones</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody id="tbody-candidatos" class="divide-y divide-gray-100"></tbody>
|
<tbody id="tbody-candidatos" class="divide-y divide-gray-100"></tbody>
|
||||||
</table>
|
</table>
|
||||||
|
<div class="mt-3 text-center">
|
||||||
|
<button id="btn-ver-mas" onclick="verMas()"
|
||||||
|
class="hidden px-4 py-1.5 bg-gray-100 hover:bg-gray-200 text-gray-700 rounded-lg text-sm">
|
||||||
|
<i class="fas fa-chevron-down mr-1"></i> Ver más
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<p id="sin-candidatos" class="hidden text-center py-6 text-gray-400 text-sm">No se encontraron registros con los filtros aplicados.</p>
|
<p id="sin-candidatos" class="hidden text-center py-6 text-gray-400 text-sm">No se encontraron registros con los filtros aplicados.</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Preview JSON -->
|
||||||
|
<div id="preview-box" class="hidden bg-white rounded-xl shadow-sm border border-blue-200">
|
||||||
|
<div class="px-6 py-4 border-b border-blue-100 flex items-center justify-between">
|
||||||
|
<h3 class="font-semibold text-gray-800"><i class="fas fa-eye mr-2 text-blue-500"></i>Preview — JSON a enviar <span id="preview-id" class="text-blue-600 font-mono text-sm"></span></h3>
|
||||||
|
<div class="flex gap-2">
|
||||||
|
<button onclick="enviarDesdePreview()"
|
||||||
|
class="px-4 py-1.5 bg-green-600 text-white rounded-lg text-sm hover:bg-green-700 font-medium">
|
||||||
|
<i class="fas fa-paper-plane mr-1"></i> Confirmar envío
|
||||||
|
</button>
|
||||||
|
<button onclick="document.getElementById('preview-box').classList.add('hidden')"
|
||||||
|
class="px-3 py-1.5 bg-gray-100 text-gray-600 rounded-lg text-sm hover:bg-gray-200">
|
||||||
|
Cancelar
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<pre id="preview-json" class="p-4 text-xs overflow-x-auto whitespace-pre-wrap bg-gray-50 text-gray-800 rounded-b-xl"></pre>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Envío manual -->
|
<!-- Envío manual -->
|
||||||
<div class="bg-white rounded-xl shadow-sm border border-gray-200">
|
<div class="bg-white rounded-xl shadow-sm border border-gray-200">
|
||||||
<div class="px-6 py-4 border-b border-gray-200">
|
<div class="px-6 py-4 border-b border-gray-200">
|
||||||
<h3 class="font-semibold text-gray-800"><i class="fas fa-paper-plane mr-2 text-green-500"></i>Enviar RDA</h3>
|
<h3 class="font-semibold text-gray-800"><i class="fas fa-paper-plane mr-2 text-green-500"></i>Enviar RDA directo</h3>
|
||||||
</div>
|
</div>
|
||||||
<div class="p-6">
|
<div class="p-6">
|
||||||
<div class="flex gap-3 items-end">
|
<div class="flex gap-3 items-end flex-wrap">
|
||||||
<div>
|
<div>
|
||||||
<label class="block text-xs font-medium text-gray-600 mb-1">Tipo</label>
|
<label class="block text-xs font-medium text-gray-600 mb-1">Tipo</label>
|
||||||
<select id="modo" class="px-3 py-2 border border-gray-300 rounded-lg text-sm">
|
<select id="modo" class="px-3 py-2 border border-gray-300 rounded-lg text-sm">
|
||||||
@@ -64,6 +88,10 @@
|
|||||||
<input id="valor" type="text" placeholder="ej: 314863"
|
<input id="valor" type="text" placeholder="ej: 314863"
|
||||||
class="w-full px-3 py-2 border border-gray-300 rounded-lg text-sm focus:ring-2 focus:ring-blue-500">
|
class="w-full px-3 py-2 border border-gray-300 rounded-lg text-sm focus:ring-2 focus:ring-blue-500">
|
||||||
</div>
|
</div>
|
||||||
|
<button onclick="previewManual()"
|
||||||
|
class="px-4 py-2 bg-blue-100 text-blue-700 rounded-lg text-sm hover:bg-blue-200 font-medium">
|
||||||
|
<i class="fas fa-eye mr-1"></i> Preview
|
||||||
|
</button>
|
||||||
<button onclick="enviarRDA()"
|
<button onclick="enviarRDA()"
|
||||||
class="px-5 py-2 bg-green-600 text-white rounded-lg text-sm hover:bg-green-700 font-medium">
|
class="px-5 py-2 bg-green-600 text-white rounded-lg text-sm hover:bg-green-700 font-medium">
|
||||||
<i class="fas fa-paper-plane mr-1"></i> Enviar
|
<i class="fas fa-paper-plane mr-1"></i> Enviar
|
||||||
@@ -84,14 +112,71 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
async function cargarCandidatos() {
|
let _offset = 0;
|
||||||
const contrato = document.getElementById('filtro-contrato').value.trim();
|
let _enviados = {}; // { idrecepcion: true/false }
|
||||||
const articulos = document.getElementById('filtro-articulos').value.trim();
|
let _previewId = null;
|
||||||
|
|
||||||
|
async function cargarEnviados() {
|
||||||
|
const r = await fetch('/test-rda/enviados');
|
||||||
|
const d = await r.json();
|
||||||
|
_enviados = d.enviados || {};
|
||||||
|
}
|
||||||
|
|
||||||
|
function marcarFila(idrecepcion, ok) {
|
||||||
|
_enviados[idrecepcion] = ok;
|
||||||
|
const tr = document.getElementById('fila_' + idrecepcion);
|
||||||
|
if (!tr) return;
|
||||||
|
const btns = tr.querySelector('.acciones');
|
||||||
|
if (!btns) return;
|
||||||
|
if (ok) {
|
||||||
|
btns.innerHTML = '<span class="px-3 py-1 bg-green-100 text-green-700 rounded text-xs font-medium">✅ Enviado</span>';
|
||||||
|
} else {
|
||||||
|
btns.innerHTML = '<span class="px-3 py-1 bg-red-100 text-red-700 rounded text-xs font-medium">❌ Error</span>'
|
||||||
|
+ btns.innerHTML;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderFila(c) {
|
||||||
|
const ya = _enviados.hasOwnProperty(c.idrecepcion);
|
||||||
|
const ok = _enviados[c.idrecepcion];
|
||||||
|
let acciones = '';
|
||||||
|
if (ya && ok) {
|
||||||
|
acciones = '<span class="px-3 py-1 bg-green-100 text-green-700 rounded text-xs font-medium">✅ Enviado</span>';
|
||||||
|
} else {
|
||||||
|
acciones = `
|
||||||
|
<button onclick="mostrarPreview(${c.idrecepcion})"
|
||||||
|
class="px-2 py-1 bg-blue-100 text-blue-700 rounded text-xs hover:bg-blue-200 mr-1">
|
||||||
|
<i class="fas fa-eye"></i>
|
||||||
|
</button>
|
||||||
|
<button onclick="enviarDesde(${c.idrecepcion})"
|
||||||
|
class="px-3 py-1 bg-green-100 text-green-700 rounded text-xs hover:bg-green-200 font-medium">
|
||||||
|
<i class="fas fa-paper-plane mr-1"></i>Enviar
|
||||||
|
</button>`;
|
||||||
|
if (ya && !ok) {
|
||||||
|
acciones = '<span class="px-2 py-1 bg-red-100 text-red-700 rounded text-xs mr-1">❌</span>' + acciones;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return `<tr id="fila_${c.idrecepcion}" class="hover:bg-gray-50 ${ya && ok ? 'opacity-50' : ''}">
|
||||||
|
<td class="py-2 pr-3 font-mono text-blue-700 font-medium">${c.idrecepcion}</td>
|
||||||
|
<td class="py-2 pr-3 font-mono">${c.factura}</td>
|
||||||
|
<td class="py-2 pr-3 text-gray-500 text-xs">${c.fecha}</td>
|
||||||
|
<td class="py-2 pr-3 text-gray-600 text-xs">${c.paciente}</td>
|
||||||
|
<td class="py-2 pr-3"><span class="px-2 py-0.5 bg-blue-50 text-blue-700 rounded text-xs font-mono">${c.contrato}</span></td>
|
||||||
|
<td class="py-2 pr-3 text-gray-500 text-xs max-w-xs truncate" title="${c.examenes}">${c.examenes} <span class="text-gray-400">(${c.total})</span></td>
|
||||||
|
<td class="py-2 text-right acciones">${acciones}</td>
|
||||||
|
</tr>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function cargarCandidatos(reset = false) {
|
||||||
|
if (reset) _offset = 0;
|
||||||
|
await cargarEnviados();
|
||||||
document.getElementById('cargando-candidatos').classList.remove('hidden');
|
document.getElementById('cargando-candidatos').classList.remove('hidden');
|
||||||
document.getElementById('tabla-candidatos').classList.add('hidden');
|
document.getElementById('tabla-candidatos').classList.add('hidden');
|
||||||
document.getElementById('sin-candidatos').classList.add('hidden');
|
document.getElementById('sin-candidatos').classList.add('hidden');
|
||||||
|
|
||||||
const params = new URLSearchParams();
|
const contrato = document.getElementById('filtro-contrato').value.trim();
|
||||||
|
const articulos = document.getElementById('filtro-articulos').value.trim();
|
||||||
|
const params = new URLSearchParams({ offset: _offset });
|
||||||
if (contrato) params.append('contrato', contrato);
|
if (contrato) params.append('contrato', contrato);
|
||||||
if (articulos) params.append('articulos', articulos);
|
if (articulos) params.append('articulos', articulos);
|
||||||
|
|
||||||
@@ -106,43 +191,86 @@ async function cargarCandidatos() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const candidatos = data.candidatos || [];
|
const candidatos = data.candidatos || [];
|
||||||
if (!candidatos.length) {
|
if (!candidatos.length && _offset === 0) {
|
||||||
document.getElementById('sin-candidatos').classList.remove('hidden');
|
document.getElementById('sin-candidatos').classList.remove('hidden');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const tbody = document.getElementById('tbody-candidatos');
|
const tbody = document.getElementById('tbody-candidatos');
|
||||||
tbody.innerHTML = '';
|
if (_offset === 0) tbody.innerHTML = '';
|
||||||
candidatos.forEach(c => {
|
candidatos.forEach(c => { tbody.innerHTML += renderFila(c); });
|
||||||
const tr = document.createElement('tr');
|
|
||||||
tr.className = 'hover:bg-gray-50';
|
|
||||||
tr.innerHTML = `
|
|
||||||
<td class="py-2 pr-3 font-mono text-blue-700 font-medium">${c.idrecepcion}</td>
|
|
||||||
<td class="py-2 pr-3 font-mono">${c.factura}</td>
|
|
||||||
<td class="py-2 pr-3 text-gray-500">${c.fecha}</td>
|
|
||||||
<td class="py-2 pr-3 text-gray-600">${c.paciente}</td>
|
|
||||||
<td class="py-2 pr-3">
|
|
||||||
<span class="px-2 py-0.5 bg-blue-50 text-blue-700 rounded text-xs font-mono">${c.contrato}</span>
|
|
||||||
</td>
|
|
||||||
<td class="py-2 pr-3 text-gray-500 text-xs max-w-xs truncate" title="${c.examenes}">${c.examenes} <span class="text-gray-400">(${c.total})</span></td>
|
|
||||||
<td class="py-2">
|
|
||||||
<button onclick="enviarDesde(${c.idrecepcion})"
|
|
||||||
class="px-3 py-1 bg-green-100 text-green-700 rounded text-xs hover:bg-green-200 font-medium">
|
|
||||||
<i class="fas fa-paper-plane mr-1"></i>Enviar
|
|
||||||
</button>
|
|
||||||
</td>
|
|
||||||
`;
|
|
||||||
tbody.appendChild(tr);
|
|
||||||
});
|
|
||||||
document.getElementById('tabla-candidatos').classList.remove('hidden');
|
document.getElementById('tabla-candidatos').classList.remove('hidden');
|
||||||
|
const btnMas = document.getElementById('btn-ver-mas');
|
||||||
|
if (candidatos.length === 10) {
|
||||||
|
btnMas.classList.remove('hidden');
|
||||||
|
} else {
|
||||||
|
btnMas.classList.add('hidden');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function verMas() {
|
||||||
|
_offset += 10;
|
||||||
|
await cargarEnviados();
|
||||||
|
const contrato = document.getElementById('filtro-contrato').value.trim();
|
||||||
|
const articulos = document.getElementById('filtro-articulos').value.trim();
|
||||||
|
const params = new URLSearchParams({ offset: _offset });
|
||||||
|
if (contrato) params.append('contrato', contrato);
|
||||||
|
if (articulos) params.append('articulos', articulos);
|
||||||
|
|
||||||
|
const resp = await fetch('/test-rda/candidatos?' + params.toString());
|
||||||
|
const data = await resp.json();
|
||||||
|
if (data.error || !data.candidatos?.length) {
|
||||||
|
document.getElementById('btn-ver-mas').classList.add('hidden');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const tbody = document.getElementById('tbody-candidatos');
|
||||||
|
data.candidatos.forEach(c => { tbody.innerHTML += renderFila(c); });
|
||||||
|
if (data.candidatos.length < 10) document.getElementById('btn-ver-mas').classList.add('hidden');
|
||||||
|
}
|
||||||
|
|
||||||
|
async function mostrarPreview(idrecepcion) {
|
||||||
|
_previewId = idrecepcion;
|
||||||
|
document.getElementById('preview-id').textContent = '#' + idrecepcion;
|
||||||
|
document.getElementById('preview-json').textContent = 'Cargando...';
|
||||||
|
document.getElementById('preview-box').classList.remove('hidden');
|
||||||
|
document.getElementById('preview-box').scrollIntoView({ behavior: 'smooth' });
|
||||||
|
|
||||||
|
const resp = await fetch('/test-rda/preview?idrecepcion=' + idrecepcion);
|
||||||
|
const data = await resp.json();
|
||||||
|
if (data.error) {
|
||||||
|
document.getElementById('preview-json').textContent = 'Error: ' + data.error;
|
||||||
|
} else {
|
||||||
|
document.getElementById('preview-json').textContent = JSON.stringify(data.json, null, 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function enviarDesdePreview() {
|
||||||
|
if (!_previewId) return;
|
||||||
|
document.getElementById('preview-box').classList.add('hidden');
|
||||||
|
document.getElementById('modo').value = 'idrecepcion';
|
||||||
|
document.getElementById('valor').value = _previewId;
|
||||||
|
await enviarRDA();
|
||||||
}
|
}
|
||||||
|
|
||||||
function enviarDesde(idrecepcion) {
|
function enviarDesde(idrecepcion) {
|
||||||
|
_previewId = null;
|
||||||
document.getElementById('modo').value = 'idrecepcion';
|
document.getElementById('modo').value = 'idrecepcion';
|
||||||
document.getElementById('valor').value = idrecepcion;
|
document.getElementById('valor').value = idrecepcion;
|
||||||
enviarRDA();
|
enviarRDA();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function previewManual() {
|
||||||
|
const valor = document.getElementById('valor').value.trim();
|
||||||
|
const modo = document.getElementById('modo').value;
|
||||||
|
if (!valor) { alert('Ingresa un número'); return; }
|
||||||
|
if (modo === 'idrecepcion') {
|
||||||
|
mostrarPreview(parseInt(valor));
|
||||||
|
} else {
|
||||||
|
alert('Preview solo disponible por IDRECEPCION');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function enviarRDA() {
|
async function enviarRDA() {
|
||||||
const modo = document.getElementById('modo').value;
|
const modo = document.getElementById('modo').value;
|
||||||
const valor = document.getElementById('valor').value.trim();
|
const valor = document.getElementById('valor').value.trim();
|
||||||
@@ -154,6 +282,7 @@ async function enviarRDA() {
|
|||||||
box.classList.remove('hidden');
|
box.classList.remove('hidden');
|
||||||
contenido.innerHTML = '<div class="text-center py-8 text-gray-400"><i class="fas fa-spinner fa-spin text-3xl"></i><p class="mt-2">Enviando...</p></div>';
|
contenido.innerHTML = '<div class="text-center py-8 text-gray-400"><i class="fas fa-spinner fa-spin text-3xl"></i><p class="mt-2">Enviando...</p></div>';
|
||||||
badges.innerHTML = '';
|
badges.innerHTML = '';
|
||||||
|
box.scrollIntoView({ behavior: 'smooth' });
|
||||||
|
|
||||||
const fd = new FormData();
|
const fd = new FormData();
|
||||||
fd.append('modo', modo);
|
fd.append('modo', modo);
|
||||||
@@ -180,16 +309,19 @@ async function enviarRDA() {
|
|||||||
if (p.tipo === 'tercero') {
|
if (p.tipo === 'tercero') {
|
||||||
html += `
|
html += `
|
||||||
<div class="flex items-start gap-3 p-3 rounded-lg border ${p.ok ? 'border-green-100 bg-green-50' : 'border-red-100 bg-red-50'}">
|
<div class="flex items-start gap-3 p-3 rounded-lg border ${p.ok ? 'border-green-100 bg-green-50' : 'border-red-100 bg-red-50'}">
|
||||||
<span class="text-lg">${icon}</span>
|
<span>${icon}</span>
|
||||||
<div class="flex-1 min-w-0">
|
<div>
|
||||||
<p class="text-sm font-medium text-gray-700">Tercero: <span class="font-mono">${p.codigo}</span> — ${p.nombre}</p>
|
<p class="text-sm font-medium text-gray-700">Tercero: <span class="font-mono">${p.codigo}</span> — ${p.nombre}</p>
|
||||||
<p class="text-xs text-gray-500 mt-0.5">${p.mensaje}</p>
|
<p class="text-xs text-gray-500">${p.mensaje}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>`;
|
</div>`;
|
||||||
} else {
|
} else {
|
||||||
|
// Marcar fila como enviada
|
||||||
|
marcarFila(p.idrecepcion, p.ok);
|
||||||
|
|
||||||
const jsonStr = JSON.stringify(p.json_enviado || {}, null, 2);
|
const jsonStr = JSON.stringify(p.json_enviado || {}, null, 2);
|
||||||
const uid = 'json_' + p.idrecepcion;
|
const uid = 'json_' + p.idrecepcion + '_' + Date.now();
|
||||||
const uid2 = 'resp_' + p.idrecepcion;
|
const uid2 = 'resp_' + p.idrecepcion + '_' + Date.now();
|
||||||
let respTns = '';
|
let respTns = '';
|
||||||
try { respTns = JSON.stringify(JSON.parse(p.respuesta_tns || '{}'), null, 2); } catch(e) { respTns = p.respuesta_tns || ''; }
|
try { respTns = JSON.stringify(JSON.parse(p.respuesta_tns || '{}'), null, 2); } catch(e) { respTns = p.respuesta_tns || ''; }
|
||||||
html += `
|
html += `
|
||||||
@@ -223,7 +355,6 @@ async function enviarRDA() {
|
|||||||
contenido.innerHTML = html;
|
contenido.innerHTML = html;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cargar candidatos al abrir la página
|
cargarCandidatos(true);
|
||||||
cargarCandidatos();
|
|
||||||
</script>
|
</script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
Reference in New Issue
Block a user