Stripe PaymentIntent: Best practice for ensuring inventory? - stripe-payments

With the charges API, a token would eventually be handed to the server that would allow you to charge against the customer's credit card, and the last step to complete the payment is handled by my server. This would allow you to do something like:
// Prevent anyone else from purchasing widget while we sell this one
lock(database){
if (widgetsAvailableCount > 0) {
widgetsAvailableCount--;
var charge = chargeService.Create(optionsForWidgetCharge);
}
else {
throw new Exception("Item is out of stock");
// Don't create charge against token in this case
}
}
This allows you to prevent a race condition where you sell the last remaining item to two people.
But with the PaymentIntents API, it seems that the final step in charging the credit card no longer happens on my server, but will happen when the client calls:
https://stripe.com/docs/js/payment_intents/confirm_card_payment
And it's not clear how long that will actually take (say, if a 3D Secure prompt is shown).
I'm trying to solve the same problem as above, avoiding the situation of accepting payment when there is no inventory left (where inventory was available at the time the payment process started but not when it was completed). I could mark in the database the item in a "reserved" state, but I'm wondering if I'm thinking about this the right way, and how others have addressed this if so.

Related

Handling Pledge (performance based) donation with Stripe

I'm working on a fundraiser app.
Users can create a fundraiser - with a donation category - pledges (performance-based) donations.
That means - if a school has a running event - parents (or any other person) can go to a participant's fundraiser page and donate x amount of money per unit (in this case meter)
for example, the parent can decide to donate $1 per meter. therefore, if the kid ran 50 meters, the total amount will be - 50$.
I want to know what will be the best way to handle this kind of donation using Stripe.
What we are doing now is:
Creating a customer (if doesnt exist already) so we can store the card for later use. creating setup intent - sending the client's secret from the back end to the front end.
let customer = stripe.customers.create(options)
stripe.setupIntents.create({customer: customer.id ...})
On the front end - A donor filling the amount per unit (1$ per meter) - the donor can tip the platform (percent of the total amount or flat)
The donor filling the card inside Stripe form.
On the back end - we are attaching the card to the customer, storing data on the db (amount, tip, customer id, intent id)
When the event is over - the user can close the fundraiser and charge all the cards based on the amount and units. for example - we have 10 kids, each kid has 5 donations, each donation is 1$ per meter, and each kid ran 50 meters.
On the back end - we are looping through all the donations related to the fundraiser. creating a payment intent that automatically charged for each donation.
let donations = Donations.find({fundraiser: fundraiserId...})
donations.forEach((item)=>{
stripe.paymentIntents.create(
{
payment_method: donation.payment_method,
amount: donation.amount * participant.units + donation.tip,
off_session: true,
confirm: true,
...
}
})
The issues we are facing:
Stripe rate limiter - allows us to do 100 calls in a second for live mode. that means we need to slow our loop with interval.
Catching errors and success - in order to catch errors and success we need to async await, stripe functions returning promise. the problem with await is that it slows down the loop alot - one solution will be to use webhook to catch all the reponses - the issue is the amount of requests from stripe - we will need also to think about a rate limiter - but in case of multiple users requesting donations charges we can end up with many many incoming requests from stripe.
To not let all the users to request payments at once (to prevent massive requests - and sending massive amount of requests to stripe) - we need to handle a queue system (so we will not exceed the limit by Stripe and we can handle incoming requests from stripe). what do you think can be a good queue system - should it be on a seperate server? - do you think there is a better solution?
what fo you think would be the best approach in general to achieve the pledges (performance based) donations system.
**I can share more code if needed. and im willing to answer any question to clear it out.

CQRS - applying command based on decision from multiple projections

Question is related to CQRS - I have user that wants to order something from web and is presented with GUI showing his balance = 100$ and stock = 1 item. Let's say we have 2 services here AccountService and StockService with separate concerns. In order to generate GUI for client third service AggregatorService listens to domain events from AccountService and StockService, projects a view and creates GUI for clients.
When user decides to order this item, he clicks a button and Command for order is sent to AccountService. Here we load AccountAggregate in order to decrease balance for the price of the item that needs to be ordered. But before I can do this, I have to check if the item is still available (or somehow to reserve it). Only thing that comes up to my mind is:
Read current stock of the item from read model of StockService, but what can happen is that other services read model is updated just a second after I read it (e.g. somebody bought the item, so actual stock is =0. but read model still has =1).
Before decreasing a balance call some method on StockService to reserve the item for some time. If order is not successful (e.g. no enough funds on balance, I would have to un-reserve it somehow). This needs to be some sync-REST call and it is probably slower than some async solution (if any).
Are there any best practices for this kind of use-case?
You have 2 options, depending on whether you embrace eventual consistency or not.
Using immediate consistency I would have an OrderService that receives the order request and it makes async calls to AccountService.ReservePayment() and StockService.ReserveStock(). If either of those fail you call AccountService.UndoReservePayment() and StockService.UndoReserveStock(). If both succeed you call AccountService.CompleteReservePayment() and StockService.CompleteReserveStock(). Make sure each reservation should have a timestamp on it so a daemon process can occasionally run and Undo any reserves that are older than an hour or so.
This approach makes the user wait until both those services complete. If either the StockService or the AccountService are slow, the user experience is slow. I suggest a better way to do this is the eventual consistency approach which gives the user a very fast experience at the expense of receiving failure messages after the fact.
With eventual consistency you assume they have enough credit and you have enough inventory, and in response to their order request you immediately send back a success message. The user is happy and they go along to buy more stuff.
The OrderCreated event is then handled asynchronously to reserve stock and credit as described above. However, since there is no time pressure to reply to the waiting user you don’t have to scale up to handle as high a throughput. If the credit check and stock check take a minute or two, the user doesn’t care because he’s off doing other things.
The price you pay here is that the user may get a success message at the time of order submission, then a few minutes later get an email saying the sale didn’t go through after all because there’s no stock. This is what many large retailers do, including Amazon, Target, Walmart, etc. Eventual consistency can go a long way towards easing the load and cost of the back end.

How to perform validation across services in microservices

Suppose there are two microservices: Order and Inventory. There is an API in order service that takes ProductId, Qty etc and place the order.
Ideally order should only be allowed to place if inventory exists in inventory service. People recommend to have Saga pattern or any other distributed transactions. That is fine and eventually consistency will be utilized.
But what if somebody wants to abuse the system. He can push orders with products (ProductIds) which are either invalid or out of inventory. System will be taking all these orders and place these orders in queue and Inventory service will be handling these invalid order.
Shouldn't this be handled upfront (in order service) rather than pushing these invalid orders to the next level (specially where productId is invalid)
What are the recommendations to handle these scenarios?
What are the recommendations to handle these scenarios?
Give your order service access to the data that it needs to filter out undesirable orders.
The basic plot would be that, while the Inventory service is the authority for the state of inventory, your Orders service can work with a cached copy of the inventory to determine which orders to accept.
Changes to the Inventory are eventually replicated into the cache of the Orders service -- that's your "eventual consistency". If Inventory drops off line for a time, Order's can continue providing business value based on the information in its cache.
You may want to be paying attention to the age in the data in the cache as well -- if too much time has passed since the cache was last updated, then you may want to change strategies.
Your "aggregates" won't usually know that they are dealing with a cache; you'll pass along with the order data a domain service that supports the queries that the aggregate needs to do its work; the implementation of the domain service accesses the cache to provide answers.
So long as you don't allow the abuser to provide his own instance of the domain service, or to directly manipulate the cache, then the integrity of the cached data is ensured.
(For example: when you are testing the aggregate, you will likely be providing cached data tuned to your specific test scenario; that sort of hijacking is not something you want the abuser to be able to achieve in your production environment).
You most definitely would want to ensure up-front that you can catch as many invalid business cases as possible. There are a couple ways to deal with this. It is the same situation as one would have when booking a seat on an airline. Although they do over-booking which we'll ignore for now :)
Option 1: You could reserve an inventory item as part of the order. This is more of a pessimistic approach but your item would be reserved while you wait for the to be confirmed.
Option 2: You could accept the order only if there is an inventory item available but not reserve it and hope it is available later.
You could also create a back-order if the inventory item isn't available and you want to support back-orders.
If you go with option 1 you could miss out on a customer if an item has been reserved for customer A and customer B comes along and cannot order. If customer A decides not to complete the order the inventory item becomes available again but customer B has now gone off somewhere else to try and source the item.
As part of the fulfillment of your order you have to inform the inventory bounded context that you are now taking the item. However, you may now find that both customer A and B have accepted their quote and created an order for the last item. One is going to lose out. At this point the one not able to be fulfilled will send a mail to the customer and inform them of the unfortunate situation and perhaps create a back-order; or ask the customer to try again in X-number of days.
Your domain experts should make the call as to how to handle the scenarios and it all depends on item popularity, etc.
I will not try to convince you to not do this checking before placing an order and to rely on Sagas as it is usually done; I will consider that this is a business requirement that you must implement.
This seems like a new sub-domain to me: bad-behavior-prevention (or how do you want to call it) that comes with a new responsibility: to prevent abusers. You could add this responsibility to the Order microservice but you would break the SRP. So, it should be done in another microservice.
This new microservice is called from your API Gateway (if you have one) or from the Orders microservice.
If you do not to add a new microservice (from different reasons) then you could implement this new functionality as a module inside of the Orders microservice but I strongly recommend to make it highly decoupled from its host (separate and private persistence/database/table).

Stripe: Can I change total of a charge after the fact?

My employer has challenged me to build him a custom Point of Sale system and stripe was my first thought for payment processing. I work in food-delivery, and as such our current (as well as every other) POS immediately charges the card (verifies it? whatever), and then at the end of the night when tips are counted (whether from the drivers or tipped receipts in the tip box) the charge changes to whatever the customer agreed to.
I see I can do a few similar things:
update metadata on a charge (not what I need)
capture a charge (not what I need - won't let you use a value higher than the initial)
do a second charge for the tip (would hope to avoid this)
save the card information with Stripe after creating a customer object and not do any charge until after I know the tip (would hope to avoid this)
But, can I verify the customer can pay the amount (that initial charge) and then increase it later once we know if/how much they tipped?
Simply put, I'd like my flow to be:
Customer orders
Charge is issued for 20$ of food (Stripe)
Food is delivered, 5$ tip secured on the receipt
Receipts are turned in, 5$ tip is entered into system
Charge is changed to reflect the added tip (now 25$) (Stripe)
Is this possible with Stripe? If so, how?
If not, do you know of any other payment system that could implement this flow?
Short answer: no, that's not possible.
You could do something like this:
Create an uncaptured charge for the base amount.
Once the customer confirms the tip, try to create a charge for the base amount + tip.
3a. If the charge succeeds, release the first uncaptured charge (by refunding it).
3b. If the charge fails, capture the first uncaptured charge (and maybe explain to your customer that they were only billed for the base amount).

Money reservation with First Data API on client credit card

I need to know is it possible to reserve or lock money with First Data API. Actually I don't know if process I am looking for is actually called "reservation", but I am thinking of standard procedure of locking certain amount of money on client CC so that client cannot spend it but I as a merchant, can return money without any cost to bank, client and myself if client or merchant wishes so. Kinda sorta like deposit. I just don't want to do full transaction and then return money with full transaction and pay every single step of it and then some for accounting nightmare.
1) Do an Authorization (a.k.a. Auth Only, Authorization hold) to freeze the maximum amount of funds you wish to access at a later date. Record the approval code from this transaction.
2) When it is time to charge the funds you wish to receive from the customer perform a Capture using the approval code received from the Authorization in step one.
Caveats:
1) You have a maximum of 30 days to capture the funds. This number may be lower for some credit cards.
2) You may only capture the funds set aside or less. You cannot capture more then the amount authorized.
3) You can only capture the funds once. This means if you capture an amount less then the total amount authorized and then you wish to go back later and get more you cannot do so. You would need to process another transaction with a fresh approval number to do so.
An Authorization hold may be what you need.

Resources