Homologação
Antes de ir a campo, execute cada cenário num terminal de homologação com o app host ativado. Os cenários de falhas e recuperação são os que evitam cobrança em dobro e fraude.
Checklist
Preparação
-
verifyHostretornaTrustedcom o host oficial instalado. - Com o host desinstalado, o app detecta
NotInstallede não libera o pagamento. - A primeira operação sem credenciamento recebe
unauthorized_callere o app dispararequestAuthorization. - A recusa do credenciamento (
authorization_denied) não é repetida automaticamente. - Builds debug e release foram credenciados separadamente.
- Com o terminal não ativado, o app oferece a ativação e dispara
activateTerminal; concluída,terminalStatuspassa a responderinitialized = true. - Cancelar o formulário de ativação no terminal devolve
cancelled, e o app continua oferecendo a ativação. - Num terminal já ativado,
activateTerminalrespondeapprovedsem abrir formulário. - As telas de pagamento mostram o logo (ou nome) e a cor do parceiro cadastrados no portal.
Operações
- Venda no crédito à vista, parcelada sem juros e parcelada com juros.
- Venda no débito.
- Venda com voucher, exibindo o saldo quando
voucherBalanceInCentsvier preenchido. - Venda por Pix aprovada e Pix não pago dentro do prazo.
- Venda recusada pelo emissor mostra
error.message. - Cancelamento pelo botão Cancelar do terminal durante a espera do cartão volta ao carrinho.
- Estorno total e parcial com
transactionId, e estorno escolhendo a transação na tela. - Estorno de voucher informando
paymentMethod = VOUCHER. - Impressão livre com texto, colunas, QR Code e imagem por
content://. - Reimpressão das vias do lojista e do cliente.
-
terminal_statuselist_transactionscom paginação pornextCursor.
Falhas e recuperação
- O
clientTransactionIdé persistido antes dolaunch. - O seu app é encerrado à força durante a autorização; ao reabrir, recupera o desfecho e não cobra de novo.
- Uma resposta
no_responseleva à recuperação, nunca a uma nova cobrança direta. - Durante uma venda, uma segunda operação recebe
busye o app aguarda. - Um duplo toque no botão de pagar gera uma única cobrança (a segunda Intent recebe
busy). - Depois de um
operation_timeout, o app recupera o desfecho e, se ainda vieroperation_timeoutpassados 2 minutos, confirma porlist_transactionsou pelo portal antes de cobrar de novo. - Terminal sem rede: a venda volta com erro e a mensagem é exibida ao operador.
- As decisões são tomadas por
statuseerror.code, nunca porresultCodeou pelo texto demessage.
Problemas comuns
| Sintoma | Causa provável | Solução |
|---|---|---|
ActivityNotFoundException ao disparar | Host não instalado, ou app sem visibilidade do pacote no Android 11+ | Instalar o host; usar o contrato, que já declara <queries> |
Toda operação volta unauthorized_caller | App não credenciado | Credenciar com requestAuthorization |
| O app não recebe resposta nenhuma | Intent disparada com startActivity | Disparar com ActivityResultLauncher ou startActivityForResult |
malformed_request numa Intent montada sem o PosIntegrationClient | Action diferente da família da operação, ou clientTransactionId vazio | Usar a action da tabela de operações e gerar um id por requisição |
| Funcionava em debug e parou em release | Assinaturas diferentes, cada uma com seu credenciamento | Credenciar o build de release |
terminal_not_initialized | Terminal não ativado, ou sem rede para carregar as tabelas | Abrir a ativação com activateTerminal(); se o terminal já estiver cadastrado, verificar a rede dele |
| Formulário de ativação ou telas com título, logo ou cor de outro parceiro | App host gerado para outro parceiro, ou cadastro do parceiro no portal preenchido com dados de outra marca | Confirmar com a Tupi o app host do parceiro, ou corrigir o cadastro no portal; o terminal aplica quando o app host é iniciado ou a tela local do terminal é aberta |
| Telas sem logo, só com o nome do parceiro | Logo cadastrado só em SVG, fora de https:// ou acima de 512 KB | Cadastrar um logo de impressão (bitmap) ou ajustar o logo no portal |
terminal_busy logo após um timeout | O terminal ainda aguarda a autorização anterior, por até 2 minutos | Recuperar o desfecho da anterior e aguardar |
| Voltar não fecha a tela de pagamento | Comportamento esperado durante a operação | Cancelar pelo botão Cancelar do terminal |
RESULT_CANCELED sem resposta | O host encerrou sem responder | Tratar como no_response e recuperar |
malformed_request com metadata | Mais de 20 chaves, chave fora de [A-Za-z0-9_.-], valor acima de 256 caracteres, total acima de 4 KB, ou valor com cara de número de cartão (13 a 19 dígitos) | Reduzir o conteúdo de metadata e retirar qualquer dado de portador |
Impressão responde internal_error | Documento sem blocos, aligns com tamanho diferente de texts, ou imagem ilegível | Corrigir o documento conforme error.message |
| Imagem não sai na impressão | content:// fora de um FileProvider, ou permissão de leitura ausente | Usar PosIntegrationClient.print, que concede a permissão |
Reimpressão responde transaction_not_found | Transação de outro terminal, feita por outro app ou pelo app do terminal, ou com mais de 24 h | Obter a via no portal |
verifyHost retorna SignatureMismatch após atualizar o host | Host assinado com chave nova sem vínculo com a anterior | Confirmar com a Tupi e atualizar o HOST_SHA256 |
Suporte
Para chamados, envie o clientTransactionId, o status, o error.code, o error.vendorCode e o horário da operação.