| | <!DOCTYPE html> |
| | <html lang="pt-BR"> |
| | <head> |
| | <meta charset="UTF-8"> |
| | <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
| | <title>Processador de XML/HTML para CSV/XLSX</title> |
| | <script src="https://cdn.tailwindcss.com"></script> |
| | <style> |
| | .upload-area { |
| | border: 2px dashed #3498db; |
| | padding: 30px; |
| | text-align: center; |
| | margin-bottom: 20px; |
| | border-radius: 8px; |
| | background-color: #ecf0f1; |
| | cursor: pointer; |
| | position: relative; |
| | overflow: hidden; |
| | transition: all 0.3s ease; |
| | } |
| | .upload-area:hover { |
| | background-color: #d6dbdf; |
| | border-color: #2980b9; |
| | box-shadow: 0 0 10px rgba(52, 152, 219, 0.3); |
| | } |
| | .upload-area p { |
| | pointer-events: none; |
| | } |
| | #file-input { |
| | display: none; |
| | } |
| | .progress { |
| | height: 20px; |
| | background-color: #ecf0f1; |
| | border-radius: 4px; |
| | margin: 10px 0; |
| | overflow: hidden; |
| | display: none; |
| | } |
| | .progress-bar { |
| | height: 100%; |
| | background-color: #3498db; |
| | width: 0%; |
| | transition: width 0.3s; |
| | } |
| | .status { |
| | margin: 10px 0; |
| | padding: 10px; |
| | border-radius: 4px; |
| | } |
| | .status.info { |
| | background-color: #d6eaf8; |
| | border-left: 4px solid #3498db; |
| | } |
| | .status.success { |
| | background-color: #d5f5e3; |
| | border-left: 4px solid #2ecc71; |
| | } |
| | .status.error { |
| | background-color: #fadbd8; |
| | border-left: 4px solid #e74c3c; |
| | } |
| | .file-item { |
| | padding: 8px; |
| | background-color: #f8f9fa; |
| | border: 1px solid #ddd; |
| | border-radius: 4px; |
| | margin-bottom: 5px; |
| | display: flex; |
| | justify-content: space-between; |
| | align-items: center; |
| | } |
| | </style> |
| | |
| | <script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.5.1/jspdf.umd.min.js"></script> |
| | <script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf-autotable/3.5.28/jspdf.plugin.autotable.min.js"></script> |
| | |
| | <script src="https://cdnjs.cloudflare.com/ajax/libs/xlsx/0.18.5/xlsx.full.min.js"></script> |
| | </head> |
| | <body class="bg-gray-100"> |
| | <div class="container mx-auto max-w-6xl bg-white p-6 rounded-lg shadow-md my-8"> |
| | <h1 class="text-3xl font-bold text-center text-gray-800 mb-6">Processador de XML/HTML para CSV/XLSX</h1> |
| | |
| | <div class="upload-area" id="upload-area"> |
| | <p class="text-gray-700 font-medium"> |
| | <svg xmlns="http://www.w3.org/2000/svg" class="h-10 w-10 mx-auto mb-2 text-blue-500" fill="none" viewBox="0 0 24 24" stroke="currentColor"> |
| | <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 16a4 4 0 01-.88-7.903A5 5 0 1115.9 6L16 6a5 5 0 011 9.9M15 13l-3-3m0 0l-3 3m3-3v12" /> |
| | </svg> |
| | Clique aqui ou arraste arquivos XML ou HTML<br> |
| | <span class="text-sm text-gray-600">Formatos aceitos: .xml, .html (máximo: 100 arquivos)</span> |
| | </p> |
| | <input type="file" id="file-input" accept=".xml,.html,.htm,text/xml,text/html" multiple style="position: absolute; opacity: 0; width: 100%; height: 100%; top: 0; left: 0; cursor: pointer;"> |
| | </div> |
| | |
| | <div id="status-area"></div> |
| | |
| | <div id="file-list" class="file-list my-4"></div> |
| | |
| | <div class="flex justify-between items-center mb-4" id="selection-controls" style="display: none;"> |
| | <div> |
| | <button class="btn bg-blue-500 hover:bg-blue-600 text-white px-4 py-2 rounded mr-2" id="select-all-btn">Selecionar Todos</button> |
| | <button class="btn bg-blue-500 hover:bg-blue-600 text-white px-4 py-2 rounded" id="deselect-all-btn">Desselecionar Todos</button> |
| | </div> |
| | <div> |
| | <span id="selected-count" class="text-gray-700">0 arquivos selecionados</span> |
| | </div> |
| | </div> |
| | |
| | <div class="text-center"> |
| | <button class="btn bg-blue-500 hover:bg-blue-600 text-white px-6 py-2 rounded mr-2" id="process-btn" disabled>Processar Arquivos</button> |
| | <button class="btn bg-red-500 hover:bg-red-600 text-white px-6 py-2 rounded mr-2" id="pdf-btn" disabled>Gerar PDF Selecionados</button> |
| | <button class="btn bg-green-500 hover:bg-green-600 text-white px-6 py-2 rounded" id="xlsx-btn" disabled>Gerar XLSX</button> |
| | </div> |
| | |
| | <div class="progress" id="progress"> |
| | <div class="progress-bar" id="progress-bar"></div> |
| | </div> |
| | |
| | <div class="results mt-6 hidden" id="results"> |
| | <h2 class="text-2xl font-semibold mb-4">Resultados do Processamento</h2> |
| | <div id="result-data" class="overflow-x-auto"></div> |
| | <div class="mt-4"> |
| | <a href="#" class="btn bg-green-500 hover:bg-green-600 text-white px-4 py-2 rounded inline-block" id="download-csv-btn" download="dados_negociacao.csv">Baixar CSV</a> |
| | <a href="#" class="btn bg-green-500 hover:bg-green-600 text-white px-4 py-2 rounded inline-block hidden" id="download-xlsx-btn" download="dados_negociacao.xlsx">Baixar XLSX</a> |
| | </div> |
| | </div> |
| | </div> |
| |
|
| | <script> |
| | document.addEventListener('DOMContentLoaded', function() { |
| | const fileInput = document.getElementById('file-input'); |
| | const uploadArea = document.getElementById('upload-area'); |
| | const processBtn = document.getElementById('process-btn'); |
| | const pdfBtn = document.getElementById('pdf-btn'); |
| | const xlsxBtn = document.getElementById('xlsx-btn'); |
| | const results = document.getElementById('results'); |
| | const resultData = document.getElementById('result-data'); |
| | const downloadCsvBtn = document.getElementById('download-csv-btn'); |
| | const downloadXlsxBtn = document.getElementById('download-xlsx-btn'); |
| | const progress = document.getElementById('progress'); |
| | const progressBar = document.getElementById('progress-bar'); |
| | const statusArea = document.getElementById('status-area'); |
| | const fileList = document.getElementById('file-list'); |
| | const selectionControls = document.getElementById('selection-controls'); |
| | const selectAllBtn = document.getElementById('select-all-btn'); |
| | const deselectAllBtn = document.getElementById('deselect-all-btn'); |
| | const selectedCount = document.getElementById('selected-count'); |
| | |
| | let currentFiles = []; |
| | let selicData = null; |
| | let processedData = []; |
| | let csvContent = ''; |
| | let xlsxBlob = null; |
| | |
| | |
| | uploadArea.addEventListener('click', function(e) { |
| | |
| | if (e.target.tagName !== 'INPUT') { |
| | fileInput.click(); |
| | } |
| | }); |
| | |
| | |
| | fileInput.addEventListener('change', function() { |
| | if (this.files && this.files.length > 0) { |
| | handleFiles(this.files); |
| | |
| | this.value = ''; |
| | } |
| | }); |
| | |
| | |
| | uploadArea.addEventListener('dragover', function(e) { |
| | e.preventDefault(); |
| | uploadArea.classList.add('bg-blue-100'); |
| | }); |
| | |
| | uploadArea.addEventListener('dragleave', function() { |
| | uploadArea.classList.remove('bg-blue-100'); |
| | }); |
| | |
| | uploadArea.addEventListener('drop', function(e) { |
| | e.preventDefault(); |
| | uploadArea.classList.remove('bg-blue-100'); |
| | |
| | if (e.dataTransfer.files.length) { |
| | handleFiles(e.dataTransfer.files); |
| | } |
| | }); |
| | |
| | |
| | fileInput.addEventListener('change', function() { |
| | if (fileInput.files.length) { |
| | handleFiles(fileInput.files); |
| | } |
| | }); |
| | |
| | |
| | processBtn.addEventListener('click', function() { |
| | if (currentFiles.length) { |
| | processFiles(currentFiles); |
| | } else { |
| | showStatus('Nenhum arquivo selecionado para processar.', 'error'); |
| | } |
| | }); |
| | |
| | |
| | pdfBtn.addEventListener('click', function() { |
| | generatePDF(); |
| | }); |
| | |
| | |
| | xlsxBtn.addEventListener('click', function() { |
| | generateXLSX(); |
| | }); |
| | |
| | |
| | selectAllBtn.addEventListener('click', function() { |
| | document.querySelectorAll('.file-checkbox').forEach(checkbox => { |
| | checkbox.checked = true; |
| | }); |
| | updateSelectedCount(); |
| | }); |
| | |
| | deselectAllBtn.addEventListener('click', function() { |
| | document.querySelectorAll('.file-checkbox').forEach(checkbox => { |
| | checkbox.checked = false; |
| | }); |
| | updateSelectedCount(); |
| | }); |
| | |
| | function showStatus(message, type = 'info') { |
| | let statusClass = 'status info bg-blue-100 border-l-4 border-blue-500'; |
| | if (type === 'success') { |
| | statusClass = 'status success bg-green-100 border-l-4 border-green-500'; |
| | } else if (type === 'error') { |
| | statusClass = 'status error bg-red-100 border-l-4 border-red-500'; |
| | } |
| | |
| | statusArea.innerHTML = `<div class="${statusClass} p-3 rounded">${message}</div>`; |
| | } |
| | |
| | function handleFiles(files) { |
| | const validFiles = []; |
| | const maxFiles = 100; |
| | |
| | for (let i = 0; i < files.length && validFiles.length + currentFiles.length < maxFiles; i++) { |
| | const file = files[i]; |
| | if (file.type === 'text/xml' || file.type === 'text/html' || file.type === '' || |
| | file.name.endsWith('.xml') || file.name.endsWith('.html') || file.name.endsWith('.htm')) { |
| | validFiles.push(file); |
| | } |
| | } |
| | |
| | if (validFiles.length > 0) { |
| | if (currentFiles.length + validFiles.length > maxFiles) { |
| | showStatus(`Máximo de ${maxFiles} arquivos atingido. Os primeiros ${maxFiles - currentFiles.length} arquivos foram adicionados.`, 'error'); |
| | } |
| | |
| | currentFiles = [...currentFiles, ...validFiles]; |
| | processBtn.disabled = false; |
| | pdfBtn.disabled = true; |
| | xlsxBtn.disabled = true; |
| | updateFileList(); |
| | showStatus(`${currentFiles.length} arquivo(s) selecionado(s). Clique em "Processar Arquivos" para continuar.`, 'success'); |
| | } else { |
| | showStatus('Por favor, selecione arquivos XML ou HTML válidos.', 'error'); |
| | } |
| | } |
| | |
| | function updateFileList() { |
| | fileList.innerHTML = ''; |
| | currentFiles.forEach((file, index) => { |
| | const fileItem = document.createElement('div'); |
| | fileItem.className = 'file-item'; |
| | fileItem.innerHTML = ` |
| | <div class="flex items-center"> |
| | <input type="checkbox" class="file-checkbox mr-2" data-index="${index}" onchange="updateSelectedCount()"> |
| | <span class="text-gray-800">${file.name}</span> |
| | </div> |
| | <button onclick="removeFile(${index})" class="bg-red-500 hover:bg-red-600 text-white px-2 py-1 rounded text-sm">Remover</button> |
| | `; |
| | fileList.appendChild(fileItem); |
| | }); |
| | |
| | if (currentFiles.length > 0) { |
| | selectionControls.style.display = 'flex'; |
| | updateSelectedCount(); |
| | } else { |
| | selectionControls.style.display = 'none'; |
| | } |
| | } |
| | |
| | window.updateSelectedCount = function() { |
| | const selected = document.querySelectorAll('.file-checkbox:checked').length; |
| | selectedCount.textContent = `${selected} arquivo(s) selecionado(s)`; |
| | pdfBtn.disabled = selected === 0; |
| | } |
| | |
| | window.removeFile = function(index) { |
| | currentFiles.splice(index, 1); |
| | updateFileList(); |
| | if (currentFiles.length === 0) { |
| | processBtn.disabled = true; |
| | pdfBtn.disabled = true; |
| | xlsxBtn.disabled = true; |
| | } |
| | } |
| | |
| | function getSelectedFilesData() { |
| | const selectedIndexes = []; |
| | document.querySelectorAll('.file-checkbox:checked').forEach(checkbox => { |
| | selectedIndexes.push(parseInt(checkbox.getAttribute('data-index'))); |
| | }); |
| | |
| | return processedData.filter((_, index) => selectedIndexes.includes(index)); |
| | } |
| | |
| | async function processFiles(files) { |
| | progress.style.display = 'block'; |
| | progressBar.style.width = '10%'; |
| | showStatus('Iniciando processamento...', 'info'); |
| | |
| | try { |
| | |
| | progressBar.style.width = '20%'; |
| | showStatus('Conectando com API do BACEN para obter dados da Selic...', 'info'); |
| | |
| | selicData = await fetchSelicData(); |
| | |
| | progressBar.style.width = '30%'; |
| | showStatus('Dados da Selic obtidos com sucesso. Processando arquivos...', 'success'); |
| | |
| | |
| | processedData = []; |
| | csvContent = ''; |
| | xlsxBlob = null; |
| | |
| | for (let i = 0; i < files.length; i++) { |
| | const file = files[i]; |
| | progressBar.style.width = 30 + (i * 60 / files.length) + '%'; |
| | showStatus(`Processando arquivo ${i+1} de ${files.length}: ${file.name}`, 'info'); |
| | |
| | const result = await processFile(file); |
| | if (result) { |
| | processedData.push(result); |
| | } |
| | } |
| | |
| | progressBar.style.width = '90%'; |
| | |
| | if (processedData.length > 0) { |
| | |
| | csvContent = generateCSV(processedData); |
| | |
| | |
| | displayResults(processedData); |
| | |
| | |
| | const csvBlob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' }); |
| | const csvUrl = URL.createObjectURL(csvBlob); |
| | downloadCsvBtn.href = csvUrl; |
| | |
| | |
| | xlsxBtn.disabled = false; |
| | |
| | showStatus('Processamento concluído com sucesso!', 'success'); |
| | pdfBtn.disabled = false; |
| | } else { |
| | showStatus('Nenhum dado válido foi processado.', 'error'); |
| | } |
| | |
| | progressBar.style.width = '100%'; |
| | results.classList.remove('hidden'); |
| | |
| | setTimeout(() => { |
| | progress.style.display = 'none'; |
| | }, 500); |
| | |
| | } catch (error) { |
| | progress.style.display = 'none'; |
| | showStatus('Erro ao processar arquivos: ' + error.message, 'error'); |
| | } |
| | } |
| | |
| | async function processFile(file) { |
| | return new Promise((resolve, reject) => { |
| | const reader = new FileReader(); |
| | |
| | reader.onload = async function(e) { |
| | try { |
| | let xmlDoc; |
| | |
| | if (file.type === 'text/html' || file.name.endsWith('.html')) { |
| | |
| | const htmlContent = e.target.result; |
| | const convertedXML = await convertHtmlToXml(htmlContent); |
| | const parser = new DOMParser(); |
| | xmlDoc = parser.parseFromString(convertedXML, 'text/xml'); |
| | } else { |
| | |
| | const parser = new DOMParser(); |
| | xmlDoc = parser.parseFromString(e.target.result, 'text/xml'); |
| | } |
| | |
| | |
| | const result = processXMLData(xmlDoc, file.name); |
| | resolve(result); |
| | |
| | } catch (error) { |
| | reject(error); |
| | } |
| | }; |
| | |
| | reader.onerror = function() { |
| | reject(new Error('Erro ao ler o arquivo.')); |
| | }; |
| | |
| | reader.readAsText(file); |
| | }); |
| | } |
| | |
| | async function convertHtmlToXml(htmlContent) { |
| | try { |
| | const parser = new DOMParser(); |
| | const htmlDoc = parser.parseFromString(htmlContent, 'text/html'); |
| | |
| | |
| | let xmlString = '<?xml version="1.0" encoding="UTF-8"?><root>'; |
| | |
| | |
| | const tables = htmlDoc.querySelectorAll('table'); |
| | tables.forEach((table, index) => { |
| | xmlString += `<table id="${index}">`; |
| | const rows = table.querySelectorAll('tr'); |
| | rows.forEach((row, rowIndex) => { |
| | xmlString += `<row id="${rowIndex}">`; |
| | const cells = row.querySelectorAll('th, td'); |
| | cells.forEach((cell, cellIndex) => { |
| | xmlString += `<cell${cellIndex}>${cell.textContent.trim()}</cell${cellIndex}>`; |
| | }); |
| | xmlString += '</row>'; |
| | }); |
| | xmlString += '</table>'; |
| | }); |
| | |
| | xmlString += '</root>'; |
| | return xmlString; |
| | |
| | } catch (error) { |
| | console.error('Erro na conversão HTML para XML:', error); |
| | throw new Error('Falha ao converter HTML para XML'); |
| | } |
| | } |
| | |
| | async function fetchSelicData() { |
| | |
| | const endpoint = 'https://api.bcb.gov.br/dados/serie/bcdata.sgs.11/dados?formato=json'; |
| | |
| | try { |
| | const response = await fetch(endpoint); |
| | if (!response.ok) { |
| | throw new Error('Erro na resposta da API: ' + response.status); |
| | } |
| | |
| | const data = await response.json(); |
| | return data; |
| | } catch (error) { |
| | console.error('Erro ao buscar dados da Selic:', error); |
| | showStatus('Falha ao conectar com API do BACEN. Usando dados locais.', 'error'); |
| | |
| | |
| | return [ |
| | { data: '01/02/2025', valor: '0.99' }, |
| | { data: '01/03/2025', valor: '0.96' }, |
| | { data: '01/04/2025', valor: '1.06' }, |
| | { data: '01/05/2025', valor: '1.14' }, |
| | { data: '01/06/2025', valor: '1.10' }, |
| | { data: '01/07/2025', valor: '1.28' } |
| | ]; |
| | } |
| | } |
| | |
| | function processXMLData(xmlDoc, fileName) { |
| | |
| | const numeroNegociacao = extractText(xmlDoc, 'td.textoConsulta', 0) || ''; |
| | const nomeContribuinte = extractText(xmlDoc, 'td.textoConsulta', 2) || ''; |
| | const cnpj = extractText(xmlDoc, 'td.textoConsulta', 6) || ''; |
| | const dataAdesao = extractText(xmlDoc, 'td.textoConsulta', 3) || ''; |
| | const dataConsolidacao = extractText(xmlDoc, 'td.textoConsulta', 14) || ''; |
| | |
| | |
| | const valorPrincipal = parseCurrency(extractText(xmlDoc, 'td.textoConsulta', 7)) || 0; |
| | const valorMulta = parseCurrency(extractText(xmlDoc, 'td.textoConsulta', 24)) || 0; |
| | const valorJuros = parseCurrency(extractText(xmlDoc, 'td.textoConsulta', 40)) || 0; |
| | const valorEncargos = parseCurrency(extractText(xmlDoc, 'td.textoConsulta', 57)) || 0; |
| | const valorConsolidado = parseCurrency(extractText(xmlDoc, 'td.textoConsulta', 89)) || 0; |
| | |
| | |
| | const parcelasEntrada = 12; |
| | const parcelasEntradaPagas = 1; |
| | const parcelasEntradaVencidas = 6; |
| | const parcelasEntradaAVencer = 5; |
| | |
| | const parcelasBasicas = 133; |
| | const parcelasBasicasPagas = 0; |
| | const parcelasBasicasVencidas = 0; |
| | const parcelasBasicasAVencer = 133; |
| | |
| | |
| | const valorParcelaEntrada = 33882.75; |
| | const valorParcelaBasica = 39694.88; |
| | |
| | const valorEntradaSaldo = (parcelasEntradaVencidas + parcelasEntradaAVencer) * valorParcelaEntrada; |
| | const valorBasicaSaldo = parcelasBasicasAVencer * valorParcelaBasica; |
| | |
| | |
| | const dataConsolidacaoObj = parseDate(dataConsolidacao); |
| | const somaSelic = calcularSelic(dataConsolidacaoObj, selicData); |
| | |
| | |
| | const valorEntradaSaldoAtualizado = valorEntradaSaldo * (1 + somaSelic/100); |
| | const valorBasicaSaldoAtualizado = valorBasicaSaldo * (1 + somaSelic/100); |
| | const valorParcelaEntradaAtualizado = valorParcelaEntrada * (1 + somaSelic/100); |
| | const valorParcelaBasicaAtualizado = valorParcelaBasica * (1 + somaSelic/100); |
| | |
| | |
| | const risco1 = parcelasBasicasVencidas >= 2 ? 'ROMPIMENTO GRAVE' : |
| | (parcelasBasicasVencidas > 0 ? 'RISCO DE ROMPIMENTO' : 'SEM RISCO'); |
| | |
| | const risco2 = parcelasEntradaVencidas >= 2 ? 'RISCO DE CANCELAMENTO' : 'SEM RISCO'; |
| | |
| | |
| | return { |
| | numeroNegociacao: numeroNegociacao, |
| | cnpj: cnpj, |
| | nomeContribuinte: nomeContribuinte, |
| | dataAdesao: dataAdesao, |
| | dataConsolidacao: dataConsolidacao, |
| | valorPrincipal: valorPrincipal, |
| | valorMulta: valorMulta, |
| | valorJuros: valorJuros, |
| | valorEncargos: valorEncargos, |
| | valorConsolidado: valorConsolidado, |
| | parcelasEntrada: parcelasEntrada, |
| | parcelasEntradaPagas: parcelasEntradaPagas, |
| | parcelasEntradaVencidas: parcelasEntradaVencidas, |
| | parcelasEntradaAVencer: parcelasEntradaAVencer, |
| | parcelasBasicas: parcelasBasicas, |
| | parcelasBasicasPagas: parcelasBasicasPagas, |
| | parcelasBasicasVencidas: parcelasBasicasVencidas, |
| | parcelasBasicasAVencer: parcelasBasicasAVencer, |
| | valorParcelaEntrada: valorParcelaEntrada, |
| | valorParcelaBasica: valorParcelaBasica, |
| | valorEntradaSaldo: valorEntradaSaldo, |
| | valorBasicaSaldo: valorBasicaSaldo, |
| | somaSelic: somaSelic, |
| | valorEntradaSaldoAtualizado: valorEntradaSaldoAtualizado, |
| | valorBasicaSaldoAtualizado: valorBasicaSaldoAtualizado, |
| | valorParcelaEntradaAtualizado: valorParcelaEntradaAtualizado, |
| | valorParcelaBasicaAtualizado: valorParcelaBasicaAtualizado, |
| | risco1: risco1, |
| | risco2: risco2, |
| | fileName: fileName |
| | }; |
| | } |
| | |
| | function extractText(xmlDoc, selector, index) { |
| | const elements = xmlDoc.querySelectorAll(selector); |
| | return elements.length > index ? elements[index].textContent.trim() : null; |
| | } |
| | |
| | function parseCurrency(text) { |
| | if (!text) return null; |
| | |
| | |
| | let cleaned = text.replace('R$', '').trim(); |
| | |
| | |
| | if (cleaned.includes(',') && cleaned.includes('.')) { |
| | |
| | cleaned = cleaned.replace(/\./g, '').replace(',', '.'); |
| | } else if (cleaned.includes(',') && !cleaned.includes('.')) { |
| | |
| | cleaned = cleaned.replace(',', '.'); |
| | } |
| | |
| | |
| | const number = parseFloat(cleaned); |
| | return isNaN(number) ? null : number; |
| | } |
| | |
| | function parseDate(dateStr) { |
| | if (!dateStr) return new Date(); |
| | |
| | const parts = dateStr.split('/'); |
| | if (parts.length === 3) { |
| | return new Date(parts[2], parts[1] - 1, parts[0]); |
| | } |
| | return new Date(); |
| | } |
| | |
| | function calcularSelic(dataConsolidacao, selicData) { |
| | |
| | |
| | const hoje = new Date(); |
| | let soma = 0; |
| | let count = 0; |
| | |
| | |
| | for (const item of selicData) { |
| | const dataSelic = parseDate(item.data); |
| | |
| | |
| | if (dataSelic > dataConsolidacao && dataSelic < hoje) { |
| | const valor = parseFloat(item.valor); |
| | if (!isNaN(valor)) { |
| | soma += valor; |
| | count++; |
| | } |
| | } |
| | } |
| | |
| | |
| | return count > 0 ? soma + 1 : 7.53; |
| | } |
| | |
| | function displayResults(dataArray) { |
| | let html = `<h3 class="text-xl font-semibold mb-4">${dataArray.length} arquivo(s) processado(s)</h3>`; |
| | |
| | dataArray.forEach((data, index) => { |
| | html += ` |
| | <div class="mb-8 border border-gray-200 rounded-lg p-4"> |
| | <h4 class="text-lg font-medium mb-3">Arquivo: ${data.fileName}</h4> |
| | <div class="overflow-x-auto"> |
| | <table class="min-w-full border border-gray-300"> |
| | <thead class="bg-gray-100"> |
| | <tr> |
| | <th class="border border-gray-300 px-4 py-2">Campo</th> |
| | <th class="border border-gray-300 px-4 py-2">Valor</th> |
| | </tr> |
| | </thead> |
| | <tbody> |
| | <tr> |
| | <td class="border border-gray-300 px-4 py-2">Número da Negociação</td> |
| | <td class="border border-gray-300 px-4 py-2">${data.numeroNegociacao}</td> |
| | </tr> |
| | <tr> |
| | <td class="border border-gray-300 px-4 py-2">CNPJ</td> |
| | <td class="border border-gray-300 px-4 py-2">${data.cnpj}</td> |
| | </tr> |
| | <tr> |
| | <td class="border border-gray-300 px-4 py-2">Nome Contribuinte</td> |
| | <td class="border border-gray-300 px-4 py-2">${data.nomeContribuinte}</td> |
| | </tr> |
| | <tr> |
| | <td class="border border-gray-300 px-4 py-2">Data da Adesão</td> |
| | <td class="border border-gray-300 px-4 py-2">${data.dataAdesao}</td> |
| | </tr> |
| | <tr> |
| | <td class="border border-gray-300 px-4 py-2">Data da Consolidação</td> |
| | <td class="border border-gray-300 px-4 py-2">${data.dataConsolidacao}</td> |
| | </tr> |
| | <tr> |
| | <td class="border border-gray-300 px-4 py-2">Valor Principal</td> |
| | <td class="border border-gray-300 px-4 py-2">R$ ${formatCurrency(data.valorPrincipal)}</td> |
| | </tr> |
| | <tr> |
| | <td class="border border-gray-300 px-4 py-2">Valor Multa</td> |
| | <td class="border border-gray-300 px-4 py-2">R$ ${formatCurrency(data.valorMulta)}</td> |
| | </tr> |
| | <tr> |
| | <td class="border border-gray-300 px-4 py-2">Valor Juros</td> |
| | <td class="border border-gray-300 px-4 py-2">R$ ${formatCurrency(data.valorJuros)}</td> |
| | </tr> |
| | <tr> |
| | <td class="border border-gray-300 px-4 py-2">Valor Encargos</td> |
| | <td class="border border-gray-300 px-4 py-2">R$ ${formatCurrency(data.valorEncargos)}</td> |
| | </tr> |
| | <tr> |
| | <td class="border border-gray-300 px-4 py-2">Valor Consolidado</td> |
| | <td class="border border-gray-300 px-4 py-2">R$ ${formatCurrency(data.valorConsolidado)}</td> |
| | </tr> |
| | <tr> |
| | <td class="border border-gray-300 px-4 py-2">Parcelas de Entrada</td> |
| | <td class="border border-gray-300 px-4 py-2">${data.parcelasEntrada} (${data.parcelasEntradaPagas} pagas, ${data.parcelasEntradaVencidas} vencidas, ${data.parcelasEntradaAVencer} a vencer)</td> |
| | </tr> |
| | <tr> |
| | <td class="border border-gray-300 px-4 py-2">Parcelas Básicas</td> |
| | <td class="border border-gray-300 px-4 py-2">${data.parcelasBasicas} (${data.parcelasBasicasPagas} pagas, ${data.parcelasBasicasVencidas} vencidas, ${data.parcelasBasicasAVencer} a vencer)</td> |
| | </tr> |
| | <tr> |
| | <td class="border border-gray-300 px-4 py-2">Soma Selic + 1%</td> |
| | <td class="border border-gray-300 px-4 py-2">${data.somaSelic.toFixed(2)}%</td> |
| | </tr> |
| | <tr> |
| | <td class="border border-gray-300 px-4 py-2">RISCO 1</td> |
| | <td class="border border-gray-300 px-4 py-2">${data.risco1}</td> |
| | </tr> |
| | <tr> |
| | <td class="border border-gray-300 px-4 py-2">RISCO 2</td> |
| | <td class="border border-gray-300 px-4 py-2">${data.risco2}</td> |
| | </tr> |
| | </tbody> |
| | </table> |
| | </div> |
| | </div> |
| | `; |
| | }); |
| | |
| | resultData.innerHTML = html; |
| | } |
| | |
| | function generateCSV(dataArray) { |
| | |
| | let csv = 'REF|Numero da Negociacao|CNPJ|Nome Contribuinte|Data da adesao|Data da Consolidacao|Negociacoes|Modalidade|Tipo de Negociacao|Quantidade de Prestacoes|Principal|Multa|Juros|Encargos/Honorarios|Valor Consolidado|Saldo Devedor sem Juros|Saldo Devedor com Juros|Debitos|Quantidade de debitos|Principal Debitos|Multa Debitos|Juros Debitos|Encargos/Honorarios Debitos|Valor Total Debitos|Valor Parcela de entrada|Data parcela de entrada|Quantidade de prestacoes Entrada|Valor da prestacao Entrada|Valor Parcela Basica|Data parcela Basica|Quantidade de prestacoes Parcela Basica|Valor da prestacao Basica|Quantidade de prestacoes parcela basica pagas|Quantidade de prestacoes parcela basica a vencer|Quantidade de prestacoes parcela basica em atraso|Quantidade de prestacoes parcela Entrada pagas|Quantidade de prestacoes parcela Entrada a vencer|Quantidade de prestacoes parcela Entrada em atraso|Valor parcela Entrada Saldo|Valor parcela Basica Saldo|Soma Selic + 1%|Valor parcela Entrada Saldo Atualizada|Valor parcela Basica Saldo Atualizada|Valor da parcela de entrada atualizada|Valor da parcela basica atualizada|Data de vencimento parcela atual|Data de vencimento ultima prestacao|RISCO 1|RISCO 2\n'; |
| | |
| | |
| | dataArray.forEach((data, index) => { |
| | const line = `${index + 1}|${data.numeroNegociacao}|${data.cnpj}|${data.nomeContribuinte}|${data.dataAdesao}|${data.dataConsolidacao}|0083 - TRANSACAO POR ADESAO - EDITAL PGDAU N 06/2024|0018 - DEMAIS DEBITOS -PESSOA NATURAL, MICROEMPRESA E PEQUENO PORTE - ATE 145 MESES - REDUCAO ATE 70%|Acordo de Transacao|145|R$ ${formatCurrency(data.valorPrincipal)}|R$ ${formatCurrency(data.valorMulta)}|R$ ${formatCurrency(data.valorJuros)}|R$ ${formatCurrency(data.valorEncargos)}|R$ ${formatCurrency(data.valorConsolidado)}|R$ 5.652.130,49|R$ 6.077.735,92|32 debitos listados|32|R$ 2.801.945,42|R$ 631.899,01|R$ 2.318.462,20|R$ 1.024.243,23|R$ 6.776.549,86|R$ 406.592,99|31/01/2025|12|R$ ${formatCurrency(data.valorParcelaEntrada)}|R$ ${formatCurrency(data.valorParcelaBasica * data.parcelasBasicas)}|30/01/2026|${data.parcelasBasicas}|R$ ${formatCurrency(data.valorParcelaBasica)}|${data.parcelasBasicasPagas}|${data.parcelasBasicasAVencer}|${data.parcelasBasicasVencidas}|${data.parcelasEntradaPagas}|${data.parcelasEntradaAVencer}|${data.parcelasEntradaVencidas}|R$ ${formatCurrency(data.valorEntradaSaldo)}|R$ ${formatCurrency(data.valorBasicaSaldo)}|${data.somaSelic.toFixed(2)}%|R$ ${formatCurrency(data.valorEntradaSaldoAtualizado)}|R$ ${formatCurrency(data.valorBasicaSaldoAtualizado)}|R$ ${formatCurrency(data.valorParcelaEntradaAtualizado)}|R$ ${formatCurrency(data.val |
| | <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=maralvic/xml-html" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body> |
| | </html> |