What should your transaction management strategy be for an e-commerce system? - language-agnostic

What is the general pattern or approach to managing transactions in a web-based e-commerce system? How do you handle the situation where more than one user tries to buy the last item, for example?

To prevent two users from purchasing the same stock item of which there is only 1 unit in stock, you need to check that each item in a user's cart has stock available right before you create an order and decrement stock for that item.
This operation will have to be atomic and only one order can be processed at any given time (read: database transaction), which should not be a problem if you are using a central database for stock management.
If stock has run out by the time a client checks out, you should remove the item from the client's cart and redirect them to their shopping cart, informing them of the situation.
Of course, this situation only occurs when two users both add the same stock item to their cart of which only one unit is in stock and one of them checks out. First come, first served. You should generally not allow clients to add products to their cart if no stock is available at that moment, unless you can order new stock within a reasonable amount of time, but in that case, the whole point is moot.
You can take a preemptive approach by checking that stock is available the moment a client initiates checkout and take the same route as above. However, that would depend on the nature of your product and the volume of transactions vs cancelled orders. If it is likely that another order for the same item was cancelled in the meantime and stock becomes available by the time a client checks out, then you don't want to lose a sale by telling the client that no stock is available. Better to let the order fail at the moment stock is not available and inform the client of the situation, which is rare after all.

Why not take the order and then get that item for the customer, perhaps a bit later? You can win a repeat customer :)

Related

How to implement "SQL Transactions" in "Clean Architecture"?

I am working on an Express-based (Nodejs) API that uses MySQL for data persistence. I have tried to follow the CLEAN ARCHITECTURE proposed by Sir R.C. Martin.
Long story short:-
There are some crop vendors and some users. A user can request an order of some crops with a defined quantity from a vendor. This puts the order in PENDING state. Then the vendor will confirm the orders he/she gets from the user.
Domain/Entity -> CROP, Use-case -> add, remove, edit, find, updateQty
Domain/Entity -> ORDER, Use-case -> request, confirm, cancel
I have to implement a confirm order functionality
I have an already recorded order with ordered item list in my DB (order in the pending state)
Now on confirming order action I need to subtract each item quantity from respective crop present in the DB record, with a check that no value turns negative (i.e. no ordered qty is more than present qty)
If it is done for all the items under a "transaction cover" then I have to commit the transaction
Else revert back to the previous state (i.e rollback)
I know how to run Mysql specific transactions using "Sequelize", but with a lot of coupling and poor source code architecture. (If I do it that way, then DB won't be like plugin anymore)
I am not able to understand how to do this while maintaining the architecture and at what layer to implement this transaction thing, use-case/data-access, or what?
Thanks in advance
I recommend keeping the transaction in the "adapters layer" by using "unit of work" pattern. This way the database remains a plug-in to the business logic.

Stock management database design

I'm creating an Intranet for my company, and we want to have a stock management in it. We sell and rent alarm systems, and we want to have a good overview of what product is still in our offices, what has been rented or sold, at what time, etc.
At the moment I thought about this database design :
Everytime we create a new contract, this contract is about a location or a sale of an item. So we have an Product table (which is the type of product : alarms, alarm watches, etc.), and an Item table, which is the item itself, with it unique serial number. I thought about doing this, because I'll need to have a trace of where a specific item is, if it's at a client house (rented), if it's sold, etc. Products are related to a specific supplier, to whom we can take orders. But here, I have a problem, shouldn't the order table be related to Product ?
The main concern here is the link between Stock, Item, Movement stock. I wanted to create a design where I'd be able to see when a specific Item is pulled out of our stock, and when it enters the stock with the date. That's why I thought about a Movement_stock table. The Type_Movement is either In / Out.
But I'm a bit lost here, I really don't know how to do it nicely. That's why I'm asking for a bit of help.
I have the same need, and here is how I tackled your stock movement issue (which became my issue too).
In order to modelize stock movement (+/-), I have my supplying and my order tables. Supplying act as my +stock, and my orders my -stock.
If we stop to this, we could compute our actual stock which would be transcribed into this SQL query:
SELECT
id,
name,
sup.length - ord.length AS 'stock'
FROM
product
# Computes the number of items arrived
INNER JOIN (
SELECT
productId,
SUM(quantity) AS 'length'
FROM
supplying
WHERE
arrived IS TRUE
GROUP BY
productId
) AS sup ON sup.productId = product.id
# Computes the number of order
INNER JOIN (
SELECT
productId,
SUM(quantity) AS 'length'
FROM
product_order
GROUP BY
productId
) AS ord ON ord.productId = product.id
Which would give something like:
id name stock
=========================
1 ASUS Vivobook 3
2 HP Spectre 10
3 ASUS Zenbook 0
...
While this could save you one table, you will not be able to scale with it, hence the fact that most of the modelization (imho) use an intermediate stock table, mostly for performance concerns.
One of the downside is the data duplication, because you will need to rerun the query above to update your stock (see the updatedAt column).
The good side is client performance. You will deliver faster responses through your API.
I think another downside could be if you are managing high traffic store. You could imagine creating another table that stores the fact that a stock is being recomputed, and make the user wait until the recomputation is finished (push request or long polling) in order to check if every of his/her items are still available (stock >= user demand). But that is another deal...
Anyway even if the stock recomputation query is using anonymous subqueries, it should actually be quite fast enough in most of the relatively medium stores.
Note
You see in the product_order, I duplicated the price and the vat. This is for reliability reasons: to freeze the price at the moment of the purchase, and to be able to recompute the total with a lot of decimals (without loosing cents in the way).
Hope it helps someone passing by.
Edit
In practice, I use it with Laravel, and I use a console command, which will compute my product stock in batch (I also use an optional parameter to compute only for a certain product id), so my stock is always correct (relative to the query above), and I never manually update the stock table.
This is an interesting discussion and one that also could be augmented with stock availability as of a certain date...
This means storing:
Planned Orders for the Product on a certain date
Confirmed Orders as of a certain date
Orders Delivered
Orders Returned (especially if this is a hire product)
Each one of these product movements could be from and to a location
The user queries would then include:
What is my overall stock on hand
What is due to be delivered on a certain date
What will the stock on hand be as of a date overall
What will the stock on hand be as of a date for a location
The inventory design MUST take into account the queries and use cases of the users to determine design and also breaking normalisation rules to provide adequate performance at the right time.
Lots to consider and it all depends on the software use cases.

How to avoid paying for the same item multiple times

I'm trying to draw a database design of an ecommerce, and fulfilment of order platform. The company currently has a distribution centre for fulfilling the orders. But they want to extend this to use its stores for a part of the fulfilment process. I have designed a database of "internet sales" and "store sales", but I am stuck on the fulfilment of the internet order, and I wonder if any of you can help me with this.
Scenario : When the customer places in an order, and the distribution centre doesn't have a stock of an item to ship to the customers, the item needs to be taken from one of the stores. This item is then sent to the customer.
But the problem is that I can't just take an item from a store, and then send it to the customers, because the item hasn't been sold in the store, its (store) stock database isn't going to be updated. If I put the item through the cash machine, the item is removed from the stock table, but there are two transactions for the same item - one transaction from the internet, and the other from the store.
I guess my question is, how do I go about processing internet orders, and avoid having two transactions on the same item?
Any helpful pointers on this issue is greatly appreciated.
Update : Here's what I have done so far after advice from Jo Douglass,
Database Design Here
Sorry, I can't post images, because I don't have enough points. And please note that the above database design isn't complete
It sounds like you have a Transaction entity, and you have or are planning on having some logic which ensures that when one of these is created for an Item, your system knows to deplete the stock level for the relevant location (either a store of the distribution centre).
You could use an entity which shows an Item being transferred from one location (a store) to another (a distribution centre), and then create some logic which works very similarly to your existing logic - depleting the stock level in the starting location, and increasing the stock level in your destination location. Then when you carry out the last part of the process (sending the item to the customer), you'll have a Transaction showing that and depleting the distribution centre's stock level. Depending on the rest of your model, you might carry this out via a change to the Transaction entity, or by creating a new entity altogether.
Alternatively, if that doesn't really model what's happening in the business very well, then maybe you just need to modify your logic (and possibly your model - hard to tell without seeing your existing model). Rather than only being able to create store transactions via use of the cash register, perhaps you simply need to be able to create a store transaction that's been kicked off via the Internet.
One idea is to go ahead and treat the item as sold from the store (through an online transaction) and credit the store's account with the sale price. The distributor has probably already received the wholesale price from the store so it's happy, the store gets credit for the sale (with at least some part of the shipping charges) so it's happy, and you don't have to create new transaction codes or any other modification to the existing database.

Disregard changes to a product description when retrieving order records

The title is somewhat hard to understand, so here is the explanation:
I am building a system, that deals with retail transactions. Meaning - purchases. I have a database with products, where each product has an ID, that is also known to the POS system. When a customer makes a purchase, the data is sent to the back-end for parsing, and is saved. Now everything is fine and dandy, until there are changes to the products name, since my client wants to see the name of the product, as it was purchased then.
How do I save this data, while also keeping a nice, normal-formed database?
Solutions I could think of are:
De-normalization, where we correlate the incoming data with the info we have in the database, and then save only the final text values, not id's.
Versioning, where we keep multiple versions of every product, and save the transactions with the id of the products version, when it came in. The problem with this one is, that as our retail store chain grows, and there are more and more changes happening to the products, the complexity of the whole product will greatly increase.
Any thoughts on this?
This is called a slowly changing dimension.
Either solution that you mention works. My preference is the second, versioning. I would have a product table that has an effdate and enddate on the record. You can easily find the current record (where enddate is null) or the record at any point in time.
The first method always strikes me as more "quick-and-dirty", but it also works. It just gets cumbersome when you have more fields and more objects you are trying to track. It does, in general though, win on performance.
If the name has to be the name as it was originally, the easiest, simplest and most reliable way to do that is to save the name of the product in the invoice line item record.
You should still link to the product with a ProductID, of course.
If you want to keep a history of name changes, you can do that in a separate table if you wish:
ProductNameID
ProductID
Date
Description
And store a ProductNameID with the invoice line item.

Preventing race conditions for ecommerce application with MySQL

I'm building a ecommerce application with MySQL, but I'm having a hard time coming up with a solution that prevents the following race condition:
Two users checkout at the same time with the same item in their cart. The store only has one item available for sale. One user should be able to purchase the last item, and the other user should see an error message because the item is out of stock.
I'm using an item counter to keep track of the number of items in inventory, so I figure I would just decrement the item after processing the user's credit card.
I know about the SELECT...UPDATE query in MySQL, but I'd like to stay away from locking rows or tables - unless that's really the best way for an ecommerce app to solve this problem.
I'm also interested in hearing other solutions other than checking/decrementing an item counter.
Why are worried about locking. It wont hurt you till you have 100s of simultaneous customers at a time and database engines like innodb are made to handle those things. You wont be able to get way from some kind of atomicity and workaround.
You need to keep application level transaction management.
checkout
reserver_the_items_in_cart
if(reservation_succesfull){
get_the_payments_done_via_payment_gatway
if(payment_successful) {
update_the_reserverd_to to sold_status
}else{
make_reserved_item_to_available.
}
}else{
show_error_that_item_not_available.
}
Other best way to handle this is never allow "show_error_that_item_not_available" to happen. Replenish inventory on time when it started running out.
The way I am going about this is
1. check availability for X books
2. if there are X books, place the actual order
3. check availability again if availability is ok, then everything is ok... if availability is off, I reverse the order and notify customer.