Estudo de Carteira Automático

Estudo de Carteira Automático

Estudo de Carteira Automático

Crie uma carteira personalizada para seu cliente em minutos. Basta selecionar o perfil do cliente, preencher o capital aportado e nome e gerar a carteira. A recomendação do comitê de alocação será sugerida automaticamente, mas você pode ajustá-la conforme as necessidades do cliente.


Carteira

100.0%

`; assetList.appendChild(assetItem); const detailsContainer = assetItem.querySelector('.asset-details-container'); // Adicionar os containers pré-preenchidos for (let i = 1; i
`; detailsContainer.appendChild(newDetails); applyAporteFormatting(); // Função para remover containers e recalcular os valores const closeBtn = newDetails.querySelector('.close-btn'); closeBtn.addEventListener('click', () => { const nomeAtivo = newDetails.querySelector('input[placeholder=""]').value.trim(); const capitalAportado = parseFloat(document.getElementById('capital').value.replace(/[^\d,-]/g, '').replace(',', '.')); // Se for "Debênture Vero" ou "CRI MRV", mantém o valor fixo de 5% if (nomeAtivo === 'Debênture Vero' || nomeAtivo === 'CRI MRV') { newDetails.remove(); updateAporteValues(detailsContainer, valorClasse); // Atualiza outros valores sem recalcular esses ativos return; // Sai da função sem recalcular os valores para esses ativos } newDetails.remove(); updateAporteValues(detailsContainer, valorClasse); // Recalcula os valores para os outros ativos updateTitleColor(detailsContainer); }); } // Função para adicionar novos containers ao clicar no botão + Adicionar const addBtn = assetItem.querySelector('.add-btn'); addBtn.addEventListener('click', () => { const newDetails = document.createElement('div'); newDetails.classList.add('asset-details'); newDetails.innerHTML = `
`; detailsContainer.appendChild(newDetails); applyAporteFormatting(); updateAporteValues(detailsContainer, valorClasse); updateTitleColor(detailsContainer); newDetails.querySelector('.close-btn').addEventListener('click', () => { newDetails.remove(); updateAporteValues(detailsContainer, valorClasse); updateTitleColor(detailsContainer); }); }); document.querySelectorAll('.asset-details').forEach(function(details) { const nomeInput = details.querySelector('input[placeholder=""]'); // Seleciona o input de nome if (nomeInput) { const nomeAtivo = nomeInput.value.trim(); // Obtém o valor do input de nome // Verifica se o nome é "Debênture Vero" ou "CRI MRV" if (nomeAtivo === 'CRA Seara (JBS)' || nomeAtivo === 'CRI Uberlândia Refrescos' || nomeAtivo === 'CRA Rede Sim') { const capitalAportado = parseFloat(document.getElementById('capital').value.replace(/[^\d,-]/g, '').replace(',', '.')); // Obtém o capital aportado const valorAporte = (capitalAportado * 0.03).toLocaleString('pt-BR', { style: 'currency', currency: 'BRL' }); // Calcula 5% do capital aportado // Atualiza o valor do input de aporte para 5% do capital const aporteInput = details.querySelector('.aporte-input'); if (aporteInput) { aporteInput.value = valorAporte; // Preenche o input de aporte } } } }); // Atualizar os valores de aporte updateAporteValues(detailsContainer, valorClasse); updateTitleColor(detailsContainer); } } } } function getPreFilledLabel(segment, field, index) { const prefilledData = { "Pós-fixado": [ { Nome: "XP Referenciado FIF RF", Ticker: "", Retorno: "11,18% em 2024", Liquidez: "Diária", Vencimento: "", Dividendo: "", Upside: "", Características: "O objetivo do fundo é obter retornos superiores aos dos Certificados de Depositos interfinanceiro (CDI)." }, { Nome: "XP Liquidez FIC RF REF DI CP RL", Ticker: "", Retorno: "Target de 12% ao ano", Liquidez: "Diária", Vencimento: "", Dividendo: "", Upside: "", Características: "A Classe tem por objetivo obter ganhos, mediante a aplicação de recursos, preponderantemente, em cotas de emissão de outras classes de fundos de investimento de renda fixa." }, { Nome: "XP Crédito Estruturado 120 FIC FIM CP", Ticker: "", Retorno: "15,47% em 2024", Liquidez: "Mercado Secundário", Vencimento: "2028", Dividendo: "", Upside: "", Características: "A São Martinho é uma empresa sucroenergética brasileira que produz açúcar, etanol e energia elétrica. É uma das maiores produtoras de cana-de-açúcar do país." }, ], "Prefixado": [ { Nome: "CRA Ubyfol", Ticker: "", Retorno: "18% a.a.", Liquidez: "Mercado Secundário", Vencimento: "2028", Dividendo: "", Upside: "", Características: "A Ubyfol é uma multinacional brasileira especialista em nutrição vegetal." }, { Nome: "LTN - JAN/2026", Ticker: "", Retorno: "14,33% a.a.", Liquidez: "Mercado Secundário", Vencimento: "2026", Dividendo: "", Upside: "", Características: "Título de renda fixa prefixada emitido pelo governo federal. Também é conhecido como Tesouro Prefixado." }, ], "Inflação": [ { Nome: "Deb. Petrobrás", Ticker: "", Retorno: "IPCA + 6,85% a.a", Liquidez: "Mercado secundário", Vencimento: "10 anos", Dividendo: "", Upside: "", Características: "Uma das maiores empresas brasileiras, a petrolífera Petrobrás vem a mercado para captar R$3 bilhões por meio de uma debênture incentivada, disponível para público geral." }, { Nome: "NTN-B - AGO/2030", Ticker: "", Retorno: "IPC-A + 7,360% a.a", Liquidez: "Mercado secundário", Vencimento: "15/08/2030", Dividendo: "", Upside: "", Características: "A NTN-B 2030 é um título público de renda fixa emitido pelo Tesouro Nacional, que se destina a proteger o investidor contra a inflação" }, ], "Fundos": [ { Nome: "TG Core", Ticker: "TGRU ", Retorno: "Retorno-alvo de 9,5% a.a. + IPCA", Liquidez: "Mercado secundário", Vencimento: "", Dividendo: "", Upside: "", Características: "O fundo investe em um portfólio de centros de conveniência e lojas comprados com um valor descontado, que contam com 232 contratos de alugueis vigentes." }, { Nome: "RZDS11 (secundário)", Ticker: "RZDS11", Retorno: "Total Return de 133% CDI", Liquidez: "Mercado secundário", Vencimento: "", Dividendo: "", Upside: "", Características: "O Riza Domus seleciona ativos no setorimobiliário, visando um portfólio que melhor se adeque às nossas perspectivas de risco-retorno-liquide." }, { Nome: "AZQI11 (secundário)", Ticker: "AZQI11", Retorno: "Total Return de 155% CDI", Liquidez: "Mercado secundário", Vencimento: "", Dividendo: "", Upside: "", Características: "O AZQI11 continua posicionado entre os melhores dividend vield (DY) da indústria de Fundos de Infraestrutura, considerando os últimos 12 meses (DY de 15,79% a.a.). Rendimento total distribuido por cota de R$ 0,375 no 49 trimestre de 2024." }, { Nome: "VGIE11 (secundário)", Ticker: "VGIE11", Retorno: "Total Return de 131% CDI", Liquidez: "Mercado secundário", Vencimento: "", Dividendo: "", Upside: "", Características: "O Fundo encerrou o mês com todo o seu patrimônio líquido alocado em Ativos-Alvo, totalizando R$ 499,3 milhões em 18 debêntures, além de investir em instrumentos de caixa." }, ], "Global (Renda Fixa)": [ { Nome: "Cleveland-Cliffs", Ticker: "", Retorno: "Dólar + 5,76% a.a", Liquidez: "D+2 dias úteis (EUA)", Vencimento: "15/04/2030", Dividendo: "", Upside: "", Características: "Uma das maiores empresas siderúrgicas e de mineração dos EUA, fundada em 1847." }, { Nome: "JP Morgan", Ticker: "", Retorno: "Dólar + 4,62% a.a", Liquidez: "D+2 dias úteis (EUA)", Vencimento: "24/01/2031", Dividendo: "", Upside: "", Características: "um dos maiores e mais influentes bancos do mundo, atuando em banco de investimento, gestão de ativos, serviços bancários e financeiros." }, { Nome: "Itaú", Ticker: "", Retorno: "Dólar + 5,03% a.a", Liquidez: "D+2 dias úteis (EUA)", Vencimento: "27/02/2030", Dividendo: "", Upside: "", Características: "O maior banco privado do Brasil e um dos maiores da América Latina." }, ], "Global (Renda Variável)": [ { Nome: "iShares U.S. Energy ETF", Ticker: "IYE", Retorno: "", Liquidez: "", Vencimento: "", Dividendo: "", Upside: "", Características: "O ETF investe em empresas do setor de energia dos EUA, incluindo petróleo, gás e serviços relacionados." }, { Nome: "Vanguard Utilities ETF", Ticker: "VPU", Retorno: "", Liquidez: "", Vencimento: "", Dividendo: "", Upside: "", Características: "O ETF investe em empresas do setor de utilidades dos EUA, como fornecedoras de eletricidade, gás e água." }, { Nome: "iShares U.S. Financials ETF", Ticker: "IYF", Retorno: "", Liquidez: "", Vencimento: "", Dividendo: "", Upside: "", Características: "O ETF investe em empresas do setor financeiro dos EUA, incluindo bancos, seguradoras e outras instituições financeiras." }, { Nome: "Vanguard FTSE Europe ETF", Ticker: "VGK", Retorno: "", Liquidez: "", Vencimento: "", Dividendo: "", Upside: "", Características: "O ETF investe em empresas da Europa, seguindo o índice FTSE desenvolvido para refletir o mercado de ações da região." }, { Nome: "iShares Trust - China Large-Cap ETF", Ticker: "FXI", Retorno: "", Liquidez: "", Vencimento: "", Dividendo: "", Upside: "", Características: "O ETF investe em grandes empresas chinesas listadas nos EUA, focando nas maiores companhias do país." }, ], "Brasil (Renda Variável)": [ { Nome: "Top Dividendos Plus", Ticker: "", Retorno: "7,0% nos últimos 12 meses", Liquidez: "", Vencimento: "", Dividendo: "", Upside: "", Características: "Nessa carteira, a XP recomenda todos os meses os melhores 10 nomes a partir de uma seleção de maiores pagadoras de dividendos entre os membros dos índices Ibovespa, Small Caps (SMLL) e IBrX 100." }, ], "Alternativos": [ { Nome: "Riza Viseu", Ticker: "", Retorno: "TIR de 24,4% a.a", Liquidez: "Mercado Secundário", Vencimento: "7 anos, prorrogáveis por mais 2 anos", Dividendo: "", Upside: "", Características: "O fundo tem como estratégia a aquisição de participação na Riva Incorporadora, subsidiaria da Direcional." }, { Nome: "HASH11", Ticker: "", Retorno: "135,75% nos últimos 12 meses", Liquidez: "", Vencimento: "", Dividendo: "", Upside: "", Características: "O HASH11 é um fundo de índice listado na B3 que replica o Nasdaq Crypto Index™ (NCI™), índice que busca refletir globalmente o movimento do mercado de criptoativos." }, ] }; return prefilledData[segment][index - 1][field] || ''; } let manualValues = {}; // Armazena os valores manualmente alterados // Função para formatar os valores de moeda conforme o usuário digita function formatCurrencyLive(input) { let value = input.value.replace(/\D/g, ''); // Remove caracteres que não são números if (value) { value = (parseFloat(value) / 100).toLocaleString('pt-BR', { style: 'currency', currency: 'BRL' }); input.value = value; } else { input.value = 'R$ 0,00'; // Valor padrão caso o campo esteja vazio } } // Função chamada quando o valor do aporte é alterado manualmente function handleAporteChange(input, detailsContainer, valorClasse) { const inputId = input.getAttribute('data-id'); let valorAporte = parseFloat(input.value.replace(/[^\d,-]/g, '').replace(',', '.')); if (isNaN(valorAporte)) valorAporte = 0; // Se o valor é superior ao valor total do segmento, altere a cor para vermelho if (valorAporte > valorClasse) { input.style.color = 'rgb(229, 73, 126)'; } else { input.style.color = '#1dc077'; } // Armazena o valor manualmente alterado assim que o usuário faz uma mudança manualValues[inputId] = valorAporte; // Atualizar os valores restantes imediatamente recalculateOtherAportes(input, detailsContainer, valorClasse); } // Função para recalcular os valores de aportes, preservando os valores manualmente alterados function updateAporteValues(detailsContainer, valorClasse) { const aporteInputs = detailsContainer.querySelectorAll('.aporte-input'); let totalManual = 0; let manualCount = 0; // Calcular o total dos aportes manuais aporteInputs.forEach(input => { const inputId = input.getAttribute('data-id'); if (manualValues[inputId] !== undefined) { totalManual += manualValues[inputId]; manualCount++; } }); const remainingValue = valorClasse - totalManual; const remainingContainers = aporteInputs.length - manualCount; // Recalcular o valor para os inputs não alterados manualmente aporteInputs.forEach(input => { const inputId = input.getAttribute('data-id'); if (manualValues[inputId] === undefined && remainingContainers > 0) { const valorPorContainer = remainingValue / remainingContainers; input.value = valorPorContainer.toLocaleString('pt-BR', { style: 'currency', currency: 'BRL' }); } }); } // Função para recalcular todos os inputs não alterados, mesmo após manual input function recalculateOtherAportes(changedInput, detailsContainer, valorClasse) { const allInputs = detailsContainer.querySelectorAll('.aporte-input'); let totalManual = 0; let numOtherInputs = 0; // Passo 1: Somar todos os valores manualmente alterados e contar os inputs que não foram manualmente alterados allInputs.forEach(input => { const manualValue = parseFloat(input.value.replace(/[^\d,-]/g, '').replace(',', '.')); // Verifica se o nome é "Debênture Vero" ou "CRI MRV" para garantir que permaneça em 5% const nomeInput = input.closest('.asset-details').querySelector('input[placeholder=""]'); const nomeAtivo = nomeInput ? nomeInput.value.trim() : ''; if (nomeAtivo === 'Debênture Vero' || nomeAtivo === 'CRI MRV') { const capitalAportado = parseFloat(document.getElementById('capital').value.replace(/[^\d,-]/g, '').replace(',', '.')); const valorFixo = (capitalAportado * 0.05).toLocaleString('pt-BR', { style: 'currency', currency: 'BRL' }); input.value = valorFixo; // Mantém o valor fixo de 5% input.dataset.manual = 'true'; // Marca como "manual" para não ser recalculado } else if (!isNaN(manualValue) && input.dataset.manual === "true") { totalManual += manualValue; } else { numOtherInputs++; } }); // Passo 2: Calcular o valor restante a ser distribuído, sem incluir os inputs de "Debênture Vero" e "CRI MRV" const remainingValue = valorClasse - totalManual; // Passo 3: Distribuir o valor restante para os inputs que não foram manualmente alterados if (numOtherInputs > 0 && remainingValue > 0) { const newAporteValue = remainingValue / numOtherInputs; allInputs.forEach(input => { const nomeInput = input.closest('.asset-details').querySelector('input[placeholder=""]'); const nomeAtivo = nomeInput ? nomeInput.value.trim() : ''; // Só recalcular se o input não for "Debênture Vero" ou "CRI MRV" e não tiver sido manualmente alterado if (!input.dataset.manual && nomeAtivo !== 'Debênture Vero' && nomeAtivo !== 'CRI MRV') { input.value = newAporteValue.toLocaleString('pt-BR', { style: 'currency', currency: 'BRL' }); } }); } // Manter o input alterado manualmente como "manual" changedInput.dataset.manual = "true"; } // Função para aplicar a formatação e eventos aos campos de "aporte" function applyAporteFormatting() { const aporteInputs = document.querySelectorAll('.aporte-input'); aporteInputs.forEach(input => { input.addEventListener('input', function () { formatCurrencyLive(this); // Formata o valor enquanto o usuário digita const detailsContainer = this.closest('.asset-details-container'); const totalSegmentValue = parseFloat(detailsContainer.parentElement.querySelector('span').textContent.replace(/[^\d,-]/g, '').replace(',', '.')); handleAporteChange(this, detailsContainer, totalSegmentValue); // Garante que o valor é salvo imediatamente }); input.addEventListener('blur', function () { const detailsContainer = this.closest('.asset-details-container'); const totalSegmentValue = parseFloat(detailsContainer.parentElement.querySelector('span').textContent.replace(/[^\d,-]/g, '').replace(',', '.')); recalculateOtherAportes(this, detailsContainer, totalSegmentValue); // Recalcula os outros valores ao perder o foco (após edição) }); }); } // Função para inicializar e atribuir o 'data-id' único a cada input de Aporte function initializeAporteInputs(detailsContainer, valorClasse) { const aporteInputs = detailsContainer.querySelectorAll('.aporte-input'); aporteInputs.forEach((input, index) => { input.setAttribute('data-id', `aporte-${index}`); input.dataset.originalValue = parseFloat(input.value.replace(/[^\d,-]/g, '').replace(',', '.')) || 0; // Armazena o valor original input.addEventListener('input', () => handleAporteChange(input, detailsContainer, valorClasse)); }); applyAporteFormatting(); // Garante que os novos inputs também tenham formatação } // Função para atualizar a cor do título com base na quantidade de containers function updateTitleColor(detailsContainer) { const titleLabel = detailsContainer.parentElement.querySelector('div > div'); const gerarPdfButton = document.getElementById('gerar-ppt'); if (detailsContainer.children.length === 0) { titleLabel.style.color = 'rgb(229, 73, 126)'; gerarPdfButton.style.display = 'none'; } else { titleLabel.style.color = ''; checkTitleColorsForPdfButton(); } } // Verificar se todos os títulos estão corretos para mostrar o botão de gerar PDF function checkTitleColorsForPdfButton() { const titles = document.querySelectorAll('.carteira-item label'); const gerarPdfButton = document.getElementById('gerar-ppt'); let anyTitleRed = false; titles.forEach(title => { if (window.getComputedStyle(title).color === 'rgb(229, 73, 126)') { anyTitleRed = true; } }); if (!anyTitleRed) { gerarPdfButton.style.display = 'inline-block'; } else { gerarPdfButton.style.display = 'none'; } } // Função para redistribuir o valor do segmento ao adicionar ou remover containers function redistributeAportes(detailsContainer, valorClasse) { const aporteInputs = [...detailsContainer.querySelectorAll('.aporte-input')]; let totalManual = 0; let numContainers = 0; // Calcular o valor restante e contar containers não editados aporteInputs.forEach(input => { const inputId = input.getAttribute('data-id'); if (!manualValues[inputId]) { numContainers++; } else { totalManual += manualValues[inputId]; } }); const valorParaRedistribuir = valorClasse - totalManual; if (numContainers > 0) { const valorPorContainer = valorParaRedistribuir / numContainers; aporteInputs.forEach(input => { const inputId = input.getAttribute('data-id'); if (!manualValues[inputId]) { input.value = valorPorContainer.toLocaleString('pt-BR', { style: 'currency', currency: 'BRL' }); } }); } } // Lógica ao adicionar/remover containers document.querySelectorAll('.add-btn').forEach(button => { button.addEventListener('click', function () { const detailsContainer = this.closest('.asset-details-container'); const valorClasse = parseFloat(detailsContainer.parentElement.querySelector('span').textContent.replace(/[^\d,-]/g, '').replace(',', '.')); // Aqui você adicionaria o novo container initializeAporteInputs(detailsContainer, valorClasse); // Inicializa os inputs do novo container redistributeAportes(detailsContainer, valorClasse); // Redistribui os valores após a adição }); }); document.querySelectorAll('.remove-btn').forEach(button => { button.addEventListener('click', function () { const detailsContainer = this.closest('.asset-details-container'); const valorClasse = parseFloat(detailsContainer.parentElement.querySelector('span').textContent.replace(/[^\d,-]/g, '').replace(',', '.')); // Aqui você removeria o container redistributeAportes(detailsContainer, valorClasse); // Redistribui os valores após a remoção }); }); // Outras funções existentes no código... document.addEventListener('DOMContentLoaded', () => { updateProfile(); document.getElementById('voltar').addEventListener('click', resetToInitialValues); document.getElementById('capital').addEventListener('input', updateAssetValues); const chartSegments = document.querySelectorAll('.chart-segments circle'); const chartTooltip = document.getElementById('chartTooltip'); chartSegments.forEach((segment, index) => { segment.addEventListener('mouseenter', (event) => { const segmentId = segment.classList[0].replace('segment-', ''); const segmentLabel = document.querySelector(`label[for=${segmentId}]`).textContent; const segmentValue = document.getElementById(segmentId).value; const capitalAportado = parseFloat(document.getElementById('capital').value.replace(/[^\d,-]/g, '').replace(',', '.')); const valorClasse = (capitalAportado * (segmentValue / 100)).toLocaleString('pt-BR', { style: 'currency', currency: 'BRL' }); chartTooltip.innerHTML = `${segmentLabel}${segmentValue}%
${valorClasse}`; chartTooltip.style.left = `${event.pageX + 1}px`; chartTooltip.style.top = `${event.pageY + 1}px`; chartTooltip.style.display = 'block'; chartSegments.forEach(s => { if (s !== segment) { s.style.opacity = '0.5'; } }); segment.style.opacity = '1'; }); segment.addEventListener('mouseleave', () => { chartTooltip.style.display = 'none'; chartSegments.forEach(s => s.style.opacity = '1'); }); segment.addEventListener('mousemove', (event) => { const containerRect = document.querySelector('.chart-container').getBoundingClientRect(); chartTooltip.style.left = `${event.clientX - containerRect.left - 80}px`; chartTooltip.style.top = `${event.clientY - containerRect.top - 80}px`; }); }); document.getElementById('simular').addEventListener('click', () => { document.getElementById('resultSection').style.display = 'block'; // Exibe a seção de resultados document.getElementById('simular').style.display = 'none'; // Esconde o botão "Gerar Carteira" updateAssetValues(); // Atualiza os valores da carteira }); document.getElementById('voltar').addEventListener('click', () => { resetToInitialValues(); // Restaura os valores iniciais // Verifica se o resultSection está visível e mantém o botão "Gerar Carteira" oculto if (document.getElementById('resultSection').style.display === 'block') { document.getElementById('simular').style.display = 'none'; } else { document.getElementById('simular').style.display = 'inline-block'; } }); document.getElementById('simular').addEventListener('click', () => { document.getElementById('resultSection').style.display = 'block'; document.getElementById('gerar-ppt').style.display = 'inline-block'; // Mostra o botão Gerar PPT updateAssetValues(); }); document.getElementById('gerar-ppt').addEventListener('click', () => { const pptx = new PptxGenJS(); const nomeCliente = document.getElementById('nome').value || 'Cliente'; const capitalAportado = document.getElementById('capital').value; // Coletar os valores dos inputs com percentuais > 0 const valores = []; const labels = []; const cores = []; let total = 0; document.querySelectorAll('.carteira-item').forEach(item => { const input = item.querySelector('input[type="range"]'); const valor = parseFloat(input.value); if (valor > 0) { const label = item.querySelector('label').textContent; valores.push(valor); labels.push(label); // Obter a cor dos sliders para usar no gráfico const cor = getComputedStyle(input).color; cores.push(cor); // Adiciona a cor de cada item ao array de cores total += valor; // Calcula o total para calcular percentuais } }); const labelsComPercentuais = labels.map((label, index) => { const percentual = ((valores[index] / total) * 100).toFixed(1); return `${label} - ${percentual}%`; // Adiciona o percentual à legenda }); // Slide 1: Texto personalizado let slide1 = pptx.addSlide(); slide1.addImage({ path: 'https://upload.wikimedia.org/wikipedia/commons/3/31/Capa_Invest2.png', x: 0, y: 0, w: '100%', h: '100%' }); slide1.addText(`Material desenvolvido exclusivamente para ${nomeCliente}.`, { x: 2.05, y: 3.17, w: 3.4, h: 0.4, fontSize: 12, color: 'F1F1F1', fontFace: 'Montserrat Light' }); // Slide 2 let slide2 = pptx.addSlide(); slide2.addImage({ path: 'https://upload.wikimedia.org/wikipedia/commons/0/00/2macroabril.png', x: 0, y: 0, w: '100%', h: '100%' }); // Slide 3 let slide3 = pptx.addSlide(); slide3.addImage({ path: 'https://upload.wikimedia.org/wikipedia/commons/d/db/3macroabril.png', x: 0, y: 0, w: '100%', h: '100%' }); // Slide 4 let slide4 = pptx.addSlide(); slide4.addImage({ path: 'https://upload.wikimedia.org/wikipedia/commons/6/67/4macroabril.png', x: 0, y: 0, w: '100%', h: '100%' }) // Slide 5 let slide5 = pptx.addSlide(); slide5.addImage({ path: 'https://upload.wikimedia.org/wikipedia/commons/4/48/5macroabril.png', x: 0, y: 0, w: '100%', h: '100%' }) // Slide 6 let slide6 = pptx.addSlide(); slide6.addImage({ path: 'https://upload.wikimedia.org/wikipedia/commons/4/4d/6macroabril.png', x: 0, y: 0, w: '100%', h: '100%' }); // Slide 7 let slide7 = pptx.addSlide(); slide7.addImage({ path: 'https://upload.wikimedia.org/wikipedia/commons/3/3e/7macroabril.png', x: 0, y: 0, w: '100%', h: '100%' }); // Slide 8 let slide8 = pptx.addSlide(); slide8.addImage({ path: 'https://upload.wikimedia.org/wikipedia/commons/7/72/8macroabril.png', x: 0, y: 0, w: '100%', h: '100%' }); // Slide 9 let slide9 = pptx.addSlide(); slide9.addImage({ path: 'https://upload.wikimedia.org/wikipedia/commons/c/cb/9macroabril.png', x: 0, y: 0, w: '100%', h: '100%' }); // Slide 10 let slide10 = pptx.addSlide(); slide10.addImage({ path: 'https://upload.wikimedia.org/wikipedia/commons/1/1b/10macroabril.png', x: 0, y: 0, w: '100%', h: '100%' }); // Slide 11 let slide11 = pptx.addSlide(); slide11.addImage({ path: 'https://upload.wikimedia.org/wikipedia/commons/6/6e/11macromaio.png', x: 0, y: 0, w: '100%', h: '100%' }); // Slide 12 let slide12 = pptx.addSlide(); slide12.addImage({ path: 'https://upload.wikimedia.org/wikipedia/commons/3/3f/12macroabril.png', x: 0, y: 0, w: '100%', h: '100%' }); // Slide 13 let slide13 = pptx.addSlide(); slide13.addImage({ path: 'https://upload.wikimedia.org/wikipedia/commons/4/41/13macroabril.png', x: 0, y: 0, w: '100%', h: '100%' }); // Slide 14 let slide14 = pptx.addSlide(); slide14.addImage({ path: 'https://upload.wikimedia.org/wikipedia/commons/2/2f/14macroabril.png', x: 0, y: 0, w: '100%', h: '100%' }); // Slide 15 let slide15 = pptx.addSlide(); slide15.addImage({ path: 'https://upload.wikimedia.org/wikipedia/commons/5/59/15macroabril.png', x: 0, y: 0, w: '100%', h: '100%' }); // Slide 16 let slide16 = pptx.addSlide(); slide16.addImage({ path: 'https://upload.wikimedia.org/wikipedia/commons/d/dd/17macromaio.png', x: 0, y: 0, w: '100%', h: '100%' }); // Slide 17 let slide17 = pptx.addSlide(); slide17.addImage({ path: 'https://upload.wikimedia.org/wikipedia/commons/a/af/17macroabril.png', x: 0, y: 0, w: '100%', h: '100%' }); // Slide 18 let slide18 = pptx.addSlide(); slide18.addImage({ path: 'https://upload.wikimedia.org/wikipedia/commons/5/52/18macroabril.png', x: 0, y: 0, w: '100%', h: '100%' }); // Slide 19 let slide19 = pptx.addSlide(); slide19.addImage({ path: 'https://upload.wikimedia.org/wikipedia/commons/3/30/19macroabril.png', x: 0, y: 0, w: '100%', h: '100%' }); // Slide 20 let slide20 = pptx.addSlide(); slide20.addImage({ path: 'https://upload.wikimedia.org/wikipedia/commons/c/cc/20macroabril.png', x: 0, y: 0, w: '100%', h: '100%' }); // Slide 21 let slide21 = pptx.addSlide(); slide21.addImage({ path: 'https://upload.wikimedia.org/wikipedia/commons/4/43/21macroabril.png', x: 0, y: 0, w: '100%', h: '100%' }); // Slide 22 let slide22 = pptx.addSlide(); slide22.addImage({ path: 'https://upload.wikimedia.org/wikipedia/commons/f/f8/22macroabril.png', x: 0, y: 0, w: '100%', h: '100%' }); // Slide 23 let slide23 = pptx.addSlide(); slide23.addImage({ path: 'https://upload.wikimedia.org/wikipedia/commons/1/15/23macroabril.png', x: 0, y: 0, w: '100%', h: '100%' }); // Slide 24 let slide24 = pptx.addSlide(); slide24.addImage({ path: 'https://upload.wikimedia.org/wikipedia/commons/8/89/24macromaio.png', x: 0, y: 0, w: '100%', h: '100%' }); // Slide 25 let slide25 = pptx.addSlide(); slide25.addImage({ path: 'https://upload.wikimedia.org/wikipedia/commons/9/92/Temp16.png', x: 0, y: 0, w: '100%', h: '100%' }); slide25.addText(`ESTRATÉGIA DE ALOCAÇÃO`, { x: 0.67, y: 0.57, w: '7.75', h: '0.56', fontSize: 30, fontFace: 'Montserrat Light', align: 'left', color: 'F1F1F1' }); slide25.addChart(pptx.ChartType.doughnut, [ { name: 'Alocação de Ativos', labels: labelsComPercentuais, values: valores } ], { x: 1.22, y: 1.88, w: 6.95, h: 3.47, holeSize: 85, showLegend: true, // Mostra a legenda legendPos: 'r', // Posição da legenda à direita legendColor: 'FFFFFF', legendFontFace: 'Montserrat Light', // Define a fonte Montserrat Light legendFontSize: 10, // Tamanho da fonte das legendas legendFontItalic: false, // Não usar itálico dataLabelColor: 'FFFFFF', // Cor do rótulo do gráfico dataLabelFontSize: 9, // Tamanho do texto dos rótulos dataLabelFontFace: 'Montserrat Bold', showPercent: false, }); slide25.addText(`100%`, { x: 2.65, y: 3.31, w: '1.82', h: '0.56', fontSize: 40, fontFace: 'Montserrat Bold', align: 'center', color: 'F1F1F1' }); slide25.addText(`Capital Aportado: ${capitalAportado}`, { x: 1.37, y: 1.04, w: '7.75', h: '0.25', fontSize: 14, fontFace: 'Montserrat Light', align: 'left', color: '1dc077' }); // Slide 26 let slide26 = pptx.addSlide(); slide26.addImage({ path: 'https://upload.wikimedia.org/wikipedia/commons/d/da/Temp17.png', x: 0, y: 0, w: '100%', h: '100%' }); slide26.hidden = true; // Slide 27 let slide27 = pptx.addSlide(); slide27.addImage({ path: 'https://upload.wikimedia.org/wikipedia/commons/f/f2/Temp18.png', x: 0, y: 0, w: '100%', h: '100%' }); slide27.hidden = true; // Slide 28 let slide28 = pptx.addSlide(); slide28.addImage({ path: 'https://upload.wikimedia.org/wikipedia/commons/1/1d/Temp19.png', x: 0, y: 0, w: '100%', h: '100%' }); slide28.hidden = true; // Slide 29 - Ativos // Função para extrair o percentual da label "retorno" function extrairPercentual(texto) { // Primeiro, vamos procurar por "IPCA + [número]%" e adicionar o IPCA de 4,35% let ipcaMatch = texto.match(/IPCA\s*\+\s*(\d+,\d+|\d+)%/i); if (ipcaMatch) { let percentual = parseFloat(ipcaMatch[1].replace(',', '.')); return 4.35 + percentual; // Adiciona o IPCA de 4,35% } // Caso contrário, procuramos apenas pelo número percentual let match = texto.match(/(\d+,\d+|\d+)%/); if (match) { return parseFloat(match[1].replace(',', '.')); } return null; // Retorna null se nenhum percentual for encontrado } // Função para adicionar o gráfico de rentabilidade function adicionarGraficoRentabilidade(slide, percentual, isIPCA) { let valoresAnuais = []; let valoresAnuaisComPorcentagem = []; // Novo array para incluir o símbolo de porcentagem for (let ano = 1; ano { container.querySelectorAll('.asset-details').forEach(asset => { const detalhesAtivo = []; let percentualRetorno = null; let nomeAtivo = ''; let tickerAtivo = ''; asset.querySelectorAll('input, textarea').forEach(input => { if (input.value.trim() !== '') { const rotulo = input.previousElementSibling.textContent.trim(); detalhesAtivo.push({ rotulo, valor: input.value.trim() }); // Extrair o percentual da label "retorno" para o gráfico if (rotulo.toLowerCase().includes('retorno')) { percentualRetorno = extrairPercentual(input.value); isIPCA = input.value.includes('IPCA'); // Verifica se o retorno inclui IPCA } // Armazenar o valor da label "nome" se existir if (rotulo.toLowerCase().includes('nome')) { nomeAtivo = input.value.trim(); } // Armazenar o valor da label "Ticker" se existir if (rotulo.toLowerCase().includes('ticker')) { tickerAtivo = input.value.trim(); } } }); if (detalhesAtivo.length > 0) { const nomeSegmento = labels[index].toUpperCase(); let backgroundImage = ''; switch (nomeSegmento) { case 'PÓS-FIXADO': backgroundImage = 'https://upload.wikimedia.org/wikipedia/commons/1/15/Temp32_1.png'; break; case 'PREFIXADO': backgroundImage = 'https://upload.wikimedia.org/wikipedia/commons/9/9c/Temp32_2.png'; break; case 'INFLAÇÃO': backgroundImage = 'https://upload.wikimedia.org/wikipedia/commons/2/24/Temp32_3.png'; break; case 'FUNDOS': backgroundImage = 'https://upload.wikimedia.org/wikipedia/commons/7/7b/Temp32_4.png'; break; case 'GLOBAL (RENDA FIXA)': backgroundImage = 'https://upload.wikimedia.org/wikipedia/commons/1/1e/Temp32_5.png'; break; case 'GLOBAL (RENDA VARIÁVEL)': backgroundImage = 'https://upload.wikimedia.org/wikipedia/commons/4/4d/Temp32_6.png'; break; case 'BRASIL (RENDA VARIÁVEL)': backgroundImage = 'https://upload.wikimedia.org/wikipedia/commons/a/a5/Temp32_7.png'; break; case 'ALTERNATIVOS': backgroundImage = 'https://upload.wikimedia.org/wikipedia/commons/4/4f/Temp32_8.png'; break; default: backgroundImage = 'https://upload.wikimedia.org/wikipedia/commons/4/4f/Temp32_8.png'; // Fallback para uma imagem padrão } let slide = pptx.addSlide(); slide.addImage({ path: backgroundImage, x: 0, y: 0, w: '100%', h: '100%' }); slide.addText(nomeSegmento, { x: 0.67, y: 0.57, w: '7.75', h: '0.56', fontSize: 30, fontFace: 'Montserrat Light', align: 'left', color: 'F1F1F1' }); const percentualSegmento = parseFloat(document.querySelectorAll('.carteira-item input[type="range"]')[index].value); const capitalTotal = parseFloat(document.getElementById('capital').value.replace(/[^\d,-]/g, '').replace(',', '.')); const valorSegmento = (capitalTotal * (percentualSegmento / 100)).toLocaleString('pt-BR', { style: 'currency', currency: 'BRL' }); slide.addText(`Aporte: ${valorSegmento}`, { x: 1.37, y: 1.04, w: '7.75', h: '0.25', fontSize: 14, fontFace: 'Montserrat Light', align: 'left', color: '1dc077' }); let yPosition = 3.32; let detalhesFormatados = []; detalhesAtivo.forEach(detalhe => { detalhesFormatados.push( { text: `• ${detalhe.rotulo} `, options: { fontFace: 'Montserrat Light', fontSize: 12, color: '1dc077' } }, { text: `${detalhe.valor}`, options: { fontFace: 'Montserrat Light', fontSize: 12, color: 'ffffff' } }, { text: '\n\n' } ); }); slide.addText(detalhesFormatados, { x: 0.67, y: yPosition, w: 4.15, h: 0.47, fontSize: 8, fontFace: 'Montserrat Light', align: 'left' }); // Adicionar gráfico de rentabilidade se o segmento for Pós-fixado, Prefixado ou Inflação if (['PÓS-FIXADO', 'PREFIXADO', 'INFLAÇÃO', 'ALTERNATIVOS', 'GLOBAL (RENDA FIXA)', 'ALTERNATIVOS'].includes(nomeSegmento) && percentualRetorno) { adicionarGraficoRentabilidade(slide, percentualRetorno, isIPCA); } if (nomeSegmento === 'GLOBAL (RENDA VARIÁVEL)') { if (nomeAtivo === 'JPM Global Select Equity') { slide.addImage({ path: 'https://upload.wikimedia.org/wikipedia/commons/8/88/JPM-1.png', x: 5.54, y: 1.80, w: 3.93, h: 3.51 }); } else if (nomeAtivo === 'Schwab US Dividend Equity') { slide.addImage({ path: 'https://upload.wikimedia.org/wikipedia/commons/7/72/Schwab-1.png', x: 5.54, y: 1.80, w: 3.93, h: 3.51 }); } } if (nomeSegmento === 'BRASIL (RENDA VARIÁVEL)') { switch (tickerAtivo) { case 'HASH11': slide.addImage({ path: 'https://upload.wikimedia.org/wikipedia/commons/e/e3/Gr%C3%A1fico_de_hash.png', x: 5.54, y: 1.80, w: 3.93, h: 3.51 }); break; case 'FLRY3': slide.addImage({ path: 'https://upload.wikimedia.org/wikipedia/commons/7/74/Gr%C3%A1fico_de_FLRY.png', x: 5.54, y: 1.80, w: 3.93, h: 3.51 }); break; case 'ELET3': slide.addImage({ path: 'https://upload.wikimedia.org/wikipedia/commons/f/fd/ELET3.png', x: 5.54, y: 1.80, w: 3.93, h: 3.51 }); break; case 'HASH11': slide.addImage({ path: 'https://upload.wikimedia.org/wikipedia/commons/b/b3/HASH11.png', x: 5.54, y: 1.80, w: 3.93, h: 3.51 }); break; default: // Não adicionar imagem se não houver correspondência break; } } } }); }); // Slide 29 let slide29 = pptx.addSlide(); slide29.addImage({ path: 'https://upload.wikimedia.org/wikipedia/commons/8/8f/Temp33.png', x: 0, y: 0, w: '100%', h: '100%' }); slide29.hidden = true; // Slide 30 let slide30 = pptx.addSlide(); slide30.addImage({ path: 'https://upload.wikimedia.org/wikipedia/commons/8/8e/Temp34.png', x: 0, y: 0, w: '100%', h: '100%' }); slide30.addText(`Fez sentido a estratégia de alocação apresentada?`, { x: 6.81, y: 1.07, h: 0.61, w: 2.55, fontSize: 12, fontFace: 'Montserrat Light', align: 'left', color: 'F1F1F1' }); slide30.addText(`Ficou claro o conceito do atendimento exclusivo?`, { x: 6.81, y: 2.25, h: 0.61, w: 2.55, fontSize: 12, fontFace: 'Montserrat Light', align: 'left', color: 'F1F1F1' }); slide30.addText(`Acredita que ele agregará aos seus investimentos?`, { x: 6.81, y: 3.43, h: 0.61, w: 2.55, fontSize: 12, fontFace: 'Montserrat Light', align: 'left', color: 'F1F1F1' }); // Slide 31 let slide31 = pptx.addSlide(); slide31.addImage({ path: 'https://upload.wikimedia.org/wikipedia/commons/0/0c/Temp35.png', x: 0, y: 0, w: '100%', h: '100%' }); // Slide 32 let slide32 = pptx.addSlide(); slide32.addImage({ path: 'https://upload.wikimedia.org/wikipedia/commons/8/8b/Temp36.png', x: 0, y: 0, w: '100%', h: '100%' }); slide32.hidden = true; // Função para baixar o arquivo PPT pptx.writeFile(`Estudo_Investimento_${nomeCliente}.pptx`) .then(() => { console.log('PPT baixado com sucesso.'); }) .catch(err => { console.error('Erro ao baixar o PPT:', err); }); }); });