Implementação

1) Instanciando a TapOnPhoneSdk

Obtendo a instância da SDK:

private val tapOnPhoneSdkInstance = TapOnPhoneSdk.instance

Métodos públicos expostos pela TapOnPhoneSdk:

class TapOnPhoneSdk {
    fun configure(context: Context, license: String)
    fun activateDevice(
        params: ActivateDeviceModel,
        listener: ActivateDeviceListener
    )
    fun isDeviceActive(listener: IsDeviceActiveListener)
    fun deactivateDevice(listener: DeactivateDeviceListener)
    fun checkDeviceStatus(listener: DeviceStatusListener)
    fun getActiveEstablishmentDetails(listener: ActiveEstablishmentDetailsListener)
    fun makeTransaction(
        params: TransactionParamsModel,
        listener: MakeTransactionListener
    )
    fun nullifyTransaction(
        transactionId: String,
        listener: NullifyTransactionListener
    )
    fun listTransactions(listener: ListTransactionsListener)
    fun getTransaction(
        transactionId: String,
        listener: GetTransactionListener
    )
    fun isNFCSupported(): Boolean
    fun isNFCEnabled(): Boolean
    fun goToNfcSetting(): Boolean
    fun isMockCardTransactionsEnabled(): Boolean
}

Pacotes utilizados:

import com.paytime.taponphonesdk.TapOnPhoneSdk
import com.paytime.taponphonesdk.external.listeners.*              // listeners
import com.paytime.taponphonesdk.external.model.activation.ActivateDeviceModel
import com.paytime.taponphonesdk.external.model.auth.EstablishmentModel
import com.paytime.taponphonesdk.external.model.device.DeviceStatusModel
import com.paytime.taponphonesdk.external.model.transaction.*      // transações
📘

Callbacks

Todos os métodos com listener são assíncronos. Os callbacks do listener são sempre chamados na main thread.

A maioria dos listeners segue o mesmo padrão:

  • onMessage(type: String, message: String): mensagens informativas sobre o andamento da operação (ex.: type = "INFO");
  • onApproved(result): sucesso da operação;
  • onError(code: String, messages: List<String>, httpStatusCode: Int?): erro da operação. Veja os códigos na seção 7) Códigos de erro.
📘

Operações simultâneas

As operações activateDevice, deactivateDevice, makeTransaction e nullifyTransaction não podem ser executadas ao mesmo tempo. Se uma delas for chamada enquanto outra estiver em andamento, o onError é chamado com o código INTERNAL_ERROR e a mensagem "Há uma operação em andamento. Aguarde a conclusão.".

1.1) Configuração

Para começar, é necessário chamar o método de configuração. O funcionamento de todos os outros métodos está atrelado à configuração, já que o context da aplicação é utilizado por todo o SDK. Se qualquer outro método for chamado antes do configure, será lançada uma IllegalStateException.

É necessário que este método seja chamado apenas uma vez. Recomenda-se chamá-lo no lifecycle de onCreate da aplicação. Chamadas seguintes não reconfiguram a SDK.

class MyApplication : Application() {
    override fun onCreate() {
        super.onCreate()
        TapOnPhoneSdk.instance.configure(this, license)
    }
}
📘

Licença

O campo license deve ser obtido junto com a Paytime. Uma licença vazia lança uma IllegalArgumentException.

1.2) Ativação do dispositivo

Para habilitar o uso da TapOnPhoneSdk, é necessário chamar o método de ativação do dispositivo. ActivateDeviceModel recebe o código de ativação do estabelecimento (disponível no cadastro do estabelecimento no portal), que deve ter no mínimo 8 caracteres.

val params = ActivateDeviceModel(activationCode)

tapOnPhoneSdkInstance.activateDevice(params, listener)

listener é uma instância da interface ActivateDeviceListener, que é usada para tratar as respostas da ativação.

val listener = object : ActivateDeviceListener {
    override fun onMessage(type: String, message: String) {
        // Andamento da ativação (ex.: "Ativando dispositivo...")
    }

    override fun onApproved(result: Any?) {
        // Dispositivo ativado com sucesso (result = true)
    }

    override fun onError(code: String, messages: List<String>, httpStatusCode: Int?) {
        // Erros
    }
}
📘

Persistência da ativação

A ativação é persistida e continua válida após o app ser fechado e reaberto. Não é necessário ativar o dispositivo a cada inicialização. Use isDeviceActive ou checkDeviceStatus para verificar o estado atual.

2) Realizar transação

Transações são realizadas através do método makeTransaction. O dispositivo precisa estar ativo; caso contrário, o onError é chamado com o código LOGON_NOT_PERFORMED.

O método makeTransaction recebe dois parâmetros: params e listener.

params é uma instância da classe TransactionParamsModel, que contém os detalhes da transação:

CampoTipoDescrição
amountLongValor da transação, em centavos.
typeTransactionTransactionTypeModelTipo da transação: CREDIT ou DEBIT.
installmentInt?Quantidade de parcelas. null ou 1 = à vista; maior que 1 = parcelado (apenas CREDIT).

listener é uma instância da interface MakeTransactionListener, que é usada para tratar as respostas da transação.

📘

Sobre valores monetários

Todos os valores monetários são tratados pela SDK como centavos. Por exemplo, uma transação de R$ 10,99 deve informar o parâmetro amount = 1099.

2.1) Realizar transação CREDIT ou DEBIT

val params = TransactionParamsModel(
    amount = 1000,
    typeTransaction = TransactionTypeModel.CREDIT,
    installment = null // ou um inteiro (ex.: 3 para crédito parcelado em 3x)
)

tapOnPhoneSdkInstance.makeTransaction(params, listener)

No callback de onApproved, o parâmetro retornado é o resultado da transação (TransactionResultModel). A transação também é salva localmente (veja 4) Listagem de transações).

val listener = object : MakeTransactionListener {
    override fun onMessage(type: String, message: String) {
        // Andamento da transação (ex.: "Iniciando transação...")
    }

    override fun onApproved(result: TransactionResultModel) {
        // Transação realizada com sucesso
        val transactionId = result.paymentData.gatewayKey
    }

    override fun onError(code: String, messages: List<String>, httpStatusCode: Int?) {
        // Erros
    }
}

TransactionResultModel:

data class TransactionResultModel(
    val status: String,
    val errorCode: String,
    val errorSource: String?,
    val errorDescription: String?,
    val paymentData: TransactionPaymentDataModel,
)

data class TransactionPaymentDataModel(
    val amount: Long,
    val currencyCode: String,
    val originalTransactionId: Long?, // apenas no cancelamento: transactionId da venda cancelada
    val transactionId: Long,
    val transactionType: String,
    val transactionDate: String,
    val applicationId: String,
    val authorizationId: String,
    val rrn: String,
    val additionalData: String,
    val ballot: Int,
    val brand: String,
    val cardFirstNumbers: String,
    val cardLastDigits: String,
    val dynamicBankData: String,
    val gatewayKey: String,
    val mid: String,
    val cvmMethod: String,
    val arqc: String,
    val date: String,
    val time: String,
)

Quando o usuário cancela a transação ou o tempo expira, o onMessage é chamado com type = "PAYMENT_CANCEL" ou type = "PAYMENT_TIME_EXPIRED", seguido do onError.

📘

Fluxo de senha

Para testar o fluxo de pedido de senha, basta criar uma transação com valor maior que o CVM Limit (R$ 200,00). Ao tentar pagar por aproximação, a SDK exibirá a opção de fornecer a senha. O limite por transação é de R$ 500,00.

3) Cancelamento/estorno de transação

Transações são estornadas através do método nullifyTransaction.

O método nullifyTransaction recebe dois parâmetros: transactionId e listener.

transactionId é um campo do tipo String. Pode ser informado o gatewayKey ou o transactionId retornados no paymentData da transação (ou no TransactionStoreModel da listagem local).

listener é uma instância da interface NullifyTransactionListener, que é usada para tratar as respostas do cancelamento. No onApproved, o retorno é um TransactionResultModel com os dados do cancelamento (paymentData.originalTransactionId contém o transactionId da venda cancelada).

tapOnPhoneSdkInstance.nullifyTransaction(transactionId, listener)
val listener = object : NullifyTransactionListener {
    override fun onMessage(type: String, message: String) {
        // Andamento do cancelamento (ex.: "Iniciando cancelamento...")
    }

    override fun onApproved(result: TransactionResultModel) {
        // Transação cancelada com sucesso
    }

    override fun onError(code: String, messages: List<String>, httpStatusCode: Int?) {
        // Erros
    }
}
📘

Observações:

  • Apenas transações do mesmo dia podem ser canceladas/estornadas;
  • Apenas transações com status PAID podem ser canceladas/estornadas;
  • A transação precisa existir na base local do dispositivo;
  • O cancelamento precisa estar habilitado para o estabelecimento. Caso contrário, o onError é chamado com a mensagem "Permissão para cancelar a transação negada.";
  • Após o cancelamento, a transação local passa a ter o status REFUNDED.

4) Listagem de transações (local)

Lista as transações executadas no dispositivo, ordenadas da mais recente para a mais antiga. O onApproved do ListTransactionsListener retorna uma Lista de TransactionStoreModel. No momento, nenhuma opção de filtros é oferecida.

tapOnPhoneSdkInstance.listTransactions(listener)
val listener = object : ListTransactionsListener {
    override fun onMessage(type: String, message: String) {}

    override fun onApproved(result: List<TransactionStoreModel>) {
        // Transações locais
    }

    override fun onError(code: String, messages: List<String>, httpStatusCode: Int?) {}
}

TransactionStoreModel:

data class TransactionStoreModel(
    val paymentMethod: TransactionPaymentMethodModel, // DEBIT, CREDIT_FULL, CREDIT_INSTALLMENT, UNKNOWN
    val transactionStatus: TransactionStatusModel,    // PAID, REFUNDED
    val transactionId: Long,
    val gatewayKey: String,
    val mid: String,
    val cvmMethod: String,
    val arqc: String,
    val amount: Long,
    val netAmount: Long,
    val installments: Int,
    val installmentAmount: Long,
    val ballot: Int,
    val authorizationId: String,
    val currencyCode: String,
    val transactionDate: String,
    val transactionDatetime: Long,   // epoch em milissegundos
    val brand: String,
    val cardFirstNumbers: String,
    val cardLastDigits: String,
    val additionalData: String,
    val rrn: String,
    val time: String,
    val date: String,
    val transactionType: String,
    val dynamicBankData: String,
    val applicationId: String,
    val createdAt: Long,             // epoch em segundos
    val syncedToBackendAt: Long?,    // epoch em segundos
    val annulmentAt: Long?,          // epoch em segundos
)
📘

Histórico local

A base local mantém as transações das últimas 72 horas. Transações mais antigas são removidas automaticamente.

5) Obter transação via ID (local)

Obtém os dados de uma transação local através do gatewayKey ou do transactionId dessa transação. O onApproved do GetTransactionListener retorna um item do tipo TransactionStoreModel ou null.

tapOnPhoneSdkInstance.getTransaction(
    transactionId: String,
    listener: GetTransactionListener
)

6) Outras operações

Sobre as operações da TapOnPhoneSdk.

6.1) isDeviceActive(listener: IsDeviceActiveListener)

Retorna se o dispositivo está ativo ou não, no onApproved(result: Boolean).

6.2) deactivateDevice(listener: DeactivateDeviceListener)

Desativa o dispositivo, tirando assim a habilidade do mesmo de fazer transações. Também limpa os dados locais da SDK. Retorna onApproved(true) ao concluir.

6.3) checkDeviceStatus(listener: DeviceStatusListener)

Retorna no onApproved um DeviceStatusModel com informações importantes: se o dispositivo é seguro, se está ativo e se pode usar o Tap On Phone.

data class DeviceStatusModel(
    val canUseTapPhone: Boolean,
    val isSecure: Boolean,
    val isActivated: Boolean
)

6.4) getActiveEstablishmentDetails(listener: ActiveEstablishmentDetailsListener)

Obtém dados do estabelecimento ativo para receber vendas no Tap On Phone. Retorna no onApproved um EstablishmentModel, ou null se o dispositivo não estiver ativo.

data class EstablishmentModel(
    val document: String,
    val firstName: String,
    val lastName: String?,
    val gatewayKey: String?,
    val softDescriptor: String,
    val phoneNumber: String,
    val mcc: String,
    val merchantId: String,
    val address: AddressModel,
    val limits: LimitsModel?
)

6.5) isNFCSupported(): Boolean

Retorna se o dispositivo possui NFC.

6.6) isNFCEnabled(): Boolean

Retorna se o NFC está ativo.

6.7) goToNfcSetting(): Boolean

Abre as configurações de NFC do dispositivo. Retorna true se a tela de configurações foi aberta e false caso contrário.

6.8) isMockCardTransactionsEnabled(): Boolean

Indica se transações de testes estão mockadas (simuladas) ou em teste real. Como são necessários cartões de testes da certificadora, em debug, todas as transações são mockadas.

📘

Transações mockadas

Com transações mockadas, ainda é necessário aproximar um cartão (qualquer cartão). O resultado é definido pelo valor:

  • Valor par (ex.: amount = 1000): transação aprovada;
  • Valor ímpar (ex.: amount = 1001): transação recusada, com código REJECTED_TRANSACTION.

Transações aprovadas no modo mockado também podem ser canceladas pelo nullifyTransaction.

7) Códigos de erro

Códigos retornados no parâmetro code do onError:

CódigoDescrição
LOGON_NOT_PERFORMEDDispositivo não ativado ou ativação expirada/inválida. Chame activateDevice novamente.
ACTIVATION_ERRORFalha ao ativar o dispositivo.
DEACTIVATION_ERRORFalha ao desativar o dispositivo.
INVALID_VALUEParâmetro inválido (ex.: código de ativação com menos de 8 caracteres).
INVALID_TRANSACTIONTransação inválida (tipo não suportado, operação cancelada pelo usuário, estorno não permitido etc.).
EMPTY_TRANSACTIONTransação não encontrada na base local.
REJECTED_TRANSACTIONTransação recusada.
INTERNAL_ERRORErro interno, tempo expirado ou operação já em andamento.

Além desses, o code pode trazer os códigos de erro retornados pelo provedor Tap On Phone. O parâmetro messages traz a descrição do erro e httpStatusCode vem preenchido quando o erro é de uma chamada de API.


Did this page help you?