fix: close inbound hold bypass paths
This commit is contained in:
@@ -162,7 +162,9 @@ public class UnifiedOrderQueryService {
|
||||
query.page(), query.size());
|
||||
PageResult<FirstlegUnifiedOrderClient.Summary> source = require(
|
||||
call(() -> firstleg.page(internalToken, request)), "统一订单履约查询响应无效");
|
||||
List<Long> orderIds = source.records().stream().map(item -> item.inbound().orderId()).toList();
|
||||
List<FirstlegUnifiedOrderClient.Summary> summaries = validateSummaries(
|
||||
source.records(), "统一订单履约查询响应无效");
|
||||
List<Long> orderIds = summaries.stream().map(item -> item.inbound().orderId()).toList();
|
||||
Map<Long, OrderEntity> orderById = orders.findByIds(tenantId, orderIds).stream()
|
||||
.collect(Collectors.toMap(OrderEntity::getId, Function.identity(), (left, right) -> left));
|
||||
Map<Long, String> latestNotes = latestNotes(tenantId, orderIds);
|
||||
@@ -170,7 +172,7 @@ public class UnifiedOrderQueryService {
|
||||
Map<Long, Integer> childCounts = childCounts(List.copyOf(orderById.values()));
|
||||
Map<Long, UnifiedOrderResponse.CoLoadGroupSummary> coLoadByOrder = coLoadGroups(
|
||||
orderIds, includeCoLoadGroups);
|
||||
List<UnifiedOrderResponse.Row> records = source.records().stream()
|
||||
List<UnifiedOrderResponse.Row> records = summaries.stream()
|
||||
.map(summary -> row(summary, orderById.get(summary.inbound().orderId()),
|
||||
latestNotes.get(summary.inbound().orderId()), childCounts,
|
||||
cargoSummaries.get(summary.inbound().orderId()),
|
||||
@@ -185,13 +187,33 @@ public class UnifiedOrderQueryService {
|
||||
call(() -> firstleg.summaries(internalToken,
|
||||
new FirstlegUnifiedOrderClient.BatchRequest(tenantId, orderIds))),
|
||||
"统一订单履约摘要响应无效");
|
||||
return data.stream().collect(Collectors.toMap(item -> item.inbound().orderId(),
|
||||
return validateSummaries(data, "统一订单履约摘要响应无效").stream()
|
||||
.collect(Collectors.toMap(item -> item.inbound().orderId(),
|
||||
Function.identity(), (left, right) -> left));
|
||||
}
|
||||
|
||||
private FirstlegUnifiedOrderClient.Detail firstlegDetail(long tenantId, long orderId) {
|
||||
return requireNullable(call(() -> firstleg.detail(internalToken,
|
||||
FirstlegUnifiedOrderClient.Detail detail = requireNullable(call(() -> firstleg.detail(internalToken,
|
||||
new FirstlegUnifiedOrderClient.DetailRequest(tenantId, orderId))), "统一订单履约详情响应无效");
|
||||
if (detail != null) validateSummary(detail.summary(), "统一订单履约详情响应无效");
|
||||
return detail;
|
||||
}
|
||||
|
||||
private List<FirstlegUnifiedOrderClient.Summary> validateSummaries(
|
||||
List<FirstlegUnifiedOrderClient.Summary> summaries, String message) {
|
||||
return summaries.stream().map(summary -> validateSummary(summary, message)).toList();
|
||||
}
|
||||
|
||||
private FirstlegUnifiedOrderClient.Summary validateSummary(
|
||||
FirstlegUnifiedOrderClient.Summary summary, String message) {
|
||||
FirstlegUnifiedOrderClient.Inbound inbound = summary == null ? null : summary.inbound();
|
||||
if (inbound == null || inbound.id() == null || inbound.tenantId() == null
|
||||
|| inbound.orderId() == null || inbound.holdFlag() == null
|
||||
|| (Boolean.TRUE.equals(inbound.holdFlag()) && !StringUtils.hasText(inbound.currentHoldReason()))
|
||||
|| (Boolean.FALSE.equals(inbound.holdFlag()) && inbound.currentHoldReason() != null)) {
|
||||
throw new BizException(ResultCode.SERVICE_UNAVAILABLE, message);
|
||||
}
|
||||
return summary;
|
||||
}
|
||||
|
||||
private Map<Long, String> latestNotes(Long tenantId, List<Long> orderIds) {
|
||||
|
||||
@@ -2,6 +2,7 @@ package com.baiyue.order.service;
|
||||
|
||||
import com.baiyue.common.core.api.ApiResponse;
|
||||
import com.baiyue.common.core.api.PageResult;
|
||||
import com.baiyue.common.core.api.ResultCode;
|
||||
import com.baiyue.common.core.exception.BizException;
|
||||
import com.baiyue.order.client.FirstlegUnifiedOrderClient;
|
||||
import com.baiyue.order.client.FirstlegColoadGroupClient;
|
||||
@@ -605,6 +606,125 @@ class UnifiedOrderQueryServiceTest {
|
||||
assertThat(captor.getValue().orderId()).isEqualTo(77L);
|
||||
}
|
||||
|
||||
@Test
|
||||
void releasedInboundProjectsFalseFlagAndNullReasonWithFirstlegPagination() {
|
||||
UnifiedOrderQuery query = new UnifiedOrderQuery(
|
||||
null, null, "INBOUNDED", null, null, null, null, null,
|
||||
null, null, null, null, null, null, null, null, null, null,
|
||||
null, null, 4, 10);
|
||||
var summary = summary("INBOUNDED", null);
|
||||
when(summary.inbound().holdFlag()).thenReturn(false);
|
||||
when(summary.inbound().currentHoldReason()).thenReturn(null);
|
||||
when(firstleg.page(eq("internal-token"), any())).thenReturn(
|
||||
ApiResponse.success(new PageResult<>(List.of(summary), 4, 10, 31, 4)));
|
||||
|
||||
var result = service.page(10001L, query);
|
||||
|
||||
assertThat(result.page()).isEqualTo(4);
|
||||
assertThat(result.size()).isEqualTo(10);
|
||||
assertThat(result.total()).isEqualTo(31);
|
||||
assertThat(result.pages()).isEqualTo(4);
|
||||
assertThat(result.records()).singleElement().satisfies(row -> {
|
||||
assertThat(row.holdFlag()).isFalse();
|
||||
assertThat(row.currentHoldReason()).isNull();
|
||||
});
|
||||
ArgumentCaptor<FirstlegUnifiedOrderClient.Query> captor =
|
||||
ArgumentCaptor.forClass(FirstlegUnifiedOrderClient.Query.class);
|
||||
verify(firstleg).page(eq("internal-token"), captor.capture());
|
||||
assertThat(captor.getValue().mainStatus()).isEqualTo("INBOUNDED");
|
||||
assertThat(captor.getValue().page()).isEqualTo(4);
|
||||
assertThat(captor.getValue().size()).isEqualTo(10);
|
||||
}
|
||||
|
||||
@Test
|
||||
void preservesLongIdentifiersBeyondJavascriptSafeIntegerRange() {
|
||||
long orderId = 9_007_199_254_740_993L;
|
||||
long inboundId = 9_007_199_254_740_994L;
|
||||
long tenantId = 9_007_199_254_740_995L;
|
||||
var summary = summary("INBOUNDED", null);
|
||||
when(summary.inbound().orderId()).thenReturn(orderId);
|
||||
when(summary.inbound().id()).thenReturn(inboundId);
|
||||
when(summary.inbound().tenantId()).thenReturn(tenantId);
|
||||
when(firstleg.page(eq("internal-token"), any())).thenReturn(
|
||||
ApiResponse.success(new PageResult<>(List.of(summary), 1, 20, 1, 1)));
|
||||
|
||||
assertThat(service.page(null, query("INBOUNDED")).records()).singleElement().satisfies(row -> {
|
||||
assertThat(row.orderId()).isEqualTo(orderId);
|
||||
assertThat(row.inboundId()).isEqualTo(inboundId);
|
||||
assertThat(row.tenantId()).isEqualTo(tenantId);
|
||||
assertThat(row.holdFlag()).isTrue();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void approvedOrderWithoutFirstlegProjectionKeepsHoldFieldsUnknown() {
|
||||
OrderEntity order = order(OrderStatus.APPROVED);
|
||||
when(orders.findOwned(10001L, 77L)).thenReturn(order);
|
||||
when(orders.findCargo(10001L, 77L)).thenReturn(List.of());
|
||||
when(orders.findParties(10001L, 77L)).thenReturn(List.of());
|
||||
when(orders.findNotes(10001L, 77L)).thenReturn(List.of());
|
||||
when(orders.findHistory(10001L, 77L)).thenReturn(List.of());
|
||||
when(firstleg.detail(eq("internal-token"), any())).thenReturn(ApiResponse.success(null));
|
||||
|
||||
assertThat(service.detail(10001L, 77L, false).summary()).satisfies(row -> {
|
||||
assertThat(row.inboundId()).isNull();
|
||||
assertThat(row.holdFlag()).isNull();
|
||||
assertThat(row.currentHoldReason()).isNull();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void missingHoldFlagFailsClosed() {
|
||||
var summary = summary("INBOUNDED", null);
|
||||
when(summary.inbound().holdFlag()).thenReturn(null);
|
||||
when(firstleg.page(eq("internal-token"), any())).thenReturn(
|
||||
ApiResponse.success(new PageResult<>(List.of(summary), 1, 20, 1, 1)));
|
||||
|
||||
assertServiceUnavailable(() -> service.page(null, query("INBOUNDED")));
|
||||
}
|
||||
|
||||
@Test
|
||||
void heldInboundWithoutReasonFailsClosed() {
|
||||
var summary = summary("INBOUNDED", null);
|
||||
when(summary.inbound().currentHoldReason()).thenReturn(" ");
|
||||
when(firstleg.page(eq("internal-token"), any())).thenReturn(
|
||||
ApiResponse.success(new PageResult<>(List.of(summary), 1, 20, 1, 1)));
|
||||
|
||||
assertServiceUnavailable(() -> service.page(null, query("INBOUNDED")));
|
||||
}
|
||||
|
||||
@Test
|
||||
void releasedInboundWithStaleReasonFailsClosed() {
|
||||
var summary = summary("INBOUNDED", null);
|
||||
when(summary.inbound().holdFlag()).thenReturn(false);
|
||||
when(summary.inbound().currentHoldReason()).thenReturn("旧扣货原因");
|
||||
when(firstleg.page(eq("internal-token"), any())).thenReturn(
|
||||
ApiResponse.success(new PageResult<>(List.of(summary), 1, 20, 1, 1)));
|
||||
|
||||
assertServiceUnavailable(() -> service.page(null, query("INBOUNDED")));
|
||||
}
|
||||
|
||||
@Test
|
||||
void malformedDetailWithoutSummaryFailsClosed() {
|
||||
OrderEntity order = order(OrderStatus.APPROVED);
|
||||
when(orders.findOwned(10001L, 77L)).thenReturn(order);
|
||||
when(orders.findCargo(10001L, 77L)).thenReturn(List.of());
|
||||
when(orders.findParties(10001L, 77L)).thenReturn(List.of());
|
||||
when(orders.findNotes(10001L, 77L)).thenReturn(List.of());
|
||||
when(orders.findHistory(10001L, 77L)).thenReturn(List.of());
|
||||
when(firstleg.detail(eq("internal-token"), any())).thenReturn(
|
||||
ApiResponse.success(new FirstlegUnifiedOrderClient.Detail(null, List.of())));
|
||||
|
||||
assertServiceUnavailable(() -> service.detail(10001L, 77L, false));
|
||||
}
|
||||
|
||||
@Test
|
||||
void firstlegCallExceptionFailsClosed() {
|
||||
when(firstleg.page(eq("internal-token"), any())).thenThrow(new IllegalStateException("boom"));
|
||||
|
||||
assertServiceUnavailable(() -> service.page(null, query("INBOUNDED")));
|
||||
}
|
||||
|
||||
@Test
|
||||
void fulfillmentTabsForwardStatusSearchAndPaginationToFirstleg() {
|
||||
List<String> statuses = List.of(
|
||||
@@ -679,6 +799,13 @@ class UnifiedOrderQueryServiceTest {
|
||||
null, null, 1, 20);
|
||||
}
|
||||
|
||||
private void assertServiceUnavailable(org.assertj.core.api.ThrowableAssert.ThrowingCallable invocation) {
|
||||
assertThatThrownBy(invocation)
|
||||
.isInstanceOf(BizException.class)
|
||||
.extracting(exception -> ((BizException) exception).getResultCode())
|
||||
.isEqualTo(ResultCode.SERVICE_UNAVAILABLE);
|
||||
}
|
||||
|
||||
private OrderEntity order(OrderStatus status) {
|
||||
OrderEntity order = new OrderEntity();
|
||||
order.setId(77L); order.setTenantId(10001L); order.setOrderNo("FL-77");
|
||||
|
||||
Reference in New Issue
Block a user