Skip to content

Commit 248fd30

Browse files
add full logistics validation api
1 parent 37514bb commit 248fd30

File tree

5 files changed

+186
-0
lines changed

5 files changed

+186
-0
lines changed
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package csembstu.alamgir.server.controller;
2+
3+
import org.springframework.beans.factory.annotation.Autowired;
4+
import org.springframework.web.bind.annotation.PostMapping;
5+
import org.springframework.web.bind.annotation.RequestBody;
6+
import org.springframework.web.bind.annotation.RestController;
7+
8+
import csembstu.alamgir.server.dto.request.DateRequestValidation;
9+
import csembstu.alamgir.server.dto.response.FullLogisticsValidationResponse;
10+
import csembstu.alamgir.server.service.ValidationApiService2;
11+
12+
@RestController
13+
public class ValidationApiController2 {
14+
15+
@Autowired
16+
private ValidationApiService2 validationApiService2;
17+
18+
@PostMapping("/full-logistics-validation")
19+
public FullLogisticsValidationResponse validateCap(@RequestBody DateRequestValidation request) {
20+
return validationApiService2.fullLogisticsValidation(request);
21+
}
22+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package csembstu.alamgir.server.dto.response;
2+
3+
import lombok.Data;
4+
5+
@Data
6+
public class CapacityViolation {
7+
private String violation;
8+
private String from;
9+
private String to;
10+
private int used_capacity; // demand maxQuantity
11+
private int capacity; // route capacity
12+
13+
public CapacityViolation(String violation, String from, String to, int used_capacity, int capacity) {
14+
this.violation = violation;
15+
this.from = from;
16+
this.to = to;
17+
this.used_capacity = used_capacity;
18+
this.capacity = capacity;
19+
}
20+
21+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package csembstu.alamgir.server.dto.response;
2+
3+
import java.util.ArrayList;
4+
import java.util.List;
5+
import lombok.Data;
6+
7+
@Data
8+
public class FullLogisticsValidationResponse {
9+
private List<String> temperature_incompatible_demands;
10+
private List<CapacityViolation> capacity_violations;
11+
private List<StorageCapacityViolation> storage_capacity_violations;
12+
13+
public FullLogisticsValidationResponse() {
14+
this.temperature_incompatible_demands = new ArrayList<>();
15+
this.capacity_violations = new ArrayList<>();
16+
this.storage_capacity_violations = new ArrayList<>();
17+
}
18+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package csembstu.alamgir.server.dto.response;
2+
3+
import lombok.Data;
4+
5+
@Data
6+
public class StorageCapacityViolation {
7+
8+
private String warehouse;
9+
private int total_required_capacity;
10+
private int storage_capacity;
11+
12+
public StorageCapacityViolation(String warehouse, int total_required_capacity, int storage_capacity) {
13+
this.warehouse = warehouse;
14+
this.total_required_capacity = total_required_capacity;
15+
this.storage_capacity = storage_capacity;
16+
}
17+
18+
}
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
package csembstu.alamgir.server.service;
2+
3+
import java.util.*;
4+
5+
import org.springframework.beans.factory.annotation.Autowired;
6+
import org.springframework.stereotype.Service;
7+
8+
import csembstu.alamgir.server.dto.request.DateRequestValidation;
9+
import csembstu.alamgir.server.dto.response.*;
10+
import csembstu.alamgir.server.entity.*;
11+
import csembstu.alamgir.server.repository.*;
12+
13+
@Service
14+
public class ValidationApiService2 {
15+
16+
@Autowired private DemandRepository demandRepository;
17+
@Autowired private RouteRepository routeRepository;
18+
@Autowired private StorageUnitRepository storageUnitRepository;
19+
20+
21+
22+
23+
24+
// Capacity Validation (Dependent on Temperature)
25+
public FullLogisticsValidationResponse fullLogisticsValidation(DateRequestValidation request) {
26+
27+
List<Demand> demands = demandRepository.findByDate(request.getDate());
28+
FullLogisticsValidationResponse response = new FullLogisticsValidationResponse();
29+
30+
// Track total capacity usage per Warehouse (Map<WarehouseLocationId,TotalQuantity>)
31+
Map<String, Integer> warehouseLoadMap = new HashMap<>();
32+
Map<String, String> warehouseNameMap = new HashMap<>();
33+
Map<String, Integer> warehouseTotalCapacityMap = new HashMap<>();
34+
35+
for (Demand demand : demands) {
36+
Product product = demand.getProduct();
37+
Location destination = demand.getLocation();
38+
List<Route> allRoutes = routeRepository.findByToLocation_Id(destination.getId());
39+
40+
// 1. FILTER: Only look at routes that passed temperature validation
41+
List<Route> safeRoutes = findTempCompatibleRoutes(product, allRoutes);
42+
43+
// If no routes are temperature safe, capacity is irrelevant
44+
if (safeRoutes.isEmpty()) {
45+
response.getTemperature_incompatible_demands().add(String.format("Product %s has no safe warehouse storage to deliver to %s",product.getName(), destination.getName()));
46+
continue;
47+
}
48+
49+
// 2. CHECK: Of the safe routes, do any satisfy min/max quantity?
50+
boolean capacityPassed = safeRoutes.stream()
51+
.anyMatch(route ->
52+
demand.getMaxQuantity() <= route.getCapacity() &&
53+
demand.getMinQuantity() >= route.getMinShipment());
54+
55+
if (!capacityPassed) {
56+
for (Route route : safeRoutes) {
57+
58+
if (demand.getMinQuantity() < route.getMinShipment())
59+
response.getCapacity_violations().add(new CapacityViolation("MIN_CAPACITY_VIOLATION", route.getFromLocation().getName(),destination.getName(), demand.getMinQuantity(), route.getMinShipment()));
60+
61+
if (demand.getMaxQuantity() > route.getCapacity())
62+
response.getCapacity_violations().add(new CapacityViolation("MAX_CAPACITY_VIOLATION", route.getFromLocation().getName(),destination.getName(), demand.getMinQuantity(), route.getMinShipment()));
63+
64+
}
65+
66+
}
67+
68+
// 3. CHECK Storage Load
69+
if (!safeRoutes.isEmpty()) {
70+
Location source = safeRoutes.get(0).getFromLocation();
71+
warehouseLoadMap.merge(source.getId(), demand.getMaxQuantity(), Integer::sum);
72+
warehouseNameMap.put(source.getId(), source.getName());
73+
74+
// Get sum of capacity of all StorageUnits at this warehouse
75+
int totalStorage = storageUnitRepository.findByLocation_Id(source.getId()).stream().mapToInt(StorageUnit::getCapacity).sum();
76+
warehouseTotalCapacityMap.put(source.getId(), totalStorage);
77+
}
78+
}
79+
80+
// 4. Final Storage Violation Check
81+
warehouseLoadMap.forEach((locId, load) -> {
82+
int capacity = warehouseTotalCapacityMap.get(locId);
83+
if (load > capacity) {
84+
response.getStorage_capacity_violations().add(new StorageCapacityViolation(warehouseNameMap.get(locId), load, capacity));
85+
}
86+
});
87+
88+
return response;
89+
}
90+
91+
92+
93+
// Find ONE compatible WAREHOUSE to pass
94+
private List<Route> findTempCompatibleRoutes(Product product, List<Route> routes) {
95+
List<Route> compatibleRoutes = new ArrayList<>();
96+
for (Route route : routes) {
97+
List<StorageUnit> units = storageUnitRepository.findByLocation_Id(route.getFromLocation().getId());
98+
99+
boolean canStore = units.stream()
100+
.anyMatch(unit ->
101+
product.getMinTemperature() >= unit.getMinTemperature() &&
102+
product.getMaxTemperature() <= unit.getMaxTemperature());
103+
if (canStore) compatibleRoutes.add(route);
104+
}
105+
return compatibleRoutes;
106+
}
107+
}

0 commit comments

Comments
 (0)