feat(appointments): unify pre-inbound planning and confirmed FBA bookings

This commit is contained in:
2026-10-10 10:38:06 +08:00
parent 24f5ccf7ff
commit c4c1bddeec
54 changed files with 1623 additions and 744 deletions
@@ -14,9 +14,9 @@ public final class AppointmentPlanningPolicy {
String destinationKey, String originCountry, String destinationCountry,
Integer packages, Instant readyFrom, Instant readyTo,
boolean eligibleForPlanning, String blockReason) { }
public record Group(String originWarehouseId, String destinationKey, long packages,
public record Group(String originWarehouseId, String destinationKey, Long packages,
int sourceCount, int customerCount, Instant readyFrom, Instant readyTo,
boolean readinessIncomplete) { }
boolean readinessIncomplete, int unknownQuantitySources) { }
public record Forecast(String sourceKey, String sourceVersion, Instant eta, Instant readyAt) { }
public record Impact(String sourceKey, String reason, Instant previousEta, Instant latestEta,
Instant confirmedAt, boolean reviewRequired) { }
@@ -28,6 +28,7 @@ public final class AppointmentPlanningPolicy {
Set<String> customers = new HashSet<>();
String origin = null, destination = null;
long packages = 0;
int unknownQuantitySources = 0;
Instant from = null, to = null;
boolean incomplete = false;
for (Cargo row : cargo) {
@@ -47,8 +48,8 @@ public final class AppointmentPlanningPolicy {
if (!origin.equals(row.originWarehouseId()) || !destination.equals(row.destinationKey())) {
throw new IllegalArgumentException("同批货物必须具有相同实际起运仓和目的地");
}
if (row.packages() == null || row.packages() <= 0) throw new IllegalArgumentException("货物箱数待核实,不能填默认数量");
packages = Math.addExact(packages, row.packages().longValue());
if (row.packages() == null || row.packages() <= 0) unknownQuantitySources++;
else packages = Math.addExact(packages, row.packages().longValue());
customers.add(row.customerId());
if (row.readyFrom() == null || row.readyTo() == null) incomplete = true;
if (row.readyFrom() != null && row.readyTo() != null && row.readyTo().isBefore(row.readyFrom())) {
@@ -58,7 +59,7 @@ public final class AppointmentPlanningPolicy {
if (row.readyTo() != null && (to == null || row.readyTo().isBefore(to))) to = row.readyTo();
}
if (from != null && to != null && to.isBefore(from)) throw new IllegalArgumentException("所选货物预计备妥窗口不相容,请分别安排");
return new Group(origin, destination, packages, sources.size(), customers.size(), from, to, incomplete);
return new Group(origin, destination, unknownQuantitySources==0?packages:null, sources.size(), customers.size(), from, to, incomplete, unknownQuantitySources);
}
/** A new forecast only requests review; it never changes an externally confirmed appointment. */