handling responses - AEVI-AppFlow/pos-android-sdk GitHub Wiki
The first version of AppFlow provided responses back via the initiation Rx stream, but due to the nature of Android component lifecycles (especially on Oreo and up), there is never any guarantee that the activity / service that initiated a flow is still alive when it is time to send the response back. Activities in particular are almost guaranteed to be destroyed for any non-trivial flow, as most of the POS devices have very limited memory. To ensure that the client receives the response reliably, the response channel is separated from the initiation rx chain via calls to standard Android services defined in the client. See Flow Response Listeners for how to define and implement these entry points.
As the Request
and Response
data is bespoke to each type of request, there is no general information on how to parse these responses. See Request Types to find detailed information on how to create requests and parse responses for each use case.
The response to a Payment
is returned in the form of a PaymentResponse
object.
To investigate the outcome of the request, you can call response.getOutcome()
. This will return a PaymentRequest.Outcome
value that can be;
-
FULFILLED
- This essentially means success - in that the full amounts defined in the request have been processed successfully -
PARTIALLY_FULFILLED
- This means that parts of the amounts were successfully processed, but not all of it. See further down for more info. -
FAILED
- No money was charged. See the FailureReason for more info (below).
In the case of the latter two options above, a FailureReason
can be parsed to get a better idea of what went wrong;
-
NONE
- No error (never used forFAILED
) -
CANCELLED
- The payment was cancelled before it could complete -
REJECTED
- The request was rejected, either due to invalid data or because there was no payment service that could handle it -
DECLINED
- The payment service declined the payment (see transactionResponse.getResponseCode() to determine the reason) -
TIMEOUT
- The flow timed out due to application and/or merchant inactivity -
ERROR
- Some unexpected error caused the payment to fail
Due to the vast amount of possible failure reasons, not every reason can be represented. If you encounter failures during development, please check the FPS system audit log / request logs in the AppFlow
app, or use Logcat.
There is a convenience method, response.isAllTransactionApproved()
, that will help you determine whether all transactions were approved or not. It is important to realise that it is possible for the outcome to be FULFILLED despite failed transactions. This is due to the way the payment flow operates, where a split app can split up the payment into multiple transactions, and it may choose to retry a transaction or move the balance forward, etc. The payment flow only cares about ensuring the amounts requested are processed - it does not care how that is done.
Important! You can check what the total amounts charged were by calling response.getTotalAmountsProcessed()
. Due to the ability for flow services to add and pay amounts, it is possible that the amounts processed is more than what you initially requested. As an example, a flow service might add tip or some fee or a charity donation, meaning the overall amounts will be greater than what your application requested initially.
You can get the full list of transactions by calling response.getTransactions()
. The Transaction
contains all the relevant input data for that transaction. It also contains a list of TransactionResponse
objects that were generated from flow services in the flow. This is often from payment applications, but may also be from value added services such as loyalty where rewards or points were used.
The TransactionResponse
contains the following mandatory fields;
- Outcome - Approved or Declined
- Amounts processed - The amounts processed (may not equal the TransactionRequest amount)
- Payment method - What method was used for payment (card, cash, etc)
In addition, it may optionally contains
- Response code - The response code, which is payment service (protocol, region, etc) specific
- Card - The details of the card used, if any, for the transaction
- References - A set of transaction references
Partially fulfilled outcomes should generally be rare, but can happen as a result of
- the payment app declining after a flow service pays off amounts (such as via loyalty points)
- a split transaction getting cancelled after at least one approved transaction
- a host/gateway performing a partial auth
- some unexpected error in the flow.
It is essential that your application can manage this outcome. There are a few different approaches to take in this scenario;
- You can initiate a new request with the remaining balance
- You can "give up" and cancel the payment. In the case of split transactions, you must ensure to reverse the transactions that were approved.
It is advisable to offer these options in your app to the merchant as he/she would be in the best position to make this decision.
You can review what flow applications were called and what type of data they may have augmented, if any, as part of the payment processing or your request.
See Augmented Data for more details.