Show stock availability on the cart page

Java · Spring Boot · intermediate · modification

Availability badges for the cart page ("In stock" / "Only 3 left" / "Out of stock"). The service sums `onHand - reserved` across warehouses for the whole cart in one grouped query, then maps the totals back onto the request lines, so the response keeps the cart's order. The request is validated at the controller (line count, SKU length, quantity range). Tested on a local cart with a stocked mug and a sold-out T-shirt: 7 available and in stock, 0 available and out of stock.

Shop backend on Spring Boot 3.3 (Java 21, Gradle with the Spring Boot plugin), Spring Data JPA with Hibernate 6.5 on PostgreSQL. Existing `StockLevel` entity (table `stock_levels`): `Long id`, `String sku`, `Long warehouseId`, `int onHand`, `int reserved`, all non-null, with a check constraint `0 <= reserved <= on_hand` and one row per SKU and warehouse. A SKU gets its first row at its first goods receipt in a warehouse, so new and pre-order catalogue items have no rows at all; a sold-out SKU keeps its rows at 0. SKUs are exact, case-sensitive codes. `SecurityConfig` permits `/api/cart/**` and `/error` to guests (guest checkout) and handles CSRF for the SPA. Showing exact counts ("Only 3 left") is a product decision.

Requirements

Files touched

--- src/main/java/com/acme/shop/inventory/StockLevelRepository.java
 package com.acme.shop.inventory;
 
+import java.util.Collection;
+import java.util.List;
 import java.util.Optional;
 
 import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.data.repository.query.Param;
 
 public interface StockLevelRepository extends JpaRepository<StockLevel, Long> {
 
     Optional<StockLevel> findBySkuAndWarehouseId(String sku, Long warehouseId);
+
+    @Query("""
+            select s.sku as sku, sum(s.onHand - s.reserved) as available
+            from StockLevel s
+            where s.sku in :skus
+            group by s.sku""")
+    List<SkuAvailability> sumAvailableBySku(@Param("skus") Collection<String> skus);
+
+    interface SkuAvailability {
+
+        String getSku();
+
+        Long getAvailable();
+    }
 }
 

Review this PR

Java practice