| <!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> |