SDK Integration for Vouchers

12. SDK Integration for Vouchers

The integration of an Android device with an SDK for a voucher transaction depends on the voucher used for a transaction. The following is an example of Travel Fund integration with Velocity SDK.

12.1 Travel Fund

Travel Fund (TF) acts as a virtual wallet and stores a customer’s cash refund. The amount is attributed to a PNR as a record locator and an expiry date, which can be retrieved and redeemed using the PNR. Merchants can configure the currencies for which TF is shown as a payment method during a transaction.

When customers select TF to make payment:

  • Travel Fund is shown on the page for making payment.
  • Customers enter their PNR number to know the voucher details such as:
  • Balance amount
  • Currency
  • Expiry date

12.2 Instantiate SDK

See Instantiate SDK for details.

12.3 Initialize Payment for Travel Fund

See Initialize Request for details.

Additionally, send the session token in the initialize payment request. The following code sample shows how to send session token in the initialize-payment request:

var paymentInfo :mPointInitializePaymentInfo
var sessionToken: String // Session Token
…

paymentInfo.addAdditionalData("session_token", sessionToken)

…

mPoint.initialize(paymentInfo)

Add the following in displayAvailablePayments (availablePayments: mPointAvailablePayments?, mpoint: mPoint? method to read voucher cards.

override fun displayAvailablePayments(availablePayments: mPointAvailablePayments?, mpoint: mPoint?) {

if(availablePayments!!.vouchers != null && availablePayments.vouchers.size > 0){
   // Read Vouchers
   }
}

After reading the vouchers, the system can identify voucher as a payment method. To check the balance in the voucher, complete the following steps:

  1. Retrieve TF. To retrieve the TF balance, call the getBalance method shown as follows.
var voucherId: String // 6-digit Booking Ref. No or PNR

var sessionToken: String
var clientInfo: mPointClientInfo 

val getBalanceCriteria = mPointGetBalanceCriteria()
getBalanceCriteria.voucherId = voucherId
getBalanceCriteria.addAdditionalData("session_token", sessionToken)
getBalanceCriteria.clientInfo = clientInfo
mPoint.delegate = this
mPoint.getBalance(getBalanceCriteria)

The previous code sample provides the response for which you need to implement displayBalance method from mPointGetBalanceDelegate interface.

override fun displayBalance(balanceDetails: mPointBalanceDetails?, p1: mPoint?) { 
// balanceDetails instance has properties amount, currency and  expiryDate. Use them to display information about Travel Fund.

}

  1. Redeem TF by using the authorize method. TF redemption has following scenarios:
  • TF amount is more than booking amount- customers can utilize the entire TF amount to pay the booking amount.
  • TF amount is less than booking amount- The UI shows that the balance amount is less than the booking amount and enables customers to make payment using another method. In this case, customers can use split payment method.

12.3.1 Authorize Payment for Voucher

To redeem the voucher, call the authorize method shown as follows:

var voucherId: String // 6-digit Booking Ref. No or PNR

var sessionToken: String

var countryCode: Int
var amount: Long 

var currencyCode:  Int

var clientInfo : mPointClientInfo

var authToken: String
var additionalData: RecordMap<String, String>

var addressInfo: mPointAddressInfo


val travelFundVoucher = mPointTravelFundVoucher()
travelFundVoucher.voucherId = voucherId
travelFundVoucher.amount = PriceInfo(countryCode,amount,
        null, null, null, currencyCode,  -1)

mPoint.authorize(mPointAuthorizeInfo()
        .setClientInfo(clientInfo)
        .setViaAuthToken(true)
        .setPassword(authToken)
        .setVoucherInfo(travelFundVoucher)
        .addAdditionalData(additionalData)
        .setAddressInfo(addressInfo))

12.4 Display Payment Confirmation

Implement the displayPaymentConfirmation callback method to receive confirmation of payment as shown in the following sample:

override fun displayPaymentConfirmation(txnInfo: mPointTxnInfo?, code: Int, mpoint: mPoint?) {
}

12.5 Split Payment

If the retrieved TF amount is less than the booking amount, the customer can opt to split the payment.
The payment can be split with the Card & Travel Fund balance. The customer can pay the remaining amount by card after the redemption of the TF balance.

If FX is enabled on the selected card for split payment, then the FX flow execution remains the same.

12.5.1 Authorize Payment for Card and Voucher

Call authorize method as shown below to pay using split option.

var voucherId: String // 6-digit Booking Ref. No or PNR

var sessionToken: String

var countryCode: Int
var travelFundBalanceAmount: Long   // Travel Fund Balance to be redeemed
var cardPendingAmount: Long   // Remaining Balance to be paid through card payment

var currencyCode:  Int

var clientInfo : mPointClientInfo

var authToken: String
var additionalData: RecordMap<String, String>

var addressInfo: mPointAddressInfo
var cardType: mPointCardInfo
var cardNumber: Long
var expMonth: Int

var expYear: Int

var cvv: String

var cardName: String 

var validFromExpMonth: Int

var validFromExpYear: Int

var isSaveCard: Boolean

var foreignExchangeInfo: mPointForeignExchangeInfo




// Voucher
var travelFundVoucher = mPointTravelFundVoucher()
    travelFundVoucher.voucherId = voucherId
 travelFundVoucher.amount = PriceInfo(countryCode, travelFundBalanceAmount, null, null, null, currencyCode,  -1)
}

// Card - Pending Amount
var priceInfo: PriceInfo? = null
    priceInfo = PriceInfo(countryCode, cardPendingAmount, null, null, null, currencyCode,  -1)



mPoint.authorize(mPointAuthorizeInfo(cardType)
        .setClientInfo(clientInfo)
        .setViaAuthToken(true)
        .setPassword(authToken)
        .setVoucherInfo(travelFundVoucher)
        .addAdditionalData(additionalData)
        .setCardNo(cardNumber)
        .setCardExpMonth(expMonth)
        .setCardExpYear(expYear)
        .setCvc(cvv)
        .setNameOnCard(cardName)
        .setCardValidFromMonth(validFromExpMonth)
        .setCardValidFromYear(validFromExpYear)
        .setStoreCard(isSaveCard)
        .setForeignExchangeOffer(foreignExchangeInfo)
        .setAddressInfo(addressInfo)
        .setPendingSplitAmount(priceInfo))

12.5.2 Authorize Payment for APM and Voucher

var mPointSplitCombination: mPointSplitCombination? = null
 
// Voucher
val travelFundVoucher = mPointTravelFundVoucher()
if(remainingBalanceToBePaidByTravelFund > 0)
{
    travelFundVoucher.voucherId = etBookingReferenceNumber.text.toString()
    travelFundVoucher.amount = PriceInfo(AppConstants.getCountryCode(country),
    (((remainingBalanceToBePaidByTravelFund.toFloat()) * getDecimalPointMultiplierFromCurrencyId(currencyCode)).roundToLong()),
    null, null, null, currencyCode,  -1)
}
 
// APM - Pending Amount
var priceInfo: PriceInfo? = null
if(remainingBalanceToBePaidByAPM > 0)
priceInfo = PriceInfo(AppConstants.getCountryCode(country),
    (((remainingBalanceToBePaidByAPM.toFloat()) * getDecimalPointMultiplierFromCurrencyId(currencyCode)).roundToLong()),
    null, null, null, currencyCode,  -1)
                
                
for(splitCombination in this.splitPayment!!.splitCombinations){
    for(paymentType in splitCombination.paymentType){
        if(paymentType.id == paymentTypeId){
            mPointSplitCombination = splitCombination
        }
    }
}                
 
mPoint.authorize(mPointAuthorizeInfo(cardType)
    .setActivity(this)
    .setAddressInfo(addressInfo)
    .setClientInfo(clientInfo)
    .setAuthToken(authToken)
    .setForeignExchangeOffer(fxInfo)
    .setPendingSplitAmount(priceInfo)
    .setVoucherInfo(travelFundVoucher)
    .addAdditionalData(additionalData)
    .setSplitCombinations(mPointSplitCombination))

12.5.3 Authorize Payment for eWallet and Voucher

var mPointSplitCombination: mPointSplitCombination? = null
 
// Voucher
val travelFundVoucher = mPointTravelFundVoucher()
if(remainingBalanceToBePaidByTravelFund > 0)
{
    travelFundVoucher.voucherId = etBookingReferenceNumber.text.toString()
    travelFundVoucher.amount = PriceInfo(AppConstants.getCountryCode(country),
    (((remainingBalanceToBePaidByTravelFund.toFloat()) * getDecimalPointMultiplierFromCurrencyId(currencyCode)).roundToLong()),
    null, null, null, currencyCode,  -1)
}
 
// eWallet- Pending Amount
var priceInfo: PriceInfo? = null
if(remainingBalanceToBePaidByWallet> 0)
priceInfo = PriceInfo(AppConstants.getCountryCode(country),
    (((remainingBalanceToBePaidByWallet.toFloat()) * getDecimalPointMultiplierFromCurrencyId(currencyCode)).roundToLong()),
    null, null, null, currencyCode,  -1)
                
                
for(splitCombination in this.splitPayment!!.splitCombinations){
    for(paymentType in splitCombination.paymentType){
        if(paymentType.id == paymentTypeId){
            mPointSplitCombination = splitCombination
        }
    }
}                
 
mPoint.authorize(mPointAuthorizeInfo(cardType)
    .setActivity(this)
    .setAddressInfo(addressInfo)
    .setClientInfo(clientInfo)
    .setAuthToken(authToken)
    .setForeignExchangeOffer(fxInfo)
    .setPendingSplitAmount(priceInfo)
    .setVoucherInfo(travelFundVoucher)
    .addAdditionalData(additionalData)
    .setSplitCombinations(mPointSplitCombination))

12.6 Display Payment Confirmation

Implement the displayPaymentConfirmation callback method to receive confirmation of payment as shown in the following sample.

override fun displayPaymentConfirmation(txnInfo: mPointTxnInfo?, code: Int, mpoint: mPoint?) {
}

When using split payment option and after getting callback in displayPaymentConfirmation, you need to call getTxnStatus method to retrieve status of the transactions. When calling the getTxnStatus, pass session ID (available in mPoint class) to retrieve all transactions from the current session.

To call getTxnStatus, use the following code sample:

if(isSplitPaymentApplicable){
    	if(mpoint!!.sessionId != null && mpoint.sessionId.isNotEmpty()){
   		mPoint.delegate = this
mPoint.getTxnStatus(-1, "", mpoint.sessionId, clientInfo)
  	  }
}

To get transaction statuses response implement following delegate method:

override fun handleTxnStatus(arrListTxnStatusInfo: ArrayList<mPointTxnStatusInfo>?, paymentStatus: Int, arrListLinkedTransactions: ArrayList<mPointLinkedTransactions>?, mPoint: mPoint?) {
        when (paymentStatus) {
           MPOINT_PAYMENT_STATUS_PENDING.id -> // Payment is Pending
           MPOINT_PAYMENT_STATUS_COMPLETE.id -> // Payment is Successful
           MPOINT_PAYMENT_STATUS_FAILED.id -> { // Payment is Failed
                        var pendingAmount: Long = 0
                        if(null != arrListTxnStatusInfo && arrListTxnStatusInfo.size > 0){
                        for (txnStatusInfo : mPointTxnStatusInfo in arrListTxnStatusInfo){
                                // Retrieve Pending Amount
                                pendingAmount = txnStatusInfo.pendingAmount
                            }
                        }
                      }
    }

The merchant front end reads the response received to know the payment status. Read the paymentStatus parameter to know the status of the payment. If a transaction status has payment status as:

  • Pending: call the getTxnStatus API again till you get the payment status either as Successful or Failed.
  • Complete: the payment is successful.
  • Failed: retry the payment.

To retry the payment, initialize the payment with the pending amount. This helps a customer complete the payment using any option.

Send the pending amount you received from back end in the initialize request. After you initialize, a customer can complete the payment using any available payment option or can split the payment. This process repeats until the transaction is successful, fails, or maximum retry is attempted.

Note: If a customer decides not to retry a failed payment, call the Post-Status API as shown in the following code sample to notify that the session is complete.

mPoint.postStatus(mPoint.sessionId

12.7 Handle Error

When using the split payment option, after getting callback in displayPaymentConfirmation you need to call getTxnStatus method to retrieve status of the transactions. When calling the getTxnStatus pass session ID (available in mPoint class) to retrieve all transactions from the current session. To call getTxnStatus, use the following code sample:

if(isSplitPaymentApplicable){
    	if(mpoint!!.sessionId != null && mpoint.sessionId.isNotEmpty()){
   		mPoint.delegate = this
              mPoint.getTxnStatus(-1, "", mpoint.sessionId, clientInfo)
  	  }
}

To get transaction statuses response implement following delegate method:

override fun handleTxnStatus(arrListTxnStatusInfo: ArrayList<mPointTxnStatusInfo>?, paymentStatus: Int, arrListLinkedTransactions: ArrayList<mPointLinkedTransactions>?, mPoint: mPoint?) {
 
            runOnUiThread {
                var pendingAmount: Long = 0
 
                if(null != arrListTxnStatusInfo && arrListTxnStatusInfo.size > 0){
                    for (txnStatusInfo : mPointTxnStatusInfo in arrListTxnStatusInfo){
                        // Retrieve Pending Amount
                        pendingAmount = txnStatusInfo.pendingAmount
                    }
                }
 
                when (paymentStatus) {
                    com.cellpointmobile.sdk.mPoint.PAYMENT_STATUS.MPOINT_PAYMENT_STATUS_PENDING.id -> 
                    // Poll getTxnStatus()
                    getTxnStatus(mPoint!!.sessionId)
                    com.cellpointmobile.sdk.mPoint.PAYMENT_STATUS.MPOINT_PAYMENT_STATUS_COMPLETE.id -> {
                        if(pendingAmount == 0L)
                            // Split Payment Successful
                        else
                            // Retry Payment with Pending Amount
                    }
                    com.cellpointmobile.sdk.mPoint.PAYMENT_STATUS.MPOINT_PAYMENT_STATUS_FAILED.id -> {
                        // Retry Payment with Pending Amount
                    }
                }
            }
    }  

The merchant front end reads the response received to know the payment status. Read the paymentStatus parameter to know the status of the payment. If a transaction status has payment status as:

  • Pending: call the getTxnStatus API again till you get the payment status either as Successful or Failed.
  • Complete: the payment is successful.
  • Failed: retry the payment.

To retry the payment, initialize the payment with the pending amount. This action helps a customer complete the payment using any option.

Send the pending amount you received from back end in the initialize request. After you initialize, a customer can complete the payment using any available payment option or can split the payment. This process repeats until the transaction is successful, fails, or maximum retries are attempted.

Note: If a customer decides not to retry a failed payment, call the Post-Status API as shown in the following code sample to notify that the session is complete:

mPoint.postStatus(mPoint.sessionId)

Refer to Handle Error for details.

12.8 Handle Status

Refer to Handle Status for details.

Note: You should verify in handle status method if the customer is trying to make a payment using split payment. If yes, you should give a call to getTxnStatus method with session ID. See the example code sample below.

if(isSplitPaymentApplicable){
    if(statusInfo!!.sessionId != null && statusInfo.sessionId.isNotEmpty()){
   	
        mPoint.delegate = this
  mPoint.getTxnStatus(-1, "", statusInfo.sessionId, clientInfo)

  	  }
}
To get transaction statuses response implement handleTxnStatus delegate method and repeat the same steps as mentioned above in handleTxnStatus method.