优化
This commit is contained in:
@@ -14,8 +14,7 @@ public interface WarehouseSupplierClient {
|
||||
ApiResponse<Snapshot> get(@RequestHeader("X-Internal-Service-Token") String token,
|
||||
@PathVariable long supplierId,
|
||||
@RequestParam(defaultValue = "true") boolean requireActive,
|
||||
@RequestParam(required = false) String category,
|
||||
@RequestParam(required = false) String scope);
|
||||
@RequestParam(required = false) String category);
|
||||
|
||||
record Snapshot(long supplierId, String name, String category, String scope, String status) {}
|
||||
record Snapshot(long supplierId, String name, String category, String status) {}
|
||||
}
|
||||
|
||||
@@ -127,7 +127,8 @@ public final class LoadingPickDtos {
|
||||
|
||||
public record Task(Long id, Long loadingPlanId, Long containerBookingId, Long inboundId,
|
||||
Integer inboundVersion, Integer loadingVersion, String cabinetNo,
|
||||
String currentContainerNo, String taskStatus,
|
||||
String currentContainerNo, String sourceType, String recordStatus,
|
||||
Long mergedIntoContainerBookingId, String taskStatus,
|
||||
String workflowStatus, Integer version, Assignment assignment,
|
||||
Review review, List<PickItem> items) {
|
||||
}
|
||||
@@ -135,6 +136,7 @@ public final class LoadingPickDtos {
|
||||
/** PDA 工作台只展示当前作业员可领取或已领取的进行中任务。 */
|
||||
public record PendingTask(Long taskId, Long loadingPlanId, Long containerBookingId,
|
||||
String cabinetNo, String currentContainerNo,
|
||||
String sourceType, String recordStatus, Long mergedIntoContainerBookingId,
|
||||
Long warehouseId, String warehouseName, String taskStatus,
|
||||
String workflowStatus, Integer version, Integer assignmentVersion,
|
||||
Integer itemCount, Integer pendingItemCount) {
|
||||
|
||||
@@ -49,6 +49,8 @@ public interface LoadingPickTaskMapper extends BaseMapper<LoadingPickTaskEntity>
|
||||
SELECT task.id AS taskId, task.loading_plan_id AS loadingPlanId,
|
||||
task.container_booking_id AS containerBookingId, task.cabinet_no AS cabinetNo,
|
||||
booking.container_no AS containerNo, booking.warehouse_id AS warehouseId,
|
||||
booking.source_type AS sourceType, booking.record_status AS recordStatus,
|
||||
booking.merged_into_container_booking_id AS mergedIntoContainerBookingId,
|
||||
booking.warehouse_name AS warehouseName, task.task_status AS taskStatus,
|
||||
CASE WHEN assignment.pick_task_id IS NULL THEN 'UNASSIGNED' ELSE 'IN_PROGRESS' END AS workflowStatus,
|
||||
task.version AS version, COALESCE(assignment.version, 0) AS assignmentVersion,
|
||||
@@ -67,6 +69,7 @@ public interface LoadingPickTaskMapper extends BaseMapper<LoadingPickTaskEntity>
|
||||
</if>
|
||||
GROUP BY task.id, task.loading_plan_id, task.container_booking_id, task.cabinet_no,
|
||||
booking.container_no, booking.warehouse_id,
|
||||
booking.source_type, booking.record_status, booking.merged_into_container_booking_id,
|
||||
booking.warehouse_name, task.task_status, task.version,
|
||||
assignment.pick_task_id, assignment.version
|
||||
ORDER BY task.id DESC
|
||||
@@ -82,6 +85,9 @@ public interface LoadingPickTaskMapper extends BaseMapper<LoadingPickTaskEntity>
|
||||
private String containerNo;
|
||||
private Long containerBookingId;
|
||||
private String cabinetNo;
|
||||
private String sourceType;
|
||||
private String recordStatus;
|
||||
private Long mergedIntoContainerBookingId;
|
||||
private Long warehouseId;
|
||||
private String warehouseName;
|
||||
private String taskStatus;
|
||||
@@ -101,6 +107,12 @@ public interface LoadingPickTaskMapper extends BaseMapper<LoadingPickTaskEntity>
|
||||
public void setContainerBookingId(Long value) { this.containerBookingId = value; }
|
||||
public String getCabinetNo() { return cabinetNo; }
|
||||
public void setCabinetNo(String value) { this.cabinetNo = value; }
|
||||
public String getSourceType() { return sourceType; }
|
||||
public void setSourceType(String sourceType) { this.sourceType = sourceType; }
|
||||
public String getRecordStatus() { return recordStatus; }
|
||||
public void setRecordStatus(String recordStatus) { this.recordStatus = recordStatus; }
|
||||
public Long getMergedIntoContainerBookingId() { return mergedIntoContainerBookingId; }
|
||||
public void setMergedIntoContainerBookingId(Long value) { this.mergedIntoContainerBookingId = value; }
|
||||
public Long getWarehouseId() { return warehouseId; }
|
||||
public void setWarehouseId(Long warehouseId) { this.warehouseId = warehouseId; }
|
||||
public String getWarehouseName() { return warehouseName; }
|
||||
|
||||
@@ -185,6 +185,7 @@ public class LoadingPickService {
|
||||
return repository.pendingTasks(operatorId, normalizedKeyword).stream()
|
||||
.map(row -> new PendingTask(row.getTaskId(), row.getLoadingPlanId(), row.getContainerBookingId(),
|
||||
row.getCabinetNo(), row.getContainerNo(),
|
||||
row.getSourceType(), row.getRecordStatus(), row.getMergedIntoContainerBookingId(),
|
||||
row.getWarehouseId(), row.getWarehouseName(), row.getTaskStatus(), row.getWorkflowStatus(),
|
||||
row.getVersion(), row.getAssignmentVersion(), row.getItemCount(), row.getPendingItemCount()))
|
||||
.toList();
|
||||
@@ -607,6 +608,9 @@ public class LoadingPickService {
|
||||
: assigned == null ? "UNASSIGNED"
|
||||
: repository.allTaskItemsResolved(task.getId()) ? "AWAITING_REVIEW" : "IN_PROGRESS";
|
||||
var booking = smartLoadingRepository.booking(task.getContainerBookingId());
|
||||
if (booking == null || !"ACTIVE".equals(booking.getRecordStatus())) {
|
||||
throw new BizException(ResultCode.NOT_FOUND, "PDA拣货任务不存在或柜次已非有效存续记录");
|
||||
}
|
||||
var owners = repository.inboundOwners(task.getId());
|
||||
Long detailInboundId = source.isEmpty() ? null : source.get(0).getInboundId();
|
||||
var owner = detailInboundId == null ? null : owners.stream()
|
||||
@@ -616,7 +620,8 @@ public class LoadingPickService {
|
||||
return new Task(task.getId(), task.getLoadingPlanId(), task.getContainerBookingId(),
|
||||
owner == null ? null : owner.inboundId(), inbound == null ? null : inbound.version(),
|
||||
inbound == null ? null : inbound.version(), task.getCabinetNo(),
|
||||
booking == null ? null : booking.getContainerNo(), task.getTaskStatus(),
|
||||
booking.getContainerNo(), booking.getSourceType(), booking.getRecordStatus(),
|
||||
booking.getMergedIntoContainerBookingId(), task.getTaskStatus(),
|
||||
workflowStatus, task.getVersion(), assignment, review, items);
|
||||
}
|
||||
|
||||
|
||||
+9
-6
@@ -15,29 +15,32 @@ public class WarehouseSupplierSnapshotService {
|
||||
@Value("${baiyue.security.internal-service-token}") private String internalToken;
|
||||
|
||||
public WarehouseSupplierClient.Snapshot booking(Long supplierId, String suppliedName) {
|
||||
return resolve(supplierId, suppliedName, "BOOKING", "INTERNATIONAL");
|
||||
return resolve(supplierId, suppliedName, "BOOKING");
|
||||
}
|
||||
|
||||
public WarehouseSupplierClient.Snapshot trucking(Long supplierId, String suppliedName) {
|
||||
return resolve(supplierId, suppliedName, "TRUCKING", null);
|
||||
return resolve(supplierId, suppliedName, "TRUCKING");
|
||||
}
|
||||
|
||||
public WarehouseSupplierClient.Snapshot customs(Long supplierId, String suppliedName) {
|
||||
return resolve(supplierId, suppliedName, "CUSTOMS", null);
|
||||
return resolve(supplierId, suppliedName, "CUSTOMS");
|
||||
}
|
||||
|
||||
private WarehouseSupplierClient.Snapshot resolve(Long supplierId, String suppliedName,
|
||||
String category, String scope) {
|
||||
String category) {
|
||||
if (supplierId == null || supplierId <= 0) {
|
||||
if (StringUtils.hasText(suppliedName)) throw new BizException(ResultCode.BAD_REQUEST,
|
||||
"供应商名称必须来自有效的供应商ID,禁止自由文本");
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
var response = client.get(internalToken, supplierId, true, category, scope);
|
||||
var response = client.get(internalToken, supplierId, true, category);
|
||||
if (response == null || !response.successful() || response.data() == null
|
||||
|| response.data().supplierId() != supplierId
|
||||
|| !"ACTIVE".equals(response.data().status())
|
||||
|| !category.equals(response.data().category())
|
||||
|| !StringUtils.hasText(response.data().name())) {
|
||||
throw new BizException(ResultCode.CONFLICT, "所选供应商不存在、未启用或类别/范围不匹配");
|
||||
throw new BizException(ResultCode.CONFLICT, "所选供应商不存在、未启用或类别不匹配");
|
||||
}
|
||||
if (StringUtils.hasText(suppliedName)
|
||||
&& !suppliedName.trim().equals(response.data().name())) {
|
||||
|
||||
@@ -80,7 +80,7 @@ components:
|
||||
warehouseId: {type: integer, format: int64, minimum: 1, description: ACTIVE domestic transit warehouse ID; warehouseName is resolved and frozen server-side.}
|
||||
shippingCompanyId: {type: integer, format: int64, minimum: 1, nullable: true, description: Optional shipping-company master-data ID; the carrier is independent from the logistics channel and booking-agent Supplier.}
|
||||
shippingCompanyName: {type: string, maxLength: 128, nullable: true, description: Optional shipping-company name snapshot.}
|
||||
bookingAgentId: {type: integer, format: int64, minimum: 1, nullable: true, description: Optional ACTIVE Warehouse supplier ID validated as BOOKING with INTERNATIONAL scope.}
|
||||
bookingAgentId: {type: integer, format: int64, minimum: 1, nullable: true, description: Optional ACTIVE Warehouse supplier ID validated only as category BOOKING; booking suppliers do not use domestic/international scope.}
|
||||
bookingAgentName: {type: string, maxLength: 128, nullable: true, description: Optional consistency hint only; the persisted snapshot always comes from Warehouse and cannot be supplied without bookingAgentId.}
|
||||
serviceTerm: {type: string, maxLength: 32, description: Required free-text Service Term snapshot, for example CY-CY.}
|
||||
freightTerm: {type: string, maxLength: 32, description: Required free-text Freight Term snapshot, for example NINGBO.}
|
||||
|
||||
@@ -34,7 +34,9 @@ paths:
|
||||
- {$ref: '#/components/parameters/TaskId'}
|
||||
- {name: warehouseId, in: query, required: true, schema: {type: integer, format: int64, minimum: 1}}
|
||||
responses:
|
||||
'200': {description: Task with current transport display fields}
|
||||
'200':
|
||||
description: Task with current transport display and ACTIVE container lifecycle fields
|
||||
content: {application/json: {schema: {$ref: '#/components/schemas/Task'}}}
|
||||
/api/platform/v1/first-leg/pda-loading/tasks/{taskId}/claim:
|
||||
post:
|
||||
summary: Atomically claim an unassigned task for the authenticated operator
|
||||
@@ -124,7 +126,7 @@ components:
|
||||
schemas:
|
||||
Task:
|
||||
type: object
|
||||
required: [id, loadingPlanId, containerBookingId, inboundId, inboundVersion, loadingVersion, cabinetNo, taskStatus, workflowStatus, version, items]
|
||||
required: [id, loadingPlanId, containerBookingId, inboundId, inboundVersion, loadingVersion, cabinetNo, sourceType, recordStatus, taskStatus, workflowStatus, version, items]
|
||||
properties:
|
||||
id: {type: integer, format: int64}
|
||||
loadingPlanId: {type: integer, format: int64}
|
||||
@@ -134,6 +136,9 @@ components:
|
||||
loadingVersion: {type: integer, minimum: 0, description: Compatibility alias of inboundVersion from the same fl_inbound_order row; /loading/complete uses this inbound loading-stage version}
|
||||
cabinetNo: {type: string}
|
||||
currentContainerNo: {type: string, nullable: true, description: Mutable transport display field; changing it never resynchronizes the task or item versions and it is never task identity}
|
||||
sourceType: {type: string, enum: [SIMULATION, OCEAN_BOOKING], description: Source of the surviving stable container identity}
|
||||
recordStatus: {type: string, enum: [ACTIVE], description: Task detail is served only from the ACTIVE container booking currently owned by the loading plan}
|
||||
mergedIntoContainerBookingId: {type: integer, format: int64, nullable: true, description: Always null for the surviving ACTIVE operational container; populated only on hidden MERGED source history}
|
||||
taskStatus: {type: string, enum: [LOADING, COMPLETED]}
|
||||
workflowStatus: {type: string, enum: [UNASSIGNED, IN_PROGRESS, AWAITING_REVIEW, COMPLETED]}
|
||||
version: {type: integer, minimum: 0}
|
||||
@@ -164,13 +169,16 @@ components:
|
||||
version: {type: integer, minimum: 0}
|
||||
PendingTask:
|
||||
type: object
|
||||
required: [taskId, loadingPlanId, containerBookingId, cabinetNo, warehouseId, taskStatus, workflowStatus, version, assignmentVersion, itemCount, pendingItemCount]
|
||||
required: [taskId, loadingPlanId, containerBookingId, cabinetNo, sourceType, recordStatus, warehouseId, taskStatus, workflowStatus, version, assignmentVersion, itemCount, pendingItemCount]
|
||||
properties:
|
||||
taskId: {type: integer, format: int64}
|
||||
loadingPlanId: {type: integer, format: int64}
|
||||
containerBookingId: {type: integer, format: int64}
|
||||
cabinetNo: {type: string}
|
||||
currentContainerNo: {type: string, nullable: true}
|
||||
sourceType: {type: string, enum: [SIMULATION, OCEAN_BOOKING]}
|
||||
recordStatus: {type: string, enum: [ACTIVE], description: Enforced by the server-side pending-task query; PDA clients must not infer or relax this filter}
|
||||
mergedIntoContainerBookingId: {type: integer, format: int64, nullable: true, description: Always null for an ACTIVE pending task}
|
||||
warehouseId: {type: integer, format: int64}
|
||||
warehouseName: {type: string, nullable: true}
|
||||
taskStatus: {type: string, enum: [LOADING]}
|
||||
|
||||
+5
-3
@@ -19,13 +19,13 @@ class WarehouseSupplierClientContractTest {
|
||||
FeignClient annotation = WarehouseSupplierClient.class.getAnnotation(FeignClient.class);
|
||||
assertThat(annotation.path()).isEqualTo("/internal/warehouse/v1/suppliers");
|
||||
Method method = WarehouseSupplierClient.class.getDeclaredMethod("get", String.class, long.class,
|
||||
boolean.class, String.class, String.class);
|
||||
boolean.class, String.class);
|
||||
assertThat(method.getAnnotation(GetMapping.class).value()).containsExactly("/{supplierId}");
|
||||
assertThat(method.getParameterAnnotations()[0][0]).isInstanceOf(RequestHeader.class);
|
||||
assertThat(((RequestHeader) method.getParameterAnnotations()[0][0]).value())
|
||||
.isEqualTo("X-Internal-Service-Token");
|
||||
assertThat(method.getParameterAnnotations()[3][0]).isInstanceOf(RequestParam.class);
|
||||
assertThat(method.getParameterAnnotations()[4][0]).isInstanceOf(RequestParam.class);
|
||||
assertThat(method.getParameterCount()).isEqualTo(4);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -33,7 +33,9 @@ class WarehouseSupplierClientContractTest {
|
||||
String ocean = Files.readString(Path.of("src/main/resources/openapi/ocean-bookings-v1.yaml"), StandardCharsets.UTF_8);
|
||||
String truck = Files.readString(Path.of("src/main/resources/openapi/truck-appointments-v1.yaml"), StandardCharsets.UTF_8);
|
||||
String customs = Files.readString(Path.of("src/main/resources/openapi/customs-v1.yaml"), StandardCharsets.UTF_8);
|
||||
assertThat(ocean).contains("bookingAgentId:", "BOOKING", "INTERNATIONAL", "persisted snapshot always comes from Warehouse");
|
||||
assertThat(ocean).contains("bookingAgentId:", "category BOOKING",
|
||||
"do not use domestic/international scope", "persisted snapshot always comes from Warehouse")
|
||||
.doesNotContain("BOOKING with INTERNATIONAL scope");
|
||||
assertThat(truck).contains("carrierId:", "TRUCKING", "persisted snapshot comes from Warehouse");
|
||||
assertThat(customs).contains("customsAgentId", "CUSTOMS", "free text cannot bypass supplier validation");
|
||||
}
|
||||
|
||||
+7
@@ -36,6 +36,9 @@ class PdaConvergenceOpenApiContractTest {
|
||||
.contains("evidence identity is taskId+inboundId+loadingPlanId+containerBookingId")
|
||||
.contains("Current fl_inbound_order.version for inboundId")
|
||||
.contains("Compatibility alias of inboundVersion from the same fl_inbound_order row")
|
||||
.contains("sourceType", "recordStatus", "mergedIntoContainerBookingId")
|
||||
.contains("Task detail is served only from the ACTIVE container booking")
|
||||
.contains("Enforced by the server-side pending-task query")
|
||||
.contains("CompleteLoadingRequest");
|
||||
|
||||
String taskLookup = yaml.substring(
|
||||
@@ -47,6 +50,10 @@ class PdaConvergenceOpenApiContractTest {
|
||||
assertThat(taskLookup)
|
||||
.contains("name: cabinetNo", "name: loadingPlanId")
|
||||
.doesNotContain("name: containerNo");
|
||||
String taskDetail = yaml.substring(
|
||||
yaml.indexOf(" /api/platform/v1/first-leg/pda-loading/tasks/{taskId}:"),
|
||||
yaml.indexOf(" /api/platform/v1/first-leg/pda-loading/tasks/{taskId}/claim:"));
|
||||
assertThat(taskDetail).contains("#/components/schemas/Task", "ACTIVE container lifecycle fields");
|
||||
assertThat(batchRequest)
|
||||
.contains("loadingPlanId:", "containerBookingId:")
|
||||
.doesNotContain("containerNo:");
|
||||
|
||||
@@ -34,7 +34,7 @@ class CustomsServiceTest {
|
||||
ReflectionTestUtils.setField(service, "objectMapper", new ObjectMapper());
|
||||
ReflectionTestUtils.setField(service, "internalToken", "token");
|
||||
when(suppliers.customs(anyLong(), anyString()))
|
||||
.thenReturn(new com.baiyue.firstleg.client.WarehouseSupplierClient.Snapshot(88L, "线下报关代理", "CUSTOMS", null, "ACTIVE"));
|
||||
.thenReturn(new com.baiyue.firstleg.client.WarehouseSupplierClient.Snapshot(88L, "线下报关代理", "CUSTOMS", "ACTIVE"));
|
||||
when(repository.completeOperation(anyLong(), anyString(), anyLong())).thenReturn(1);
|
||||
}
|
||||
|
||||
|
||||
+3
@@ -29,6 +29,9 @@ class LoadingPickPdaTaskSqlContractTest {
|
||||
assertThat(sql)
|
||||
.contains("task.task_status = 'LOADING'")
|
||||
.contains("booking.record_status = 'ACTIVE'")
|
||||
.contains("booking.source_type AS sourceType")
|
||||
.contains("booking.record_status AS recordStatus")
|
||||
.contains("booking.merged_into_container_booking_id AS mergedIntoContainerBookingId")
|
||||
.contains("assignment.pick_task_id IS NULL OR assignment.assignee_id = #{operatorId}")
|
||||
.contains("booking.warehouse_id AS warehouseId")
|
||||
.doesNotContain("tenantId");
|
||||
|
||||
@@ -62,7 +62,7 @@ class ContainerServiceTest {
|
||||
when(warehouses.active(anyString(), anyLong(), anyLong())).thenAnswer(invocation ->
|
||||
activeWarehouse(invocation.getArgument(2, Long.class), "DOMESTIC", "上海中转仓"));
|
||||
when(suppliers.trucking(202L, "拖车公司A"))
|
||||
.thenReturn(new WarehouseSupplierClient.Snapshot(202L, "拖车公司A", "TRUCKING", null, "ACTIVE"));
|
||||
.thenReturn(new WarehouseSupplierClient.Snapshot(202L, "拖车公司A", "TRUCKING", "ACTIVE"));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -17,6 +17,7 @@ import com.baiyue.firstleg.entity.LoadingPickItemEntity;
|
||||
import com.baiyue.firstleg.entity.LoadingPickOperationEntity;
|
||||
import com.baiyue.firstleg.entity.LoadingPickTaskEntity;
|
||||
import com.baiyue.firstleg.entity.LoadingPlanItemEntity;
|
||||
import com.baiyue.firstleg.entity.ContainerBookingEntity;
|
||||
import com.baiyue.firstleg.entity.InboundStatusHistoryEntity;
|
||||
import com.baiyue.firstleg.loading.mapper.LoadingInboundMapper;
|
||||
import com.baiyue.firstleg.loading.bridge.dto.LoadingModelBridgeDtos.Link;
|
||||
@@ -30,6 +31,7 @@ import com.baiyue.firstleg.oceanbooking.entity.OceanBookingContainerAllocationEn
|
||||
import com.baiyue.firstleg.oceanbooking.entity.OceanBookingEntity;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.mockito.InOrder;
|
||||
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
|
||||
@@ -70,6 +72,16 @@ class LoadingPickServiceTest {
|
||||
@Resource
|
||||
private LoadingPickService service;
|
||||
|
||||
@BeforeEach
|
||||
void activeOperationalContainer() {
|
||||
ContainerBookingEntity booking = new ContainerBookingEntity();
|
||||
booking.setId(99L);
|
||||
booking.setContainerNo("CSLU1234567");
|
||||
booking.setSourceType("SIMULATION");
|
||||
booking.setRecordStatus("ACTIVE");
|
||||
when(smartLoadingRepository.booking(99L)).thenReturn(booking);
|
||||
}
|
||||
|
||||
@Test
|
||||
void opensTaskOnlyAfterReleasedBookingAndRealContainerNumber() {
|
||||
var booking = new com.baiyue.firstleg.entity.ContainerBookingEntity();
|
||||
@@ -212,6 +224,7 @@ class LoadingPickServiceTest {
|
||||
task.setContainerBookingId(40L); task.setCabinetNo("CAB-001");
|
||||
var booking = new com.baiyue.firstleg.entity.ContainerBookingEntity();
|
||||
booking.setId(40L); booking.setContainerNo("MSCU-NEW");
|
||||
booking.setSourceType("SIMULATION"); booking.setRecordStatus("ACTIVE");
|
||||
when(repository.taskByCabinet("CAB-001", 101L)).thenReturn(task);
|
||||
when(repository.taskByPlan(10L, 101L)).thenReturn(task);
|
||||
when(smartLoadingRepository.booking(40L)).thenReturn(booking);
|
||||
@@ -224,6 +237,53 @@ class LoadingPickServiceTest {
|
||||
assertThat(byCabinet.id()).isEqualTo(20L);
|
||||
assertThat(byPlan.id()).isEqualTo(20L);
|
||||
assertThat(byCabinet.currentContainerNo()).isEqualTo("MSCU-NEW");
|
||||
assertThat(byCabinet.sourceType()).isEqualTo("SIMULATION");
|
||||
assertThat(byCabinet.recordStatus()).isEqualTo("ACTIVE");
|
||||
assertThat(byCabinet.mergedIntoContainerBookingId()).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void pendingTasksExposeServerFilteredContainerLifecycle() {
|
||||
var row = new com.baiyue.firstleg.mapper.LoadingPickTaskMapper.PendingTaskRow();
|
||||
row.setTaskId(20L);
|
||||
row.setLoadingPlanId(10L);
|
||||
row.setContainerBookingId(99L);
|
||||
row.setCabinetNo("CAB-001");
|
||||
row.setContainerNo("MSCU-001");
|
||||
row.setSourceType("SIMULATION");
|
||||
row.setRecordStatus("ACTIVE");
|
||||
row.setMergedIntoContainerBookingId(null);
|
||||
row.setWarehouseId(101L);
|
||||
row.setTaskStatus("LOADING");
|
||||
row.setWorkflowStatus("UNASSIGNED");
|
||||
row.setVersion(0);
|
||||
row.setAssignmentVersion(0);
|
||||
row.setItemCount(1);
|
||||
row.setPendingItemCount(1);
|
||||
when(repository.pendingTasks(9L, null)).thenReturn(List.of(row));
|
||||
|
||||
var result = service.pendingTasks(9L, null).get(0);
|
||||
|
||||
assertThat(result.sourceType()).isEqualTo("SIMULATION");
|
||||
assertThat(result.recordStatus()).isEqualTo("ACTIVE");
|
||||
assertThat(result.mergedIntoContainerBookingId()).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void taskDetailRejectsMergedContainerSource() {
|
||||
LoadingPickTaskEntity task = task();
|
||||
ContainerBookingEntity merged = new ContainerBookingEntity();
|
||||
merged.setId(99L);
|
||||
merged.setSourceType("OCEAN_BOOKING");
|
||||
merged.setRecordStatus("MERGED");
|
||||
merged.setMergedIntoContainerBookingId(88L);
|
||||
when(repository.task(20L)).thenReturn(task);
|
||||
when(smartLoadingRepository.booking(99L)).thenReturn(merged);
|
||||
when(repository.items(20L, 101L)).thenReturn(List.of());
|
||||
when(repository.cartonLabels(20L)).thenReturn(List.of());
|
||||
|
||||
assertThatThrownBy(() -> service.task(20L, 101L))
|
||||
.isInstanceOf(BizException.class).hasMessageContaining("已非有效存续记录");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -345,6 +405,9 @@ class LoadingPickServiceTest {
|
||||
assertThat(result.loadingVersion()).isEqualTo(7);
|
||||
assertThat(result.loadingPlanId()).isEqualTo(10L);
|
||||
assertThat(result.containerBookingId()).isEqualTo(99L);
|
||||
assertThat(result.sourceType()).isEqualTo("SIMULATION");
|
||||
assertThat(result.recordStatus()).isEqualTo("ACTIVE");
|
||||
assertThat(result.mergedIntoContainerBookingId()).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
+16
-6
@@ -34,19 +34,29 @@ class WarehouseSupplierSnapshotServiceTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void resolvesActiveBookingSupplierWithFixedScopeAndServerName() {
|
||||
when(client.get("internal-token", 7L, true, "BOOKING", "INTERNATIONAL"))
|
||||
.thenReturn(ApiResponse.success(new WarehouseSupplierClient.Snapshot(7L, "海运代理", "BOOKING", "INTERNATIONAL", "ACTIVE")));
|
||||
void resolvesActiveBookingSupplierByCategoryWithoutScopeAndUsesServerName() {
|
||||
when(client.get("internal-token", 7L, true, "BOOKING"))
|
||||
.thenReturn(ApiResponse.success(new WarehouseSupplierClient.Snapshot(7L, "海运代理", "BOOKING", "ACTIVE")));
|
||||
var snapshot = service.booking(7L, "海运代理");
|
||||
assertThat(snapshot.name()).isEqualTo("海运代理");
|
||||
verify(client).get("internal-token", 7L, true, "BOOKING", "INTERNATIONAL");
|
||||
verify(client).get("internal-token", 7L, true, "BOOKING");
|
||||
}
|
||||
|
||||
@Test
|
||||
void rejectsClientNameThatDiffersFromWarehouseSnapshot() {
|
||||
when(client.get(anyString(), eq(9L), eq(true), eq("CUSTOMS"), isNull()))
|
||||
.thenReturn(ApiResponse.success(new WarehouseSupplierClient.Snapshot(9L, "真实报关行", "CUSTOMS", null, "ACTIVE")));
|
||||
when(client.get(anyString(), eq(9L), eq(true), eq("CUSTOMS")))
|
||||
.thenReturn(ApiResponse.success(new WarehouseSupplierClient.Snapshot(9L, "真实报关行", "CUSTOMS", "ACTIVE")));
|
||||
assertThatThrownBy(() -> service.customs(9L, "伪造名称"))
|
||||
.isInstanceOf(BizException.class).hasMessageContaining("不一致");
|
||||
}
|
||||
|
||||
@Test
|
||||
void rejectsSupplierSnapshotWithWrongCategoryOrInactiveStatus() {
|
||||
when(client.get("internal-token", 7L, true, "BOOKING"))
|
||||
.thenReturn(ApiResponse.success(new WarehouseSupplierClient.Snapshot(
|
||||
7L, "错误代理", "TRUCKING", "ACTIVE")));
|
||||
|
||||
assertThatThrownBy(() -> service.booking(7L, null))
|
||||
.isInstanceOf(BizException.class).hasMessageContaining("类别不匹配");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user