intento2 / script.js
alcantarm's picture
Update script.js
5ecd624 verified
Raw History Blame Contribute Delete
7.67 kB
window.addEventListener('DOMContentLoaded', () => {
const CLP = new Intl.NumberFormat('es-CL', { style: 'currency', currency: 'CLP', maximumFractionDigits: 0 });
// Inputs y elementos
const input = document.getElementById('invoice-input');
const budgetInput = document.getElementById('budget-input');
const dropzone = document.getElementById('dropzone');
const budgetDropzone = document.getElementById('budget-dropzone');
const tbody = document.getElementById('tbody');
const budgetTbody = document.getElementById('budget-tbody-right');
const total = document.getElementById('total');
const errorEl = document.getElementById('error');
const budgetError = document.getElementById('budget-error');
const processBtn = document.getElementById('process-btn');
const resetBtn = document.getElementById('reset-btn');
const summary = document.getElementById('summary');
const recordsTbody = document.getElementById('records-tbody');
// Datos
const docs = [];
const records = [];
let budgetFile = null;
// Funciones auxiliares
const fmtDate = iso => new Date(iso).toLocaleString();
const randomAmount = (min, max) => Math.floor(Math.random() * (max - min + 1)) + min;
const randomFolio = () => 'F' + Math.floor(100000 + Math.random() * 900000);
const parseCSV = content => {
const lines = content.split('\n');
for (const line of lines) {
const matches = line.match(/(\d{1,3}(?:\.\d{3})*|\d+)/g);
if (matches && matches.length > 0) {
const amount = parseInt(matches[0].replace(/\./g, ''));
if (!isNaN(amount) && amount > 1000) return amount;
}
}
return null;
};
// Renderizar tablas
const renderDocs = () => {
total.textContent = `${docs.length} en total`;
tbody.innerHTML = '';
if (!docs.length) {
tbody.innerHTML = `<tr><td colspan="5" style="text-align:center;color:var(--muted);padding:24px;">Aún no hay documentos. Sube un PDF o imagen para comenzar.</td></tr>`;
} else {
docs.forEach((d, i) => {
const monto = CLP.format(d.amount);
const tr = document.createElement('tr');
tr.innerHTML = `<td>${i+1}</td><td>${d.folio}</td><td>${d.name}</td><td>${fmtDate(d.loadedAt)}</td><td>${monto}</td>`;
tbody.appendChild(tr);
});
}
};
const renderBudget = () => {
budgetTbody.innerHTML = '';
if (!budgetFile) {
budgetTbody.innerHTML = `<tr><td colspan="3" style="text-align:center;color:var(--muted);padding:16px;">Aún no se ha cargado el presupuesto.</td></tr>`;
} else {
const tr = document.createElement('tr');
tr.innerHTML = `<td>${budgetFile.name}</td><td>${fmtDate(budgetFile.loadedAt)}</td><td>${CLP.format(budgetFile.amount)}</td>`;
budgetTbody.appendChild(tr);
}
};
const updateSummary = () => {
if (!budgetFile || !docs.length) {
summary.innerHTML = '';
return;
}
const totalDocs = docs.reduce((sum, doc) => sum + (doc.amount || 0), 0);
const variation = budgetFile.amount - totalDocs;
const percentVariation = budgetFile.amount > 0 ? (variation / budgetFile.amount * 100) : 0;
summary.innerHTML = `<strong>Total documentos:</strong> ${CLP.format(totalDocs)}<br>
<strong>Presupuesto:</strong> ${CLP.format(budgetFile.amount)}<br>
<strong>Variación:</strong> ${CLP.format(variation)} (${percentVariation.toFixed(1)}%)`;
};
const renderRecords = () => {
recordsTbody.innerHTML = '';
if (!records.length) {
recordsTbody.innerHTML = `<tr><td class="empty" colspan="5">No hay registros todavía. Guarda un proceso para verlo aquí.</td></tr>`;
} else {
records.forEach((record, i) => {
const tr = document.createElement('tr');
const variationText = record.diff >= 0 ? `+${CLP.format(record.diff)}` : CLP.format(record.diff);
tr.innerHTML = `<td>${record.docsCount}</td><td>${CLP.format(record.docsSum)}</td><td>${CLP.format(record.budget)}</td><td>${variationText}</td>
<td><button class="delete-btn" onclick="deleteRecord(${i})">Eliminar</button></td>`;
recordsTbody.appendChild(tr);
});
}
};
window.deleteRecord = idx => {
if (!isNaN(idx) && idx >= 0 && idx < records.length) {
records.splice(idx, 1);
renderRecords();
}
};
// Subir archivos
const addFiles = files => {
const nowIso = new Date().toISOString();
errorEl.textContent = '';
Array.from(files).forEach(f => {
if (f) {
docs.unshift({ name: f.name, loadedAt: nowIso, file: f, amount: randomAmount(10000, 250000), folio: randomFolio() });
} else {
errorEl.textContent = 'Solo se permiten archivos PDF o imágenes.';
}
});
renderDocs();
updateSummary();
};
const setBudgetFromFile = f => {
if (!f) return;
if (!f.name.toLowerCase().endsWith('.csv')) {
budgetError.textContent = 'Solo se permite un archivo CSV.';
return;
}
budgetError.textContent = '';
const reader = new FileReader();
reader.onload = e => {
const content = e.target.result;
let amount = parseCSV(content);
if (amount === null) amount = randomAmount(200000, 2000000);
budgetFile = { name: f.name, loadedAt: new Date().toISOString(), amount };
renderBudget();
updateSummary();
};
reader.readAsText(f);
};
// Eventos
input.addEventListener('change', () => { addFiles(input.files); input.value = ''; });
budgetInput.addEventListener('change', () => { if (budgetInput.files.length > 0) { setBudgetFromFile(budgetInput.files[0]); budgetInput.value = ''; } });
// Drag & drop facturas
['dragenter', 'dragover'].forEach(evt => dropzone.addEventListener(evt, e => { e.preventDefault(); e.stopPropagation(); dropzone.classList.add('drag'); }));
['dragleave', 'drop'].forEach(evt => dropzone.addEventListener(evt, e => {
e.preventDefault(); e.stopPropagation(); dropzone.classList.remove('drag');
if (e.type === 'drop') addFiles(e.dataTransfer.files);
}));
// Drag & drop presupuesto
['dragenter', 'dragover'].forEach(evt => budgetDropzone.addEventListener(evt, e => { e.preventDefault(); e.stopPropagation(); budgetDropzone.classList.add('drag'); }));
['dragleave', 'drop'].forEach(evt => budgetDropzone.addEventListener(evt, e => {
e.preventDefault(); e.stopPropagation(); budgetDropzone.classList.remove('drag');
if (e.type === 'drop' && e.dataTransfer.files.length > 0) setBudgetFromFile(e.dataTransfer.files[0]);
}));
processBtn.addEventListener('click', async () => {
if (!budgetFile || !docs.length) {
alert('Carga al menos un PDF/imagen y un CSV de presupuesto.');
return;
}
processBtn.textContent = 'Procesando...'; processBtn.disabled = true;
await new Promise(r => setTimeout(r, 800));
const totalDocs = docs.reduce((sum, d) => sum + d.amount, 0);
records.push({ docsCount: docs.length, docsSum: totalDocs, budget: budgetFile.amount, diff: budgetFile.amount - totalDocs });
renderRecords();
processBtn.textContent = 'Procesar'; processBtn.disabled = false;
});
resetBtn.addEventListener('click', () => {
if (confirm('¿Estás seguro de que quieres reiniciar todo?')) {
docs.length = 0;
records.length = 0;
budgetFile = null;
errorEl.textContent = '';
budgetError.textContent = '';
input.value = '';
budgetInput.value = '';
renderDocs();
renderBudget();
renderRecords();
updateSummary();
summary.innerHTML = '';
}
});
// Inicial
renderDocs();
renderBudget();
renderRecords();
});