fix(pda): allow receiving photo lookup by container
This commit is contained in:
+26
@@ -95,6 +95,19 @@ public class ReceivingContainerController {
|
|||||||
.contentLength(download.content().length).body(download.content());
|
.contentLength(download.content().length).body(download.content());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@GetMapping("/{containerNo}/unload-photos/files/{fileId}/download")
|
||||||
|
public ResponseEntity<byte[]> downloadContainerPhoto(@AuthenticationPrincipal AuthenticatedUser user,
|
||||||
|
@PathVariable String containerNo,
|
||||||
|
@PathVariable String fileId) {
|
||||||
|
PdaWarehouseIdentity identity = identity(user);
|
||||||
|
var download = service.downloadContainerPhoto(identity.overseasWarehouseId(), containerNo, fileId);
|
||||||
|
return ResponseEntity.ok().cacheControl(CacheControl.noStore())
|
||||||
|
.header(HttpHeaders.CONTENT_DISPOSITION,
|
||||||
|
ContentDisposition.inline().filename(download.fileName(), StandardCharsets.UTF_8).build().toString())
|
||||||
|
.contentType(MediaType.parseMediaType(download.contentType()))
|
||||||
|
.contentLength(download.content().length).body(download.content());
|
||||||
|
}
|
||||||
|
|
||||||
@GetMapping("/current/domestic-loading-photos/{evidenceType}/content")
|
@GetMapping("/current/domestic-loading-photos/{evidenceType}/content")
|
||||||
public ResponseEntity<byte[]> downloadDomesticLoadingPhoto(@AuthenticationPrincipal AuthenticatedUser user,
|
public ResponseEntity<byte[]> downloadDomesticLoadingPhoto(@AuthenticationPrincipal AuthenticatedUser user,
|
||||||
@PathVariable String evidenceType) {
|
@PathVariable String evidenceType) {
|
||||||
@@ -107,6 +120,19 @@ public class ReceivingContainerController {
|
|||||||
.contentLength(download.content().length).body(download.content());
|
.contentLength(download.content().length).body(download.content());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@GetMapping("/{containerNo}/domestic-loading-photos/{evidenceType}/content")
|
||||||
|
public ResponseEntity<byte[]> downloadContainerDomesticLoadingPhoto(@AuthenticationPrincipal AuthenticatedUser user,
|
||||||
|
@PathVariable String containerNo,
|
||||||
|
@PathVariable String evidenceType) {
|
||||||
|
PdaWarehouseIdentity identity = identity(user);
|
||||||
|
var download = service.downloadContainerDomesticLoadingPhoto(identity.overseasWarehouseId(), containerNo, evidenceType);
|
||||||
|
return ResponseEntity.ok().cacheControl(CacheControl.noStore())
|
||||||
|
.header(HttpHeaders.CONTENT_DISPOSITION,
|
||||||
|
ContentDisposition.inline().filename(download.fileName(), StandardCharsets.UTF_8).build().toString())
|
||||||
|
.contentType(MediaType.parseMediaType(download.contentType()))
|
||||||
|
.contentLength(download.content().length).body(download.content());
|
||||||
|
}
|
||||||
|
|
||||||
@PostMapping("/current/sign")
|
@PostMapping("/current/sign")
|
||||||
public ApiResponse<ReceivingContainerResponses.Session> sign(@AuthenticationPrincipal AuthenticatedUser user,
|
public ApiResponse<ReceivingContainerResponses.Session> sign(@AuthenticationPrincipal AuthenticatedUser user,
|
||||||
@Valid @RequestBody ReceivingContainerRequests.Sign request) {
|
@Valid @RequestBody ReceivingContainerRequests.Sign request) {
|
||||||
|
|||||||
+4
@@ -22,6 +22,10 @@ public interface ReceivingContainerSessionMapper extends BaseMapper<ReceivingCon
|
|||||||
"WHERE active_container_key=#{activeContainerKey} LIMIT 1")
|
"WHERE active_container_key=#{activeContainerKey} LIMIT 1")
|
||||||
ReceivingContainerSession findActiveByContainer(@Param("activeContainerKey") String activeContainerKey);
|
ReceivingContainerSession findActiveByContainer(@Param("activeContainerKey") String activeContainerKey);
|
||||||
|
|
||||||
|
@Select("SELECT * FROM ll_receiving_container_session " +
|
||||||
|
"WHERE container_no=#{containerNo} ORDER BY created_at DESC LIMIT 1")
|
||||||
|
ReceivingContainerSession findLatestByContainerNo(@Param("containerNo") String containerNo);
|
||||||
|
|
||||||
@Select("SELECT * FROM ll_receiving_container_session WHERE active_container_key IS NOT NULL")
|
@Select("SELECT * FROM ll_receiving_container_session WHERE active_container_key IS NOT NULL")
|
||||||
List<ReceivingContainerSession> findActiveContainers();
|
List<ReceivingContainerSession> findActiveContainers();
|
||||||
|
|
||||||
|
|||||||
+41
-2
@@ -70,8 +70,12 @@ public class ReceivingContainerService {
|
|||||||
private static final String PLATFORM_SCOPE = "0";
|
private static final String PLATFORM_SCOPE = "0";
|
||||||
private static final String PHOTO_DOWNLOAD_PATH =
|
private static final String PHOTO_DOWNLOAD_PATH =
|
||||||
"/api/pda/v1/last-leg/receiving-containers/current/unload-photos/files/{fileId}/download";
|
"/api/pda/v1/last-leg/receiving-containers/current/unload-photos/files/{fileId}/download";
|
||||||
|
private static final String CONTAINER_PHOTO_DOWNLOAD_PATH =
|
||||||
|
"/api/pda/v1/last-leg/receiving-containers/{containerNo}/unload-photos/files/{fileId}/download";
|
||||||
private static final String DOMESTIC_PHOTO_DOWNLOAD_PATH =
|
private static final String DOMESTIC_PHOTO_DOWNLOAD_PATH =
|
||||||
"/api/pda/v1/last-leg/receiving-containers/current/domestic-loading-photos/{type}/content";
|
"/api/pda/v1/last-leg/receiving-containers/current/domestic-loading-photos/{type}/content";
|
||||||
|
private static final String CONTAINER_DOMESTIC_PHOTO_DOWNLOAD_PATH =
|
||||||
|
"/api/pda/v1/last-leg/receiving-containers/{containerNo}/domestic-loading-photos/{type}/content";
|
||||||
private static final String PALLET_MERGE_HINT =
|
private static final String PALLET_MERGE_HINT =
|
||||||
"该入库计划可选择合托:合托时扫描同目的仓已使用的托盘码,独立收货时扫描新托盘码;不强制合托";
|
"该入库计划可选择合托:合托时扫描同目的仓已使用的托盘码,独立收货时扫描新托盘码;不强制合托";
|
||||||
private static final int MAX_PACKAGES_PER_PALLET = 66;
|
private static final int MAX_PACKAGES_PER_PALLET = 66;
|
||||||
@@ -275,6 +279,39 @@ public class ReceivingContainerService {
|
|||||||
return domesticEvidenceFiles.download(bookingId, evidence.getSourceFileId());
|
return domesticEvidenceFiles.download(bookingId, evidence.getSourceFileId());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public UnloadPhotoFileGateway.DownloadedFile downloadContainerPhoto(
|
||||||
|
long overseasWarehouseId, String containerNo, String fileId) {
|
||||||
|
ReceivingContainerSession session = requireContainerPhotoSession(overseasWarehouseId, containerNo);
|
||||||
|
long parsedFileId = positiveFileId(fileId);
|
||||||
|
if (signedPhotos(session).stream().noneMatch(photo -> fileId.equals(photo.fileId()))) {
|
||||||
|
throw new ResponseStatusException(HttpStatus.NOT_FOUND, "该柜没有对应的卸柜照片");
|
||||||
|
}
|
||||||
|
return unloadPhotos.download(PLATFORM_SCOPE, session.getId(), parsedFileId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public DomesticLoadingEvidenceGateway.DownloadedFile downloadContainerDomesticLoadingPhoto(
|
||||||
|
long overseasWarehouseId, String containerNo, String evidenceType) {
|
||||||
|
ReceivingContainerSession session = requireContainerPhotoSession(overseasWarehouseId, containerNo);
|
||||||
|
String type = requiredEvidenceType(evidenceType);
|
||||||
|
var evidence = domesticEvidence.find(session.getSourceContainerBookingId(), type);
|
||||||
|
if (evidence == null) throw notFound("当前柜没有该国内装柜照片");
|
||||||
|
long bookingId;
|
||||||
|
try { bookingId = Long.parseLong(session.getSourceContainerBookingId()); }
|
||||||
|
catch (NumberFormatException exception) { throw new ResponseStatusException(
|
||||||
|
HttpStatus.SERVICE_UNAVAILABLE, "当前柜国内照片来源无效", exception); }
|
||||||
|
return domesticEvidenceFiles.download(bookingId, evidence.getSourceFileId());
|
||||||
|
}
|
||||||
|
|
||||||
|
private ReceivingContainerSession requireContainerPhotoSession(long overseasWarehouseId, String containerNo) {
|
||||||
|
String value = trim(containerNo);
|
||||||
|
if (value == null) throw notFound("柜号不能为空");
|
||||||
|
ReceivingContainerSession session = sessions.findLatestByContainerNo(value);
|
||||||
|
if (session == null || !Objects.equals(session.getOverseasWarehouseId(), overseasWarehouseId)) {
|
||||||
|
throw notFound("当前仓没有该柜的照片");
|
||||||
|
}
|
||||||
|
return session;
|
||||||
|
}
|
||||||
|
|
||||||
public void requireCurrentWarehouse(String operatorKey, long overseasWarehouseId) {
|
public void requireCurrentWarehouse(String operatorKey, long overseasWarehouseId) {
|
||||||
requireSessionWarehouse(sessions.findActiveByOperator(activeOperatorKey(operatorKey)), overseasWarehouseId);
|
requireSessionWarehouse(sessions.findActiveByOperator(activeOperatorKey(operatorKey)), overseasWarehouseId);
|
||||||
}
|
}
|
||||||
@@ -1050,7 +1087,8 @@ public class ReceivingContainerService {
|
|||||||
if (bookingId == null) return List.of();
|
if (bookingId == null) return List.of();
|
||||||
return domesticEvidence.listByContainer(bookingId).stream()
|
return domesticEvidence.listByContainer(bookingId).stream()
|
||||||
.map(value -> new ReceivingContainerResponses.DomesticLoadingPhoto(value.getEvidenceType(),
|
.map(value -> new ReceivingContainerResponses.DomesticLoadingPhoto(value.getEvidenceType(),
|
||||||
evidenceLabel(value.getEvidenceType()), DOMESTIC_PHOTO_DOWNLOAD_PATH.replace("{type}", value.getEvidenceType())))
|
evidenceLabel(value.getEvidenceType()), CONTAINER_DOMESTIC_PHOTO_DOWNLOAD_PATH
|
||||||
|
.replace("{containerNo}", session.getContainerNo()).replace("{type}", value.getEvidenceType())))
|
||||||
.toList();
|
.toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1384,7 +1422,8 @@ public class ReceivingContainerService {
|
|||||||
private List<ReceivingContainerResponses.SignedPhoto> signPhotos(ReceivingContainerSession session) {
|
private List<ReceivingContainerResponses.SignedPhoto> signPhotos(ReceivingContainerSession session) {
|
||||||
return signedPhotos(session).stream()
|
return signedPhotos(session).stream()
|
||||||
.map(photo -> new ReceivingContainerResponses.SignedPhoto(photo.role(), photo.fileId(),
|
.map(photo -> new ReceivingContainerResponses.SignedPhoto(photo.role(), photo.fileId(),
|
||||||
PHOTO_DOWNLOAD_PATH.replace("{fileId}", photo.fileId())))
|
CONTAINER_PHOTO_DOWNLOAD_PATH.replace("{containerNo}", session.getContainerNo())
|
||||||
|
.replace("{fileId}", photo.fileId())))
|
||||||
.toList();
|
.toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -84,6 +84,17 @@ paths:
|
|||||||
application/octet-stream: { schema: { type: string, format: binary } }
|
application/octet-stream: { schema: { type: string, format: binary } }
|
||||||
'403': { description: fileId 未绑定到当前操作员的当前柜会话三类签收照片 }
|
'403': { description: fileId 未绑定到当前操作员的当前柜会话三类签收照片 }
|
||||||
'404': { description: 当前柜会话或照片不存在 }
|
'404': { description: 当前柜会话或照片不存在 }
|
||||||
|
/api/pda/v1/last-leg/receiving-containers/{containerNo}/unload-photos/files/{fileId}/download:
|
||||||
|
get:
|
||||||
|
summary: 按柜号下载卸柜签收照片
|
||||||
|
description: 权限 lastleg:pda:operate;按当前 PDA 绑定仓和柜号读取历史或当前柜的签收照片,不要求存在未完成接柜会话。
|
||||||
|
security: [{ bearerAuth: [] }]
|
||||||
|
parameters:
|
||||||
|
- { name: containerNo, in: path, required: true, schema: { type: string } }
|
||||||
|
- { name: fileId, in: path, required: true, schema: { type: string, pattern: '^[1-9][0-9]{0,18}$' } }
|
||||||
|
responses:
|
||||||
|
'200': { description: 签收照片字节流, content: { image/jpeg: { schema: { type: string, format: binary } }, image/png: { schema: { type: string, format: binary } } } }
|
||||||
|
'404': { description: 当前仓没有该柜或照片不存在 }
|
||||||
/api/pda/v1/last-leg/receiving-containers/current/domestic-loading-photos/{evidenceType}/content:
|
/api/pda/v1/last-leg/receiving-containers/current/domestic-loading-photos/{evidenceType}/content:
|
||||||
get:
|
get:
|
||||||
summary: 查看当前柜国内装柜照片
|
summary: 查看当前柜国内装柜照片
|
||||||
@@ -100,6 +111,17 @@ paths:
|
|||||||
application/octet-stream: { schema: { type: string, format: binary } }
|
application/octet-stream: { schema: { type: string, format: binary } }
|
||||||
'404': { description: 当前柜或指定类型照片不存在 }
|
'404': { description: 当前柜或指定类型照片不存在 }
|
||||||
'503': { description: 国内照片服务暂不可用 }
|
'503': { description: 国内照片服务暂不可用 }
|
||||||
|
/api/pda/v1/last-leg/receiving-containers/{containerNo}/domestic-loading-photos/{evidenceType}/content:
|
||||||
|
get:
|
||||||
|
summary: 按柜号查看国内装柜照片
|
||||||
|
description: 权限 lastleg:pda:operate;按当前 PDA 绑定仓和柜号读取历史或当前柜的国内装柜照片,不要求存在未完成接柜会话。
|
||||||
|
security: [{ bearerAuth: [] }]
|
||||||
|
parameters:
|
||||||
|
- { name: containerNo, in: path, required: true, schema: { type: string } }
|
||||||
|
- { name: evidenceType, in: path, required: true, schema: { type: string, enum: [PHOTO_STEP_1, PHOTO_STEP_2, PHOTO_STEP_3, PHOTO_STEP_4, SEAL] } }
|
||||||
|
responses:
|
||||||
|
'200': { description: 国内装柜照片字节流, content: { image/jpeg: { schema: { type: string, format: binary } }, image/png: { schema: { type: string, format: binary } } } }
|
||||||
|
'404': { description: 当前仓没有该柜或指定类型照片不存在 }
|
||||||
/api/pda/v1/last-leg/receiving-containers/current/sign:
|
/api/pda/v1/last-leg/receiving-containers/current/sign:
|
||||||
post:
|
post:
|
||||||
summary: 签收当前柜
|
summary: 签收当前柜
|
||||||
|
|||||||
+2
@@ -140,6 +140,8 @@ class ReceivingContainerContractTest {
|
|||||||
assertTrue(yaml.contains(prefix + "/current/receipts/pallet:"));
|
assertTrue(yaml.contains(prefix + "/current/receipts/pallet:"));
|
||||||
assertTrue(yaml.contains(prefix + "/current/complete:"));
|
assertTrue(yaml.contains(prefix + "/current/complete:"));
|
||||||
assertTrue(yaml.contains(prefix + "/current/unload-photos/files/{fileId}/download:"));
|
assertTrue(yaml.contains(prefix + "/current/unload-photos/files/{fileId}/download:"));
|
||||||
|
assertTrue(yaml.contains(prefix + "/{containerNo}/unload-photos/files/{fileId}/download:"));
|
||||||
|
assertTrue(yaml.contains(prefix + "/{containerNo}/domestic-loading-photos/{evidenceType}/content:"));
|
||||||
assertFalse(yaml.contains("/api/pda/v1/last-leg/receiving-containers/{planNo}"));
|
assertFalse(yaml.contains("/api/pda/v1/last-leg/receiving-containers/{planNo}"));
|
||||||
String receivingPaths = yaml.substring(yaml.indexOf(prefix), yaml.indexOf("/api/platform/v1/last-leg/orders:"));
|
String receivingPaths = yaml.substring(yaml.indexOf(prefix), yaml.indexOf("/api/platform/v1/last-leg/orders:"));
|
||||||
List<String> successResponses = receivingPaths.lines().map(String::trim)
|
List<String> successResponses = receivingPaths.lines().map(String::trim)
|
||||||
|
|||||||
Reference in New Issue
Block a user