Skip to content

Hubtel POS SDK Documentation

The Hubtel POS SDK comprises a suite of packages that collectively facilitate point-of-sale terminal transactions on All-In-One devices.

The SDK is organized in 3 layers. And each layer of the SDK is designed to deliver a unique set of functionalities, ensuring a comprehensive and efficient handling of point-of-sale terminal transactions in the apps requiring these capabilities such as the Bank POS app.

OBJECTIVES

The primary objective of this SDK is to isolate all Point-Of-Sale (POS) hardware-related functionality, thereby ensuring complete separation from product applications.

Through this segregation, it is hoped that the product team can innovate freely within their product apps, without worrying about the performance of the POS-hardware.

Similarly, the segregation would also encourage research and innovation in the tooling aspect of the project.

FUNCTIONALITY

The Hubtel POS SDK offers two primary functionalities to its dependencies:

  • First, process card payments.
  • And second, generate receipts for all transactions.

To process card payments, the card must be read, its data extracted, interpreted, and the order processed by the SDK. Rephrased, at the highest level, the SDK primarily handles payment processing. However, beneath this surface, the SDK performs many more tasks.

For receipt generation, the SDK provides a receipt creator that generates any type of printable document, which is then passed to the SDK for printing processing.

SDK LAYERS

As pointed out previously, the Hubtel POS SDK is structured across three layers:

  • The PUB-API (Public API)
  • The DEV-API (Device API)
  • The SHARED-API (Shared Module API)

The PUBLIC API (PUB-API)

The PUB-API is the hubtel-pos-sdk module in the Platform-App-Android-Hubtel-Library project. The module is a public api that exposes the basic functionalities that are required of the SDK.

Primarily, the module exposes an init() method, and a PosDevice property.

The init() initialises the SDK, it is recommended to invoke this method very early in app startup processes.

The PosDevice property is appropriately named posDevice. PosDevice is an interface that defines a card processor, a printer, serial number and device type.

Each of these shall be discussed in detail in the SHARED-API section of this documentation.

kotlin
interface PosDevice {
    val cardProcessor: POSDeviceProcessor
    val cardPrinter: POSPrinter
    val serialNumber: String
    val deviceType: PosDeviceType
}

The cardProcessor exposes a start(chargeInfo: ChargeInfo), cancel() methods and cardProcessListener property.

  • The start() method initiates and processes payments.
  • The cancel() method terminates all active card transaction processes.
  • The cardProcessListener monitors the progress of the transaction. These events can be monitored to facilitate communication between the SDK and the dependent application. The snippet below illustrates how this property can be utilized:
kotlin
LaunchedEffect(cardProcessor.cardProcessListener) {
    cardProcessor.cardProcessListener.collect { result: CardProcessResult ->
        when (result) {
            is CardProcessResult.Message -> {
                message = result.value
            }

            is CardProcessResult.BasicInformation -> {
                val cardHolderName = result.cardHolderName
                val cardNumber = result.maskedCard
                val cardExpiryDate = result.expiryDate
                val entryMode = result.entryMode
            }

            is CardProcessResult.PaymentCompleted -> {
                val message = "Payment successfully."
            }

            is CardProcessResult.Error -> {
                val errorMessage = result.message
            }

            is CardProcessResult.Cancel -> {
                val message = "User cancelled transaction"
            }

            is CardProcessResult.OnKeyPressed -> {
                val pin = result.data
            }

            else -> {}
        }
    }
}

The cardPrinter, on the other hand, exposes a print(creator: ReceiptCreator) method that facilitates receipts generation.

The serialNumber property returns the serial number of the device.

The deviceType property returns the device on which the SDK is running e.g. JTact, Z90, and PAX. These are enum values defined in PosDeviceType of the SHARED-Module API.

Below is a snippet demonstrating how the HubtelPOSKit can be used to access these methods and properties:

kotlin
val posDevice = HubtelPOSKit.posDevice
val posDeviceType: PosDeviceType = HubtelPOSKit.posDevice.deviceType
val cardProcessor = posDevice.cardProcessor
val cardPrinter = posDevice.cardPrinter
val serialNumber = posDevice.serialNumber

ADDING A DEVICE TO THE SDK

In addition, the HubtelPOSKit has a private getCurrentDevice(context: Context): PosDevice method that takes context and returns a PosDevice.

To add a new device to the SDK, the DEV-API (Device API) must be defined in the devices layer. Next, this getCurrentDevice method should be modified to be able to return the new device. Following are the devices currently defined:

kotlin
private fun getCurrentDevice(context: Context): PosDevice {
    return when (getPOSManufacturer()) {
        POSManufacturer.BLU_Z90 -> Z90Device(context)
        POSManufacturer.JTACT_V56 -> JTactDevice(context)
        else -> error("No supported device found.")
    }
}

To add a new device, say, RJ_45, the method would have to be updated to be like so:

kotlin
private fun getCurrentDevice(context: Context): PosDevice {
    return when (getPOSManufacturer()) {
        POSManufacturer.BLU_Z90 -> Z90Device(context)
        POSManufacturer.JTACT_V56 -> JTactDevice(context)
        POSManufacturer.RJ_45 -> RJ45Device(context)
        else -> error("No supported device found.")
    }
}

Now, if the SDK is launched on a RJ_45 device, it should run smoothly without any issues.

The SHARED-API (Shared Module API)

The SHARED-API represents the shared module within the Platform-App-Android-Library project. This module houses the fundamental classes and methods that underpin the APIs for all devices within the library. This section delves into the detailed components of the SHARED-API.

The SHARED-API is structured around several core packages, which include:

  • card_delegates (com.hubtel.pos.shared.card_delegates)
  • device (com.hubtel.pos.shared.device)
  • network (com.hubtel.pos.shared.network)
  • printer (com.hubtel.pos.shared.printer)
  • resources (com.hubtel.pos.shared.resources)
  • utils (com.hubtel.pos.shared.utils)

The device Package

The device package encapsulates the definitions for POSDevice, POSDeviceProcessor, and POSPrinter interfaces.

The POSDeviceProcessor interface outlines two key methods: start(chargeInfo: ChargeInfo) and cancel(), along with a property cardProcessListener of type Flow<CardProcessResult>.

Within the Device API, this interface is implemented by specific device classes, which are responsible for tailoring the implementation to the unique characteristics of each device.

Following is an example how a Z90 device would implement this interface:

kotlin
class Z90Device(private val context: Context) : PosDevice {

    private val system by lazy {
        DriverManager.getInstance().baseSysDevice
    }

    override val cardProcessor: POSDeviceProcessor = Z90Processor(context)

    override val cardPrinter: POSPrinter = Z90Printer()

    override val serialNumber: String
        get() = ...

    override val deviceType: PosDeviceType
        get() = PosDeviceType.Z90


    init {
        Z90Utils.initZ90Device(context, system)
    }

}

The POSDevice interface is a mandatory component of the Device API, and the naming convention for the implementing class typically reflects the device model or name, appended with Device. Examples include Z90Device, JTactDevice, and PAXDevice.

Each device class implementation is anticipated to initialize the device within its constructor, setting properties such as init{}, serialNumber: String, deviceType: PosDeviceType, cardProcessor: POSDeviceProcessor, and cardPrinter: POSPrinter.

The PosDeviceType is a Kotlin enum class that enumerates all the devices compatible with the library.

The deviceType: PosDeviceType property was introduced upon the request of the Product Team.

kotlin
enum class PosDeviceType {
    Z90,
    JTACT,
    PAX
}

The POSPrinter interface defines a print(creator: ReceiptCreator) method that must be implemented by the Device API like so:

kotlin
class Z90Printer : POSPrinter {
    override suspend fun print(creator: ReceiptCreator): Unit =
        suspendCoroutine { continuation ->
    }
}

class JTactPrinter : POSPrinter {
    override suspend fun print(creator: ReceiptCreator): Unit =        suspendCoroutine { continuation ->
    }
}

The POSManufacturer enum class serves as a definitive source for identifying the model of a device and its associated list of identifiers, which typically include processor names. This enumeration is instrumental in distinguishing between various device models within the system.

The DeviceUtils file includes a function named getPOSManufacturer(). This function is pivotal in determining the manufacturer of the device currently in use. When combined with the getCurrentDevice(context: Context) method from the HubtelPOSKit, it plays a crucial role in initializing the device with the correct configuration and settings.