feat: paso 4 ventas en automation + fixes varios
- Automation: agrega Paso 4 (Ventas/Crear) con fetch _SQL_VENTAS, filtro por excluded_ventas_set, loop de envío y log de actividad - Automation: _guardar_envio ahora almacena idrecepcion y contrato para que /ventas reconozca registros enviados por automation - Contratos: corrige NameError en toggle_excluir (faltaba request: Request) - Ventas: agrega check if not q en send_one y send para evitar TypeError - Ventas HTML: agrega columna Contrato en la tabla de facturas - json_generator: normaliza etnia >2 chars a '99' (ej: 999 → 99) - json_generator: agrega campo ciudadExp usando el mismo cod_ciudad Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 4.6
parent
21eb99d18d
commit
73062af8bc
@@ -48,7 +48,7 @@
|
||||
<span id="preview-fecha" class="text-sm text-gray-500"></span>
|
||||
</div>
|
||||
<div class="p-6 space-y-4">
|
||||
<div class="grid grid-cols-4 gap-4">
|
||||
<div class="grid grid-cols-5 gap-4">
|
||||
<div class="bg-blue-50 rounded-lg p-4 text-center">
|
||||
<div id="cnt-pacientes" class="text-3xl font-bold text-blue-600">0</div>
|
||||
<div class="text-sm text-blue-700 mt-1">Pacientes</div>
|
||||
@@ -66,6 +66,11 @@
|
||||
<div class="text-sm text-orange-700 mt-1">Pre-servicios</div>
|
||||
<div class="text-xs text-orange-400">RCXC / SC</div>
|
||||
</div>
|
||||
<div class="bg-emerald-50 rounded-lg p-4 text-center">
|
||||
<div id="cnt-ventas" class="text-3xl font-bold text-emerald-600">0</div>
|
||||
<div class="text-sm text-emerald-700 mt-1">Ventas</div>
|
||||
<div class="text-xs text-emerald-400">Ventas/Crear</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<p class="text-xs font-medium text-gray-600 mb-2">Pacientes — clic para ver sus recepciones:</p>
|
||||
@@ -75,6 +80,10 @@
|
||||
<p class="text-xs font-medium text-orange-600 mb-2 mt-2">Pre-servicios RCXC / SC — clic para ver JSON:</p>
|
||||
<div id="preview-ps-table" class="border border-orange-100 rounded-lg overflow-hidden text-sm"></div>
|
||||
</div>
|
||||
<div id="ventas-section" class="hidden">
|
||||
<p class="text-xs font-medium text-emerald-600 mb-2 mt-2">Facturas Venta — clic para ver JSON:</p>
|
||||
<div id="preview-vta-table" class="border border-emerald-100 rounded-lg overflow-hidden text-sm"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -110,6 +119,16 @@
|
||||
</div>
|
||||
<div id="p3-detalle" class="divide-y divide-gray-100 hidden"></div>
|
||||
</div>
|
||||
<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="flex items-center gap-3">
|
||||
<div class="w-8 h-8 bg-emerald-500 rounded-full flex items-center justify-center text-white text-sm font-bold">4</div>
|
||||
<span class="font-semibold text-gray-800">Facturas Venta</span>
|
||||
</div>
|
||||
<span id="p4-badge" class="text-sm text-gray-400">Esperando...</span>
|
||||
</div>
|
||||
<div id="p4-detalle" class="divide-y divide-gray-100 hidden"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -133,7 +152,7 @@
|
||||
<strong id="modal-fecha" class="text-blue-600"></strong>:
|
||||
</p>
|
||||
|
||||
<div class="grid grid-cols-4 gap-3">
|
||||
<div class="grid grid-cols-5 gap-3">
|
||||
<div class="bg-blue-50 rounded-lg p-3 text-center">
|
||||
<div id="modal-cnt-pac" class="text-2xl font-bold text-blue-600">0</div>
|
||||
<div class="text-xs text-blue-700">Terceros</div>
|
||||
@@ -154,6 +173,11 @@
|
||||
<div class="text-xs text-orange-700">Pre-servicios</div>
|
||||
<div class="text-xs text-orange-400">RCXC / SC</div>
|
||||
</div>
|
||||
<div class="bg-emerald-50 rounded-lg p-3 text-center">
|
||||
<div id="modal-cnt-vta" class="text-2xl font-bold text-emerald-600">0</div>
|
||||
<div class="text-xs text-emerald-700">Ventas</div>
|
||||
<div class="text-xs text-emerald-400">Ventas/Crear</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="bg-amber-50 border border-amber-200 rounded-lg px-4 py-3 text-xs text-amber-700 flex items-start gap-2">
|
||||
@@ -214,6 +238,7 @@ async function previewAutomation() {
|
||||
document.getElementById('cnt-recepciones').textContent = data.recepciones;
|
||||
document.getElementById('cnt-examenes').textContent = data.examenes;
|
||||
document.getElementById('cnt-preservicios').textContent = data.preservicios || 0;
|
||||
document.getElementById('cnt-ventas').textContent = data.ventas || 0;
|
||||
document.getElementById('preview-fecha').textContent = data.fecha;
|
||||
|
||||
const psTable = document.getElementById('preview-ps-table');
|
||||
@@ -240,6 +265,31 @@ async function previewAutomation() {
|
||||
psSection.classList.add('hidden');
|
||||
}
|
||||
|
||||
const vtaTable = document.getElementById('preview-vta-table');
|
||||
const vtaSection = document.getElementById('ventas-section');
|
||||
if (data.ventas_preview && data.ventas_preview.length > 0) {
|
||||
vtaTable.innerHTML = data.ventas_preview.map((vta, i) => {
|
||||
const key = `vta-json-${i}`;
|
||||
_rdaJsonStore[key] = vta.json;
|
||||
return `
|
||||
<div>
|
||||
<div class="flex items-center gap-3 px-4 py-2.5 hover:bg-emerald-50 cursor-pointer select-none border-b border-emerald-100"
|
||||
onclick="toggleVta('${key}', this)">
|
||||
<i class="fas fa-chevron-right text-emerald-300 text-xs transition-transform duration-150" id="vtachev-${i}"></i>
|
||||
<span class="font-mono text-emerald-700 font-medium w-32">${vta.factura}</span>
|
||||
<span class="text-gray-500 w-24 text-xs">${vta.fecha}</span>
|
||||
<span class="font-mono bg-emerald-100 text-emerald-800 px-1.5 py-0.5 rounded text-xs w-14 text-center">${vta.contrato || '—'}</span>
|
||||
<span class="text-gray-600 flex-1 text-xs">Pac. ${vta.paciente}</span>
|
||||
<span class="text-xs text-emerald-500">${vta.examenes} examen(es)</span>
|
||||
</div>
|
||||
<div id="${key}" class="hidden bg-gray-900 text-green-300 text-xs font-mono p-4 overflow-x-auto whitespace-pre border-b border-emerald-100"></div>
|
||||
</div>`;
|
||||
}).join('');
|
||||
vtaSection.classList.remove('hidden');
|
||||
} else {
|
||||
vtaSection.classList.add('hidden');
|
||||
}
|
||||
|
||||
const table = document.getElementById('preview-table');
|
||||
if (data.pacientes === 0) {
|
||||
table.innerHTML = '<div class="p-4 text-gray-400 text-center">No hay pacientes para esta fecha</div>';
|
||||
@@ -297,6 +347,7 @@ function abrirModalConfirmar() {
|
||||
document.getElementById('modal-cnt-rec').textContent = d.recepciones;
|
||||
document.getElementById('modal-cnt-exa').textContent = d.examenes;
|
||||
document.getElementById('modal-cnt-ps').textContent = d.preservicios || 0;
|
||||
document.getElementById('modal-cnt-vta').textContent = d.ventas || 0;
|
||||
|
||||
document.getElementById('modal-lista-pac').innerHTML = d.pacientes_preview.map(p => `
|
||||
<div class="flex items-center gap-3 px-3 py-1.5 border-b border-gray-50 text-xs last:border-0">
|
||||
@@ -327,6 +378,8 @@ async function confirmarEnvio() {
|
||||
document.getElementById('p2-badge').className = 'text-sm text-gray-400';
|
||||
document.getElementById('p3-badge').textContent = 'Esperando...';
|
||||
document.getElementById('p3-badge').className = 'text-sm text-gray-400';
|
||||
document.getElementById('p4-badge').textContent = 'Esperando...';
|
||||
document.getElementById('p4-badge').className = 'text-sm text-gray-400';
|
||||
|
||||
const contrato = document.getElementById('contrato-input').value.trim();
|
||||
const form = new FormData();
|
||||
@@ -364,8 +417,14 @@ async function confirmarEnvio() {
|
||||
col2: `Pac. ${d.paciente} — ${d.examenes} examen(es)`,
|
||||
col3: `${d.ok ? '✅' : '❌'} ${d.msg || ''}`, ok: d.ok,
|
||||
})));
|
||||
renderBadge('p4-badge', r.paso4_ventas.enviados, r.paso4_ventas.errores);
|
||||
renderDetalle('p4-detalle', r.paso4_ventas.detalle.map(d => ({
|
||||
col1: `${d.factura}`,
|
||||
col2: `Pac. ${d.paciente} — ${d.examenes} examen(es)`,
|
||||
col3: `${d.ok ? '✅' : '❌'} ${d.msg || ''}`, ok: d.ok,
|
||||
})));
|
||||
|
||||
const totalErr = r.paso1_terceros.errores + r.paso2_rda.errores + r.paso3_preserv.errores;
|
||||
const totalErr = r.paso1_terceros.errores + r.paso2_rda.errores + r.paso3_preserv.errores + r.paso4_ventas.errores;
|
||||
showToast(totalErr === 0 ? 'Envío completado sin errores' : `Completado con ${totalErr} error(es)`,
|
||||
totalErr === 0 ? 'success' : 'warning');
|
||||
} catch (e) {
|
||||
@@ -405,6 +464,17 @@ function togglePs(id, row) {
|
||||
if (chev) chev.style.transform = hidden ? 'rotate(90deg)' : '';
|
||||
}
|
||||
|
||||
function toggleVta(id, row) {
|
||||
const div = document.getElementById(id);
|
||||
const chev = row.querySelector('[id^="vtachev-"]');
|
||||
const hidden = div.classList.contains('hidden');
|
||||
if (hidden && _rdaJsonStore[id]) {
|
||||
div.textContent = JSON.stringify(_rdaJsonStore[id], null, 2);
|
||||
}
|
||||
div.classList.toggle('hidden', !hidden);
|
||||
if (chev) chev.style.transform = hidden ? 'rotate(90deg)' : '';
|
||||
}
|
||||
|
||||
function renderBadge(id, enviados, errores) {
|
||||
const el = document.getElementById(id);
|
||||
if (errores === 0) {
|
||||
|
||||
Reference in New Issue
Block a user