Error Handling¶
In most error cases, the applications are still running and a Status
object is passed to the POS. There are a couple of scenarios discussed later that
involve hard crashes or uncaught exceptions that must be handled differently.
Status and its Subclasses¶
All of the events are derived from Status
, and most methods return a
Status object, with only a few exceptions. In these scenarios, if
the status code (Status.getStatus()
) returns non-zero, an error has
occurred. In most cases, Status.getMessage()
returns a localized,
human readable message that can be displayed to the cashier if the error cannot
be automatically handled. In some cases, the status code will be assigned some
constant value that can be automatically handled, such as those defined in
CommerceConstants
or in the appropriate
Status
subclass for the event type, but some will not. In the cases
where it is not found, it can be helpful to try again depending on the context
(see PSDK State Transitions).
When the status code is non-zero after calling a method¶
Many methods, such as TransactionManager.login()
, return a Status object.
Check this status object for a non-zero status code after calling to make sure that
the login request could be submitted. An error when calling a method is generally
due to some unready state or invalid parameter. Invalid parameters should be caught
during development/testing, and should not be present in the field. An unready
state can happen if the POI has not fully booted, such as after a recent restart
of the device, and will generally require some delay before attempting the action.
Most of these errors that occur in the field can be handled by displaying
Status.getMessage()
to the cashier and enabling them to retry or cancel
the action. If they cancel, it is the responsibility of the POS to restore the
correct state, e.g., if some merchandise failed to add to the POI display, the
merchandise should probably be removed from the cart so the display and the cart
can be kept in sync.
When the status code is non-zero for a received event¶
It is possible for any of the events to be sent to the listener with an error.
When an error has occurred, the event might not contain any of the expected objects,
e.g., a PaymentCompletedEvent
might return null for
PaymentCompletedEvent.getPayment()
. Depending on the exact event,
these errors should be handled differently, and really depend on the product
requirements and paradigms in the POS.
Note
A payment card decline or user-canceled payment is not considered an error, since it is a normally expected authorization result, therefore the status code will be 0 in this case. In payment cases, an error could be returned if the card was invalid, or the payment host returned an error, or many other scenarios. In this case, the status code will be one specific to the host or payment app, and should be included in the display to the cashier to help them if they reach out for support.
Errors without Status¶
If the commerce listener is destroyed, the status will not be received.
If the POS or the Payment Service crashes.
An error status is returned indicating the connection is lost.
In any of these scenarios, it is best to use the common recovery scenarios below, selecting the appropriate one for the state during which the error occurred.
Note
The payment service runs in a separate process, and does not keep the commerce listener from being destroyed. See Create a Commerce Listener.
Common Error & Recovery Scenarios¶
Session Start Failure¶
This is generally caused by being in the wrong state when attempting to start a
session (see PSDK State Transitions). This can generally be resolved by querying
the current state to determine what next steps ought to be taken, e.g., if the
state is TransactionManager.STATE_SESSION_OPEN
, then the POS should
end the old session. If this is still not working, it might be due to a
mismatch of the android state and the POI state. Use
TransactionManager.abort()
followed by
TransactionManager.endSession()
, thoroughly resetting the state of
the POI and allowing the current state to become accurate, after which starting
the session should work smoothly.
It’s also possible for this to fail because the POI is not yet fully booted. In this case, it’s best to display a prompt to the cashier allowing them to retry the operation at their discretion, prompting them to make sure the POI is ready.
Recovering Event not received for Payment¶
This is generally caused either by a crash or a destroyed commerce listener. If a crash, when the application comes back up, it must log in but starting a session will fail. Proceed to recovering the last transaction below.
If the listener is no longer valid, a new one must be created and added using
TransactionManager.addSessionListener(listener)
, then proceed to
recovering the last transaction below.
If the connection is lost, the POS will receive a PaymentCompletedEvent
with PaymentCompletedEvent.getStatus()
equaling StatusCode.DEVICE_CONNECTION_LOST
.
In this case, the only thing to do is to call PaymentSdk.tearDown()
and then initialize
to recover the connection. To obtain the last transaction result, create a TransactionQuery
object, use TransactionQuery.setQueryingLastTransaction(true)
to mark it as recovering the
information about the most recent payment, and then examine the information returned in the
TransactionQueryEvent
. The payment’s authorization result will be IN_PROGRESS if it is still processing,
it can be cancelled as Cancel the Transaction, or it will contain the actual result.
It is possible to abort a transaction if it is still in progress using
TransactionManager.abort()
. Sometimes this is preferred to recovering
the status of the transaction, though it may require the customer to present their
card again, or even possibly key in their loyalty information, and is not the
ideal solution.
Recovering Event not received for Basket Action¶
This is generally caused either by a crash or a destroyed commerce listener. If
this wasn’t received due to a crash, it is best to follow the steps for
recovering-a-session. If the listener is no longer valid, a new one must
be created and added using TransactionManager.addSessionListener(listener)
.
See Create a Commerce Listener for more information on commerce listeners.
Recovering a Session¶
Losing the connection to an active session on the POI is generally caused only
by a crash. If a payment was not in progress, it’s best to start a new session
and restore the basket. See session-start-failure, as simply calling
TransactionManager.startSession(...)
will likely fail, and then
restore the basket (Restoring a Basket from a Previous Order). If a payment was in progress when
this occurred, see recovering-a-payment.
Invalid Card and similar issues during Payment¶
There are many common error scenarios where a payment will not have an
AuthorizationResult
, or even where the PaymentCompletedEvent
will not have a Payment
object. These cases include when the
user has presented an invalid card (e.g. expired), or the card read has failed,
or any number of other scenarios. The PaymentCompletedEvent.getStatus()
will be non-zero, and the string from
PaymentCompletedEvent.getMessage()
will be localized for the cashier
and should be displayed as a prompt, generally with an option to retry the
payment.
Printer Error Codes¶
STATUS_SUCCESS 0
STATUS_ERROR 1
STATUS_OUT_OF_PAPER 2
STATUS_OVER_TEMPERATURE 4
STATUS_PAPER_JAM 8
STATUS_LOW_BATTERY 16