fix(inbound): expose original command for resource confirmation recovery

This commit is contained in:
2026-10-05 02:13:22 +08:00
parent b000b056d1
commit a0a4e03da9
7 changed files with 126 additions and 9 deletions
@@ -86,7 +86,7 @@ public class InboundPlanController {
if (user == null || user.tenantId() == null || user.tenantId() != 0L || !"PLATFORM".equals(user.appCode())) {
throw new ResponseStatusException(HttpStatus.FORBIDDEN, "仅平台账号可预览整柜入库计划");
}
return ApiResponse.success(service.previewContainer(sourceContainerBookingId));
return ApiResponse.success(containerConversion.preview(sourceContainerBookingId));
}
@GetMapping("/{planNo}")
@@ -23,8 +23,20 @@ public record ContainerInboundPlanPreviewResponse(
int totalSuggestedPalletCount,
int totalPlannedPalletCount,
boolean ready,
List<Group> groups
List<Group> groups,
ResourceRetry resourceRetry
) {
/** Original persisted command; distinct from the current display snapshot. */
public record ResourceRetry(String idempotencyKey, long snapshotVersion, String snapshotHash) { }
public ContainerInboundPlanPreviewResponse withResourceRetry(ResourceRetry retry) {
return new ContainerInboundPlanPreviewResponse(sourceContainerBookingId, containerNo,
overseasWarehouseId, overseasWarehouseCode, overseasWarehouseName, snapshotVersion, snapshotHash,
totalOrderCount, readyOrderCount, blockedOrderCount, pendingOrderCount, pendingPalletCount,
sourcePalletCount, supplementPalletCount, existingPlannedPalletCount, totalSuggestedPalletCount,
totalPlannedPalletCount, ready, groups, retry);
}
public record Group(
String destinationType,
String destinationWarehouseId,
@@ -47,6 +47,20 @@ public class ContainerInboundPlanConversionCoordinator {
@Resource private ObjectMapper objectMapper;
@Resource private PlatformTransactionManager transactionManager;
@org.springframework.transaction.annotation.Transactional(readOnly = true)
public ContainerInboundPlanPreviewResponse preview(String sourceContainerBookingId) {
ContainerInboundPlanPreviewResponse current = plans.previewContainer(sourceContainerBookingId);
ContainerPlanConversionCommand command = commands.findByBooking(current.sourceContainerBookingId());
if (command == null || !"LOCAL_COMMITTED".equals(command.getStatus())) return current;
if (trimToNull(command.getIdempotencyKey()) == null || command.getSnapshotVersion() == null
|| command.getSnapshotVersion() < 0 || command.getSnapshotHash() == null
|| !command.getSnapshotHash().matches("[a-f0-9]{64}")) {
throw new ResponseStatusException(HttpStatus.CONFLICT, "原柜级转换命令缺少重试依据,请联系管理员核查");
}
return current.withResourceRetry(new ContainerInboundPlanPreviewResponse.ResourceRetry(
command.getIdempotencyKey(), command.getSnapshotVersion(), command.getSnapshotHash()));
}
/**
* Saves one manually adjusted plan, then materializes every plan in the container as soon as
* the last logical plan is complete. The manual endpoint is therefore never a separate pallet
@@ -270,7 +270,7 @@ public class InboundPlanService {
orders.stream().map(ContainerInboundPlanPreviewResponse.Order::suggestedPalletCount)
.filter(Objects::nonNull).mapToInt(Integer::intValue).sum(),
orders.stream().map(ContainerInboundPlanPreviewResponse.Order::plannedPalletCount)
.filter(Objects::nonNull).mapToInt(Integer::intValue).sum(), blocked == 0, groups);
.filter(Objects::nonNull).mapToInt(Integer::intValue).sum(), blocked == 0, groups, null);
}
private ContainerInboundPlanPreviewResponse.Order previewOrder(