尾程订单列表查询修改

This commit is contained in:
2026-10-21 21:49:48 +08:00
parent 5356a8c898
commit bbf8f2f792
5 changed files with 161 additions and 4 deletions
@@ -0,0 +1,56 @@
package com.baiyue.order.controller;
import com.baiyue.common.core.api.ApiResponse;
import com.baiyue.common.core.api.PageResult;
import com.baiyue.order.dto.PreDepartureOrderDtos;
import com.baiyue.order.dto.UnifiedOrderQuery;
import com.baiyue.order.dto.UnifiedOrderResponse;
import com.baiyue.order.service.UnifiedOrderQueryService;
import jakarta.annotation.Resource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.stream.Collectors;
/** Service-only aggregate query. It intentionally has no platform-user permission. */
@RestController
@RequestMapping("/internal/order/v1/predeparture-orders")
public class InternalPreDepartureOrderController {
@Resource private UnifiedOrderQueryService service;
@Value("${baiyue.security.internal-service-token}") private String expectedToken;
@GetMapping
public ApiResponse<PageResult<PreDepartureOrderDtos.Row>> page(
@RequestHeader(value="X-Internal-Service-Token", required=false) String token,
@RequestParam(required=false) Long customerId, @RequestParam(required=false) String orderNo,
@RequestParam(required=false) String inboundCode, @RequestParam(defaultValue="1") int page,
@RequestParam(defaultValue="200") int size) {
if (expectedToken == null || expectedToken.isBlank() || token == null || !java.security.MessageDigest.isEqual(expectedToken.getBytes(StandardCharsets.UTF_8), token.getBytes(StandardCharsets.UTF_8))) throw new org.springframework.web.server.ResponseStatusException(org.springframework.http.HttpStatus.FORBIDDEN);
if (page < 1 || size < 1 || size > 2000) throw new org.springframework.web.server.ResponseStatusException(org.springframework.http.HttpStatus.BAD_REQUEST);
Map<Long, UnifiedOrderResponse.Row> all = new LinkedHashMap<>();
// 由统一订单服务一次返回全部履约状态,再按实际开船事实筛选。
for (long sourcePage = 1; ; sourcePage++) {
UnifiedOrderQuery q = new UnifiedOrderQuery(null, orderNo, "PRE_DEPARTURE", customerId, null, null,
inboundCode, null, null, null, null, null, null, null, null, null, null, null,
null, null, sourcePage, 200, null);
var result = service.platformPage(customerId, q);
result.records().forEach(row -> { if (row.transport() == null || row.transport().actualSailingAt() == null) all.putIfAbsent(row.orderId(), row); });
if (sourcePage >= result.pages()) break;
}
List<PreDepartureOrderDtos.Row> rows = all.values().stream().sorted(Comparator.comparing(UnifiedOrderResponse.Row::createdAt, Comparator.nullsLast(Comparator.reverseOrder())))
.map(this::row).toList();
int from = Math.min((page - 1) * size, rows.size());
int to = Math.min(from + size, rows.size());
long total = rows.size(), pages = total == 0 ? 0 : (total + size - 1) / size;
return ApiResponse.success(new PageResult<>(rows.subList(from, to), page, size, total, pages));
}
private PreDepartureOrderDtos.Row row(UnifiedOrderResponse.Row r) {
var t = r.transport();
return new PreDepartureOrderDtos.Row(r.orderId(), r.customerId(), r.orderNo(), r.inboundCode(), r.mainStatus(),
r.customerName(), r.lxCode(), r.receivingWarehouseName(), r.destinationWarehouseName(), r.destinationCode(),
r.totalPackageCount(), r.actualVolumeCbm() == null ? r.expectedVolumeCbm() : r.actualVolumeCbm(),
r.actualGrossWeightKg(), r.totalNetWeightKg(), r.expectedArrivalAt(), t == null ? null : t.containerNo(),
t == null ? null : t.cabinetNo(), t == null ? null : t.estimatedSailingAt(), t == null ? null : t.actualSailingAt(), r.createdAt(), r.updatedAt());
}
}
@@ -0,0 +1,17 @@
package com.baiyue.order.dto;
import java.time.LocalDateTime;
/** Internal read model used by lastleg to show orders before an actual sailing fact exists. */
public final class PreDepartureOrderDtos {
private PreDepartureOrderDtos() {}
public record Query(Long customerId, String orderNo, String inboundCode, int page, int size) {}
public record Row(Long orderId, Long customerId, String orderNo, String inboundCode,
String mainStatus, String customerName, String lxCode,
String receivingWarehouseName, String destinationWarehouseName,
String destinationCode, Integer packageCount, java.math.BigDecimal volumeCbm,
java.math.BigDecimal grossWeightKg, java.math.BigDecimal netWeightKg,
LocalDateTime expectedArrivalAt, String containerNo, String cabinetNo,
LocalDateTime estimatedSailingAt, LocalDateTime actualSailingAt,
LocalDateTime createdAt, LocalDateTime updatedAt) {}
}
@@ -148,7 +148,7 @@ public class UnifiedOrderQueryService {
/** 状态投影和当前页摘要共用原筛选,候选订单用于服务内批量收敛范围。 */
private FirstlegUnifiedOrderClient.Query statusRequest(Long tenantId, UnifiedOrderQuery query, List<Long> candidates) {
String status = Set.of("PENDING_REVIEW", "COMPLETED").contains(
String status = Set.of("PENDING_REVIEW", "COMPLETED", "PRE_DEPARTURE").contains(
query.mainStatus() == null ? "" : query.mainStatus()) ? null : query.mainStatus();
return new FirstlegUnifiedOrderClient.Query(tenantId, query.keyword(), query.orderNo(), status,
query.customerId(), query.receivingWarehouseId(), query.destinationWarehouseId(), query.inboundCode(),
@@ -261,7 +261,7 @@ public class UnifiedOrderQueryService {
private PageResult<UnifiedOrderResponse.Row> pageFromFirstleg(Long tenantId, UnifiedOrderQuery query,
boolean includeCoLoadGroups) {
List<FirstlegUnifiedOrderClient.StatusRow> matching = matchingStatusRows(tenantId, query).stream()
.filter(row -> !StringUtils.hasText(query.mainStatus()) || query.mainStatus().equals(row.mainStatus()))
.filter(row -> !StringUtils.hasText(query.mainStatus()) || "PRE_DEPARTURE".equals(query.mainStatus()) || query.mainStatus().equals(row.mainStatus()))
.collect(Collectors.collectingAndThen(Collectors.toMap(FirstlegUnifiedOrderClient.StatusRow::orderId,
Function.identity(), (left, right) -> left, java.util.LinkedHashMap::new),
values -> List.copyOf(values.values())));
@@ -682,7 +682,7 @@ public class UnifiedOrderQueryService {
if (query.taxMode() != null && !Set.of("TAX_REFUND", "BUY_DECLARATION").contains(query.taxMode())) {
throw new BizException(ResultCode.BAD_REQUEST, "taxMode仅支持TAX_REFUND或BUY_DECLARATION");
}
if (StringUtils.hasText(query.mainStatus())
if (StringUtils.hasText(query.mainStatus()) && !"PRE_DEPARTURE".equals(query.mainStatus())
&& !MAIN_STATUSES.contains(query.mainStatus())
&& !WORKFLOW_STATUSES.contains(query.mainStatus())
) {
@@ -708,7 +708,7 @@ public class UnifiedOrderQueryService {
}
private boolean requiresFirstlegQuery(UnifiedOrderQuery query) {
return (StringUtils.hasText(query.mainStatus())
return ("PRE_DEPARTURE".equals(query.mainStatus()) || StringUtils.hasText(query.mainStatus())
&& !Set.of("PENDING_REVIEW", "COMPLETED").contains(query.mainStatus()))
|| query.expectedArrivalDate() != null
|| StringUtils.hasText(query.feeReviewStatus()) || StringUtils.hasText(query.containerNo())