const { chromium } = require('playwright'); const fs = require('fs'); (async () => { const browser = await chromium.launch({ headless: false }); const context = await browser.newContext({ userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36' }); const page = await context.newPage(); try { console.log('🚀 Iniciando Automação de Guia Odontológica...'); // LOGIN await page.goto('https://viventerisportalcredenciado.topsaudehub.com.br/', { waitUntil: 'networkidle' }); await page.fill('#usuario', '0005010'); await page.fill('#senha', 'Cclinic#03'); await page.click('#login-submit'); await page.waitForURL('**/AreaLogada**'); // 1. Tratamento Odontológico console.log('1. Acessando Tratamento Odontológico...'); await page.click('text="Tratamento Odontológico"'); await page.waitForTimeout(2000); // 2. Lupa de pesquisa console.log('2. Clicando na pesquisa (lupa)...'); // Tentativa de achar o botão de busca que abre o modal de beneficiário const searchBtn = page.locator('.fa-search, .glyphicon-search, button[title*="Pesquisar"]').first(); await searchBtn.click(); await page.waitForTimeout(1000); // 3. CPF do Beneficiário console.log('3. Inserindo CPF: 005.983.051-49...'); // Esperar o campo ficar visível no modal const cpfInput = page.locator('input[id*="cpf"], input[name*="cpf"], .cpf-mask').first(); await cpfInput.fill('005.983.051-49'); // 4. Pesquisar console.log('4. Clicando em Pesquisar...'); await page.click('button:has-text("Pesquisar"), #btnPesquisarBeneficiario'); await page.waitForTimeout(2000); // 5. Clica na coluna número beneficiário console.log('5. Selecionando beneficiário resultado...'); // Espera especificamente por um link que pareça um número de cartão ou nome const linkBeneficiario = page.locator('table tbody tr td a').first(); await linkBeneficiario.waitFor({ state: 'visible', timeout: 5000 }); await linkBeneficiario.click(); await page.waitForTimeout(2000); // Espera carregar os dados dele // 6. Botão + console.log('6. Clicando em Adicionar (+)...'); // O botão + muitas vezes só aparece após selecionar o beneficiário const btnMais = page.locator('.fa-plus, .btn-success, #btnNovoRegistro, a:has-text("Novo"), button:has-text("+")').first(); await btnMais.waitFor({ state: 'visible', timeout: 5000 }); await btnMais.click(); await page.waitForTimeout(2000); // 7. Dropdown tipo atendimento console.log('7. Selecionando Tipo de Atendimento...'); await page.waitForTimeout(2000); // Verifica se existe um select de endereço primeiro const enderecoSelect = page.locator('select[id*="endereco"], select[name*="endereco"]').first(); if (await enderecoSelect.count() > 0) { console.log('Selecionando endereço de atendimento...'); await enderecoSelect.selectOption({ index: 1 }); await page.waitForTimeout(1000); } // Tenta encontrar o select de tipo de atendimento especificamente const selectTipo = page.locator('select[id*="tipo_solicitacao"], select[id*="tipoAtendimento"], select:has-text("Tratamento")').first(); await selectTipo.waitFor({ state: 'visible', timeout: 5000 }).catch(() => console.log('Aviso: Select de tipo não visível ainda.')); const options = await selectTipo.evaluate(sel => Array.from(sel.options).map(o => o.text)).catch(() => []); console.log('Opções no select de tipo:', options); try { await selectTipo.selectOption({ label: /Tratamento Odontológico/i }); } catch (e) { console.log('Tentando selecionar pelo índice 1...'); await selectTipo.selectOption({ index: 1 }); } // 8 e 9. Lupa Profissional Executante console.log('8. Selecionando Profissional Executante...'); await page.waitForTimeout(2000); // Agora temos o ID exato do botão! const btnBuscaProf = page.locator('#btnBuscaPrestadorExecutante').first(); await btnBuscaProf.waitFor({ state: 'visible', timeout: 5000 }); await btnBuscaProf.click(); await page.waitForTimeout(2000); // Clica no profissional na tabela console.log('Selecionando o primeiro profissional da lista...'); const linkProf = page.locator('table tbody tr td a').first(); if (await linkProf.count() > 0) { await linkProf.click(); } else { console.log('⚠️ Nenhum profissional encontrado na tabela. Aguardando instrução.'); return; // PARA e aguarda } await page.waitForTimeout(1000); // 10. Profissional Solicitante console.log('10. Preenchendo Solicitante: Murilo...'); const solicitanteInput = page.locator('input[id*="solicitante"], input[name*="Solicitante"]').first(); if (await solicitanteInput.count() === 0) { console.log('⚠️ Campo "Profissional Solicitante" não encontrado. Aguardando instrução.'); return; } await solicitanteInput.waitFor({ state: 'visible', timeout: 5000 }); await solicitanteInput.clear(); await solicitanteInput.fill('Murilo'); // 11. Justificativa (APENAS se for urgência - Valor 4) const tipoAtendimentoValue = await page.locator('#tipoAtendimento').inputValue(); if (tipoAtendimentoValue === '4') { console.log('Detectado Urgência / Emergência. Preenchendo Justificativa...'); await page.fill('#observacaoJustificativa', 'Paciente com dor aguda, necessidade de atendimento de urgência.'); } else { console.log('Tipo de atendimento normal. Pulando justificativa.'); } // 12. Próximo console.log('12. Clicando em Próximo...'); await page.click('button:has-text("Próximo"), #btnProximo'); await page.waitForTimeout(2000); // 13. Incluir console.log('13. Clicando em Incluir...'); await page.click('#adicionarProcedimeto'); await page.waitForTimeout(2000); // EXTRAÇÃO DE CÓDIGOS (Como solicitado pelo usuário na primeira vez) console.log('🔍 Extraindo lista de procedimentos disponíveis...'); const procedimentos = await page.evaluate(() => { const items = Array.from(document.querySelectorAll('input[id*="procedimento"], select[id*="procedimento"], .lista-procedimentos td')); // Tenta pegar de um select se houver const sel = document.querySelector('select[id*="procedimento"]'); if (sel) return Array.from(sel.options).map(o => `${o.value} - ${o.text}`); return items.map(i => i.innerText || i.value).filter(t => t && t.length > 5); }); if (procedimentos.length > 0) { fs.writeFileSync('procedimentos_encontrados.txt', procedimentos.join('\n')); console.log('✅ Lista de procedimentos salva em procedimentos_encontrados.txt'); } // 15, 16 e 17. Dados do Tratamento console.log('15. Lançando procedimento 85100196...'); const procInput = page.locator('#codProcedimento').first(); await procInput.waitFor({ state: 'visible', timeout: 10000 }); await procInput.fill('85100196'); // Espera e clica no item do autocomplete console.log('Selecionando item no autocomplete...'); const autocompleteItem = page.locator('.ui-menu-item-wrapper:has-text("85100196")').first(); await autocompleteItem.waitFor({ state: 'visible', timeout: 5000 }); await autocompleteItem.click(); await page.waitForTimeout(2000); console.log('16. Selecionando Dente 18...'); const selectDente = page.locator('#cmbDente').first(); await selectDente.waitFor({ state: 'visible', timeout: 5000 }); await selectDente.selectOption('18'); await page.waitForTimeout(1000); // Selecionar a checkbox da Face "V" console.log('17. Selecionando Face V...'); const checkV = page.locator('#codFaceV').first(); await checkV.waitFor({ state: 'visible', timeout: 5000 }); // Tenta clicar forçado no input ou clica na label (que é o que o usuário vê) try { await checkV.check({ force: true }); } catch (e) { await page.click('label[for="codFaceV"]'); } // 18. Incluir procedimento (Botão Incluir dentro do modal) console.log('18. Incluindo procedimento na lista...'); await page.click('#btnIncluirProcedimento'); await page.waitForTimeout(2000); // Se houver um botão de fechar/salvar o popup geral (como o btnSalvarPopUP que vimos antes) const btnFechar = page.locator('#btnSalvarPopUP').first(); if (await btnFechar.isVisible()) { console.log('Fechando popup de procedimentos...'); await btnFechar.click(); await page.waitForTimeout(1000); } // 19. Finalizar console.log('19. Finalizando guia...'); await page.click('button:has-text("Próximo")'); await page.waitForTimeout(1000); await page.click('button:has-text("Próximo"), #btnFinalizar'); // 20. Captura de GTO console.log('20. Capturando resultado da GTO...'); await page.waitForTimeout(3000); const resultadoHTML = await page.content(); const gtoMatch = resultadoHTML.match(/\d{8,12}/); // Tenta achar um número longo que seria a GTO const status = resultadoHTML.includes('Autorizado') ? 'AUTORIZADO' : 'VERIFICAR STATUS'; console.log(`--- RESULTADO --- GTO: ${gtoMatch ? gtoMatch[0] : 'Não localizada'} | STATUS: ${status}`); } catch (error) { console.error('❌ Erro na automação:', error.message); await page.screenshot({ path: 'erro-guia-odonto.png' }); } finally { console.log('Processo interrompido para análise. O navegador ficará aberto por 60s.'); await page.waitForTimeout(60000); await browser.close(); } })();