Setup SDK
ClientFactory used to create Client interface instance with specified parameter.
import android.view.Display
ClientFactory.bindConfiguration(
SDKConfiguration.defaultConfiguration(
clientApplicationInfo = PackageInfo(
applicationName = applicationInfo.name, applicationPackage = packageName
)
)
).bindContext(
context = applicationContext
).bindProtocolConfiguration(
RetailerConfiguration(saleID = "Communicator_SALE") ).bindInterceptor(
interceptor = { message: DomainMessage >
when (message) {
/ Check message type
is SuccessRetailerLoginResponse,
is ErrorRetailerLoginResponse,
is SuccessRetailerLogoutResponse > {
/Handle message
}
}
}
).bindEventObserver { event: ObservableEvent >
when (event) {
is ObservableEvent.ServerEvent > Logger.d("New server event") is ObservableEvent.TransactionStateChanged >
when (event.state) {
is IdleTransactionState >
bringToForeground(MainActivity :class)
else > {
/ Ignore
}
}
}
}.build()
SDKConfiguration stands here forinterprocess communication parameters.
Destination's Application parameters should be specified here. Application's Name and package.
bindConfiguration(
SDKConfiguration.defaultConfiguration(
clientApplicationInfo = PackageInfo(
applicationName = applicationInfo.name,
applicationPackage = packageName
)
)
)
ProtocolConfiguration stands for specific protocol parameters.
Our case is Nexo Retailer Protocol v3. Your application's parameters as ECR might be specified here.
bindProtocolConfiguration(
RetailerConfiguration(saleID = "Communicator_SALE")
)
Interceptor class which will handle all of the responses from Payment Application.
Incoming parameter has generic type DomainMessage all of the messages in app2app communication are subtypes of this class. to specify handling strategy for each response typecheck is recommended. In this example, reaction on SuccessRetailerLoginResponse, ErrorRetailerLoginResponse, SuccessRetailerLogoutResponse is illustrated.
Each operation as Payment/Reversal/Refund etc has it's own message type. It could be found manually through documentation package retailer-protocol.
bindInterceptor(
interceptor = { message: DomainMessage >
when (message) {
/ Check message type
is SuccessRetailerLoginResponse,
is ErrorRetailerLoginResponse,
is SuccessRetailerLogoutResponse > {
/Handle message
}
}
Map of requests and responses for main operations
Login
Request: RetailerLoginRequest
Response: RetailerLoginResponse
Response Subtypes:
SuccessRetailerLoginResponse
FailedRetailerLoginResponse
Payment
Request: RetailerPaymentRequest
Response:
RetailerPaymentResponse
RetailerDisplayRequest
Response Subtypes:
SuccessRetailerPaymentResponse
ErrorRetailerPaymentResponse
Payment request is used for Refunds, Pre-Authorisations and Pre-Authorisation Completions as well. There
is no separate subtypes for those operations. DisplayRequest will notify during processing which operation
is being executed.
Abort
Request: RetailerAbortRequest
Response: RetailerAbortResponse
Response Subtypes: ErrorRetailerPaymentResponse
If AbortRequest was sent after payment request started execution, it will be ignored.
Reversal
Request: RetailerReversalRequest
Response: RetailerReversalResponse
Response Subtypes:
SuccessRetailerReversalResponse
ErrorRetailerReversalResponse
Transaction Status
Request: TransactionStatus
Response:
RetailerTransactionStatusResponse
RetailerDisplayRequest
Response Subtypes:
SuccessRetailerTransactionStatusResponse
ErrorRetailerTransactionStatusResponse
EventObserver class
EventObserver class which will handle all of PaymentApplication states changes and events.
Observer receives ObservableEvent instances. There are two subtypes of it:
ObservableEvent.ServerEvent - stands for some events happend in Payment Application
TransactionStateChanged - stands for state changes. For example, when Payment Application starts PaymentProcessing, EventObserver will receive PaymentTransactionState instance. When PaymentProcessing considered finished by Payment Application, EventObserver will receive IdleTransactionState instance. Transitions between states might be recognized through saving previously notified state's instances.
bindEventObserver { event: ObservableEvent
when (event) {
is ObservableEvent.ServerEvent Logger.d("New server event"
is ObservableEvent.TransactionStateChanged
when (event.state) {
is IdleTransactionState
bringToForeground(MainActivity :class
else
Ignor
}
}
}
}
BringToForeground
bringToForeground(MainActivity :class) - is function, responsible for "dragging" to foreground your application after state changes in Payment Application. MainActivity:class is placeholder for your currently running application's activity. If your application is Single-Activity you can don't worry about activity transitions so just provide your Main Activity class as in example.
PaymentTransactionSate -> If active/present: switch back to your application during payment authorization.
IdleTransactionState -> If active/present: swith back to your application at the end of payment.
For example: You'd like show advertisement in your application or custom transaction details during payment processing instead of Payment Application's spinner. All you have to do to achive it - specify path for PaymentTransactionState like here:
bindEventObserver { event: ObservableEvent
when (event) {
is ObservableEvent.ServerEvent Logger.d("New server event"
is ObservableEvent.TransactionStateChanged
when (event.state) {
is PaymentTransactionState
bringToForeground(MainActivity :class
else
Ignor
}
}
}
}
now, when Payment Processing started in Payment Application your will be brought to foreground. If you also would like to transit to foreground your application after Payment Applications finish transaction, add corresponding path for IdleTransactionState:
bindEventObserver { event: ObservableEvent
when (event) {
is ObservableEvent.ServerEvent Logger.d("New server event"
is ObservableEvent.TransactionStateChanged
when (event.state) {
is IdleTransactionState
bringToForeground(MainActivity :class
is PaymentTransactionState
bringToForeground(MainActivity :class
else
Ignor
}
}
}
}
SDK Usage
Once you've done with SetUp, you can use instance returned by ClientFactory::build function to initiate
communication with Payment Application.
Client interface
It used to send requests and response for those requests will be delivered to previously registered in 1.3
Interceptor.
interface Client {
/**
* Send Login request
suspend fun sendLoginRequest()
/**
* Send Payment request
*
* @param transactionID - identifies transaction, should be unique for each one
* @param saleReferenceId - identification of a Sale global transaction for a s
* @param paymentAmounts - transaction amounts information
suspend fun sendPaymentRequest(
saleReferenceId: String,
transactionID: String,
paymentAmounts: PaymentAmounts,
paymentType: PaymentType
)
/**
* Send Logout request
suspend fun sendLogoutRequest()
/**
* Get last completed in Payment Application transaction status
suspend fun sendTransactionStatusRequest(messageReference:
MessageReference)
/**
* Used for terminal Update/Activation depending on [RetailerAdminExtension.act
suspend fun sendAdminRequest(adminExtension: RetailerAdminExtension)
/**
* Send test connection request
suspend fun sendTestConnectionRequest(
diagnosisRequestArguments:
RetailerMessageArguments.DiagnosisRequestMessageArguments
)
/**
* Reversal request stands for transaction cancellation
* @param poiTransactionId - identifies transaction, should be unique for each
* @param saleReferenceId - identification of a Sale global transaction for a s
* @param transactionData - look at [RetailerMessageArguments.ReversalRequestMe
suspend fun sendReversalRequest(
saleReferenceId: String,
poiTransactionId: String,
transactionData:
RetailerMessageArguments.ReversalRequestMessageArguments.TransactionAmountsData
)
}
Nexo Retailer protocol specificities
Every communication session should start with RetailerLoginRequest - Client::sendLoginRequest. If session was interrupted due to:
Payment Application update
Payment Application restar
Client's (your) application restar
Connection between applications was lost
RetailerLogoutRequest was sent
New Login procedure should be triggered to instantiate the session. Otherwise requests from your application will be considered unauthorised and will be ignored by Payment Application.