Overview
The Product Distribution Dashboard provides two levels of metrics: global metrics for high-level overview and detailed metrics for in-depth analysis. All metrics are cached for performance and automatically invalidated when distribution runs.
Global Metrics
Global metrics provide a high-level snapshot of the entire distribution system:
MetricsService.java:38-56
@ Cacheable ( "globalMetrics" )
public GlobalMetricsDTO calculateGlobalMetrics () {
logger . info ( "Calculating global metrics" );
try {
MetricsRepository . GlobalMetricsProjection projection = metricsRepository . getGlobalMetrics ();
GlobalMetricsDTO result = metricsMapper . toGlobalMetricsDTO (projection);
logger . info ( "Global metrics calculated: {} shipments, {} units, {} km average, {} unfulfilled units" ,
result . totalShipments (), result . fulfilledUnits (),
result . averageDistance (), result . unfulfilledUnits ());
return result;
} catch ( Exception e ) {
logger . error ( "Error calculating global metrics" , e);
return createEmptyGlobalMetrics ();
}
}
Global Metrics Fields
Total number of stock assignments created across all warehouses and stores
Total number of product units successfully shipped
Total number of product units that could not be fulfilled due to capacity or stock shortages
Average shipping distance in kilometers across all assignments
Detailed Metrics
Detailed metrics support filtering by warehouse, store, or product for granular analysis:
MetricsService.java:58-121
@ Cacheable ( value = "detailedMetrics" , key = "#criteria.warehouseId + '_' + #criteria.storeId + '_' + #criteria.productId" )
public DetailedMetricsDTO calculateDetailedMetrics ( StockAssignmentCriteria criteria) {
logger . info ( "Calculating detailed metrics" );
try {
String warehouseId = criteria . getWarehouseId ();
String storeId = criteria . getStoreId ();
String productId = criteria . getProductId ();
MetricsRepository . DetailedMetricsProjection basicMetrics = metricsRepository . getDetailedMetrics (
warehouseId, storeId, productId);
Double fulfillmentRate = calculateFulfillmentRate (
basicMetrics . getTotalFulfilled (), basicMetrics . getTotalUnfulfilled ());
StoresServedDTO storesServed = metricsMapper . toStoresServedDTO (basicMetrics);
// ... additional metric calculations
return new DetailedMetricsDTO (
efficiencyScore,
fulfillmentRate,
basicMetrics . getTotalDistance (),
basicMetrics . getTotalShipments (),
storesServed,
basicMetrics . getAvgShipmentSize (),
basicMetrics . getUniqueProductsDistributed (),
basicMetrics . getUniqueProductsRequested (),
capacityUtilization,
unfulfilledDemand,
basicMetrics . getTotalFulfilled (),
distanceStats,
unitsByWarehouse,
topProducts
);
} catch ( Exception e ) {
logger . error ( "Error calculating detailed metrics" , e);
return createEmptyDetailedMetrics ();
}
}
Detailed Metrics Fields
Composite score (0-100) calculated from fulfillment rate, distance, and capacity utilization MetricsService.java:146-155
private Integer calculateEfficiencyScore ( Double fulfillmentRate, Double averageDistance, Double capacityUtilization) {
double normalizedDistance = Math . max ( 0 , 1 - (averageDistance / MAX_DISTANCE_FOR_NORMALIZATION));
double normalizedDistancePercent = normalizedDistance * 100.0 ;
double score = (fulfillmentRate * FULFILLMENT_RATE_WEIGHT) +
(normalizedDistancePercent * DISTANCE_WEIGHT) +
(capacityUtilization * CAPACITY_WEIGHT);
return Math . max ( 0 , Math . min ( 100 , ( int ) Math . round (score)));
}
Weights:
Fulfillment Rate: 70%
Distance: 20%
Capacity: 10%
Distance is normalized against 5000 km threshold (covers European and some international routes).
Percentage of demand successfully fulfilled (0-100) MetricsService.java:123-127
private Double calculateFulfillmentRate ( Long totalShipped, Long totalUnfulfilled) {
long totalDemanded = totalShipped + totalUnfulfilled;
if (totalDemanded == 0 ) return 0.0 ;
return ( double ) totalShipped / totalDemanded * 100.0 ;
}
Total distance covered by all shipments in kilometers
Number of stock assignments matching the filter criteria
Information about store coverage
totalStores: Total number of unique stores served
withFullFulfillment: Stores that received 100% of requested products
withPartialFulfillment: Stores that received some but not all products
avgFulfillmentRate: Average fulfillment rate across stores
avgDistancePerStore: Average shipping distance per store
Average number of units per shipment
uniqueProductsDistributed
Number of distinct products actually shipped
Number of distinct products requested (including unfulfilled)
Capacity Utilization
Tracks how efficiently store capacity is being used:
Store capacity usage metrics {
percentage : number ; // Capacity used as percentage (0-100)
totalUsed : number ; // Total units allocated to stores
totalCapacity : number ; // Total available store capacity
}
High Capacity Utilization (>90%): May indicate need for additional store capacity or product variety adjustment.
Low Capacity Utilization (<50%): May indicate overstocking, poor demand forecasting, or insufficient product variety.
Distance Statistics
Provides insights into shipping distances:
Statistical breakdown of shipping distances
minDistance: Shortest shipment distance in km
maxDistance: Longest shipment distance in km
avgDistance: Average shipment distance in km
Weighted Average Distance:
MetricsService.java:129-144
private Double calculateWeightedAverageDistance ( List < WarehouseUnitsDTO > unitsByWarehouse) {
if (unitsByWarehouse == null || unitsByWarehouse . isEmpty ()) {
return 0.0 ;
}
double totalWeightedDistance = 0.0 ;
long totalUnits = 0 ;
for ( WarehouseUnitsDTO warehouse : unitsByWarehouse) {
totalWeightedDistance += warehouse . totalUnits () * warehouse . avgDistance ();
totalUnits += warehouse . totalUnits ();
}
if (totalUnits == 0 ) return 0.0 ;
return totalWeightedDistance / totalUnits;
}
Weighted by shipment volumes to reflect actual distribution costs more accurately.
Unfulfilled Demand Analysis
Tracks demand that could not be satisfied:
Breakdown of unfulfilled demand by reason {
totalUnfulfilled : number ; // Total unfulfilled units
dueToStockShortage : number ; // Units missing due to insufficient warehouse stock
dueToCapacityShortage : number ; // Units missing due to store capacity limits
}
Analysis Guidelines:
Stock Shortage High stock shortage indicates:
Need to increase warehouse inventory
Consider additional suppliers
Review demand forecasting
Capacity Shortage High capacity shortage indicates:
Stores need more space
Adjust demand expectations
Stagger deliveries over time
Top Products Tracking
Identifies most distributed products:
List of top products by volume (limited to top 10) {
productId : string ;
totalUnits : number ;
totalShipments : number ;
avgDistance : number ;
}
Useful for:
Identifying best-selling products
Planning warehouse stock levels
Optimizing warehouse product placement
Understanding distribution patterns
Units by Warehouse
Breaks down distribution by warehouse:
Distribution metrics per warehouse {
warehouseId : string ;
totalUnits : number ;
totalShipments : number ;
avgDistance : number ;
}
Helps identify:
Warehouse utilization balance
Geographic coverage effectiveness
Potential consolidation opportunities
Underutilized distribution centers
Caching Strategy
Metrics are cached to improve performance:
@ Cacheable ( "globalMetrics" )
@ Cacheable ( value = "detailedMetrics" , key = "#criteria.warehouseId + '_' + #criteria.storeId + '_' + #criteria.productId" )
Cache is automatically invalidated when distribution runs:
@ CacheEvict ( value = { "globalMetrics" , "detailedMetrics" }, allEntries = true )
Cache Configuration:
spring.cache.type =simple
spring.cache.cache-names =globalMetrics,detailedMetrics
Using Metrics for Decision Making
Optimize Warehouse Locations
Review avgDistance in unitsByWarehouse
High average distances suggest need for warehouses closer to stores
Compare totalUnits across warehouses to balance distribution load
Monitor fulfillmentRate and unfulfilledDemand
If dueToStockShortage is high, increase warehouse inventory
If dueToCapacityShortage is high, expand store capacity or adjust expectations
Track efficiencyScore over time
Score below 70 indicates problems with fulfillment, distance, or capacity
Focus improvements on the factor with lowest weighted contribution
Use capacityUtilization.percentage
Target 70-85% utilization for optimal balance
Review storesServed.withPartialFulfillment to identify problem stores
API Endpoints
Access metrics via REST API:
Global Metrics
Detailed Metrics
Query Parameters:
warehouseId (optional): Filter by warehouse
storeId (optional): Filter by store
productId (optional): Filter by product
All filters are optional and can be combined.
Next Steps
Dashboard View metrics in the interactive dashboard
Data Management Learn about data sources and refresh cycles