354 lines
13 KiB
Markdown
354 lines
13 KiB
Markdown
# Como Verificar Status do Pagamento PIX
|
|
|
|
Este guia mostra como implementar a verificação de status do pagamento PIX no frontend, incluindo um botão manual e polling automático.
|
|
|
|
## Endpoint Disponível
|
|
|
|
```
|
|
GET /mercadopago/payment/by-reference/{external_reference}
|
|
```
|
|
|
|
### Resposta de Exemplo
|
|
|
|
```json
|
|
{
|
|
"has_payment": true,
|
|
"latest_payment": {
|
|
"id": 123456789,
|
|
"status": "approved",
|
|
"transaction_amount": 0.01,
|
|
"payment_method_id": "pix",
|
|
"external_reference": "pedido-123"
|
|
},
|
|
"is_approved": true,
|
|
"status": "approved",
|
|
"count": 1
|
|
}
|
|
```
|
|
|
|
## Implementação no Frontend
|
|
|
|
### Opção 1: Botão Manual para Verificar Status
|
|
|
|
```html
|
|
<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<title>Verificar Pagamento PIX</title>
|
|
</head>
|
|
<body>
|
|
<div id="payment-status">
|
|
<h2>Status do Pagamento</h2>
|
|
<p id="status-message">Aguardando verificação...</p>
|
|
<button id="check-status-btn" onclick="checkPaymentStatus()">
|
|
Verificar Status do Pagamento
|
|
</button>
|
|
</div>
|
|
|
|
<script>
|
|
// Obtenha o external_reference da URL ou de onde você salvou
|
|
const externalReference = new URLSearchParams(window.location.search).get('ref') || 'pedido-123';
|
|
const apiBaseUrl = 'https://bff.saveinmed.com.br'; // Ajuste para sua URL
|
|
|
|
async function checkPaymentStatus() {
|
|
const btn = document.getElementById('check-status-btn');
|
|
const message = document.getElementById('status-message');
|
|
|
|
btn.disabled = true;
|
|
btn.textContent = 'Verificando...';
|
|
message.textContent = 'Verificando status do pagamento...';
|
|
|
|
try {
|
|
const response = await fetch(
|
|
`${apiBaseUrl}/mercadopago/payment/by-reference/${externalReference}`
|
|
);
|
|
|
|
if (!response.ok) {
|
|
throw new Error('Erro ao verificar status');
|
|
}
|
|
|
|
const data = await response.json();
|
|
|
|
if (!data.has_payment) {
|
|
message.textContent = 'Pagamento ainda não foi criado. Aguarde...';
|
|
message.style.color = 'orange';
|
|
} else {
|
|
const status = data.latest_payment.status;
|
|
const isApproved = data.is_approved;
|
|
|
|
if (isApproved) {
|
|
message.textContent = '✅ Pagamento aprovado! Redirecionando...';
|
|
message.style.color = 'green';
|
|
// Redireciona para página de sucesso
|
|
setTimeout(() => {
|
|
window.location.href = 'https://app.saveinmed.com.br/pagamento/sucesso';
|
|
}, 2000);
|
|
} else if (status === 'pending') {
|
|
message.textContent = '⏳ Pagamento pendente. Aguarde a confirmação...';
|
|
message.style.color = 'orange';
|
|
} else if (status === 'rejected' || status === 'cancelled') {
|
|
message.textContent = '❌ Pagamento recusado ou cancelado.';
|
|
message.style.color = 'red';
|
|
} else {
|
|
message.textContent = `Status: ${status}`;
|
|
message.style.color = 'gray';
|
|
}
|
|
}
|
|
} catch (error) {
|
|
message.textContent = 'Erro ao verificar status: ' + error.message;
|
|
message.style.color = 'red';
|
|
} finally {
|
|
btn.disabled = false;
|
|
btn.textContent = 'Verificar Status do Pagamento';
|
|
}
|
|
}
|
|
|
|
// Verificar automaticamente ao carregar a página
|
|
window.addEventListener('load', () => {
|
|
checkPaymentStatus();
|
|
});
|
|
</script>
|
|
</body>
|
|
</html>
|
|
```
|
|
|
|
### Opção 2: Polling Automático (Recomendado)
|
|
|
|
```html
|
|
<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<title>Aguardando Pagamento PIX</title>
|
|
<style>
|
|
body {
|
|
font-family: Arial, sans-serif;
|
|
max-width: 600px;
|
|
margin: 50px auto;
|
|
padding: 20px;
|
|
text-align: center;
|
|
}
|
|
.status-card {
|
|
border: 2px solid #ddd;
|
|
border-radius: 10px;
|
|
padding: 30px;
|
|
margin: 20px 0;
|
|
}
|
|
.pending {
|
|
border-color: #ffa500;
|
|
background-color: #fff8e1;
|
|
}
|
|
.approved {
|
|
border-color: #4caf50;
|
|
background-color: #e8f5e9;
|
|
}
|
|
.rejected {
|
|
border-color: #f44336;
|
|
background-color: #ffebee;
|
|
}
|
|
button {
|
|
background-color: #2196F3;
|
|
color: white;
|
|
border: none;
|
|
padding: 12px 24px;
|
|
border-radius: 5px;
|
|
cursor: pointer;
|
|
font-size: 16px;
|
|
margin-top: 20px;
|
|
}
|
|
button:hover {
|
|
background-color: #1976D2;
|
|
}
|
|
button:disabled {
|
|
background-color: #ccc;
|
|
cursor: not-allowed;
|
|
}
|
|
.spinner {
|
|
border: 4px solid #f3f3f3;
|
|
border-top: 4px solid #2196F3;
|
|
border-radius: 50%;
|
|
width: 40px;
|
|
height: 40px;
|
|
animation: spin 1s linear infinite;
|
|
margin: 20px auto;
|
|
}
|
|
@keyframes spin {
|
|
0% { transform: rotate(0deg); }
|
|
100% { transform: rotate(360deg); }
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<h1>Verificando Pagamento</h1>
|
|
|
|
<div id="status-card" class="status-card pending">
|
|
<div id="spinner" class="spinner"></div>
|
|
<h2 id="status-title">Aguardando confirmação do pagamento...</h2>
|
|
<p id="status-message">Por favor, aguarde enquanto verificamos o status do seu pagamento.</p>
|
|
<p id="status-details"></p>
|
|
</div>
|
|
|
|
<button id="check-btn" onclick="checkPaymentStatus()">Verificar Agora</button>
|
|
|
|
<script>
|
|
const externalReference = new URLSearchParams(window.location.search).get('ref') || 'pedido-123';
|
|
const apiBaseUrl = 'https://bff.saveinmed.com.br'; // Ajuste para sua URL
|
|
let pollingInterval = null;
|
|
let checkCount = 0;
|
|
const maxChecks = 60; // Máximo de 60 verificações (5 minutos se verificar a cada 5 segundos)
|
|
|
|
async function checkPaymentStatus() {
|
|
const card = document.getElementById('status-card');
|
|
const title = document.getElementById('status-title');
|
|
const message = document.getElementById('status-message');
|
|
const details = document.getElementById('status-details');
|
|
const spinner = document.getElementById('spinner');
|
|
const btn = document.getElementById('check-btn');
|
|
|
|
try {
|
|
const response = await fetch(
|
|
`${apiBaseUrl}/mercadopago/payment/by-reference/${externalReference}`
|
|
);
|
|
|
|
if (!response.ok) {
|
|
throw new Error('Erro ao verificar status');
|
|
}
|
|
|
|
const data = await response.json();
|
|
checkCount++;
|
|
|
|
if (!data.has_payment) {
|
|
title.textContent = 'Aguardando criação do pagamento...';
|
|
message.textContent = 'O pagamento ainda não foi registrado. Aguarde alguns instantes.';
|
|
details.textContent = `Verificações realizadas: ${checkCount}/${maxChecks}`;
|
|
card.className = 'status-card pending';
|
|
} else {
|
|
const status = data.latest_payment.status;
|
|
const isApproved = data.is_approved;
|
|
const paymentId = data.latest_payment.id;
|
|
const amount = data.latest_payment.transaction_amount;
|
|
|
|
if (isApproved) {
|
|
spinner.style.display = 'none';
|
|
title.textContent = '✅ Pagamento Aprovado!';
|
|
message.textContent = 'Seu pagamento foi confirmado com sucesso!';
|
|
details.textContent = `ID do pagamento: ${paymentId} | Valor: R$ ${amount.toFixed(2)}`;
|
|
card.className = 'status-card approved';
|
|
btn.style.display = 'none';
|
|
|
|
// Para o polling
|
|
if (pollingInterval) {
|
|
clearInterval(pollingInterval);
|
|
}
|
|
|
|
// Redireciona após 3 segundos
|
|
setTimeout(() => {
|
|
window.location.href = 'https://app.saveinmed.com.br/pagamento/sucesso';
|
|
}, 3000);
|
|
} else if (status === 'pending') {
|
|
title.textContent = '⏳ Pagamento Pendente';
|
|
message.textContent = 'Aguardando confirmação do banco. Isso pode levar alguns segundos.';
|
|
details.textContent = `ID: ${paymentId} | Verificações: ${checkCount}/${maxChecks}`;
|
|
card.className = 'status-card pending';
|
|
} else if (status === 'rejected' || status === 'cancelled') {
|
|
spinner.style.display = 'none';
|
|
title.textContent = '❌ Pagamento Não Aprovado';
|
|
message.textContent = `Status: ${status}. Por favor, tente novamente.`;
|
|
details.textContent = `ID: ${paymentId}`;
|
|
card.className = 'status-card rejected';
|
|
btn.style.display = 'none';
|
|
|
|
// Para o polling
|
|
if (pollingInterval) {
|
|
clearInterval(pollingInterval);
|
|
}
|
|
} else {
|
|
title.textContent = `Status: ${status}`;
|
|
message.textContent = 'Aguardando atualização do status...';
|
|
details.textContent = `ID: ${paymentId}`;
|
|
}
|
|
}
|
|
|
|
// Para o polling se atingiu o máximo de verificações
|
|
if (checkCount >= maxChecks) {
|
|
if (pollingInterval) {
|
|
clearInterval(pollingInterval);
|
|
}
|
|
btn.style.display = 'block';
|
|
message.textContent += ' Polling automático parado. Use o botão para verificar manualmente.';
|
|
}
|
|
|
|
} catch (error) {
|
|
spinner.style.display = 'none';
|
|
title.textContent = 'Erro ao Verificar';
|
|
message.textContent = 'Ocorreu um erro ao verificar o status: ' + error.message;
|
|
details.textContent = '';
|
|
card.className = 'status-card rejected';
|
|
}
|
|
}
|
|
|
|
// Inicia polling automático a cada 5 segundos
|
|
function startPolling() {
|
|
checkPaymentStatus(); // Verifica imediatamente
|
|
pollingInterval = setInterval(checkPaymentStatus, 5000); // Depois a cada 5 segundos
|
|
}
|
|
|
|
// Para o polling
|
|
function stopPolling() {
|
|
if (pollingInterval) {
|
|
clearInterval(pollingInterval);
|
|
pollingInterval = null;
|
|
}
|
|
}
|
|
|
|
// Inicia quando a página carrega
|
|
window.addEventListener('load', startPolling);
|
|
|
|
// Para quando a página é fechada
|
|
window.addEventListener('beforeunload', stopPolling);
|
|
</script>
|
|
</body>
|
|
</html>
|
|
```
|
|
|
|
## Como Usar
|
|
|
|
1. **Após criar a preferência**, salve o `external_reference`
|
|
2. **Redirecione o usuário** para o `init_point` do Mercado Pago
|
|
3. **Crie uma página de "Aguardando Pagamento"** com o código acima
|
|
4. **Passe o `external_reference`** como parâmetro na URL: `?ref=pedido-123`
|
|
5. **A página fará polling automático** e redirecionará quando o pagamento for aprovado
|
|
|
|
## Exemplo de Fluxo
|
|
|
|
```javascript
|
|
// 1. Criar preferência
|
|
const response = await fetch('/mercadopago/preference', {
|
|
method: 'POST',
|
|
body: JSON.stringify({
|
|
items: [...],
|
|
external_reference: 'pedido-123',
|
|
back_urls: {
|
|
success: 'https://app.saveinmed.com.br/pagamento/sucesso',
|
|
pending: 'https://app.saveinmed.com.br/pagamento/aguardando?ref=pedido-123',
|
|
failure: 'https://app.saveinmed.com.br/pagamento/erro'
|
|
}
|
|
})
|
|
});
|
|
|
|
const preference = await response.json();
|
|
|
|
// 2. Redirecionar para o Mercado Pago
|
|
window.location.href = preference.init_point; // ou sandbox_init_point
|
|
|
|
// 3. Quando o usuário voltar (via back_urls.pending), a página de aguardando
|
|
// fará polling automático até detectar que o pagamento foi aprovado
|
|
```
|
|
|
|
## Notas Importantes
|
|
|
|
- O polling verifica a cada 5 segundos
|
|
- Para automaticamente após 60 verificações (5 minutos)
|
|
- Redireciona automaticamente quando o pagamento é aprovado
|
|
- O usuário pode clicar no botão para verificar manualmente a qualquer momento
|
|
|
|
|