Implementando el SDK en tu proyecto
En esta sección aprenderás a usar nuestro SDK para controlar las operaciones del lector NetPay MINI
1. Implementando las interfaces
Crea una actividad (activity) que implemente las siguientes interfaces: ITransactionListener, IReportsListener y sus métodos correspondientes.
Implementación
class KotlinActivity : AppCompatActivity(), ITransactionListener, IReportsListener, IPasswordListener {
override fun selectedAppAction(apps: List<String>, action: (Int) -> Unit) {
TODO("Not yet implemented")
}
override fun valuesToProcessing(values:
(total: Double,
tip: Double,
reference: String,
promotion: String) -> Unit) {
TODO("Not yet implemented")
}
override fun transactionsResult(message: String, processed: Boolean) {
TODO("Not yet implemented")
}
override fun posTransactionEnumResult(result: NpTransactionEnum) {
TODO("Not yet implemented")
}
override fun reverseResult(message: String, processed: Boolean) {
TODO("Not yet implemented")
}
override fun refundResult(message: String, processed: Boolean) {
TODO("Not yet implemented")
}
override fun errorResult(npErrorEnum: NpErrorEnum) {
TODO("Not yet implemented")
}
override fun provideSignaturePathResult(intent: Intent) {
TODO("Not yet implemented")
}
override fun startingPaymentProcessing() {
TODO("Not yet implemented")
}
override fun imageResult(processed: Boolean, image: String?, message: String?) {
TODO("Not yet implemented")
}
override fun changePassword(
isSuccess: Boolean,
messageError: String?,
result: RecoverPasswordResponse?
) {
TODO("Not yet implemented")
}
override fun reportSalesByDateAndUserResult(
processed: Boolean,
message: String?,
reportSales: List<ResponseSale>?
) {
TODO("Not yet implemented")
}
override fun reportSaleDetailsResult(response: ResponseSaleDetail?, success: Boolean) {
TODO("Not yet implemented")
}
}
2. Declarando e inicializando variables
Antes de implementar los métodos anteriores debemos de clarar e inicializar los objetos que contienen las funcionalidades que vamos a utilizar.
Declaración global de variables
private val connectReader: IConnectReader by lazy { ConnectReaderDevice(this) }
private lateinit var transaction: INpTransactions
private lateinit var reports: INpReports
private lateinit var miniPreferences: IMiniPreferences
private lateinit var binding: ActivityMainBinding
private lateinit var passwordUpdate: INpPassword
private lateinit var bluetoothManager: BluetoothManager
Inicializar los objetos en el método onCreate()
Implemenación
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
// Initialize actions for transactions
transaction = NpTransactions(this, connectReader, this)
reports = NpReports(this, this)
miniPreferences = MiniPreferences(this)
passwordUpdate = NpPassword(this,this)
bluetoothManager = getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager
//TODO IMPORTANTE #1 setInitializeSDK
val userNameDefault = "[email protected]"
val userPass = "Y0uRP4s5w0rD"
miniPreferences.setInitializeSDK(userNameDefault, userPass, ConfigSdk.DEV)
}
Información
El objeto ConfigSdk, tiene las constantes necesarias para trabajar sobre ambiente Sandbox.
- Sandbox: ConfigSdk.DEV
Field | Type | Description |
---|---|---|
userNameDefault | String | NetPay user. |
password | String | Password. |
ConfigSdk | String | Environment. |
3. Conectando el dispositivo
Inicializa el objeto connectReader en el método onCreate().
Implementación
connectReader.initialize { result ->
when (result) {
is ConnectDiscoveryState.Started -> {
Toast.makeText(this, "find device started", Toast.LENGTH_SHORT).show()
}
is ConnectDiscoveryState.Found -> {
val device = result.deviceConnected
connectAndCancelFindingDevice(
result.deviceConnected.deviceName,
result.deviceConnected.deviceAddress
)
binding.startTransactionAction.apply {
text = "Iniciar Transacción: ${device.deviceName}"
}
enableButton(binding.startTransactionAction)
Toast.makeText(this, "Device found: ${device.deviceName}", Toast.LENGTH_SHORT).show()
}
is ConnectDiscoveryState.Finished -> {
Toast.makeText(this, "finish finding device", Toast.LENGTH_SHORT).show()
}
}
}
Registra el dispositivo en el método onStart().
Implementación:
override fun onStart() {
super.onStart()
connectReader.registerReceiver()
}
Agrega la función startConnectReaderDevice() e invocala en el método onRequestPermissionResult() una vez que el permiso haya sido concedido.
Implementación:
private fun startConnectReaderDevice() {
connectReader.findAdapterDevices { result ->
if (!connectReader.adapterIsEnabled()) {
startActivityForResult(
connectReader.adapterEnableRequestIntent(),
ENABLE_BT_REQUEST_CODE
)
}
Log.i("FIND ADAPTER MSG", result.message)
}
}
Crea una función para mostrar los resultados de la conexión y llámala durante la inicialización del lector connectReader
Implementation:
private fun connectAndCancelFindingDevice(deviceName: String, deviceAddress: String) {
connectReader.registerDevice(deviceName, deviceAddress)
}
Ejecuta la función connectAndCancelFindingDevice() después de seleccionar el dispositivo.
Field | Type | Description |
---|---|---|
deviceName | String | Nombre de tu dispositivo MINI |
deviceAddress | String | Dirección MAC del lector NetPay MINI |
4. Generando una transacción
Inicializa una transacción con los siguientes datos:
transaction.initialize(
config = ConfigSdk.DEV,
userName = userNameDefault,
password = //contraseña,
requireSignature = false
)
Campo | Tipo | Descripción |
---|---|---|
config | String | Indica el ambiente sobre el cual se estará trabajando. |
userName | String | Nombre de usuario. |
password | String | Contraseña. |
requireSignature | Bool | Indica si el estará habilitada la funcionalidad de solicitar firma digital durante el proceso de cobro, si esta bandera es false significa que el voucher no tendrá la firma digital impresa. |
Implementar el método callback valuesToProcessing(...).
override fun valuesToProcessing(values: (total: Double, tip: Double, reference: String, promotion: String) -> Unit) {
val total = binding.editAmount.text.toString()
val referenceText = binding.editTextReference.text.toString()
val referenceEncoded = encodeString(referenceText)
val promSelected = binding.spinnerPromotion.text.toString()
val promotionSelected = PromotionEnum.values().find { it.text == promSelected }
promotionSelected?.let { values(total.toDouble(), 0.0, referenceEncoded, promotionSelected.value) }
}
Campo | Tipo | Descripción |
---|---|---|
reference | String | Referencia de la transacción. Este valor es generado por el comercio. |
total | Double | Monto total a cobrar (incluyendo propina). |
promotion | String | Indica si la transacción se cobrará a meses sin intereses (3, 6, 9, 12 ó 18). Esto se implementó en el código anterior haciendo uso de una clase Enum. |
tip | Double | Monto de propina. |
Algunas tarjetas pueden tener múltiples aplicaciones, para estos casos, usen el método selectedAppAction().
5. Obteniendo la respuesta de una transacción
El resultado de una transacción será recibido por el método callback **transactionsResult()**.
override fun transactionsResult(message: String, processed: Boolean) {
runOnUiThread {
Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
if (processed) {
Log.d(TAG, "transactionsResult message: $message")
refundLastTransactionId(message.split(":")[1])
binding.editOrderId.setText(message.split(":")[2])
binding.tvResponse.setText(message)
binding.refundAction.setText("Refund: ${message.split(":")[2]}")
}
}
}
Campo | Tipo | Descripción |
---|---|---|
message | String | En caso de una transacción aprobada, aquí se estarán recibiendo el transactionTokenId y el orderId. |
processed | Bool | Indica si la transacción fue exitosa. |
En caso de que no sea recibida la respuesta de una transacción habrá un reverso, esto indica que el resultado de la transacción será mostrado por el método callback reverseResult(). Cuando una transacción se reversa, esta se cancela de forma automática aún cuando haya sido aprobada.
override fun reverseResult(message: String, processed: Boolean) {
runOnUiThread {
Toast.makeText(this, "reverse: $message", Toast.LENGTH_SHORT).show()
}
}
6. Cancelando una transacción
Para poder cancelar una transacción es necesario contar con el transactionId de la transacción.
transaction.processRefund(
transactionId = transactionId
)
Field | Type | Description |
---|---|---|
transactionId | String | Identificador de la transacción generado por NetPay y recibido en la respuesta |
7. Obteniendo la respuesta de una transacción cancelada
La respuesta de una transacción cancelada se recibirá en el método refundResult().
override fun refundResult(message: String, processed: Boolean) {
runOnUiThread {
Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
binding.refundAction.text = "refund: $message"
}
}
8. Visualizando un reporte de ventas
Para consultar un reporte de ventas se debe proporcionar un rango de fechas.
reports.getReportSalesByDateAndUser(
startDate = sdf.format(Date()),
endDate = null,
userId = null
) {
runOnUiThread {
Log.w(TAG, it)
Toast.makeText(this, it, Toast.LENGTH_SHORT).show()
}
}
Field | Type | Description |
---|---|---|
startDate | String | Fecha inicial desde donde se iniciará la búsqueda. Formato admitido: yyyy-MM-dd. |
endDate | String (Opcional) | Fecha final desde donde se terminará la búsqueda. Formato admitido: yyyy-MM-dd. En caso de requerir solo un valor, puede dejar este parámetro con valor null. |
userId | String (Opcional) | Identificador del usuario que realizó la venta. Si es null este método devolvera todas las transacciones. |
9. Obteniendo la respuesta de un reporte de ventas
La respuesta de este servicio regresa un arreglo con la toda la información de las ventas en el rango de fechas dado. Esta respuesta se recibirá en el método reportSalesByDateAndUserResult().
override fun reportSalesByDateAndUserResult(
processed: Boolean,
message: String?,
reportSales: List<ResponseSale>?
) {
Log.i(TAG, "reportSalesByDateAndUserResult")
reportSales?.let {
val resultStr: String = Gson().toJson(reportSales)
binding.tvResponse.text = resultStr
//Gson
//val sales = fromJson(reportSales.report?.valueList, SalesResponseValue::class.java).value
}
message?.let {
Log.i(TAG, "message: $message")
}
}
Ejemplo del objeto JSON recibido.
{
"contentType": "Report",
"resourceName": "ReportSalesByDateAndUser",
"report": {
"valueList": {
"value": [
{
"orderId": "5227220201019144140737",
"transactionId": "1511f0ba-284d-460f-9e33-e66507a96106",
"cardNumber": "9898",
"userId": "36142",
"transTypeCd": "A",
"transStatus": "C",
"transDate": "2020-10-19T14:41:41-0500",
"authCode": "222222",
"amount": "2.00",
"responseCode": "00",
"responseMsg": "Aprobada",
"authDate": "2020-10-19T14:41:41-0500",
"userName": "[email protected]",
"ticketID": "",
"voucherID": "",
"tipAmount": 0.0,
"latitude": 25.654299,
"longitude": -100.215834,
"web": false
}
]
}
},
"response": {
"approved": true,
"responseCode": "00",
"responseMsg": "Aprobada",
"timeIn": "1603301717167",
"timeOut": "1603301717628",
"type": "JSON"
}
}
Campo | Descripción | Tipo | Valor de ejemplo |
---|---|---|---|
orderId | Identificador de la orden, generado por NetPay | String | "5227220201019134607260" |
transactionId | Identificador de la. transacción, generado por NetPay | String | "e4a7844f-95e6-4cc8-ad6d-93960b1f9e7e" |
cardNumber | Últimos 4 dígitos de la tarjeta | String | "9898" |
userId | Identificador del usuario que realizo la venta | String | "36142" |
transTypeCd | Indica el tipo de transacción que fue efecutada | String | "A" - Card "P" - Cash |
transStatus | Estatus de la transacción. | String | "C" - Approved "D" - Rejected "V" - Canceled "RV" - Reversed |
transDate | Fecha en la que se crea la transacción | String | "2020-10-19T13:46:07-0500" |
authCode | Código de autorización del banco | String | "222222" |
amount | Monto total cobrado | String | "200.00" |
responseCode | Código de respuesta | String | "00" - Approved "05" - Rejected |
responseMsg | Mensaje de respuesta | String | "Aprobada" |
authDate | Fecha en la cual fue procesada la transacción | String | "2020-10-19T13:46:08-0500" |
userName | Usuario que realizo la venta | String | "[email protected]" |
tipAmount | Monto de propina cobrado | Double | 10.0 |
latitude | Latitud desde donde se originó la transacción | Double | 25.6714 |
longitude | Longitud desde donde se originó la transacción | Double | -100.309 25 |
10. Visualizando los detalles de una transacción
The sale detail is used to obtain more information about the sale and it is necessary to have a transactionId.
reports.getReportSalesDetail(
binding.editTransaccionId.text.toString()
) {
runOnUiThread {
Log.w(TAG, it)
Toast.makeText(this, it, Toast.LENGTH_SHORT).show()
}
}
Campo | Tipo | Descripción |
---|---|---|
transactionId | String | Identificador de la transacción |
11. Obteniendo la respuesta de los detalles de la transacción
La respuesta será recibida en al método reportSalesByDateAndUserResult().
override fun reportSaleDetailsResult(response: ResponseSaleDetail?, success: Boolean) {
runOnUiThread {
if (!success) {
binding.tvResponse.text = "Ha ocurrido un error"
Log.d("Error Report Mensaje", response.toString())
} else {
val resultStr: String = Gson().toJson(response)
binding.tvResponse.text = resultStr
}
Toast.makeText(this, "Proceso terminado", Toast.LENGTH_SHORT).show()
}
}
Ejemplo del objeto JSON recibido
{
"contentType": "Report",
"resourceName": "ReportSalesDetail",
"order": {
"orderId": "5227220201019174732079",
"transaction": {
"type": "A",
"authCode": "222222",
"transactionId": "c4f9b0d8-8867-4186-827e-ddecbb0074b0",
"merchantId": "7489228",
"total": {
"total": 2.58,
"tip": 0.0
},
"authDate": "2020-10-19T17:47:33-0500",
"transStatus": "C",
"bankName": "SANTANDER",
"cardTypeName": "MASTERCARD",
"cardNature": "D",
"arqc": "3F33B0E72B90BAC5",
"aid": "A0000000041010",
"spanRoute": "8710",
"web": false
},
"cashierId": 36142,
"cashierName": "Farmacias Test ",
"products": [
{
"id": 0,
"amount": 1.0,
"price": 2.58,
"description": "Cobro directo",
"lastUpdateTimestamp": 1559326021000
}
]
},
"report": {},
"response": {
"approved": true,
"responseCode": "00",
"responseMsg": "Aprobada",
"timeIn": "1603300499469",
"timeOut": "1603300509133",
"type": "JSON"
}
}
Campo | Descripción | Tipo | Valor de ejemplo |
---|---|---|---|
merchantId | Identificador de afiliación | String | "7489228" |
bankName | Nombre de la entidad bancaría | String | "SANTANDER" |
cardTypeName | Marca de tarjeta | String | "MASTERCARD" |
cardNature | Naturaleza de la tarjeta | String | "D" - Debit "C" - Credit |
arqc | ARQC | string | "3F33B0E72B90BAC5" |
aid | Application Id. | String | "A0000000041010" |
12. Consultando el voucher de una venta
Para consultar el voucher generado por una venta se debe contar con el orderId.
transaction.getImageVoucher(
orderId = binding.editOrderId.text.toString()
) {
runOnUiThread {
Log.w(TAG, it)
}
}
Campo | Tipo | Descripción |
---|---|---|
orderId | String | Identificador de la orden, generado por NetPay obtenido en la respuesta |
13. Obteniendo la respuesta de la consulta del voucher
La respuesta será obtenido en el método imageResult().
override fun imageResult(processed: Boolean, image: String?, message: String?) {
runOnUiThread {
if (processed) {
image?.let {
binding.tvResponse.text = image
binding.imageVoucher.setImageBitmap(base64ToBitmap(image))
}
} else {
val mesageObj = Gson().fromJson(message, ResponseErrorVoucher::class.java)
Toast.makeText(
this,
"processed: $processed message: ${mesageObj.message ?: "null"}",
Toast.LENGTH_SHORT
).show()
}
}
}
La imágen estará codificada en un string base 64.
Updated 5 months ago