0

Creating an order in my custom Laravel shop takes some time, because of an third party API call. To prevent users from submitting the checkout form twice, I disable the submit bitton and show and replace it with a process icon via Javascript.

Nevertheless some customers can not wait 10 seconds to complete the process. They reload the page and submit the form again. In this case, the shop generates two orders.

Now I could prevent the form from sumbitting multiple times serversited with token match (Prevent Multiple Submitting in one button laravel). Actually, this solution will causes other issues. So I can not simply redirect the customer to the success-page, because the order process might not be complete. Otherwise the customer is stuck in the checkout page.

What is best practise for this problem?

Malenfant
  • 3
  • 1
  • Is your order form submitting via an Ajax request to the server? Is the order checking out a basket (stored in DB) or is it creating an order directly from the products select on the front end form? – Jon White Feb 27 '21 at 09:29
  • The cart is stored as a cookie. The order details are stored in the session id. The form ist submitted directly via html to the server. It contains nothing but an "place order" field. I am using no Ajax here. The order is created after submit out of the cookie and the session data. During this process, an API call is made to check stock (dropshipping). If the API call fails, the user is redirected to the cart-page. Otherwise the order is stored in DB. – Malenfant Feb 27 '21 at 10:03
  • Okay I see. An Ajax request to submit the form may be your best bet here. That way the page can show a spinner with the button disabled until the response is returned. At which point you can redirect to the next page. This gives the user an indication that something is happening and they don't need to refresh as well as prevents the user from being able to submit again. – Jon White Feb 27 '21 at 10:12
  • Alternatively you could make the external API call a queued job to be processed asynchronously. That way the form submit response is quick and the API call can take all the time it needs. The only problem is if you need the result of the external API call in the next page? – Jon White Feb 27 '21 at 10:14
  • Is your form written purely in a blade file or are you using vue components? – Jon White Feb 27 '21 at 10:18
  • The queue is a good idear, but I need the result to proceed the process. There is no way to reserve the dropshipper´s products in any way. So I have to minimize the timespan between checking the stock and placing the order. A spinner and a disabled button are already in place after submitting the form, but customers dont´t care. – Malenfant Feb 27 '21 at 10:44
  • Thinking out loud: If I store the form token in DB right after after submitting the form and I delete this entry in the end of the creation process, it must be possible to check the state of process with an Ajax request before submitting the form, right? Indeed this becomes much more comlicated... – Malenfant Feb 27 '21 at 10:44
  • Actually, I am using no vue. I am Looking forward to use it in upcoming projects. – Malenfant Feb 27 '21 at 10:45
  • Perhaps you could call the third party API to get your dropshipping data with some kind of spinner to show the process working before you disable the submit button. So the user can't submit until AFTER the droppshipping API has returned its response? – Jon White Feb 27 '21 at 11:15
  • Ok, it think separating the API call from the order creation process is the way to go. Although it won't completely solve the problem. Even if the order takes a second to create, a customer could reload the checkoutpage right after submitting the form and submit it aganin. I wonder, how other webshops handel this issue. – Malenfant Feb 27 '21 at 13:08
  • Okay, that sounds like a step in the right direction. I should probably write it up as a proper answer. – Jon White Feb 27 '21 at 18:38

1 Answers1

1

As per our discussion in the comments on your original post:

The primary issue is the length of time it takes the server to process the form submission which gives the user the opportunity to get impatient and refresh the page and then submit the same data twice. Your external API call to get your drop shipping data is the process costing the most time.

So I would suggest getting the drop shipping data before allowing the final submission of the form. You could possibly do it as an Ajax request and keep the submit button disabled until the drop shipping data is returned. That way when the user submits the form, the server-side processing time is minimised.

There is still a chance that processing time for the form submission could still be long enough for the user to refresh the page before the submission is complete.

I think the remaining process should be short enough for users not to have the opportunity to refresh the page before the submission is complete. If it is then you may need to look at any processes in the submission logic that take time and either prepare them prior to submission like with the drop shipping API call or push them out to queue workers.

You could also make your persistence to the database the final action in the submission process before returning its response. That way, if the user is able to refresh before the process is complete, there is a minimum possibility that data has been persisted meaning that if the form is submitted a second time, the data is least likely to be duplicated.

You could go down the route of setting a token in the form to ensure the form can only be loaded once or storing a "prospective" order throughout your previous steps and making the submission the simple action of marking the "prospective" order as a "real" order. But these approaches feel an over-complication of the typical form submission request approach that assumes the request and response cycle would not be interrupted.

Jon White
  • 682
  • 4
  • 12
  • I am going to get the API call before the final submit and try to push the confirm mails in a queue. This should to the job. Thank you for this detailed answer. It helped me alot. – Malenfant Feb 27 '21 at 20:01