views:

234

answers:

4

this question is similar to this one but with a twist (so the answer accepted for the older question is not valid in the following scenario)

i have a site for selling tickets (PHP/MYSQL). Suppose i have just one ticket left:

  • buyer A puts the ticket in her cart and goes to the payment gateway page (ie. paypal)
  • the ticket is locked for 5 minutes, so buyer B cannot buy it
  • buyer A waits 5 minutes with the paypal page open, doing nothing
  • the ticket is unlocked so buyer B puts it in his cart and goes the the paypal page
  • buyer A executes the payment procedure on paypal with success
  • buyer B executes the payment procedure on paypal with success

i can wait longer but i don't think this will solve the issue in the more general case. moreover, if i do that, it will be possibile to make some kind of DoS, locking the items in stock for large periods of time.

what's the best way to handle this scenario ?

+1  A: 

How about a more social solution instead of a technical one? Why not make it absolutely obvious that a ticket will become unlocked when you wait too long?

Peter Stuifzand
this won't solve the issue as, even if it is obvious, both payers end up doing two legal payment for one item.
gpilotino
Yes, you are right, it won't stop one of the two customers from buying a ticket in the way described. You could also say that the first customer waited to long. Maybe you can include your 5 minute rule in your Paypal request...?
Peter Stuifzand
in this case the question becomes: do (all) payment gateways support (configurable) timeouts ? even if, this will solve only the first half =)
gpilotino
Ok, I checked Paypal docs and couldn't find anything that looked like my suggestion.Another way to look at this may be: how often does this happen?
Peter Stuifzand
very often on high traffic sites that sell tickets (because people tend to hurry up trying to buy them)
gpilotino
It looks like you're saying two different things: 'people tend to hurry up' and people waiting for 5 minutes :D
Peter Stuifzand
they don't wait when there are tickets in stock, just when they're nearly finished (and this happens in minutes), that's the problem.
gpilotino
+5  A: 

All payment gateways will do a postback to let you know (eg) the payment reference etc. Most will also postback authorisation/authentication information, such as CSC/CVV2 check results so that you (the merchant) have the final say in whether to accept the payment or not.

On receipt of the postback you should be able to check if the ticket is still 'locked', and if not then issue a payment reversal through the payment gateway to cancel the payment. You then need to display a message 'sorry, timeout exceeded please try again'

If the gateway doesnt support an 'instant reversal' style functionality, then they will at least support some sort of 'void' functionality whereby the funds are never actually taken from the customers card, and the authorisation hold drops off automatically (usually after two days, though it can take longer on some cards). For the (hopefully small) number of transactions that time-out, this may be acceptable. It would be worth monitoring how many transactions time-out so that the time-out period can be adjusted.

Alternatively, if the ticket is no longer locked, (and again, if the gateway supports it) send back a Refund payment.

PaulG
afaik the postback happens after the payment has suceeded so still both users will find less money on their cc suddenly. correct me if i'm wrong but this will be the equivalent of manually go to the payment gateway backend and check "don't accept this payment" (payment reversals usually take days so i want to avoid coping with thousands p.r. possibly).
gpilotino
Cant speak for every gateway, but I know most of the UK ones allow you to send a 'reversal' message back to cancel the payment. This is an instant reversal and doesnt take the usual two or more days to drop off.
PaulG
nice to know, i'll invetsigate that thank you
gpilotino
+2  A: 

I think you should not block the ticket if someone puts it in his cart as in those 5 mins. you might end up driving away few other customers...

I suggest you to allow everyone to add the ticket to his/her cart unless someone actually makes the payment and buys it. Now when others proceed for checkout, just flash a message as "Sorry You Are Late... Ticket Sold Out !!!" and ticket should be removed from their cart.

This way the ticket will not be blocked from your customers and still the scenario of two people making payment for the same ticket will not arise.

Aditya
you know if the payment is successfully completed only after it is finalized. if both users are already on the payment (ie. paypal) page you have no control: they'll both pay (on paypal) for the latest ticket.
gpilotino
+1  A: 

It is likely that you can not use an external payment gateway entry page and do what it is you are trying to do.

Paypal and many other processors have a direct web service integration route. This means you collect the payment information on your page, it gets submitted to your server, and you make the web service call and get an immediate response from the processor. (I don't remember what PayPal calls the product that does this, but it used to be named PayFlow Pro and was bought from Verisign.)

So you don't lock the tickets when they are placed in the cart. Your workflow would be:

  1. Collect payment information.
  2. Once payment info is posted back to your server: a. Try to lock the tickets - return failure if not available b. On successful lock, process authorization
  3. On successful authorization, tickets are removed from the available pool.
  4. On unsuccessful authorization or error, tickets are unlocked and available for other users.

No need to deal with lock timeouts. They are only locked long enough to verify a valid payment.

You didn't ask about solving the issue while preventing PCI exposure. Since you'll probably ask:

There are processors out there that allow you to embed the payment information collection in your own page. There are some that allow you to obtain a "token" to replace a card number so that your server never receives a card number. The token can then be used on the server side web service call. You get what you need and you don't have to deal with PCI issues around receiving card numbers.

Nathan