贴标申请,仓储转运

This commit is contained in:
2026-10-14 11:36:35 +08:00
parent 83dc6dea3f
commit e14bdb4f49
37 changed files with 884 additions and 32 deletions
@@ -24,6 +24,27 @@ public class PdaCargoDiscardController {
@Valid @RequestBody PdaCargoDiscardDtos.Scan request) {
return ApiResponse.success(service.resolve(PdaWarehouseIdentity.require(user), request.palletNo()));
}
@PostMapping(value = "/{discardNo}/pallets/{palletNo}/photos/files", consumes = org.springframework.http.MediaType.MULTIPART_FORM_DATA_VALUE)
public ApiResponse<com.baiyue.lastleg.discard.dto.CargoDiscardResponses.Photo> uploadPhoto(
@AuthenticationPrincipal AuthenticatedUser user, @PathVariable String discardNo, @PathVariable String palletNo,
@RequestParam("file") org.springframework.web.multipart.MultipartFile file) {
return ApiResponse.success(service.uploadPhoto(PdaWarehouseIdentity.require(user), discardNo, palletNo,
user.userId() == null ? 0L : user.userId(), file));
}
@GetMapping("/{discardNo}/pallets/{palletNo}/photos/files")
public ApiResponse<List<com.baiyue.lastleg.discard.dto.CargoDiscardResponses.Photo>> photos(
@AuthenticationPrincipal AuthenticatedUser user, @PathVariable String discardNo, @PathVariable String palletNo) {
return ApiResponse.success(service.photos(PdaWarehouseIdentity.require(user), discardNo, palletNo));
}
@GetMapping("/{discardNo}/pallets/{palletNo}/photos/files/{fileId}/download")
public org.springframework.http.ResponseEntity<byte[]> downloadPhoto(@AuthenticationPrincipal AuthenticatedUser user,
@PathVariable String discardNo, @PathVariable String palletNo, @PathVariable long fileId) {
var file = service.downloadPhoto(PdaWarehouseIdentity.require(user), discardNo, palletNo, fileId);
return org.springframework.http.ResponseEntity.ok().cacheControl(org.springframework.http.CacheControl.noStore())
.header(org.springframework.http.HttpHeaders.CONTENT_DISPOSITION,
org.springframework.http.ContentDisposition.inline().filename(file.fileName(), java.nio.charset.StandardCharsets.UTF_8).build().toString())
.contentType(org.springframework.http.MediaType.parseMediaType(file.contentType())).body(file.content());
}
@PostMapping("/{discardNo}/pallets/{palletNo}/confirm")
public ApiResponse<PdaCargoDiscardDtos.PalletTask> confirm(@AuthenticationPrincipal AuthenticatedUser user,
@PathVariable String discardNo, @PathVariable String palletNo, @Valid @RequestBody PdaCargoDiscardDtos.Confirm request) {
@@ -12,7 +12,8 @@ public final class PdaCargoDiscardDtos {
private PdaCargoDiscardDtos() { }
public record Scan(@NotBlank @Size(max = 128) String palletNo) { }
public record ActualLine(@NotNull Long itemId, @PositiveOrZero int actualPackages) { }
public record Confirm(@NotEmpty List<@Valid ActualLine> lines) { }
public record Confirm(@NotEmpty List<@Valid ActualLine> lines,
@NotEmpty @Size(max = 20) List<@NotNull @jakarta.validation.constraints.Positive Long> photoFileIds) { }
public record Sku(Long itemId, String skuCode, String productName, int plannedPackages,
Integer actualPackages, String status) { }
public record PalletTask(String discardNo, String customerId, String overseasWarehouseId,
@@ -23,6 +23,7 @@ import java.util.stream.Collectors;
@Service
public class PdaCargoDiscardService {
@Resource private com.baiyue.lastleg.discard.service.CargoDiscardPhotoService photoService;
@Resource private CargoDiscardApplicationMapper applications;
@Resource private CargoDiscardItemMapper items;
@Resource private CargoDiscardCartonMapper cartons;
@@ -78,6 +79,8 @@ public class PdaCargoDiscardService {
|| !application.getCustomerId().equals(item.getCustomerId())
|| !Objects.equals(application.getId(), item.getApplicationId())))
throw conflict("废弃申请终态存在未完成明细,不能恢复作业结果");
photoService.confirm(application, task.palletNo(), request.photoFileIds(),
palletItems.stream().allMatch(item -> "COMPLETED".equals(item.getPdaStatus())));
// A completed pallet is an immutable result, including the final pallet after application completion.
if (palletItems.stream().allMatch(item -> "COMPLETED".equals(item.getPdaStatus()))) return task;
if (terminal) throw conflict("废弃终态不能执行未完成托盘");
@@ -109,6 +112,36 @@ public class PdaCargoDiscardService {
.findFirst().orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "托盘不属于该废弃单"));
}
@Transactional
public CargoDiscardResponses.Photo uploadPhoto(PdaWarehouseIdentity identity, String discardNo, String palletNo,
long operatorUserId, org.springframework.web.multipart.MultipartFile file) {
CargoDiscardApplication application = photoApplication(identity, discardNo, palletNo, true);
var task = palletTasks(application).stream().filter(t -> t.palletNo().equals(palletNo.trim())).findFirst().orElseThrow();
if (!CargoDiscardService.APPROVED.equals(application.getStatus()) || "COMPLETED".equals(task.status()))
throw conflict("已完成或未审核的废弃托盘不能上传照片");
return photoService.upload(application, task.palletNo(), identity.operatorKey(), operatorUserId, file);
}
@Transactional(readOnly = true)
public List<CargoDiscardResponses.Photo> photos(PdaWarehouseIdentity identity, String discardNo, String palletNo) {
return photoService.list(photoApplication(identity, discardNo, palletNo, false), palletNo.trim(), false);
}
@Transactional(readOnly = true)
public com.baiyue.lastleg.discard.gateway.CargoDiscardPhotoFileGateway.DownloadedFile downloadPhoto(
PdaWarehouseIdentity identity, String discardNo, String palletNo, long fileId) {
return photoService.download(photoApplication(identity, discardNo, palletNo, false), palletNo.trim(), fileId, false);
}
private CargoDiscardApplication photoApplication(PdaWarehouseIdentity identity, String discardNo, String palletNo, boolean lock) {
var warehouseId = String.valueOf(identity.overseasWarehouseId());
var application = lock ? applications.findNoByWarehouse(discardNo, warehouseId) : applications.readNoByWarehouse(discardNo, warehouseId);
if (application == null) throw new ResponseStatusException(HttpStatus.NOT_FOUND, "废弃任务不存在或不属于当前仓库");
if (palletTasks(application).stream().noneMatch(t -> t.palletNo().equals(palletNo.trim())))
throw new ResponseStatusException(HttpStatus.NOT_FOUND, "托盘不属于该废弃单");
return application;
}
private List<PdaCargoDiscardDtos.PalletTask> palletTasks(CargoDiscardApplication application) {
return items.listApplication(application.getCustomerId(), application.getId()).stream()
.collect(Collectors.groupingBy(this::physicalGroupKey, LinkedHashMap::new, Collectors.toList()))