Ir para o conteúdo

Consulta de Pagamentos via API


Esta é uma consulta via Content Provider que possibilita que outros aplicativos possam consultar informações sobre os pagamentos efetuados, sendo possível realizar filtros e obter diversos dados dos pagamentos, inclusive sua situação.

Integração com Aplicação de Pagamentos via Content Provider

Só será permitido listar pagamentos feitos pela própria aplicação que está realizando a consulta.

Declare essa permissão no AndroidManifest.xml do seu Aplicativo para ter acesso ao Content Provider.

<uses-permission android:name="br.com.phoebus.android.payments.provider.READ_PERMISSION"/>

content://br.com.phoebus.android.payments.provider/payments/transactions

URI (Uniform Resource Identifier) para obtenção de informações de pagamentos.

Para realizar o request da consulta de pagamento por período entre datas, é necessário adicionar essa dependência.

implementation 'com.jakewharton.threetenabp:threetenabp:1.0.3'

Métodos

Assinatura Descrição
List<Payment> findAll(PaymentProviderRequest request) Método utilizado para obter uma lista de Payment por meio de um PaymentProviderRequest.
List<Payment> findNonSynced(PaymentProviderRequest request) Método utilizado para obter uma lista de Payment por meio de um PaymentProviderRequest a partir das transações não sincronizadas com a Paystore.
List<PaymentV2> findAllV2(PaymentProviderRequest request) Método utilizado para obter uma lista de PaymentV2 por meio de um PaymentProviderRequest.
List<PaymentV2> findNonSyncedV2(PaymentProviderRequest request) Método utilizado para obter uma lista de PaymentV2 por meio de um PaymentProviderRequest a partir das transações não sincronizadas com a Paystore.

Info

Transações não sincronizadas com a Paystore são as transações que ainda não tiveram o envio completo dos seus dados pelo additionalInfo que é responsável por enviar dados como comprovantes, estatísticas, versão do app entre outros.

Parâmetro de entrada

Nome Tipo Obrigatório Descrição
request PaymentProviderRequest Sim Parâmetro que armazenará o filtro da pesquisa e os dados que deverão ser retornados.

Filtros

Nome Tipo Obrigatório Descrição
status PaymentStatus Não Filtra os pagamentos cuja situação está na lista passada (aceita mais de um valor).
startDate Date Não Filtra os pagamentos cuja data seja maior ou igual ao valor passado.
finishDate Date Não Filtra os pagamentos cuja data seja menor ou igual ao valor passado.
lastUpdateQuery Boolean Não Indica se a consulta será feita com base na data e hora da transação (caso esse campo não seja preenchido ou receba 'false') ou na data e hora da última atualização dela (caso esse campo receba 'true').
startValue BigDecimal Não Filtra os pagamentos cujo valor seja maior ou igual ao valor passado.
finishValue BigDecimal Não Filtra os pagamentos cujo valor seja menor ou igual ao valor passado.
paymentId String Não Filtra os pagamentos cujo identificador da transação para a aplicação de pagamentos seja o valor passado.
lastDigits String Não Filtra os pagamentos cujos últimos 4 dígitos do PAN do cartão usado na transação seja igual ao valor passado.
productShortName String Não Identificador de produto, retorna apenas transações de um produto.
ticketNumber String Não ticketNumber gerado pelo terminal para a transação.
batchPend Boolean Não Filtra as transações que ainda estão estão no lote pendente (transações novas).
lastBatch Boolean Não Filtra as transações do último lote fechado.
batchNumber String Não Filtra as transações de um lote.
acquirerResponseCode String Não Filtra transações com base no código de resposta do host.
note String Não Texto adicional que é inserido como Nota. (pode ser o número da fatura)
dni String Não Número do Documento.
qrId String Não Identificador QrCode gerado pelo terminal de captura.
operationMethod Integer Não Filtra transações segundo a forma de operação. Admita os seguintes valores: 0 - Apenas com cartão físico (ler ou datilografado); 1 - Somente com QRCode.
appTransactionId String Não Identificador da transação integrada para o software. O Identificador referido é aquele utilizado na aplicação que originou a solicitação de pagamento.

Retorno

A consulta de pagamentos retorna os pagamentos que obedecerem aos filtros informados, e os estornos associados a eles (inclusive estornos negados).

Os filtros informados são aplicados apenas aos campos dos pagamentos.

A lista de pagamentos retornados deve estar ordenada de forma ascendente pelo campo date do pagamento.

Em cada pagamento, a lista de estornos retornados deve estar ordenada de forma ascendente pelo campo date do estorno. Não retorna devoluções não referenciadas.

Nome Tipo Descrição
id String Identificador da transação para a aplicação de pagamentos. Esta é a informação a ser usada para a confirmação e desfazimento.
value BigDecimal Valor do pagamento. Este é o valor que foi aprovado pela adquirente. Deve ser validado sempre na resposta, ainda que tenha sido passado como parâmetro, pois há adquirentes que, para algumas situações, aprovam valores diferentes dos solicitados.
paymentType PaymentType Tipo de pagamento (Débito, Crédito, Voucher, etc.).
installments Integer Quantidade de parcelas do pagamento.
acquirerName String Adquirente que autorizou o pagamento.
cardBrand String Bandeira do cartão.
cardBin String BIN do cartão.
cardPanLast4Digits String Últimos 4 dígitos do PAN do cartão.
captureType CaptureType Forma de captura do cartão.
status PaymentStatus Situação do pagamento.
date Date Data/hora do pagamento para a aplicação de pagamentos.
acquirerId String Identificador da transação para a adquirente. Este é o identificador que consta no arquivo que a adquirente fornece (EDI). Desta forma, é possível realizar a conciliação do pagamento com a transação integrada.
acquirerResponseCode String Código de resposta da adquirente.
acquirerResponseDate String Data/hora retornada pela adquirente.
acquirerAuthorizationNumber String Número da autorização fornecido pela adquirente (consta no comprovante do cliente Portador do Cartão).
clientVia String Conteúdo do comprovante - via do cliente.
merchantVia String Conteúdo do comprovante - via do estabelecimento.
additionalValueType AdditionalValueType Presente apenas quando existe um valor adicional no contexto da transação executada.
additionalValue BigDecimal Presente apenas quando existe um valor adicional no contexto da transação executada.
accountTypeId String Presente apenas quando existe um tipo de conta no contexto da transação executada.
planId String Presente apenas quando existe um plano no contexto da transação executada.
productShortName String Identificador de produto, retorna apenas transações de um produto.
batchNumber String Número de lote.
nsuTerminal String NSU gerado pelo terminal para a transação.
cardHolderName String Nome do cliente no cartão.
lastTrx Boolean Indica 'true' se é a última transação aprovada, e 'falso' caso contrário.
terminalId String Identificação do terminal.
originalValue BigDecimal Valor orginal da venda. Presente em pagamentos com QRCode, cujo beneficio foi aplicado ao valor da venda.
appTransactionId String Identificador de transação para o aplicativo de pagamento. Esta é a informação que será usada para confirmar e desfazer o pagamento.
acquirerNsu String NSU Adquirente para consulta e identificação de transações.
ticketNumber String ticketNumber gerado pelo terminal para a transação.
acquirerAdditionalMessage String Mensagem adicional enviada pela adquirente na resposta da transação.
note String Texto adicional que é inserido como Nota. (pode ser o número da fatura)
dni String Número do Documento.
qrId String Identificador QrCode gerado pelo terminal de captura.
aid String AID para identificar a aplicação para processar a transação. É retornado em transações EMV.
cardAppName String APN, ou nome da aplicação do cartão. É retornado em transações EMV.
ErrorData.paymentsResponseCode String Código de resposta para o erro que ocorreu. Vide Códigos de Resposta
ErrorData.responseMessage String Mensagem descritiva da causa da não autorização. Se a transação foi negada pela adquirente, conterá a mensagem retornada pela adquirente.
Exemplo de retorno quando dois pagamentos obedecem aos críterios informados

As estruturas "payment" e "reversals" são as mesmas usadas na consulta de última transação aprovada e confirmada ;

[
 {
    "payment": {
        ...
    },
    "reversals": [
      {
         ...
      },
      {
         ...
      },
      {
         ...
      }
    ]
 },
 {
    "payment": {
        ...
    },
    "reversals": [
      {
         ...
      },
      {
         ...
      },
      {
         ...
      }
    ]
 }
]

Info

É possível customizar quais informações estarão presentes na resposta. Para isso, deve ser passado um array de Strings com as colunas desejadas para o método query() do Content Resolver. Caso use a API de acesso ao provider, pode utilizar o método setColumns() do PaymentProviderRequest.

Info

Para facilitar o uso, são disponibilizadas classes de acesso ao provider:

  • PaymentProviderRequest
  • PaymentProviderApi
  • PaymentContract

Exemplo

package br.com.phoebus.payments.demo;

import androidx.appcompat.app.AppCompatActivity;
import android.content.pm.PackageManager;
import android.graphics.Color;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ListView;
import android.widget.Spinner;
import android.widget.TextView;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import br.com.phoebus.android.payments.api.Payment;
import br.com.phoebus.android.payments.api.PaymentStatus;
import br.com.phoebus.android.payments.api.PaymentV2;
import br.com.phoebus.android.payments.api.exception.ClientException;
import br.com.phoebus.android.payments.api.provider.PaymentProviderApi;
import br.com.phoebus.android.payments.api.provider.PaymentProviderRequest;
import br.com.phoebus.payments.demo.utils.CredentialsUtils;

public class ConsultaDePagamentosActivity extends AppCompatActivity {

    private PaymentProviderApi api;                                 // Objeto para realizar as buscas.
    private PaymentProviderRequest mPaymentRequest;                 // Objeto de requisição das buscas.
    private Button ultimoBotaoPressionado;                          // Objeto que armazena e modifica a cor do último botão selecionado.
    private List<PaymentStatus> mStatus     = new ArrayList<>();    // Objeto que armazena o status que deve ser pesquisado.
    private List<PaymentV2> listPaymentsV2  = null;                 // Objeto que recebe a lista das transações pesquisadas com os métodos findAllV2 e findNonSyncedV2.
    private List<Payment> listPayments      = null;                 // Objeto que recebe a lista das transações pesquisadas com os métodos findAll e findNonSynced.
    private List<String> simpleListPayments = new ArrayList<>();    // Objeto que recebe a lista simplificada das transações pesquisadas para exibir.
    private final int FIND_ALL_V2           = 0;                    // Constante que sinaliza que o método a ser executado é o findAllV2.
    private final int FIND_NON_SYNCED_V2    = 1;                    // Constante que sinaliza que o método a ser executado é o findNonSyncedV2.
    private final int FIND_ALL              = 2;                    // Constante que sinaliza que o método a ser executado é o findAll.
    private final int FIND_NON_SYNCED       = 3;                    // Constante que sinaliza que o método a ser executado é o findNonSynced.
    private final int PAYMENT               = 4;                    // Constante que sinaliza o tipo Payment.
    private final int PAYMENT_V2            = 5;                    // Constante que sinaliza o tipo PaymentV2.

    // Array que contém os status para serem escolhidos
    private String[] arrayStatus            = {"TODOS", "PENDING", "CONFIRMED", "CANCELLED", "REVERSED", "PROCESSING", "DENIED", "UNREACHABLE", "WAITING_VALIDATION", "WAITING_CAPTURE", "REFUNDED_DEVOLUTION"};

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_consulta_de_pagamentos);
        api = PaymentProviderApi.create(this);                      // instanciando objeto para realizar as buscas.

        try {
            mPaymentRequest = createRequest();                      // instanciando objeto de requisição das buscas.
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        }

        ListView listViewPayments = findViewById(R.id.list_view_lista_pagamentos);
        ArrayAdapter<String> adapterListView = new ArrayAdapter<>(this,
                android.R.layout.simple_list_item_1, android.R.id.text1, simpleListPayments);

        listViewPayments.setAdapter(adapterListView);

        TextView textViewListPayment = findViewById(R.id.text_view_list_payments);

        Spinner spinner = findViewById(R.id.spinner_status);

        ArrayAdapter<String> adapter = new ArrayAdapter<>(this, android.R.layout.simple_spinner_item, arrayStatus);
        adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
        spinner.setAdapter(adapter);

        spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
            @Override
            public void onItemSelected(AdapterView<?> parentView, View selectedItemView, int position, long id) {
                String itemSelecionado = (String) parentView.getItemAtPosition(position);

                mStatus.clear();                                          // Limpando objeto que armazena o status que deve ser pesquisado.

                if(!itemSelecionado.equals(arrayStatus[0])) {             // Verfificando o item selecionado.
                    mStatus.add(PaymentStatus.valueOf(itemSelecionado));  // Adicionando o item selecionado ao objeto que armazena o status que deve ser pesquisado.
                    mPaymentRequest.setStatus(mStatus);                   // Setando no objeto de requisição das buscas o status que deve ser pesquisado.
                }
                else
                    mPaymentRequest.setStatus(null);                      // Caso o item selecionado seja "Todos" o status do objeto de requisição recebe null
                                                                          // sinalizando que não existe filtro de status para a pesquisa.

            }

            @Override
            public void onNothingSelected(AdapterView<?> parentView) {}
        });

        Button btn_find_all_v2 = findViewById(R.id.btn_find_all_v2);
        btn_find_all_v2.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                alterarCorBotaoPressionado(btn_find_all_v2);                                                // Chama o método para alteração de cor do botão selecinado.
                listPaymentsV2 = consultaPagamentosV2(FIND_ALL_V2);                                         // Chama método gerenciador de busca para executar o findAllV2.
                textViewListPayment.setText(updateLableListPayments(PAYMENT_V2, listPaymentsV2.size()));    // Atualiza o titulo da lista pesquisada.
                updateSimpleListPayment(PAYMENT_V2);                                                        // Atualiza a lista simples para exibição.
                adapterListView.notifyDataSetChanged();                                                     // Atualiza a adapter para exibição.
            }
        });

        Button btn_find_non_synced_v2 = findViewById(R.id.btn_find_non_synced_v2);
        btn_find_non_synced_v2.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                alterarCorBotaoPressionado(btn_find_non_synced_v2);                                         // Chama o método para alteração de cor do botão selecinado.
                listPaymentsV2 = consultaPagamentosV2(FIND_NON_SYNCED_V2);                                  // Chama método gerenciador de busca para executar o findNonSyncedV2.
                textViewListPayment.setText(updateLableListPayments(PAYMENT_V2, listPaymentsV2.size()));    // Atualiza o titulo da lista pesquisada.
                updateSimpleListPayment(PAYMENT_V2);                                                        // Atualiza a lista simples para exibição.
                adapterListView.notifyDataSetChanged();                                                     // Atualiza a adapter para exibição.
            }
        });

        Button btn_find_all = findViewById(R.id.btn_find_all);
        btn_find_all.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                alterarCorBotaoPressionado(btn_find_all);                                                   // Chama o método para alteração de cor do botão selecinado.
                listPayments = consultaPagamentos(FIND_ALL);                                                // Chama método gerenciador de busca para executar o findAll.
                textViewListPayment.setText(updateLableListPayments(PAYMENT, listPayments.size()));         // Atualiza o titulo da lista pesquisada.
                updateSimpleListPayment(PAYMENT);                                                           // Atualiza a lista simples para exibição.
                adapterListView.notifyDataSetChanged();                                                     // Atualiza a adapter para exibição.
            }
        });

        Button btn_find_non_synced = findViewById(R.id.btn_find_non_synced);
        btn_find_non_synced.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                alterarCorBotaoPressionado(btn_find_non_synced);                                            // Chama o método para alteração de cor do botão selecinado.
                listPayments = consultaPagamentos(FIND_NON_SYNCED);                                         // Chama método gerenciador de busca para executar o findNonSynced.
                textViewListPayment.setText(updateLableListPayments(PAYMENT, listPayments.size()));         // Atualiza o titulo da lista pesquisada.
                updateSimpleListPayment(PAYMENT);                                                           // Atualiza a lista simples para exibição.
                adapterListView.notifyDataSetChanged();                                                     // Atualiza a adapter para exibição.
            }
        });

    }

    protected void onDestroy() {
        super.onDestroy();
    }

    private List<Payment> consultaPagamentos(int function)          // Gerencia, executa e retorna a lista de Payment do método de busca selecionado.
    {
        List<Payment> listPayments =  new ArrayList<>();;

        try {
            if (FIND_ALL == function)
                listPayments = api.findAll(mPaymentRequest);        // Realiza a busca de todas a transações considerando os filtros do mPaymentRequest.
            else if (FIND_NON_SYNCED == function)
                listPayments = api.findNonSynced(mPaymentRequest);  // Realiza a busca de todas a transações não sincronizadas com a Paystore
                                                                    // considerando os filtros do mPaymentRequest.

        } catch (ClientException e) {
            e.printStackTrace();
        }

        return listPayments;
    }

    private List<PaymentV2> consultaPagamentosV2(int function)      // Gerencia, executa e retorna a lista de PaymentV2 do método de busca selecionado.
    {
        List<PaymentV2> listPayments =  new ArrayList<>();;

        try {
            if (FIND_ALL_V2 == function)
                listPayments = api.findAllV2(mPaymentRequest);      // Realiza a busca de todas a transações considerando os filtros do mPaymentRequest.
            else if (FIND_NON_SYNCED_V2 == function)
                listPayments = api.findNonSyncedV2(mPaymentRequest);// Realiza a busca de todas a transações não sincronizadas com a Paystore
                                                                    // considerando os filtros do mPaymentRequest.
        } catch (ClientException e) {
            e.printStackTrace();
        }
        return listPayments;
    }

    private PaymentProviderRequest createRequest() throws PackageManager.NameNotFoundException { // Cria o objeto de requisição de busca.
        PaymentProviderRequest result = null;

        result = new PaymentProviderRequest(CredentialsUtils.getMyAppInfo(this.getPackageManager(), getApplicationContext().getPackageName()), new Date());

        return result;
    }

    private void updateSimpleListPayment(int tipo)  // Atualiza a lista simple para exibição.
    {
        if (PAYMENT_V2 == tipo) {
            if (!listPaymentsV2.isEmpty()) {
                simpleListPayments.clear();
                for (PaymentV2 payment : listPaymentsV2) {
                    simpleListPayments.add("Status: " + payment.getPaymentStatus() + " | Valor: R$" + payment.getValue());
                }
            } else
                simpleListPayments.clear();
        }
        else if (PAYMENT == tipo)
        {
            if (!listPayments.isEmpty()) {
                simpleListPayments.clear();
                for (Payment payment : listPayments) {
                    simpleListPayments.add("Status: " + payment.getPaymentStatus() + " | Valor: R$" + payment.getValue());
                }
            } else
                simpleListPayments.clear();
        }
    }

    private String updateLableListPayments(int tipo, int qnt)  // Formata o título da lista de pagamentos pesquisada.
    {
        return "Resultado: tipo(" + (PAYMENT==tipo? "Payment":"PaymentV2") + ") qnt.(" + qnt + ")";
    }

    private void alterarCorBotaoPressionado(Button botao) {
        if (ultimoBotaoPressionado != null) {
            ultimoBotaoPressionado.setBackgroundResource(android.R.drawable.btn_default);
        }

        botao.setBackgroundColor(Color.parseColor("#3e50b3"));
        ultimoBotaoPressionado = botao;
    }
}

Acesse CredentialsUtils.java para obeter a classe.

xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".ConsultaDePagamentosActivity">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:gravity="center">

            <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:orientation="vertical"
                android:gravity="top">

                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="Status do pagamento"
                    android:textSize="16sp"
                    android:textColor="@android:color/black"
                    android:layout_gravity="center"
                    android:layout_marginTop="8dp"
                    android:layout_marginBottom="8dp"
                    android:layout_marginLeft="8dp"
                    android:layout_marginRight="8dp" />
                <Spinner
                    android:id="@+id/spinner_status"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:gravity="center"
                    android:layout_marginTop="8dp"
                    android:layout_marginBottom="8dp"
                    android:layout_marginLeft="8dp"
                    android:layout_marginRight="8dp"
                    />

            </LinearLayout>


            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:orientation="horizontal"
                android:gravity="center">

                <Button
                    android:id="@+id/btn_find_all_v2"
                    android:layout_width="160dp"
                    android:layout_height="wrap_content"
                    android:text="findAllV2()"
                    android:textAllCaps="false"
                    android:layout_marginTop="8dp"
                    android:layout_marginBottom="8dp"
                    android:layout_marginLeft="8dp"
                    android:layout_marginRight="8dp"/>

                <Button
                    android:id="@+id/btn_find_non_synced_v2"
                    android:layout_width="160dp"
                    android:layout_height="wrap_content"
                    android:text="findNonSyncedV2()"
                    android:textAllCaps="false"
                    android:layout_marginTop="8dp"
                    android:layout_marginBottom="8dp"
                    android:layout_marginLeft="8dp"
                    android:layout_marginRight="8dp"/>

            </LinearLayout>

            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:orientation="horizontal"
                android:gravity="center">

                <Button
                    android:id="@+id/btn_find_all"
                    android:layout_width="160dp"
                    android:layout_height="wrap_content"
                    android:text="findAll()"
                    android:textAllCaps="false"
                    android:layout_marginTop="8dp"
                    android:layout_marginBottom="8dp"
                    android:layout_marginLeft="8dp"
                    android:layout_marginRight="8dp"/>

                <Button
                    android:id="@+id/btn_find_non_synced"
                    android:layout_width="160dp"
                    android:layout_height="wrap_content"
                    android:text="findNonSynced()"
                    android:textAllCaps="false"
                    android:layout_marginTop="8dp"
                    android:layout_marginBottom="8dp"
                    android:layout_marginLeft="8dp"
                    android:layout_marginRight="8dp"/>

            </LinearLayout>


        <TextView
            android:id="@+id/text_view_list_payments"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Resultado: tipo() qnt.()"
            android:textSize="16sp"
            android:textColor="@android:color/black"
            android:layout_gravity="center"
            android:layout_marginTop="8dp"
            android:layout_marginBottom="8dp"
            android:layout_marginLeft="8dp"
            android:layout_marginRight="8dp"
            />

        <ListView
            android:id="@+id/list_view_lista_pagamentos"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />

    </LinearLayout>

</androidx.constraintlayout.widget.ConstraintLayout>

Resultado

Implementando o exemplo é possível manipular de forma simples a busca dos pagamentos sincronizados ou não sincronizados com a Paystore, também é possível selecionar um filtro de pesquisa pela status da transação, selecionar o método de pesquisa e verificar o tipo e a quantidade de transações obtidas.