feat(transaccion): envío RDA directo por prefijo + número de factura

Nuevo endpoint POST /transaccion/send-direct y panel "Enviar RDA directo"
en la UI: ingresa Tipo (prefijo) y Número, busca en Firebird y envía a TNS
sin necesidad de rango de fechas ni pasar por el flujo de preview.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Lizandro Guarnizo
2026-07-09 15:10:41 -05:00
co-authored by Claude Sonnet 4.6
parent d3a6ab7ab6
commit 3baa6e5f75
2 changed files with 194 additions and 0 deletions
+91
View File
@@ -47,6 +47,43 @@
</div>
</div>
<!-- Enviar RDA directo -->
<div class="bg-white rounded-xl shadow-sm border border-indigo-200">
<div class="px-6 py-4 border-b border-indigo-100 flex items-center gap-2">
<i class="fas fa-bolt text-indigo-500"></i>
<h3 class="font-semibold text-gray-800">Enviar RDA directo</h3>
</div>
<div class="p-5 space-y-3">
<div>
<label class="block text-xs font-medium text-gray-600 mb-1">Consulta SQL</label>
<select id="d-query" class="w-full px-3 py-2 border border-gray-300 rounded-lg text-sm">
<option value="">Seleccionar...</option>
{% for q in queries %}
<option value="{{ q.id }}">{{ q.name }}</option>
{% endfor %}
</select>
</div>
<div class="grid grid-cols-2 gap-2">
<div>
<label class="block text-xs font-medium text-gray-600 mb-1">Tipo</label>
<input id="d-prefijo" type="text" placeholder="LHXC"
class="w-full px-3 py-2 border border-gray-300 rounded-lg text-sm uppercase"
style="text-transform:uppercase">
</div>
<div>
<label class="block text-xs font-medium text-gray-600 mb-1">Número</label>
<input id="d-numero" type="text" placeholder="4358"
class="w-full px-3 py-2 border border-gray-300 rounded-lg text-sm">
</div>
</div>
<button onclick="enviarDirecto()" id="btn-directo"
class="w-full px-4 py-2 bg-indigo-600 hover:bg-indigo-700 text-white rounded-lg text-sm font-medium">
<i class="fas fa-paper-plane mr-1"></i> Enviar ahora
</button>
<div id="directo-result" class="hidden"></div>
</div>
</div>
<!-- Resumen -->
<div id="resumen-box" class="hidden bg-white rounded-xl shadow-sm border border-gray-200 p-5">
<div class="grid grid-cols-3 gap-2 text-center mb-4">
@@ -351,6 +388,60 @@ function closeModal() {
document.getElementById('modal-detalle').classList.add('hidden');
}
async function enviarDirecto() {
const qid = document.getElementById('d-query').value;
const prefijo = document.getElementById('d-prefijo').value.trim().toUpperCase();
const numero = document.getElementById('d-numero').value.trim();
const resultBox = document.getElementById('directo-result');
if (!qid) { showToast('Selecciona una consulta SQL', 'warning'); return; }
if (!prefijo || !numero) { showToast('Ingresa Tipo y Número', 'warning'); return; }
const btn = document.getElementById('btn-directo');
showLoading(btn);
resultBox.classList.add('hidden');
const fd = new URLSearchParams({ query_id: qid, prefijo, numero });
let result;
try {
const resp = await fetch('/transaccion/send-direct', { method: 'POST', credentials: 'include', body: fd });
result = await resp.json();
} catch(e) {
result = { success: false, message: String(e) };
}
hideLoading(btn, '<i class="fas fa-paper-plane mr-1"></i> Enviar ahora');
if (result.success) {
const r0 = (result.resultados || [])[0] || {};
resultBox.innerHTML = `
<div class="bg-green-50 border border-green-200 rounded-lg p-3 text-xs space-y-1">
<div class="font-semibold text-green-700"><i class="fas fa-check-circle mr-1"></i>Enviado correctamente</div>
<div class="text-gray-600">Factura: <strong>${escHtml(r0.factura||'')}</strong> — IDRECEP: ${r0.idrecepcion||''}</div>
<div class="text-gray-500">${escHtml(r0.message||'')}</div>
<button onclick="verDirectoJSON(this)" data-json='${JSON.stringify(r0.json||{}).replace(/'/g,"&#39;")}'
class="mt-1 text-blue-600 underline">Ver JSON enviado</button>
</div>`;
} else {
const msgs = (result.resultados||[]).map(r => escHtml(r.message||'')).join('<br>') || escHtml(result.message||'Error');
resultBox.innerHTML = `
<div class="bg-red-50 border border-red-200 rounded-lg p-3 text-xs">
<div class="font-semibold text-red-700"><i class="fas fa-times-circle mr-1"></i>Error al enviar</div>
<div class="text-gray-600 mt-1">${msgs}</div>
</div>`;
}
resultBox.classList.remove('hidden');
}
function verDirectoJSON(btn) {
try {
const obj = JSON.parse(btn.dataset.json);
document.getElementById('modal-titulo').innerHTML = '<i class="fas fa-code mr-2 text-indigo-500"></i>JSON — Envío directo';
document.getElementById('tab-json').innerHTML = syntaxHighlight(obj);
document.getElementById('tab-tns').textContent = '(usa ver resultado arriba)';
showTab('tab-json');
document.getElementById('modal-detalle').classList.remove('hidden');
} catch(e) {}
}
function escHtml(s) { return String(s).replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;'); }
function escAttr(s) { return String(s).replace(/"/g,'&quot;').replace(/'/g,'&#39;'); }