Cobrar
Contrato v1 del SDK 1.0.0-beta.3. Todavía está en Beta.
Un cobro es un ActivityResultContract: registras FinoraPago.Cobrar(), lanzas una SolicitudCobro y recibes un ResultadoCobro. Tu app se identifica por su paquete y su firma, que Android le entrega a FINORA Pago; ningún campo de la solicitud sirve para hacerse pasar por otra app.
La solicitud
val solicitud = SolicitudCobro.Builder()
.montoCentavos(12_500) // obligatorio, > 0
.moneda("VES") // VES (por defecto) o USD
.referenciaExterna("PED-1001") // obligatoria, clave de idempotencia
.sucursalCodigo("CENTRO") // o .sucursalId(42): una de las dos
.pedido("1001") // opcional, lo ve el cliente
.descripcion("Pedido 1001") // opcional
.medio("TARJETA") // opcional
.pagador("V", "12345678") // opcional, tipo y número de documento
.build()
| Método | Extra del Intent | Regla |
|---|---|---|
| — | finora.version_contrato | 1. Lo pone el SDK |
montoCentavos | finora.monto_centavos (Long) | Mayor que cero, en la unidad menor |
moneda | finora.moneda | VES o USD |
referenciaExterna | finora.referencia_externa | Letras, dígitos y . _ : -, de 1 a 64 |
sucursalCodigo | finora.sucursal_codigo | Código de la tienda en FINORA, de 1 a 40: letras, dígitos y . _ - |
sucursalId | finora.sucursal_id (Long) | Id de la tienda en FINORA |
pedido | finora.pedido | Hasta 64 caracteres |
descripcion | finora.descripcion | Hasta 140 caracteres |
medio | finora.medio | Ver abajo. Sin medio: los habilitados en el terminal; si el comercio tiene la Tarjeta FINORA encendida, el cliente elige (FINORA Pago 0.16.0) |
pagador | finora.pagador_tipo_documento, finora.pagador_documento | V, E, J, P o G y de 5 a 10 dígitos, juntos |
Si usas otro lenguaje o no quieres la dependencia, puedes construir el Intent a mano con la acción com.dcgeeks.finora.pago.action.SDK_COBRAR, el paquete com.dcgeeks.finora.pago y estos extras. Debes lanzarlo con startActivityForResult (o registerForActivityResult): con startActivity FINORA Pago no sabe quién llama y responde NO_AUTORIZADO.
Medios
medio | Qué hace |
|---|---|
TARJETA | Cobra con tarjeta de débito o crédito en el lector, sin mostrar selector |
TARJETA_FINORA | Cobra con la tarjeta prepago de FINORA (pase en el teléfono del cliente o QR), sin el lector de tarjetas bancarias. Ver Tarjeta FINORA |
TAP_TO_PHONE | Solo en la variante de demostración |
PAGO_MOVIL | No disponible en el terminal: responde NO_LISTO con código MEDIO_NO_DISPONIBLE |
FINORA Pago envía el medio pedido al servidor al crear la orden, que lo aplica al cobro igual que en el cobro en la nube. El servidor solo admite TARJETA, TARJETA_FINORA y TAP_TO_PHONE; cualquier otro valor se rechaza con MEDIO_NO_DISPONIBLE y tu app recibirá NO_LISTO sin que se lea la tarjeta.
El resultado
registerForActivityResult(FinoraPago.Cobrar()) { r: ResultadoCobro ->
when {
r.aprobada -> entregar(r)
r.estado.requiereConsulta -> marcarParaConsultar(r)
r.reintentable -> ofrecerReintento(r)
else -> mostrar(r.mensaje)
}
}
| Propiedad | Extra | Contenido |
|---|---|---|
estado | estado | Ver Estados y errores |
aprobada | aprobada | true solo si estado == APROBADA |
reintentable | reintentable | No hubo dinero y puedes volver a intentarlo |
codigoRespuesta | codigo_respuesta | Código del emisor (00, 51…) o de FINORA (REFERENCIA_USADA…) |
mensaje | mensaje | Texto para mostrar. No decidas por el texto |
autorizacion, rrn, stan | autorizacion, rrn, stan | Datos de la autorización |
ultimos4, marca | ultimos4, marca | El único dato de la tarjeta que recibes |
medio | medio | Medio con que se cobró |
terminalId | terminal_id | Terminal de FINORA Pago |
referenciaFinora | referencia_finora | Referencia del cobro en FINORA: con ella se consulta y se concilia |
referenciaExterna | referencia_externa | La tuya |
sucursalCodigo, sucursalNombre | sucursal_codigo, sucursal_nombre | Tienda a la que FINORA atribuyó la venta |
montoCentavos, moneda | monto_centavos, moneda | |
firmaCapturada | firma_capturada | El cliente firmó en pantalla |
comprobanteUrl | comprobante_url | Próximamente, detrás de un interruptor aún no activo. En el primer cobro el enlace llegará por el webhook intencion.resultado; en la app solo al consultar o repetir el cobro con la misma referenciaExterna |
fechaHora | fecha_hora | ISO-8601 en UTC |
simulado | simulado | Lector simulado o variante de demostración: no hubo dinero real |
estadoVerificado | estado_verificado | false solo en una APROBADA que FINORA Pago tenía en el equipo y no pudo confirmar con el servidor (ver Idempotencia). true en todo lo demás y si FINORA Pago no envía el campo (anterior a 0.15.2) |
Si FINORA Pago no devuelve nada (el sistema cerró su pantalla, el proceso murió), el SDK te entrega SIN_RESPUESTA, que se trata igual que EN_DUDA. Si FINORA Pago no está instalado, NO_INSTALADO sin abrir ninguna pantalla.
El monto que se cobra
Al crear la orden, el servidor devuelve a FINORA Pago el total de la orden (montoTotalCentavos), nunca lo que quede pendiente, junto con tu referenciaExterna, la sucursal atribuida y el estado de la orden. FINORA Pago compara tu montoCentavos con ese total antes de leer la tarjeta: si no coinciden, responde CONFLICTO y no cobra.
Si el servidor con el que habla FINORA Pago no admite cobros por el SDK, FINORA Pago responde NO_LISTO con el código MERCHANT_SIN_SOPORTE, sin leer la tarjeta.
Idempotencia
referenciaExterna es tu clave de idempotencia. FINORA Pago la recuerda por terminal y por app, y el servidor también: repetir la referencia nunca crea una segunda orden.
| Repites la misma referencia… | Pasa esto |
|---|---|
Tras APROBADA | FINORA Pago consulta la venta en el servidor con la misma referencia, sin tocar el lector: pagada → la misma APROBADA (estadoVerificado = true); anulada → CONFLICTO REFERENCIA_USADA; servidor sin respuesta → la misma APROBADA con estadoVerificado = false |
Tras EN_DUDA | FINORA Pago te repite el mismo resultado, sin tocar el lector. Si el veredicto aprobado del emisor llegó después, antes de responder consulta la venta igual que tras APROBADA: pagada → APROBADA (estadoVerificado = true); anulada → CONFLICTO REFERENCIA_USADA; servidor sin respuesta → APROBADA con estadoVerificado = false (FINORA Pago 0.15.3 o posterior) |
| Con otro monto | CONFLICTO con código CONFLICTO_IDEMPOTENCIA |
Tras NO_COBRADA u OCUPADO | Se atiende de nuevo; el servidor devolverá la misma orden |
Tras RECHAZADA, tras CANCELADA con referenciaFinora, o tras anular | CONFLICTO con código REFERENCIA_USADA: usa una referencia nueva, por ejemplo PED-1001-2 |
Si el cobro está aprobado en el equipo y la venta se anula por una vía que FINORA Pago no ve (el portal del comercio o la consola), repetir la referencia ya no devuelve APROBADA: FINORA Pago consulta la venta y responde CONFLICTO con código REFERENCIA_USADA. Si el servidor no responde, devuelve la APROBADA guardada con estadoVerificado = false para que decidas si consultas antes de entregar. La 0.15.1 respondía APROBADA sin consultar.
Desde la 0.15.3 la consulta vale para toda APROBADA repetida, también la de un cobro que quedó EN_DUDA y cuyo veredicto aprobado llegó después: la 0.15.2 la respondía sin consultar. Exige la 0.15.3 o posterior.
Si FINORA Pago pierde su registro local de un cobro (datos de la app borrados, o el cobro salió del registro tras unos 300 cobros más) y repites la referencia de una venta ya anulada, FINORA Pago consulta el estado de la venta en el servidor y responde CONFLICTO con código REFERENCIA_USADA, nunca APROBADA. Si el servidor dice que la venta está pagada pero el equipo ya no tiene los datos de la aprobación, responde EN_DUDA: consulta la intención por referenciaFinora desde tu servidor. La 0.15.0 podía responder APROBADA en ese caso; exige la 0.15.1 o posterior.
Un cobro a la vez
FINORA Pago atiende un solo cobro por equipo. Si ya está cobrando, responde OCUPADO: espera y reintenta con la misma referencia.
El botón «Atrás»
Si el usuario pulsa «Atrás» antes de que se cree el cobro, recibes CANCELADA sin efecto. Con el cobro en pantalla solo se puede cancelar en las fases que lo admiten; mientras se autoriza, nunca.