This commit is contained in:
2026-08-26 15:24:48 +08:00
parent 3f9ee28d22
commit 4ae236fe11
18 changed files with 198 additions and 92 deletions
@@ -3,6 +3,7 @@ package com.baiyue.lastleg.inboundplan.pda.dto;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Pattern;
import jakarta.validation.constraints.Positive;
import jakarta.validation.constraints.Size;
@@ -14,7 +15,8 @@ public final class ReceivingContainerRequests {
public record Action(@NotBlank @Size(max = 255) String idempotencyKey) { }
public record Sign(@NotNull @Size(min = 3, max = 3) List<@Valid SignedPhoto> photos,
@NotBlank @Size(max = 255) String idempotencyKey) { }
public record SignedPhoto(@NotNull ReceivingPhotoRole role, @Positive long fileId) { }
public record SignedPhoto(@NotNull ReceivingPhotoRole role,
@NotBlank @Pattern(regexp = "^[1-9][0-9]{0,18}$") String fileId) { }
public record CartonResolve(@NotBlank String cartonMark) { }
public record SkuResolve(@NotBlank @Size(max = 128) String skuCode) { }
public record PalletResolve(@NotBlank String palletCode, @NotBlank String inboundCode) { }
@@ -17,7 +17,7 @@ public final class ReceivingContainerResponses {
int totalPackages, int receivedPackages, int pendingPackages,
List<Inbound> inbounds) { }
public record SignedPhoto(ReceivingPhotoRole role, long fileId) { }
public record SignedPhoto(ReceivingPhotoRole role, String fileId) { }
public record Inbound(String inboundCode, String destinationType,
String overseasWarehouseId, String overseasWarehouseName,
@@ -48,5 +48,5 @@ public final class ReceivingContainerResponses {
String destinationType, String palletCode, int acceptedPackages,
int receivedPackages, int pendingPackages, String sessionStatus) { }
public record Photo(long fileId, String fileName, String contentType, long sizeBytes) { }
public record Photo(String fileId, String fileName, String contentType, long sizeBytes) { }
}
@@ -169,7 +169,7 @@ public class ReceivingContainerService {
String customerId = session.getCustomerId();
if (!"WAIT_SIGN".equals(session.getStatus())) throw conflict("Unload photos can only be uploaded before signing");
UnloadPhotoFileGateway.UploadedFile uploaded = unloadPhotos.upload(customerId, session.getId(), operatorId, file);
return new ReceivingContainerResponses.Photo(uploaded.fileId(), uploaded.fileName(), uploaded.contentType(), uploaded.sizeBytes());
return new ReceivingContainerResponses.Photo(Long.toString(uploaded.fileId()), uploaded.fileName(), uploaded.contentType(), uploaded.sizeBytes());
}
@Transactional
@@ -181,7 +181,7 @@ public class ReceivingContainerService {
String customerId = session.getCustomerId();
if (!"WAIT_SIGN".equals(session.getStatus())) throw conflict("Container has already been signed");
List<ReceivingContainerResponses.SignedPhoto> photos = validateSignPhotos(request);
List<Long> photoFileIds = photos.stream().map(ReceivingContainerResponses.SignedPhoto::fileId).toList();
List<Long> photoFileIds = photos.stream().map(photo -> positiveFileId(photo.fileId())).toList();
photoFileIds.forEach(fileId -> unloadPhotos.validate(customerId, session.getId(), fileId));
LocalDateTime now = LocalDateTime.now();
session.setSignPhotos(write(photos)); session.setStatus("SIGNED"); session.setSignedAt(now);
@@ -513,9 +513,9 @@ public class ReceivingContainerService {
Set<com.baiyue.lastleg.inboundplan.pda.dto.ReceivingPhotoRole> roles = request.photos().stream()
.map(ReceivingContainerRequests.SignedPhoto::role).collect(Collectors.toSet());
if (roles.size() != 3 || roles.contains(null)) throw conflict("Each unload photo role is required exactly once");
Set<Long> fileIds = request.photos().stream().map(ReceivingContainerRequests.SignedPhoto::fileId)
Set<Long> fileIds = request.photos().stream().map(value -> positiveFileId(value.fileId()))
.collect(Collectors.toSet());
if (fileIds.size() != 3 || fileIds.stream().anyMatch(value -> value == null || value <= 0)) {
if (fileIds.size() != 3) {
throw conflict("Unload photo file IDs must be positive and unique");
}
return request.photos().stream()
@@ -523,6 +523,16 @@ public class ReceivingContainerService {
.map(value -> new ReceivingContainerResponses.SignedPhoto(value.role(), value.fileId())).toList();
}
private long positiveFileId(String value) {
try {
long fileId = Long.parseLong(value);
if (fileId > 0) return fileId;
} catch (NumberFormatException ignored) {
// Validation normally rejects this before the service; keep the domain fail-closed.
}
throw conflict("Unload photo file ID must be a positive decimal string");
}
private SkuRef requireSku(InboundRef ref, String skuCode) {
SkuRef result = skuRef(ref, skuCode);
if (result == null) throw notFound("SKU is not part of the selected inbound code");