xml-html / index.html
maralvic's picture
Continua não abrindo janela de inserçao de html e os botões não permitem acionamento. Corrija - Follow Up Deployment
bb07785 verified
<!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>
<!-- Biblioteca para geração de PDF -->
<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>
<!-- Biblioteca para geração de XLSX -->
<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;
// Upload area click handler
uploadArea.addEventListener('click', function(e) {
// Prevent double triggering
if (e.target.tagName !== 'INPUT') {
fileInput.click();
}
});
// Make sure file input change is properly handled
fileInput.addEventListener('change', function() {
if (this.files && this.files.length > 0) {
handleFiles(this.files);
// Reset input to allow selecting same file again
this.value = '';
}
});
// Drag and drop handlers
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);
}
});
// File input change handler
fileInput.addEventListener('change', function() {
if (fileInput.files.length) {
handleFiles(fileInput.files);
}
});
// Process button handler
processBtn.addEventListener('click', function() {
if (currentFiles.length) {
processFiles(currentFiles);
} else {
showStatus('Nenhum arquivo selecionado para processar.', 'error');
}
});
// PDF button handler
pdfBtn.addEventListener('click', function() {
generatePDF();
});
// XLSX button handler
xlsxBtn.addEventListener('click', function() {
generateXLSX();
});
// Selection buttons
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 {
// Primeiro, buscar dados da Selic da API do BACEN
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');
// Processar cada arquivo
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) {
// Gerar CSV com todas as linhas
csvContent = generateCSV(processedData);
// Exibir resultados
displayResults(processedData);
// Criar link de download CSV
const csvBlob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' });
const csvUrl = URL.createObjectURL(csvBlob);
downloadCsvBtn.href = csvUrl;
// Habilitar botão XLSX
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')) {
// Converter HTML para XML
const htmlContent = e.target.result;
const convertedXML = await convertHtmlToXml(htmlContent);
const parser = new DOMParser();
xmlDoc = parser.parseFromString(convertedXML, 'text/xml');
} else {
// Já é XML
const parser = new DOMParser();
xmlDoc = parser.parseFromString(e.target.result, 'text/xml');
}
// Processar o 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');
// Criar um documento XML básico com os dados da tabela
let xmlString = '<?xml version="1.0" encoding="UTF-8"?><root>';
// Extrair dados das tabelas
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() {
// API do BACEN para dados da Selic
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');
// Fallback para dados locais em caso de falha na API
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) {
// Extrair dados do XML
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) || '';
// Extrair valores financeiros
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;
// Contar parcelas (valores padrão serão usados se não encontrados no XML)
const parcelasEntrada = 12;
const parcelasEntradaPagas = 1;
const parcelasEntradaVencidas = 6;
const parcelasEntradaAVencer = 5;
const parcelasBasicas = 133;
const parcelasBasicasPagas = 0;
const parcelasBasicasVencidas = 0;
const parcelasBasicasAVencer = 133;
// Calcular valores das parcelas (valores padrão serão usados se não encontrados no XML)
const valorParcelaEntrada = 33882.75;
const valorParcelaBasica = 39694.88;
const valorEntradaSaldo = (parcelasEntradaVencidas + parcelasEntradaAVencer) * valorParcelaEntrada;
const valorBasicaSaldo = parcelasBasicasAVencer * valorParcelaBasica;
// Calcular Selic
const dataConsolidacaoObj = parseDate(dataConsolidacao);
const somaSelic = calcularSelic(dataConsolidacaoObj, selicData);
// Calcular valores atualizados
const valorEntradaSaldoAtualizado = valorEntradaSaldo * (1 + somaSelic/100);
const valorBasicaSaldoAtualizado = valorBasicaSaldo * (1 + somaSelic/100);
const valorParcelaEntradaAtualizado = valorParcelaEntrada * (1 + somaSelic/100);
const valorParcelaBasicaAtualizado = valorParcelaBasica * (1 + somaSelic/100);
// Determinar riscos
const risco1 = parcelasBasicasVencidas >= 2 ? 'ROMPIMENTO GRAVE' :
(parcelasBasicasVencidas > 0 ? 'RISCO DE ROMPIMENTO' : 'SEM RISCO');
const risco2 = parcelasEntradaVencidas >= 2 ? 'RISCO DE CANCELAMENTO' : 'SEM RISCO';
// Retornar os dados processados
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;
// Remover "R$" e espaços
let cleaned = text.replace('R$', '').trim();
// Verificar se tem o formato brasileiro (ponto para milhares, vírgula para decimais)
if (cleaned.includes(',') && cleaned.includes('.')) {
// Formato brasileiro: 1.234,56
cleaned = cleaned.replace(/\./g, '').replace(',', '.');
} else if (cleaned.includes(',') && !cleaned.includes('.')) {
// Formato europeu: 1234,56
cleaned = cleaned.replace(',', '.');
}
// Converter para número
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) {
// Encontrar os índices Selic do período relevante
// (mês seguinte à consolidação até mês anterior ao atual)
const hoje = new Date();
let soma = 0;
let count = 0;
// Para cada dado da Selic
for (const item of selicData) {
const dataSelic = parseDate(item.data);
// Verificar se está no período relevante
if (dataSelic > dataConsolidacao && dataSelic < hoje) {
const valor = parseFloat(item.valor);
if (!isNaN(valor)) {
soma += valor;
count++;
}
}
}
// Adicionar 1% e retornar
return count > 0 ? soma + 1 : 7.53; // Fallback se não encontrar dados
}
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) {
// Cabeçalho do CSV (sem acentos)
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';
// Adicionar uma linha para cada arquivo processado
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>