feat: offer credit card, debit card and PIX, with the bank's 3-D Secure step
All checks were successful
Build and deploy / Validate source (push) Successful in 5s
Build and deploy / Integration suite on a real stack (push) Successful in 2m3s
Build and deploy / Secret scan and release gate (push) Successful in 5s
Build and deploy / Publish images (push) Successful in 1m31s
All checks were successful
Build and deploy / Validate source (push) Successful in 5s
Build and deploy / Integration suite on a real stack (push) Successful in 2m3s
Build and deploy / Secret scan and release gate (push) Successful in 5s
Build and deploy / Publish images (push) Successful in 1m31s
The payment page lists credit card (preselected), debit card and PIX. Each card option limits Mercado Pago's form to its kind; debit is paid at once. Card payments ask for 3-D Secure when the issuer requires it, and a challenge opens the bank's page in a frame, which needs PAYMENT_CHALLENGE_SOURCES=https: (frames and form posts only). A card left waiting for that confirmation stops blocking a new attempt after ten minutes, and a refusal reported by the notification returns the customer to the payment choice. Written from the documentation; not yet run with a real debit card. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -225,10 +225,29 @@
|
||||
pedido=[]; itemAtual=null; limpaPaineis();
|
||||
await window.dtfClearCart?.();
|
||||
await refresh();
|
||||
} else if (quote.payment?.status==='rejected') {
|
||||
// Refused after the bank's confirmation or the provider's review.
|
||||
clearInterval(waitTimer);
|
||||
await refresh();
|
||||
message('Pagamento recusado. Tente de novo ou escolha outra forma de pagamento.');
|
||||
}
|
||||
} catch(_) {}
|
||||
},3000);
|
||||
}
|
||||
// 3-D Secure: the bank's own page, opened by posting its request in a frame.
|
||||
function showChallenge(challenge, into) {
|
||||
unmountCard();
|
||||
const frame=document.createElement('iframe');
|
||||
frame.name='confirmacaoBanco'; frame.title='Confirmação do banco'; frame.className='desafio';
|
||||
const form=document.createElement('form');
|
||||
form.method='POST'; form.action=challenge.url; form.target=frame.name;
|
||||
const input=document.createElement('input');
|
||||
input.type='hidden'; input.name='creq'; input.value=challenge.creq;
|
||||
form.append(input);
|
||||
into.replaceChildren(node('p','Confirme o pagamento na página do seu banco, abaixo.','pagNota'),frame,form);
|
||||
form.submit();
|
||||
form.remove();
|
||||
}
|
||||
function confirmado(quote) {
|
||||
clearInterval(waitTimer);
|
||||
const box=node('div',null,'confirmado');
|
||||
@@ -242,7 +261,7 @@
|
||||
// Paying: card (the default, paid on this page) or PIX (paid on its own page).
|
||||
async function escolhaPagamento(quote, version) {
|
||||
const session=await ready;
|
||||
const opcoes=[...(session.payment_public_key?[['card','Cartão de crédito']]:[]),['pix','PIX']];
|
||||
const opcoes=[...(session.payment_public_key?[['credito','Cartão de crédito'],['debito','Cartão de débito']]:[]),['pix','PIX']];
|
||||
let escolhido=opcoes[0][0];
|
||||
const grupo=node('div',null,'metodos');
|
||||
grupo.setAttribute('role','radiogroup'); grupo.setAttribute('aria-label','Forma de pagamento');
|
||||
@@ -256,7 +275,7 @@
|
||||
async function pinta() {
|
||||
radios.forEach(el=>el.setAttribute('aria-checked',String(el.dataset.metodo===escolhido)));
|
||||
unmountCard(); area.replaceChildren(); message('');
|
||||
if (escolhido==='card') { await showCard(quote.approved, area, version); return; }
|
||||
if (escolhido!=='pix') { await showCard(quote.approved, area, version, escolhido); return; }
|
||||
area.append(node('p','Ao pagar, mostramos o QR code e o código copia e cola. O pedido vai para a produção assim que o PIX é confirmado.','pagNota'));
|
||||
button('Pagar',async event=>{
|
||||
if (!cartOk()) { await refresh(); return; }
|
||||
@@ -325,7 +344,7 @@
|
||||
function unmountCard() {
|
||||
if (cardBrick) { try { cardBrick.unmount(); } catch(_) {} cardBrick=null; }
|
||||
}
|
||||
async function showCard(approved, into, version) {
|
||||
async function showCard(approved, into, version, tipo) {
|
||||
const holder=node('div');
|
||||
holder.id='cardPaymentBrick';
|
||||
into.append(holder);
|
||||
@@ -338,7 +357,10 @@
|
||||
const mp=new window.MercadoPago(session.payment_public_key,{locale:'pt-BR'});
|
||||
cardBrick=await mp.bricks().create('cardPayment','cardPaymentBrick',{
|
||||
initialization:{amount:approved.total_cents/100, payer:{email:approved.customer.mail}},
|
||||
customization:{paymentMethods:{maxInstallments:12},
|
||||
// Each option takes only its kind of card; debit is paid at once.
|
||||
customization:{paymentMethods:tipo==='debito'
|
||||
? {maxInstallments:1,types:{excluded:['credit_card']}}
|
||||
: {maxInstallments:12,types:{excluded:['debit_card']}},
|
||||
visual:{style:{customVariables:{baseColor:'#FFA81A',buttonTextColor:'#03060B'}}}},
|
||||
callbacks:{
|
||||
onReady:()=>{},
|
||||
@@ -350,6 +372,7 @@
|
||||
type:'card', token:data.token, payment_method_id:data.payment_method_id,
|
||||
installments:Number(data.installments)||1,
|
||||
issuer_id:data.issuer_id==null?null:String(data.issuer_id)}});
|
||||
if (result.challenge) { showChallenge(result.challenge, into); waitForOrder(); return; }
|
||||
if (result.status==='approved' || result.status==='pending') {
|
||||
unmountCard();
|
||||
into.replaceChildren(node('p',result.status==='approved'
|
||||
|
||||
Reference in New Issue
Block a user