STEP 4 Configure a payment

Executing a payment transaction between a mobile wallet app and an acceptance terminal - such as a POS, a fuel pump, or an ATM - requires both the app and the terminal to send and receive information about the transaction through the Paydiant platform.

Payment Data Flow

A given transaction might have numerous exchanges of data before completion, depending on its complexity, but in the simplest representation:

  1. The transaction is initiated by either the mobile wallet app or the acceptance terminal through a checkout token request.
  2. The non-initiating participant then scans and decodes the checkout token and requests to join the transaction represented by the token.
  3. The acceptance terminal communicates the amount owed.
  4. The app returns the consumer's consent to pay the amount owed, along with the selected payment account.
  5. Paydiant contacts the 3rd party processor responsible for authorizing payments for the selected tender and communicates the result to the acceptance terminal.
  6. The acceptance terminal completes the transaction and Paydiant issues a receipt to the app.

Along the way, many other circumstances are possible:

  • The consumer may wish to add a tip
  • The consumer may wish to apply a coupon discount
  • The consumer may wish to pay with multiple tenders, such as a gift card and a credit card.
  • The acceptance terminal may need to record points earned toward a loyalty rewards program

Regardless of the type and complexity of the transaction or the number of steps to process it, transaction data is passed between the mobile app, the acceptance terminal, and the Paydiant platform through the following two methods:

  • retrieveTransactionData requests updated information about the transaction.
  • updateTransation submits relevant data to progress the transaction forward.

Each of these calls includes a property that identifies the flow rule associated with the call instance. The flow rule indicates the current state of the transaction that the call addresses. Thus, the data passed in the call is contingent on the flow rule value.

BASIC PAYMENT IMPLEMENTATION STEPS

  1. Display or scan the QR Code.
  2. Get transaction details submitted by POS.
  3. Prompt user to select an eligible tender.
  4. Submit the payment information.
  5. Display a payment confirmation summary.

1. Display or scan the QR Code

To initiate a transaction on the Paydiant platform, one of the transaction participants (the mobile app or the acceptance terminal) must request a checkout token and generate a QR Code that can be scanned and decoded by the other participant so both parties are connected to the same transaction.

Implement the set of calls corresponding to the manner in which the mobile app will engage in the transaction.

Code-on-Phone

In the Code-on-Phone transaction initiation use case, the mobile app requests the checkout token and displays the generated QR Code for the POS or other acceptance point to scan.

IMPLEMENTATION STEPS

  1. Define Token Management service connection.
  2. Set the service listeners to handle callbacks.
  3. Invoke obtainCheckoutToken for the applicable transaction type.
  4. Configure the success callback to generate the QR image and display it for scanning by the POS.
  5. Disconnect the service connection and remove the listeners.
  if (captureTokenService == null)
  {
      captureTokenService = new TokenManagementService(getActivity());
      captureTokenService.setListener(tokenManagementListenerAdapter);
      captureTokenService.obtainCheckoutToken(AppConstants.TOKEN_TYPE_PURCHASE, 200, 200);
  } catch (PaydiantException e)
  {
      Log.d(TAG, e.getErrorMessage());
  }
  @Override
  public void onObtainCheckoutSuccess(Bitmap tokenImage, String qrCode)
  {
      super.onObtainCheckoutSuccess(tokenImage, qrCode);
      captureToken = qrCode;
      qrImageView.setImageBitmap(tokenImage);
      releaseTokenTextView.setVisibility(View.VISIBLE);
      progressBar.setVisibility(View.VISIBLE);
      mRetrieveTransactionThread.start(qrCode);
      Log.v("CODE ON PHONE", qrCode);
  }

Tip: As a Best Practice, Paydiant advises setting the brightness of the screen to 80% while displaying the QR Code for optimum scanning performance.

Code-on-POS

In the Code-on-POS transaction initiation use case, the acceptance point (such as a POS or ATM) requests the checkout token and displays the generated QR Code for the mobile app to scan.

This use case begins at the point that the user engages the app to make a payment by whatever means the app has designed that behavior, such as a "scan token" button or menu item.

IMPLEMENTATION STEPS

  1. Create the relevant service connection.
  2. Set the service listeners to handle callbacks.
  3. Activate the camera view to capture the image.
  4. Configure the success callback to generate the QR image and then release the token after it has been scanned by the POS.
  5. Disconnect the service connection and remove the listeners.
if (captureTokenService == null)
{
    captureTokenService = new TokenManagementService(getActivity().getApplicationContext());
    captureTokenService.setListener(tokenMgmtListenerAdapter);
}
private CameraConfigParameters getCameraConfigParameters()
{
    CameraConfigParameters cameraConfigParams = new CameraConfigParameters();
    cameraConfigParams
        .setOrientation(Camera.Parameters.SCENE_MODE_PORTRAIT);
    return cameraConfigParams;
}
{
    captureTokenService.startCameraSession(surfaceView);
}
getActivity().unbindService(transactionFlowMgtServiceConnection);
getActivity().unbindService(paymentAccountManagementServiceConnection);
captureTokenService.stopCameraSession();
captureTokenService.removeCaptureTokenListener();
}

2. Get transaction details submitted by POS

Upon successful initiation of the transaction by either retrieval or scanning of the checkout token, the mobile app must request the relevant transaction information submitted by the POS, such as the amount due, which payment tenders are supported, whether discounts or tips are eligible for this transaction, etc.

First, submit the retrieveTransactionMetaDataWithoutPolling request call, passing the previously obtained checkoutToken value and specifying DISCOVERY as the current flow rule. Configure blocking until paydiantReferenceId and supportedTenderTypes are returned.

if (transactionFlowManagementService != null) {
    captureToken = result;
    CheckoutToken checkoutToken = new CheckoutToken();
    checkoutToken.setCheckoutTokenValue(captureToken);
    checkoutToken.setCheckoutTokenType(CheckoutTokenType.PURCHASE);
    TransactionMetaDataParameters params = new TransactionMetaDataParameters();
    params.setCheckoutToken(checkoutToken);
    params.setDiscoveryType(DiscoveryType.PURCHASE);
    params.setExecutingFlowRule(TransactionFlowRule.RETRIEVE_TRANSACTION_META_DATA_DISCOVERY);
    transactionFlowManagementService.retrieveTransactionMetaDataWithoutPolling(params);
}

Next, configure the callbacks to handle the possible responses from the platform and continue or cancel the transaction accordingly. For example, if the current user's registered payment accounts don't match any of the supported tenders, the app will need to inform the user gracefully. There may also be additional data related to offers or loyalty or other transaction variations that are out of scope in this phase of the tutorial.

    @Override
    public void onRetrieveTransactionMetaDataSuccess(TransactionMetaDataResponse transactionMetaDataResponse) {
            super.onRetrieveTransactionMetaDataSuccess(transactionMetaDataResponse);
            Log.v(TAG, "onRetrieveTransactionMetaDataSuccess");
            if (transactionMetaDataResponse.getNextExecutingFlowRule().equals(TransactionFlowRule.PROCESS_PAYMENT)) {
                TransactionParameters transactionParameters = new TransactionParameters();
                for (TransactionFlowRuleSpecification flowRuleSpecification: transactionMetaDataResponse.getTransactionFlowRuleSpecifications()) {
                    if (flowRuleSpecification.getTransactionFlowRule().equals(transactionMetaDataResponse.getNextExecutingFlowRule()))
                        if (flowRuleSpecification.isExpectsPaymentTenders()) {

3. Prompt user to select an eligible tender

Determine which payment accounts are eligible for the transaction based on supportedTenderTypes array and only display matching payment accounts in wallet for selection by user for payment or notify user that no registered payment accounts are supported for the transaction.

if (paymentAccountsList!=null && paymentAccountsList.size() > 0) {
List String paymentAccounts=new ArrayList < > ();
paymentAccounts.add(paymentAccountsList.get(0).getPaymentAccountUri());                        transactionParameters.setPaymentAccounts(paymentAccounts);
}

4. Submit the payment information

When the user selects a payment account, submit the selection using the updateTransaction call with the TransactionFlowRule value set to PROCESS_PAYMENT.

transactionParameters.setCheckoutToken(transactionMetaDataResponse.getCheckoutToken());
transactionParameters.setTransactionKey(transactionMetaDataResponse.getTransactionKey());
transactionParameters.setExecutingFlowRule(TransactionFlowRule.PROCESS_PAYMENT);
transactionParameters.setCustomerConfirmationForPOSRequestedPayments(false);
transactionFlowManagementService.updateTransaction(transactionParameters);
}\\
onUpdateTransactionSuccess methods will get the success call of update transaction.Check the transaction status here.
if(transactionResponse.getTransactionStatus().equals(TransactionStatus.CLOSED)) {
        AlertDialog.Builder alert = new AlertDialog.Builder(getActivity());
        alert.setPositiveButton(getString(R.string.button_label_ok), new DialogInterface.OnClickListener() {

5. Display a payment confirmation summary

If the updateTransaction success callback returns a nextExecutingTransactionFlowRle value of RetrieveTransactionMetaDataSummary, the transaction is complete! Retrieve the summary for the transaction, which will include the payment result and other transaction details.

    @Override
    public void onClick(DialogInterface dialog, int which) {
    Intent receiptIntent = new Intent(getActivity(), PaymentReceiptActivity.class);
    Bundle bundle = new Bundle();
    bundle.putString(PaymentReceiptActivity.ARG_REF_ID, transactionResponse.getTransactionKey().getPaydiantReferenceId());
    receiptIntent.putExtras(bundle);
    startActivity(receiptIntent);
    }
    });
    alert.setTitle("Success");
    alert.setMessage("You paid " + transactionResponse.getTransactionDetail().getCurrentPaymentResult().getCurrencyCode() + " " +
        transactionResponse.getTransactionDetail().getCurrentPaymentResult().getPaidOrRefundAmount());
    alert.show();
    }
    else {
        AlertDialog.Builder alert = new AlertDialog.Builder(getActivity());
        alert.setPositiveButton(getString(R.string.button_label_ok), null);
        alert.setTitle("Error");
        alert.setMessage("payment error");
        alert.show();
    }
Feedback

Have feedback?

Let us know.