Getnet DocsGetnet Docs

Procesar una transacción de compra

Esta guía explica cómo iniciar una transacción de compra estándar utilizando la app Tap on Phone. Utiliza un Android Intent para iniciar la interfaz de pago, pasar los detalles de la transacción (como el importe y la moneda) y gestionar la respuesta cuando el pago finalice.

Prerrequisitos

Antes de procesar una compra, asegúrate de que tienes:

  • Inicializada correctamente la app Tap on Phone. (Consulta Inicializando el POS o compruébalo utilizando Comprobación del Estado del POS).
  • El userId, userToken y merchantId asociados a la sesión actual.
  • Implementadas las APIs Activity Result de AndroidX en tu proyecto.

Paso 1: Registrar el Activity Result Launcher

Cuando el pago finaliza, la app Tap on Phone devuelve el control a tu app a través de un Activity Result. Debes registrar un callback para gestionar este resultado.

val paymentResultLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
    val data = result.data

    if (result.resultCode == Activity.RESULT_OK && data != null) {
        // The transaction process completed and generated a receipt.
        val status = data.getStringExtra("status") ?: "None"

        if (status == "APPROVED") {
            println("Payment approved successfully!")
            // Extract receipt data and display success to the merchant
        } else {
            val declineCause = data.getStringExtra("declineCause") ?: "Unknown"
            println("Payment declined: $declineCause")
            // Display decline reason to the merchant
        }
    } else if (result.resultCode == Activity.RESULT_CANCELED) {
        // The user canceled the payment, or a pre-transaction error occurred.
        val errorCode = data?.getStringExtra("errorCode") ?: "None"
        val errorMessage = data?.getStringExtra("errorMessage") ?: "User Canceled"
        println("Payment canceled or failed: $errorMessage ($errorCode)")
    }
}

Una respuesta RESULT_OK significa que el proceso ha finalizado, pero no garantiza que el pago haya sido aprobado. Evalúa siempre la cadena status dentro de los datos del intent devuelto.

Paso 2: Escuchar el ID de la transacción (recomendado)

En cuanto la app Tap on Phone comienza a procesar el intent de pago, transmite (broadcasts) un sdkTransactionId único. Si tu app falla (crash) o pierde el Activity Result final, necesitas este ID para recuperar el estado de la transacción.

Registra un broadcast receiver antes de iniciar el intent de pago:

val transactionIdReceiver = object : BroadcastReceiver() {
    override fun onReceive(context: Context?, intent: Intent?) {
        val transactionId = intent?.getStringExtra("sdkTransactionId")
        println("Transaction started with ID: $transactionId")
        // Save this ID temporarily in case you need to recover the transaction
    }
}

// Register the receiver
ContextCompat.registerReceiver(
    requireActivity(), // or 'this' if in an Activity
    transactionIdReceiver,
    IntentFilter("com.dejamobile.cbp.sps.TRANSACTION_BROADCAST_RESPONSE"),
    ContextCompat.RECEIVER_EXPORTED
)

La app Tap on Phone podría emitir este broadcast varias veces por llamada de intent si se produce un error durante la transacción y se genera un nuevo ID de transacción.

Paso 3: Construir e iniciar el intent de pago

Crea un intent explícito dirigido a la POSActivity de la app Tap on Phone. Debes incluir los detalles de la transacción como extras.

Presta especial atención al importe (amount):

  • Importe (Amount): Debes proporcionar el importe total en céntimos (por ejemplo, $12.00 es 1200). Este valor representa el importe total de la transacción, incluyendo las propinas.
  • Propina (Tip): Si proporcionas un importe de propina, también debes proporcionarlo en céntimos. Esto es estrictamente un metadato. La app Tap on Phone no añade la propina al campo amount automáticamente.
private fun performPurchase(amountInCents: Long, tipInCents: Long? = null) {
    // 1. Calculate the final total amount
    var finalAmount = amountInCents
    if (tipInCents != null) {
        finalAmount += tipInCents
    }

    // 2. Build the intent
    val intent = Intent().apply {
        setClassName(
            "com.dejamobile.cbp.sps.app",
            "com.dejamobile.cbp.sps.app.POSActivity"
        )

        // Session Identifiers
        putExtra("userId", userId)
        putExtra("userToken", userToken)
        putExtra("merchantId", merchantId)

        // Transaction Details
        putExtra("transactionType", "PURCHASE")
        putExtra("amount", finalAmount)
        if (tipInCents != null) {
            putExtra("tip", tipInCents)
        }

        // Optional Configuration
        putExtra("paymentMode", "Card") // Default is "Card". "Link" is also supported.
        putExtra("externalTransactionReference", "ORDER-12345") // Link this payment to your internal order ID
        putExtra("locale", "en_US") // Force a specific language on the payment screen
        putExtra("transitionAuto", true) // Automatically transition back to your app after completion
    }

    // 3. Launch the intent
    paymentResultLauncher.launch(intent)
}

Paso 4: Gestionar el resultado

Cuando inicias el intent, la app Tap on Phone toma el control de la pantalla, solicita al usuario que acerque una tarjeta o dispositivo, y procesa el pago con la red adquirente.

Una vez finalizado, la interfaz de Tap on Phone se cierra y tu paymentResultLauncher recibe el resultado. Extrae los datos del recibo para formatear un recibo para el cliente o registrar la transacción en tu backend.

  • Recuerda cancelar el registro (unregister) de tu transactionIdReceiver tras la finalización del pago para evitar fugas de memoria (memory leaks).

Próximos pasos