SAP Commerce Cloud proposes a default stock level management strategy that fits in most of the cases. When business team wants to deviate from this standard, some difficulty can appear and often platform performance is impacted.
This article will explain what’s standard and what’s the philosophy behind. Then, you will see how much room for improvement is possible while preserving performance.
Standard Stock Level Management
By default stock level is stored internally by SAP Commerce. We don’t need to request external system as PoS (Point Of Service) or Warehouse for getting stock information. And the stock is consumed when we’ve an order placement confirmed.
Dedicated Online Stock
When PoS can allocate stock dedicated for the web shop, we’re in ideal situation. In this case, stock can be consumed by SAP Commerce itself and we don’t have stock concurrency consommation by physical shop.
However, we can still have concurrency stock consommation between users themselves. This case happens when two or more users are buying the same product at the same time and they’re placing order at the same moment. We can understand this situation arrives in two different situations :
-
- Rare product with high appetite. E.g. luxury market or aggressive promotion campaign.
-
- Consumer product. E.g. spare part or food.
For the both cases, to prevent out of stock situation, we’ve what we call reserved stock. This stock is potentially never sell and it acts as a buffer. When concurrency situation happens, then this buffer can be consumed without leading to out of stock situation.
Complexity is to determine what’s the right value for the reserved stock to maximize stock utilisation and to minimise out of stock situation.
We might be tempted to perform synchronous call toward back-end for checking stock before order placement validation. That’s not recommended and SAP Commerce product didn’t make this choice for user experience and performance reason.
As we see just above, this situation happens when we’ve high user traffic to handle. In this context, synchronous call could blocks the system and deteriorate the whole platform performance.
Then every night (or low traffic period), we can perform data synchronisation with back-end system to re-aligned internal SAP Commerce stock value with reality.
Shared Stock
In other case when we have global / shared stock, SAP Commerce is consuming stock during the day with no view global view on stock level. Still, reserved stock can be also used to limit out of stock situation.
Now complexity is to evaluate what will be consumed stock per physical shop during the day.
And at the end of day, we can perform data synchronisation to re-aligned internal SAP Commerce stock value with reality.
Dependencies
In standard, stock level can be used in many different aspect:
-
- By the search. search engine (Solr) needs to index this stock value
-
- By the promotion. We can increase product demand when stock value is remained high.
-
- By shipping. We should determine how we should divide order into consignment according sourcing possibility.
All those aspects demands some complex business logic computation and it is why we need to have internal stock level information with no external synchronous calls.
Data synchronisation
Stock level should be re-synchronized at least every day when traffic is low. And we should not perform global stock level synchronization during peak traffic otherwise we will lost cache benefit.
This data synchronisation is performed in standard by Integration API Module / Inbound sync.
Customization
By default
Default commerce service strategy is implemented in this following bean/class
commerceservices-spring.xml
<alias alias="stockLevelStatusStrategy" name="commerceStockLevelStatusStrategy"/>
<bean id="commerceStockLevelStatusStrategy"
class="de.hybris.platform.commerceservices.stock.strategies.impl.CommerceStockLevelStatusStrategy">
<property name="defaultLowStockThreshold" value="5"/>
<property name="commerceStockLevelCalculationStrategy" ref="commerceStockLevelCalculationStrategy"/>
</bean>
<alias alias="commerceStockLevelCalculationStrategy" name="defaultCommerceStockLevelCalculationStrategy"/>
<bean id="defaultCommerceStockLevelCalculationStrategy"
class="de.hybris.platform.commerceservices.stock.strategies.impl.DefaultCommerceAvailabilityCalculationStrategy"
/>
DefaultCommerceAvailabilityCalculationStrategy
calculateAvailability() {
[...]
stockLevel.getAvailable() - stockLevel.getReserved() + (long) stockLevel.getOverSelling();
[...]
}
Warehousing version is proposed when we activate order management module which is using same default strategy above.
warehousing-spring.xml
<alias alias="stockLevelStatusStrategy" name="warehousingStockLevelStatusStrategy"/>
<bean id="warehousingStockLevelStatusStrategy"
class="de.hybris.platform.warehousing.atp.strategy.impl.WarehousingStockLevelStatusStrategy"
parent="commerceStockLevelStatusStrategy"/>
WarehousingStockLevelStatusStrategy
public StockLevelStatus checkStatus(final Collection<StockLevelModel> stockLevels) {
[...]
availability = getCommerceStockLevelCalculationStrategy().calculateAvailability(filteredStockLevels);
[...]
We can see that stock availability is simply calculated locally as : stock level – reserved + over selling
Over selling is the opposite of reserved notion. It can be used to sell more than real stock capacity knowing that stock re-provisioning will be done in acceptable time to honor the order.
Synchronous stock verification
One common requirement is to check in synchronous the stock availability to back-end system.
When reserved stock value cannot be calculated and product re-provisioning is difficult or impossible (stock liquidation), we could sacrifice performance to better stock control.
This requirement can fit
-
- for B2B market where basket entries are expensive and stock limited.
-
- for B2C market where traffic is smoothed over time and we want to do stock clearance/liquidation
But it doesn’t fit in classic B2C market where we have peak traffic period and aggressive promotion campaign.
In this approach, we will have connection/thread retention for each stock verification call. That will increase memory consumption and over stress SAP Commerce node. This memory consumption will depends on user traffic plus on response time latency on 3rd party that provides stock level.
Stock verification should be implemented by overriding placeOrderCartValidator bean
validators-v2-spring.xml
<alias name="defaultPlaceOrderCartValidator" alias="placeOrderCartValidator"/>
<bean id="defaultPlaceOrderCartValidator"
class="de.hybris.platform.commercewebservices.core.validator.PlaceOrderCartValidator">
</bean>
Cart stock booking
Another common requirement is to book product stock at cart level to ensure that customer will get the product at the end of checkout process. It is first arrived, first served strategy.
This strategy is generating a lot write database access. Each Cart action will trigger several database queries : read stock, update stock, invalidate stock cache, read stock for other requests. And this behavior can become exponential where Bundle is part of product catalogue.
In short, stock level change at Cart level, it is a performance killer.
This requirement should be studied carefully and it is more suitable for B2B market where stock level is low and user traffic is light.
Performance impact could be mitigated by implementing asynchronous stock change strategy inspired from asyncSessionPersisterRunnable approach. The idea is to centralize stock change into one thread/queue that will control database writing activity. Drawback is that stock booking is not in real time. In other words, stock reservation is not guaranteed by the system. It is what we can call a best effort strategy.
For more advanced solution, you should consider to integrate SAP Order Management for Sourcing and Availability
Conclusion
Stock management is serious topic and it should not be underestimated. It can have negative performance impact and/or business impact.
SAP Expert service team can help you to ensure a suitable stock management configuration/implementation regarding your business specificity.