Getting started with App 2 App Integration
EasyPOS Integration Guidelines for Sunmi P2 Devices
Introduction
This document explains the steps required to integrate Partner applications with the CM POS Payments App-2-app integration solution. This integration is based on the usage of the CM POS Payments SDK and Terminal app on an Android based Sunmi payment device.
In order to be able to use this library, the integrator has the possibility to choose between the following flavours:
-
Developing a pure native Android app that will include the library as dependency to start transactions and other operations on CM POS Payments gateway.
-
Developing a hybrid Android app that uses Web Views, of which the native part of the app will include the CM POS Payments Android POS integration library to start transactions and other operations on CM POS Payments gateway.
At this point in time, CM POS Payments does not support the SDK to be called from a browser running on the payment terminal.
Terminology
Term | Description |
---|---|
App-2-app integration | Integration between two applications, namely Partner and CM POS Payments Terminal application, which are on the same Sunmi device |
CM POS Payments Android POS integration SDK | Android library that can be used in Partner applications to integrate with CM POS Payments apps and perform payment transactions. |
CM POS Payments Terminal application | Android based application which calls the CM POS Payments Gateway to process the payment |
Development Sunmi Payment device | Sunmi device that is used for development purposes and testing the application integration |
ECR | Electronic Cash Register, and in the context of this document the ECR will be an Android based app providing the ECR features. |
Partner application | Android based application developed by the partner integrating with CM POS Payments payment solution for payment acceptance |
Sunmi | Payment terminal device manufacturer of the Sunmi P2 payment terminals. |
App-2-app integration is supported by all CM provided Sunmi mobile devices (Sunmi P2 Pro, Sunmi P2 Lite, Sunmi P2 Mini).
Download the CM POS Payments apps
The following steps describe how to download the CM POS Payments Terminal application for the Development Sunmi Payment device. Once you have performed the Development activities as described in chapter 5, you can verify that the payment flow performs as expected with the Partner application.
Step | Reference visual |
---|---|
Click ‘App Store’ on your Sunmi device | |
Choose and install the Terminal app | |
You are done! |
Dependencies between library and Terminal version
Terminal version is the minimum version needed to use each version of the Integration SDK
Integration Library version | Terminal version | Changelog |
---|---|---|
1.0.0 | 1.1.0 | Initial version |
1.0.1 | 1.1.1 | Forward auto timezone not enabled error |
1.1.0 | 1.2.0 |
|
1.1.2 | 2.0.0 | Fix crash in some edge cases |
1.1.3 | 2.0.1 |
|
1.1.4 | 2.7.0 |
|
Payment solution overview
This chapter provides an overview of the required applications and how they work together as a payment solution. The transaction flow is described step by step.
Partner application, payment library and Terminal application
The App-2-app integration for the Sunmi Android platform consists of two applications and one library:
-
The Partner application: Android based application developed by the partner integrating with CM POS Payments payment solution for payment acceptance
-
The CM POS Payments Terminal application: handling card entry and the payment flow. It can perform payments and refund transactions. Also handles receipts for transactions.
-
The CM POS Payments Android POS integration library: provides functionality to handle transactions on the gateway. It requests transaction data to Partner application and forwards it to the terminal application. It also provides functionality to get information about old transactions and other info that may be useful for integrators, such as current currency code used by terminal app.
Partners need to have their Android app running on the same physical device as the CM POS Payments Terminal application and include the CM POS Payments Android POS integration library as a dependency on their app.
Transaction Flow
In this section we explain how the Partner application initiates a transaction and we describe both the transaction flow through the terminal application and the interactions between it and the user.
The basic functioning of the Integration library is that Partner Applications can send the transaction request (doTransaction()
method on the Integration service class inside the Integration library) together with the call-back object. Once the result of the transaction is received, the library will trigger the appropriate call-back method.
A transaction starts with the merchant entering an amount. The device is then handed over to the cardholder, who presents their card, authorizes the transaction, and receives the transaction outcome. The device is then handed back to the merchant and, if needed, receipts are printed.
Transition between applications is seamless and the entire flow appears as if it is handled by the ECR application alone. This is done thanks to the integration library which integrates the call to the terminal application within partner’s application context.
Also, it is important to mention that transaction flow in Terminal application does not manifest itself to the user in any way. When Terminal app is opened from the launcher screen it starts some functionality checks, such as terminal configuration availability, correct keys on device, network connection and gateway availability, and after those checks are finished, a banner advising the user to switch to an ECR application (In this case, the partner application) is displayed.
It is important to point out that while the Terminal application UI is visible during a transaction, it is not possible to interact with the Partner application.
You can also see on the diagram that sdk takes into account the possibitlity that the terminal app or device can crash by any reason. In that case, Partner App should request the status of the transaction to be certain about the result of the operation. (see "Dealing with unexpected scenarios" chapter)
I18n and language negotiation
The default language in which the user interface is presented by the CM POS Payments application is the language configured in the shop configuration in the Gateway. It is expected that the partner application does the same.
The CM POS Payments application will switch to the cardholder preferred language if suggested by the EMV card and if the translation into this language exists. The CM POS Payments application will switch language, if applicable, after the language setting on the card has been read.
It is the responsibility of the partner application developers to make their application support the languages they want to use.
If the partner wants to override the language set for the shop, they can provide a language code to the CM POS Payments applications. The CM POS Payments applications will use that language, provided it is supported by our applications. If a language code is provided that is not supported by CM POS Payments, our applications will default to the English language.
Development Guidelines
This section explains how your app communicates with the CM POS Payments applications.
A card payment goes through the following flow:
-
The Partner application uses the CM POS Payments Android POS integration library to start a transaction with the appropriate data (transaction type, amount, currency…).
-
The CM POS Payments POS Payments Terminal application receives the information thanks to the integration library and calls the CM POS Payments POS Payments Gateway to process the payment.
-
CM POS Payments POS Payments Android POS integration library receives the transaction result from Terminal app and send it back to the Partner applications using a call-back. The result consists of a result data and the receipts for the transaction (if any) from the Gateway.
-
The Partner application performs the transaction result and provides printer receipts.
Integration Mechanism
In order to pass data to the CM POS Payments app, the Partner app needs to use the CM POS Payments Android POS integration library methods and wait for a result. To be able to use these methods, Partner application need to include the library as a dependency in the code. Integration library can be used to integrate in two different environments: development and production. You should include the correct dependency for the correct environment in which you are operating. The usage of the debug version allows registered developers to use our development environment which offers simulators for various test scenarios. A complete working example app is available at Github, to give you a head start in integrating with the SDK.
Import Integration SDK as a dependency
Code Sample. add jitpack repository to your main build or settings gradle file
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
google()
mavenCentral()
maven { url 'https://jitpack.io' }
}
}
Code Sample. dependency for production environment
dependencies {
...
// CM POS Payments Android POS Integration library
implementation 'com.github.cmdotcom.android-pos-integration-sdk-
kotlin:androidposintegrationsdk:<version-tag>'
}
Code Sample. dependency for development environment
dependencies {
...
// CM POS Payments Android POS Integration library
implementation 'com.github.cmdotcom.android-pos-integration-sdk-
kotlin:androidposintegrationsdk-debug:<version-tag>'
}
Please note: the "-debug" SDK will connect to our test environment, whereas the SDK without "-debug" in the name will connect to our production environment. The difference between the two environments:
-
Test environment: payments are simulated
-
Production environment: payments are real
It is the responsibility of the integrator to be able to produce two different builds of the same application, one for each environment that is targeted. <version-tag> should be change for the correct version number available in release notes
Creating a signed APK according to Sunmi Requirements
The APK needs to support the Android V1 and V2 signature. The Android build.gradle configuration automatically compiles signingConfigs and V1, V2 signing. For Sunmi applications both signatures need to be turned on, otherwise the APK upload in the MDM will fail.
android {
...
signingConfigs {
...
release {
...
v1SigningEnabled = true
v2SigningEnabled = true
}
}
Finally, in the AndroidManifest.xml, the option extractNativeLibs needs to be set to true:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="....">
...
<application
android:extractNativeLibs="true"
...>
...
</application>
</manifest>
Import Integration SDK as a binary
-
Download the desired .aar file from releases
-
Place the downloaded file into your project. We recommend create a folder called 'lib' near 'src' folder of the app module.
-
Add the import in your build gradle file:
dependencies {
[...]
// CM POS Payments Android POS Integration library
implementation files('lib/<aar_file_name>')
}
Once this is done, your application should initialize the application with your android context application so CM POS Payments library can communicate with CM POS Payments Terminal application:
Code Sample. Initialization of CM POS Payments Android POS integration library.
override fun onCreate() {
super.onCreate()
AndroidPosIntegration.init(this)
}
Once you have done this you can access the PosIntegrationService instance in your code by using the getInstance
method of the AndroidPosIntegration
object in CM POS Payments Android POS Integration Library
Code Sample. Getting the CM POS PaymentsPaymentService instace.
val service = AndroidPosIntegration.getInstance()
This PosIntegrationService has a list of methods that can be used to perform operation in CM POS Payments environment. The methods are the following:
interface PosIntegrationService {
fun doTransaction(data: TransactionData, callback:TransactionCallback)
fun transactionStatuses(data: RequestStatusData, callback:StatusesCallback)
fun getLastReceipt(options: LastReceiptOptions, callback:ReceiptCallback)
fun getTerminalDayTotals(options:DayTotalsOptions, callback: ReceiptCallback)
fun getTerminalInfo(callback: TerminalInfoCallback)
fun finishPreAuth(data: PreAuthFinishData, callback:TransactionCallback)
}
doTransaction: Is used to perform a transaction on CM POS Payments app.
transactionStatuses: It is used to request status of a previous transaction performed by CM POS Payments Terminal app.
getLastReceipt: It is used to request the receipt of the last transaction performed by Terminal application.
getTerminalDayTotals: It is used to request the totals information from the gateway.
getTerminalInfo: It is used to request information about the merchant shop in which the terminal is connected.
finishPreAuth: It is used to finish a previously pre authorized transaction.
Passing data to the library for Transaction flow
Data can be passed to the CM POS Payments Android POS Integration library by using a payment object with the appropriate data.
Code Sample. Transaction Data.
data class TransactionData(val type: TransactionType,
val amount: BigDecimal,
val currency: Currency,
val orderReference: String) {
var language: String? = null
var refundStan: String? = null
var refundDate: Date? = null
var isCaptureSignature = true
var isShowReceipt = true
}
Values for the payment data attributes are specified following this table;
Attribute Name | Data Type/ Class | Required | Default |
---|---|---|---|
type | com.cm.androidposintegration.enums.TransactionType Three options. | Mandatory | |
amount | BigDecimal | Mandatory | |
currency | java.util.Currency | Mandatory | |
orderReference | String(max 14) | Mandatory | |
language | String(2) | Optional | System Language |
refundStan | String(6) | Optional | |
refundDate | java.util.Date | Optional | |
isCaptureSignature | boolean | Optional | true |
isShowReceipt | boolean | Optional | true |
Attributes explanation
type is a field in which you can specify the type of transaction that you want to use. An Enum is defined on the integration library so partners can choose between payment, refund or pre authorization.
amount is the transaction (payment or refund) amount. It is mandatory. It is represented as a BigDecimal including the decimal separator. For example, an amount in euro’s is represented as "12,34", twelve euros and thirty four cents.
currency is a java.util.Currency object and indicates the currency in which the transaction will be performed. There is a merchant shop configuration present on the gateway. This configuration contains the store currency among other parameters. Partners can retrieve that currency using the getInfo operation present on the library. CM POS Payments terminal app can perform a transaction using a different currency from the default one, although in some cases that is not recommended (See ref for details).
orderReference is a mandatory string of up to 14 characters. You are free to put in any text. The CM POS Payments app will return your order reference in the receipt lines (see recovery procedure). Transactions are not accepted in case the order reference is not present in the intent. Order reference needs to have a unique ID per POS for each transaction and date. Order reference may contain a maximum of 14 alphanumeric characters without special characters.
laguante is specified as a two-character string that represents a valid Locale language. Should be set using ISO-639-1 Code ("EN" for English, "NL" for Dutch, …) We currently support English, French, Dutch, German and Spanish. If you need other languages, please contact us. Language is configured in the merchant shop configuration in the Gateway. Only specify a language via the Intent if you need a language different from what is configured in the Gateway for your shop.
refundStan It is a String up to 6 characters. It represents the system trace audit number. It is only used for refund transactions and it can be found on the receipt for the previous transaction that has to be refunded
transactionDate is the date and time of the transaction. It is a java.util.Date object representing the date of the previous transaction. It is only used for refund transactions.
isCaptureSignature is a Boolean, indicating whether the Terminal application should perform on-screen signature capture for signature CVM transactions. When set to true and the transaction CVM is signature, the Terminal application will ask the user to sign on screen and send the signature back on the receipt to the partner application as a bitmap (see receipt handling on library for more details). This is the default behaviour. Partners can override that behaviour by setting this attribute to false.
isShowReceipt Indicates if the receipt(s) need(s) to be shown in CM POS Payments Terminal app. Default value is true, so terminal is always showing the receipts. Partners can override that behaviour by setting that attribute to false.
Example of Transaction PaymentData object that can be used for the transaction:
-
Transaction type: purchase
-
Value: 5.95€
-
Currency: EUR
-
Order reference: 0303-000112
Code Sample. Transaction Data object creation for Payment Transaction
val data = TransactionData(TransactionType.PURCHASE, BigDecimal(5.95), Currency
.getInstance("EUR"),"0303-000112")
Transactions of type "Refund"
There are two possibilities when a refund transaction is sent as Transaction Type on the Transaction object: Standard refund transaction and STAN/TX refund transaction.
In the first case, no other information is required and the refund transaction will be performed with the amount sent.
In the second case, STAN and Transaction date information linked to a previous transaction, need to be provided to CM POS Payments application in the following form:
TRANSACTION_STAN: string (6 characters. 6 STAN digits from the previous transaction) TRANSACTION_DATE: string (8 characters with the following format: “dd/MM/yy”)
If the transaction type received by CM POS Payments app is "refund" and no other related information - like the STAN and transaction date - is present on the transaction object, the refund will be processed as standard refund flow. If transaction type is refund and STAN and Transaction date are present, refund flow will be linked to a previous existing transaction. If only one of the STAN and TX Date is present, an error will be returned by CM POS Payments Terminal app.
Example of Transaction Data object for a Refund transaction
-
Transaction type: refund
-
Value: 5.95€
-
Currency: EUR
-
Order reference: 0303-000113
-
STAN of previous transaction: 065987
-
Date of previous transaction: February 1st, 2021
Code Sample. Transaction Data object creation for Refund Transaction
val data = TransactionData(
TransactionType.REFUND,
BigDecimal(5.95),
Currency.getInstance("EUR"),
"0303-000113"
)
data.refundStan = "065987" // Can be found on the receipt
val dateFormat = SimpleDateFormat("dd/MM/yy")
data.refundDate = dateFormat.parse("01/02/21") // Can be found on the receipt
Transactions of type Pre Auth
Support of pre-authorization transactions is dependent on the acquirer that is used. Please contact sales to find out which acquirers are supported.
CM POS Payments payment system supports also the functionality to pre authorize a transaction and confirm it or cancel it afterwards. In order to pre authorize a transaction, the method doTransaction
can be used with the transaction type of the TransactionData
object set to PRE_AUTH
Code Sample. Transaction Data object creation for Pre Auth. Transaction
val data = TransactionData(
TransactionType.PRE_AUTH,
BigDecimal(5.95),
Currency.getInstance("EUR"),
"0303-000113"
)
Finishing a pre authorized transaction
A transaction that has been pre authorized then needs to be finished at some point in time. To do that, the POS integration library has a method that can confirm or cancel a previosly pre authorized transaction. This method receives a PreAuthFinishData object with the corresponding information to confirm or cancel a pre authorized transaction.
Finish pre authorization transaction
Same as with a doTransaction
operation, IntegrationLirary needs to receive the data for the operation and a transaction callback to send the result once it is has been received from CM POS Payments Terminal app.
The data class used for this operation is PreAuthFinishData. This class contains the following information:
Code Sample. PreAuhtFinishData class.
class PreAuthFinishData(val type:PreAuthFinishType, val originalStan: String,
val originalDate: Date, val orderRef: String) {
var amount: BigDecimal? = null
var currency: Currency? = null
var isShowReceipt: Boolean = true
}
Values for the payment data attributes are specified following this table;
Attribute Name | Data Type/ Class | Required | Default |
---|---|---|---|
type | com.cm.androidposintegration.enums.PreAuthFinishType | Mandatory | |
originalStan | String | Mandatory | |
originalDate | String | Mandatory | |
orderRef | String | Mandatory | |
amount | BigDecimal | Conditional | |
currency | Currency | Conditional | |
isShowReceipt | Boolean | Mandatory | true |
Atributes explanation
type: There are two possible values for this attribute SALE_AFTER_PRE_AUTH
and CANCEL_PRE_AUTH
.
originalStan: It is the stan of the previously pre authorized transaction
originalDate: It is the date of the previously pre authorized transaction
orderRef: It is the order reference use to identify the current transaction
amount: It is the amount of the operation. This parameter is mandatory when confirming a pre authorized transaction but is not needed when canceling a previously pre authorized transaction.
currency: It is the currency that will be used in the transaction. Same as the previous one is mandatory when confirming a pre authorized transaction but is not needed when canceling a previously pre authorized transaction.
isShowReceipt: This parameter indicates whether the terminal will show the receipt or not. In any case, this receipt will be included in the callback data that is going to be received by the partner application
Confirming a previously pre authorized transaction
In order to confirm a pre authorized transaction, CM POS Payments payment platform accepts two possible scenarios:
-
Confirm the transaction with the total amount used in the previously pre authorized transaction
-
Confirm the transaction with smaller amount than the one used in the previously pre authorized transaction.
It is not possible to confirm a pre authorized transaction with a higher amount that the one used in the first pre authorization transaction.
Canceling a previously pre authorized transaction
Cancel a pre authorized transaction is also possible. For this operation an amount can be sent, but it is going to be ignored as CM POS Payments payment platform is always canceling the total amount that was pre authorized in the original transaction.
Receiving results
In order to receive the results for a transaction with the CM POS Payments android POS integration library, partners have to define a call-back object that will be called back as soon as the result has been processed by the library.
Code Sample. Definition of TransactionCallback
interface TransactionCallback {
fun onResult(data : TransactionResultData)
fun onError (error : ErrorCode)
fun onCrash ()
}
Object defined by Partner application needs to implement this interface. When library has the result of the transaction, it will call method onResult on the call-back and Partner application can get the result using the parameter on the call-back. For that, the class TransactionResultData is used
Values for the Transaction Result Data attributes are specified following this table:
Atribute Name | Data Type/ Class | present |
---|---|---|
transactionResult | com.cm.androidposintegration.enums.TransactionResult | always |
orderReference | String(max 14) | always |
amount | BigDecimal | always |
authResponseCode | String | If Tx processed |
cardEntryMode | String | If Tx processed |
ecrId | String | If present on the receipt |
processorName | String | If present on the receipt |
transactionDateTime | java.util.Date | If present on the receipt |
transactionId | String | If Tx Processed |
cardScheme | String | If present on the receipt |
aid | String | if present on the receipt |
cardNumber | String | If present on the receipt |
cardType | Integer | If Tx Processed |
stan | String | If present on the receipt |
merchantReceipt | com.cm.androidposintegration.beans.ReceiptData | If merchant receipt received from Gateway |
customerReceipt | com.cm.androidposintegration.beans.ReceiptData | If customer receipt received from Gateway |
Attributes Explanation
transactionResult: The resultCode you receive on the call-back. It is an enum defined on the library and can be one of the following:
SUCCESS ("Operation was successful")
CANCELLED ("Operation was cancelled")
AUTHORIZATION_FAILURE ("Operation did not have authorization")
AUTHORIZATION_TIMEOUT ("Timeout in last operation authorization")
CARD_BLOCKED ("Card used is blocked")
CARD_INVALID ("Card used is invalid")
DECLINED_BY_CARD ("Operation was declined by card")
INSUFICIENT_FUNDS ("Not sufficient funds to perform last authorization")
FAILED ("Operation failed")
AMOUNT_EXCEEDED ("Amount of last operation exceeded the limit")
HOST_BLOCKED_PRINT_RECEIPT ("Operation couldn’t be performed. Receipt of the last
transaction pending")
REQUEST_RECEIPT("Request Receipt of current Transaction")
Each value has its own description so it is easy for users to understand what happened with the transaction.
orderReference: Is the order reference used in the transaction this value was received to perform the transaction and it is sent back to the partner application
amount: Is the amount received for the transaction.
authResponseCode: Is the authorization response code received on the transaction. It is only present if the transaction has been processed.
cardEntryMode: Is the card entry mode used in the transaction. It is present only if the transaction has been processed. It has one of the following values:
"CARD_ENTRY_MODE_MAG_STRIPE"
"CARD_ENTRY_MODE_MAG_STRIPE_FALL_BACK"
"CARD_ENTRY_MODE_ICC"
"CARD_ENTRY_MODE_CONTACTLESS"
"CARD_ENTRY_MODE_CONTACTLESS_MAG"
processorName: Is the name of the payment processor used in the transaction. It can also be found on the receipt lines.
transactionDateTime: It is the date and time of the transaction received from the gateway.
transactionId: It is the internal transaction id used in CM POS Payments gateway
cardScheme: Is the Scheme of the card (Mastercard, Visa, …) used in the transaction.
aid: Is the AID of the card used in the transaction
cardNumber: It is the masked pan of the card that has been used in the transaction.
cardType: It is an integer that indicates the type of the card used in the transaction. It can have the following values:
MAGNETIC CARD: 1
NFC CARD: 4
ICC (CHIP): 2
stan: Is the System Trace Audit Number of the transaction. It can also be found on the transaction.
merchantReceipt: It is the transaction receipt for the merchant. It is received if the merchant receipt was sent by the gateway. It is an object of the class com.CM POS Payments.androidposintegration.beans.ReceiptData
customerReceipt: It is the transaction receipt for the customer. It is received if the customer receipt was sent by the gateway. Same as merchant receipt, it is an object of the class com.CM POS Payments.androdposintegration.beans.ReceiptData
Receipt Data
The receipt data object received by partners has two attributes:
var receiptLines: Array<String>?
var signature: ByteArray?
receiptLines: is an array with the formatted lines of the receipt
signature: It is a Byte Array with the bitmap signature performed on Screen if the receipt needs a signature. It is only present if the signature has been done on the device. You can create a bitmap from the signature byte array present on the receipt using BitmapFactory.decodeByteArray(…)
:
signatureInMerchantReceipt = BitmapFactory.decodeByteArray(
merchantReceiptgetSignature(),
0,
merchantReceipt.getSignature().length
)
Simple Receipt Sample
Shopname
Terminal: PPCCVBZS
Merchant: 654321
ECR: E_SUNMI_P2lite
_PL0919CQ00283
STAN: 130075
CONTACTLESS
AID: A0000000043060
MAESTRO
Card: ********0308
Cardnb: 0
Date: 19-07-21 09:52:52
AC: F9A1D8E9A1014A60
Processor: CCV
Auth. code: FA5822
Auth. resp. code: 00
Amount: EUR 2,49
REF: 7000135
Payment approved
CARDHOLDER RECEIPT
shop footer
Receipt with signature sample
Shopname
Terminal: PPCCVBZS
Merchant: 654321
ECR: E_SUNMI_P2lite
_PL0919CQ00283
STAN: 130075
CONTACTLESS
AID: A0000000043060
MAESTRO
Card: ********0308
Cardnb: 0
Date: 19-07-21 09:52:52
AC: F9A1D8E9A1014A60
Processor: CCV
Auth. code: FA5822
Auth. resp. code: 00
Amount: EUR 2,49
REF: 7000135
Payment approved
MERCHANT RECEIPT
CARDHOLDER SIGNATURE
......................
shop footer
It is responsibility of your application to print the signature in the appropriate position on the merchant receipt.
Error Cases
CM POS Payments android POS integration library uses onResult
method in the callback when there is no error on the transaction flow between the card, terminal and gateway. However, it could be the case when some situations may lead into errors in the flow (e.g.: connection lost). For those cases, the method onError
is used. CM POS Payments library also creates an ErrorCode Enum object with the following values:
NO_ERROR (0, "No error")
UNKNOWN_ERROR (-1, "Unknown error")
AMOUNT_INVALID (-2, "Amount used was invalid")
NO_INTERNET (-12, "Device is not connected to the network")
POS_NOT_CONFIGURED (-18, "Device is not configured in gateway")
AUTO_TIMEZONE_NOT_ENABLED(-23, "Autotimezone is not enabled on device")
BAD_TIMEZONE (-24, "Timezone on the device is not correct")
HOST_NOT_CONNECTED (-25, "Cannot connect with the gateway")
MERCHANT_ORDER_REF_NOT_PRESENT (-29, "Order reference not present in request data")
TIMEOUT (-30, "Timeout reaching the gateway")
REPEATED_OPERATION (-31, "Transaction already in progress")
MERCHANT_ORDER_REF_TOO_LONG (-32, "Order ref exceeds allowed length")
AMOUNT_LIMIT_EXCEEDED (-33, "Transaction exceeds allowed limit")
INTERNAL_PROCESSING_ERROR (-34, "Internal processing error during transaction flow. Transaction couldn't be processed")
INVALID_ORIGINAL_DATA(-35, "Data related with previous transaction is invalid")
LOW_BATTERY_LEVEL(-36, "Battery level is too low to start a transaction")
WRONG_EMV_AUTHORIZATION_DATE_AND_TIME(-37, "Wrong date and time in authorization request. Please reboot your device.")
TRANSACTION_STATUS_ERROR (-50, "Status information not received")
INFO_REQUEST_FAILED (-51, "Info Request towards the gateway has failed")
Values also contain a description so users can know what went wrong with the previous transaction.
Dealing with unexpected scenarios
The CM POS Payments app handles recovery of the payment transaction. This means, the CM POS Payments app receives a payment request from partner application using the payment library and takes responsibility for properly handling that.
After processing, the app will return the result of the payment (which can have succeeded or failed) or it will return an ErrorCode result containing information on a failed operation.
But CM POS Payments integration library can also call onCrash
because of a crash on Terminal CM POS Payments. If this is the case or if the Partner app crashes or is not capable of receiving the result for whatever reason, the CM POS Payments integration library app allows Partner app to recover by requesting information of past transactions. This means we always need an order reference to be able to retrieve results of previous transactions. That is why order reference is a required attribute in the Transaction Data object needed by library to perform a transaction. Order reference does not need to be unique, because multiple transactions can refer to the same order reference. This happens when transactions fail, and new transactions are started with the same order reference for the same payment.
Requesting transaction information for an existing order reference
If the partner app needs to recover, or wants to retrieve old transaction results, the CM POS Payments integration library allows the partner app to request the status of the previous transaction associated with an order reference. The method on the The CM POS Payments app will return the results for that order reference that were sent previously.
This is flow for requesting the transaction status:
Because the order reference is not unique on a transaction level - the payment for a particular order reference can be retried a number of times, resulting in multiple transactions with the same order reference - a request for previous transaction results can result in multiple results. Of these, one may be a success result, the others are typically failure results.
The method to be used to retrieved this statuses is transactionStatuses
. It receives an object of class RequestStatusData
:
data class RequestStatusData (var orderReference: String? = null,
var page: Int = 0,
var size: Int = 0,
var sortField: String? = null,
var sortValue: String? = null) {
constructor (orderReference: String) : this() {
this.orderReference = orderReference
}
}
Please note that you can create an object of class RequestStatusData with no info or an object passing the value for the merchant order reference. This is due to the fact that the transaction status can be requested with no specific order reference and you will received the status of all transactions performed by the Sunmi device that is being used in the current day.
page: It is an integer and can be used to indicate the number of the start page of the result (useful if there are too many transactions associated to one order reference)
size: It is an integer and can be used to indicate the number of statuses per reply (if 0 it is ignored).
sortFiled: It can be used to indicate in which field sorting needs to be performed.
sortValue: It can be used to indicate which type of sorting needs to be applied. Possible values are "asc" for ascending or "desc" for descending.
Example
val requestData = RequestStatusData("003-00012")
PayplazaPaymentService.transactionStatuses(requestData, statusesCallback)
StatusesCallback is used to receive the result in the same way that TransactionCallback is used to received the result of a transaction.
statusesCallback object also has a method onResult
to receive the result of the statuses request to CM POS Payments Terminal app.
interface StatusesCallback {
fun onResult(data : TransactionStatusesData)
fun onError (error : ErrorCode)
fun onCrash ()
}
TransactionStatusesData class is defined as follows:
data class TransactionStatusesData constructor(val statusesInfo: List
<TransactionStatusData>?,
val errorMessage: String,
val totalCount: Int): Parcelable
statusesInfo is a list of objects of class TransactionStatusData
, which contains the information for one transaction:
class TransactionStatusData (val amount: BigDecimal,
val currency: Currency,
val result: TransactionResult,
val type: TransactionType,
var receipt: ReceiptData? = null) : Parcelable {
The transaction Status Data contains the amount of the transaction, the currency used in that transaction, the result of the transaction, the type of the transaction and the receipt of the transaction. statusesInfo
attribute contains a list of all transactions associated with the order reference used.
Sending an operation when there is already one operation in progress
It may be the case that integrators send more than one operation at the same time to the SDK. Terminal app can process only one operations at a time so SDK must ensure it.
In the case that integrators send more than one operations, the SDK it will call onError
and sends REPEATED_OPERATION (-31, "Transaction already in progress")
back to integrator's ECR.
It's up to integrators to implement onError
callback and decide next actions. In order to perform a proper integration please implement onResult(data : TransactionStatusesDa)
, onError(error : ErrorCode)
, onCrash()
callbacks. Check section <<5.4, 5.4>> for more details.
Receiving REQUEST_RECEIPT as transaction result
This is an special case of the recovery procedure. There are situations in which the CM POS Payments Terminal has received the transaction result but it is not possible to get the receipts of the transaction (e.g.: because of a connection lost event). In this case, we cannot be certain of the transaction result until the receipt is received for the transaction.
If CM POS Payments Integration library responds with that result, that means that Partner application should use the method getLastReceipt
in order to complete the current transaction (see chapter 6 for more information about this operation).
Other Operations in SDK
Last Receipt functionality
It is also possible to request the receipt for the last transaction performed by CM POS Payments terminal application. This can be used to retrieve a copy of the last receipt received on Partner application, but also to retrieve the receipt of the last transaction even if the result did not reach your application.
This is the flow for requesting the receipt of the previous transaction:
Request for the last receipt
val lastReceiptOptions = LastReceiptOptions(true)
paymentService.getLastReceipt(options, receiptCallback)
lastReceiptOptions: is an object containing the options for the operation:
val isShowReceipt: Boolean
You can select whether to show the receipt in CM POS Payments Terminal application or not by setting that attribute to true (receipt shown in terminal app) or false (receipt not shown in terminal app).
receiptCallback is a ReceiptCallback object that will be used by the CM POS Payments Android POS integration library to call Partner application back when the result of the operation and the receipt (if any) are received from the gateway.
fun onResult(data : LastReceiptResultData)
fun onError (error : ErrorCode)
fun onCrash ()
receiptCallback object must implement ReceiptCallback interface which means that it needs to implement the onResult, onError and onCrash methods (same as other call-back objects) data is an object of class LastReceiptResultData which has the following attribute
val receiptData : ReceiptData
This receiptData is the same as the receipt received on the transaction operations and contains the receipt received from the gateway.
If anything goes wrong in the call to the gateway, method onError will be triggered with the appropriate information, same as with the other functionality on the CM POS Payments Library.
Day totals functionality
CM POS Payments also provides integrators with the possibility to request the total amount money handled by the device in one day. We call that the Day totals of the terminal.
This is the flow for the get Terminal day totals functionality.
Partners can make use of that functionality by calling the day totals operation on the library service:
val dayTotalsOptions = DayTotalsOptions(true)
dayTotalsOptions.setFrom("10:00")
paymentService.getTerminalDayTotals(dayTotalsOptions, receiptCallback)
dayTotalsOptions is an object containing the options for the operation:
val isShowReceipt: Boolean
var from : String? = null
Same as with the last receipt functionality, you can select whether to show the receipt in terminal application or not. You can also select the hour of the present day from which the day totals will be calculated. If Partner application does not set that parameter, terminal will take 00:00
as the default hour and the day totals will be calculated from that time to the current time of the day in which the request is submitted.
receiptCallback is the same call-back that must be implemented for the last receipt functionality (see Last Receipt functionality chapter)
Request Info functionality
CM POS Payments Terminal also provides this functionality to retrieve some useful information for partners. Terminal is configured on a merchant store on the gateway with some information (like the store name, address, language of the store, currency to use, …). This information can be requested by partners by using this functionality present on the CM POS Payments integration library.
Request info data sample
paymentService.getTerminalInfo(infoCallback)
In this case, there is no need to send extra information on the request, therefore, the only parameters present on the call.
infoCallback is an object of class TerminalInfoCallback. Partner object must implement the methods present on the interface same as with other functions present on the library. It contains the following functions
fun onResult(data : TerminalInfoData)
fun onError (error : ErrorCode)
fun onCrash ()
onResult method is called when CM POS Payments Library has received the information requested by Partner application. Parameter data contains all the data that is sent by Terminal application:
var storeName: String? = null
var storeAddress: String? = null
var storeCity: String? = null
var storeZipCode: String? = null
var storeLanguage: String? = null
var storeCountry: String? = null
var storeCurrency: Currency? = null
var deviceSerialNumber: String? = null
var versionNumber: String? = null
storeName is the name of the store in which the terminal is configured on the gateway.
storeAddress is the address of the store in which the terminal is configured on the gateway.
storeCity is the city of the store in which the terminal is configured on the gateway.
storeZipCode is the zip code of the store in which the terminal is configured on the gateway.
storeLanguage is the default language of the store in which the terminal is configured on the gateway
storeCurrency is the default currency of the store in which the terminal is configured on the gateway
deviceSerialNumber is the serial number of the sunmi device in which the terminal application is running.
versionNumber is the version number of the terminal application.
onResult method in TerminalInfoCallback interface is the same as previous callbacks on the other operations.
Technical Support
When building and integrating, it can happen that technical support is required. In order for us to answer any technical questions you might have, we require at least the following information to be sent along with the question(s):
Validating Sunmi software versions
The Sunmi terminal
-
The type of terminal (P2Pro, P2Lite, P2Mini, etc)
-
Is it a development terminal or a production terminal?
-
The serial number of your terminal
-
The OS version of your terminal
-
The library version of the Sunmi Pay Hardware Service (SPHS)
-
The web view version on the Sunmi terminal
-
The App store service provider that your Sunmi terminal is linked to
The POS Payments Terminal app
-
The merchant store that your terminal is linked to
-
The software version of the SDK that is used to integrate with the Terminal app
-
The software version of the POS Payments Terminal app that you are integrating with
For technical questions, please contact CM POS Payments via [email protected]
Simulator Test scenarios
In order to do a full system test there are several test scenario’s that will result in a response message which is not successful. These messages are triggered by the usage of the following amounts and the corresponding results are being presented by the simulators CM POS Payments created on its development platform. To make the CM POS Payments platform as accurate as possible, CM POS Payments has several simulators imitating the behavior of important processors.
The only response code for a successful transaction is SUCCESS. With all other response codes the transaction has failed. Other (fail) messages may occur in production environment. To use contactless flow and error codes are required. The same codes are used but with a different amount.
case | Value | Description | Result Code | |
All | Under NFC limit | |||
1 | €200,01 | €20,01 | The cardholder has reached the total amount limit of his/her card | AMOUNT_EXCEEDED |
2 | €200,02 | €20,02 | The cardholder does not have enough funds to buy the goods | INSUFFICIENT_FUNDS |
3 | €200,03 | €20,03 | The issuer was not able to respond in time | AUTHORIZATION_TIMEOUT |
4 | €200,04 | €20,04 | The issuer denies the transaction due to special conditions, i.e., fraud suspect | AUTHORIZATION_FAILURE |
5 | €200,05 | €20,05 | The card used is valid but has been blocked, i.e., exceeded the number of PIN tries | CARD_BLOCKED |
6 | €200,06 | €20,06 | The card used is not valid anymore, i.e., the card is expired | CARD_INVALID |
7 | €200,07 | €20,07 | The cardholder has entered a wrong PIN and the processor gives another opportunity to enter it correctly | PIN_INCORRECT_RETRY |
8 | €200,08 | €20,08 | This case represents the generic error case. | FAILED |
9 | SCA | €20.90 | The issuer asks for further identification, in this case the PIN is needed | SCA_ADDITION_REQUIRED |
10 | €20.91 | The issuer asks to change the interface used to perform a contact chip transaction | CONTACT_CHIP_REQUIRED | |
11 | €17,70 | €17,70 | The DCC inquiry is not available. | DCC_SERVICE_NOT_AVAILABLE |
12 | €17,80 | €17,80 | The DCC inquiry is rejected. | DCC_INQUIRY_DENIED |
13 | €17,90 | €17,90 | The DCC inquiry has the incorrect format and has been abandoned by the processor. | DCC_SERVICE_ABANDONED |
14 | €27,90 | €27,90 | The markup text extension cannot be found. | DCC_NO_MARKUP_TEXT_EXTENSION |
15 | €27,80 | €27,80 | The markup percentage cannot be found. | DCC_NO_MARKUP_PERCENTAGE |
16 | €170,70 | €170,70 | The authorization response from processor is delayed | SUCCESS |
Cases 7, 9 and 10 can be performed by sending the corresponding amount from partner application, but PayPlaza terminal application is going to handle the Pin Retry and SCA process by itself. This way, if the process is successful, partner Application will receive SUCCESS as a result code or the corresponding error code otherwise. Cases 11, 12, 13, 14 and 15 are meant to test dcc wrong scenarios. Terminal will receive the error codes indicated in the description but will continue with the transaction without including any DCC processing. Therefore, if the process of the transaction is successful, partner application will receive SUCCESS as a result code or the corresponding error code otherwise.
As mentioned before, the PayPlaza platform has several different Processor simulators, which try to mimic the real world behavior of actual processors in production. As a result it should be noted that not all cases are supported by every processor, which will be reflected in the behavior of the processor simulators as stated below.
Case | OmniPay Simulator | CCV Simulator | Equens Simulator | SIX Simulator | Amex Simulator |
---|---|---|---|---|---|
1 | YES | YES | YES | YES | Not Supported |
2 | YES | YES | YES | YES | Not Supported |
3 | YES | YES | YES | Not Supported | Not Supported |
4 | YES | YES | YES | YES | YES |
5 | YES | YES | YES | YES | YES |
6 | YES | YES | YES | YES | Not Supported |
7 | YES | Not Supported | Not Supported | YES | YES |
8 | YES | YES | YES | YES | YES |
9 | YES | YES | YES | YES | Not Supported |
10 | YES | YES | YES | YES | Not Supported |
11 | NO | NO | NO | YES | NO |
12 | NO | NO | NO | YES | NO |
13 | NO | NO | NO | YES | NO |
14 | NO | NO | NO | YES | NO |
15 | NO | NO | NO | YES | NO |
16 | YES | YES | YES | YES | YES |
Integration with Java native application
Our library is written in Kotlin, but it is fully compatible with an Android Java application. The integration with a Java application is the same as with a Kotlin written application.
Once the library is included as dependency in the gradle file, the library needs to be initialized with the context of the application.
Code Sample. initialize library in Java application
@Override
public void onCreate() {
super.onCreate();
AndroidPosIntegration.INSTANCE.init(this);
...
}
In the previous example, in the onCreate method of the class that is extending the Android Application class, the AndroidPosIntegration.init()
method is called from the Java code. The INSTANCE
part is needed as compatibility between Java and Kotlin library.
Once the application has been initialized, an instance of the PosIntegrationService can be got using the following code:
Code Sample. get PosIntegrationService instance from CM POS Payments AndroidPosIntegrationLibrary
PosIntegrationService paymentService = AndroidPosIntegration.INSTANCE.getInstance();
Updated 5 months ago