5

In an Android app, I'm working on, we have a problem regarding payments.

When the user wants to place an order, we do an API request that will return a payment URL and a payment ID. The URL is the webpage we will open for the payment, the ID is used to retrieve the status of the payment from our API. When we request the status of the payment from our API, it will return either "success", "cancelled", or "pending". When the payment has completed or when the user clicks the cancel link inside the payment webpage, the user will be redirected to a URL that is handled by the app. If the user is redirected, we will proceed to either order confirmation page (when payment was successful) or back to the checkout page (when payment was cancelled by clicking the cancel link in the webpage). Payment webpage is opened using a Chrome Custom Tab.

The problem occurs when the user closes the browser before finishing or cancelling the payment and then returns to our app. When the user comes back to our app without being redirected by the browser, the app will do a status request to check whether we should proceed to the order confirmation page. When the browser is closed, one of the following scenarios can occur:

  1. User has paid but closed the browser before redirection happened. The status request will return "success", and we can proceed to order confirmation screen.
  2. User has not paid, clicked cancel button in the payment webpage, but closed the browser before redirection happened. The status request will return "cancelled" and we can send the user back to the checkout screen.
  3. User has paid, but payment is still being processed. User closes browser and returns to the app. The status request will return "pending"
  4. User does not want to pay and just closed the browser because he wants to go back to the checkout page to change something in the form, the status request will return "pending" because the API doesn't know the user closed the browser

Scenario 1 and 2 are perfectly fine, but 3 and 4 cause problems. When the status request returns "pending", the app doesn't know if it's scenario 3 or 4. The app will show a dialogue on top of the checkout screen that says "payment pending". The problem is, when this happens the app doesn't know if 1) the payment is still processing and will succeed sometime in the future or 2) will never succeed because the user never paid. If the user closes this dialogue, it is still possible that the payment succeeds and the user will not know. We had many complaints of users who closed this dialogue and then tried to order again, resulting in an accidental double order.

We tried some workaround by making the dialogue non-closable for at least 30 seconds to give the payment some time to process, but that will bring a very bad UX for users who just closed the dialogue to return to checkout screen (scenario 4).

Is there any Android feature we're missing that could solve the issue? Is there any other solution? We would like to see approaches to other apps.

Ibraheem Zafar
  • 346
  • 1
  • 9
Mark Buikema
  • 2,483
  • 30
  • 53

3 Answers3

0

this is how I would handle it :

after user selected the product or products, you should create a order entity for those and give the order an id in this level user cant change the order it should pay or cancel the order ( or for changing it you are canceling the order and after a change you are creating a new order for it ) assign the payment id to the order and when user wants to pay the order check the last payment id for the order and specify the payment status of the order. if there is a chance that after the user pays the order and before browser redirects to app user would close the browser that is not a problem because after user returns to order activity of the application we have stored the last payment id for the current order and we can check the status of the payment and act base on that if there is a pending status for the order (let's say payment service need's 30min to do the payment processing and to specify the payment was successful or failed ) we could tell the user about that and give it option to cancel the payment and if the money was transformed for the canceled payment we should return the money (which should not happen because you have checked the payment status with payment service and it was pending and you said to payment service that should cancel that pending payment) to user and also we should cancel the order too.

if you have other scenarios or some bugs in this scenario tell me to find a solution fo it

Amir Hossein Mirzaei
  • 2,325
  • 1
  • 9
  • 17
0

Well, the solution is highly dependent on the payment provider you are using, though all the major ones have ways to handle it built-in within their API/SDK.

The most correct one is not to depend on the redirect because it is generally a bad idea due to the reasons you've just mentioned. I would recommend using some system of webhooks and sockets both on the payment provider side and your backend.

If the payment provider has no hook for needed events I would create a recurring job to check the status of the payment from the payment provider API with the paymentId provided from Android client. The job would be active only while the payment is pending. When the status is changed it would be nice to have sockets implemented both on the backend and clients to notify the client about changes without one more recurring job on the client.

If the payment provider has webhook needed to check the status of payments - use it instead of a recurring job.

If there are no paymentId provided - track all the pending payments for the particular user.

Android UI changes will be minimal in this case - some info about status updating and, maybe, fancy loader. Sockets should be implemented, though along with some data storing and reactive refresh of UI based on the values changed.

Since it is a question regarding Android I will recommend some android techs to handle it on Android client-side. So - Socket.io for sockets, Room or some reactive sharedpref(even android native one will work) to store data, LiveData to update UI.

This is the way I was working with and the way I would implement in future. It may not be ideal but moving all the major payment related stuff to the backend is a good idea.

There might be some specific for such combination errors and bugs also - but each approach will have some.

Hope this answer helps you somehow.

Ibraheem Zafar
  • 346
  • 1
  • 9
Pavlo Ostasha
  • 14,527
  • 11
  • 35
  • Honestly, this does not really help. The problem is, when I get a "pending" state, my app is unable to differentiate between "closed browser" and "payment processing" state, because they will both show as "pending". – Mark Buikema Feb 10 '20 at 08:40
  • While the app cannot do that(it may know but with the help of hacks and kludges) the payment provider might know that - take this info from it. – Pavlo Ostasha Feb 10 '20 at 09:03
0

Try to handle With Api it's better solution for you.

Step1: Store user status in your database when you receive payment Status(success/cancelled/pending)

Now if any user try to close browser though last transaction status is saved in your Database.

Step2: Then after try to fetch user order status by calling your api in onresume method of android.

At that time You definitely got accurate payment status because it's already saved in your database.

So when your close browser accidentally or some other reason. he will redirected to your app and at time your on resume method of application is called and he will see proper status of app.

Note: We do same in CCAvenue Payment Gateway. In their payment gateway we write of code on redirect URl and Cancle URL Method to Store payment Status.

Nimesh Patel
  • 1,394
  • 13
  • 26