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,userTokenymerchantIdasociados 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.00es1200). 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
amountautomá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
transactionIdReceivertras la finalización del pago para evitar fugas de memoria (memory leaks).
Próximos pasos
- Aprende a extraer y formatear todos los datos del recibo en Gestión de Resultados de Transacciones.
- Comprende cómo procesar cancelaciones y reembolsos en Procesar un Reembolso o Cancelación.