This commit is contained in:
2026-09-20 15:03:24 +08:00
parent a7d458cddd
commit 0e52f4e11e
16 changed files with 246 additions and 5 deletions
@@ -12,6 +12,8 @@ import jakarta.validation.Valid;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@@ -40,6 +42,14 @@ public class InternalPendingReviewOrderController {
return ApiResponse.success(service.page(query));
}
@PostMapping("/batch")
public ApiResponse<java.util.List<PendingReviewOrderDtos.Row>> batch(
@RequestHeader(value = "X-Internal-Service-Token", required = false) String token,
@Valid @RequestBody PendingReviewOrderDtos.BatchRequest request) {
requireToken(token);
return ApiResponse.success(service.batch(request.orderIds()));
}
private void requireToken(String token) {
byte[] supplied = token == null ? new byte[0] : token.getBytes(StandardCharsets.UTF_8);
if (!MessageDigest.isEqual(expectedToken, supplied)) {
@@ -4,6 +4,8 @@ import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.AssertTrue;
import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
import org.springframework.format.annotation.DateTimeFormat;
@@ -41,6 +43,11 @@ public final class PendingReviewOrderDtos {
}
}
public record BatchRequest(
@NotEmpty @Size(min = 1, max = 100) List<@NotNull @Min(1) Long> orderIds
) {
}
public record Row(
@Schema(type = "string", pattern = "^[1-9][0-9]*$") Long orderId,
String orderNo,
@@ -5,6 +5,8 @@ import com.baiyue.common.core.api.ResultCode;
import com.baiyue.common.core.exception.BizException;
import com.baiyue.order.dto.PendingReviewOrderDtos;
import com.baiyue.order.entity.OrderCargoEntity;
import com.baiyue.order.entity.OrderEntity;
import com.baiyue.order.entity.OrderStatus;
import com.baiyue.order.repository.OrderRepository;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
@@ -40,16 +42,33 @@ public class PendingReviewOrderQueryService {
var source = orders.pendingReviewPage(channelCodes, query.warehouseId(), query.customerId(),
normalize(query.inboundCode()), createdFrom, createdBefore, expectedArrivalFrom,
expectedArrivalBefore, query.excludedOrderIds(), query.page(), query.size());
List<Long> orderIds = source.records().stream().map(order -> order.getId()).toList();
return new PageResult<>(rows(source.records()), source.page(), source.size(), source.total(), source.pages());
}
public List<PendingReviewOrderDtos.Row> batch(List<Long> requestedOrderIds) {
if (requestedOrderIds == null || requestedOrderIds.isEmpty() || requestedOrderIds.size() > 100
|| requestedOrderIds.stream().anyMatch(java.util.Objects::isNull)
|| requestedOrderIds.stream().anyMatch(id -> id <= 0)
|| requestedOrderIds.stream().distinct().count() != requestedOrderIds.size()) {
throw new BizException(ResultCode.VALIDATION_FAILED, "待审核订单ID必须为1至100个不同的正整数");
}
Map<Long, OrderEntity> byId = orders.findByIds(null, requestedOrderIds).stream()
.filter(order -> !Boolean.TRUE.equals(order.getDeleted()))
.filter(order -> order.getStatus() == OrderStatus.SUBMITTED)
.collect(Collectors.toMap(OrderEntity::getId, order -> order));
return rows(requestedOrderIds.stream().map(byId::get).filter(java.util.Objects::nonNull).toList());
}
private List<PendingReviewOrderDtos.Row> rows(List<OrderEntity> source) {
List<Long> orderIds = source.stream().map(OrderEntity::getId).toList();
Map<Long, Integer> packageCounts = orders.findCargoByOrderIds(null, orderIds).stream()
.collect(Collectors.groupingBy(OrderCargoEntity::getOrderId,
Collectors.summingInt(cargo -> cargo.getPackageCount() == null ? 0 : cargo.getPackageCount())));
var rows = source.records().stream().map(order -> new PendingReviewOrderDtos.Row(
return source.stream().map(order -> new PendingReviewOrderDtos.Row(
order.getId(), order.getOrderNo(), order.getInboundCode(), order.getCustomerId(),
order.getCustomerName(), order.getReceivingWarehouseId(), order.getChannelCode(),
order.getChannelName(), packageCounts.getOrDefault(order.getId(), 0), order.getCreatedAt(),
order.getExpectedArrivalAt(), "PENDING_REVIEW")).toList();
return new PageResult<>(rows, source.page(), source.size(), source.total(), source.pages());
}
private static List<String> normalizeChannelCodes(List<String> values) {
@@ -137,6 +137,30 @@ paths:
application/json:
schema: {$ref: '#/components/schemas/PendingReviewOrderPageEnvelope'}
'403': {description: 内部服务令牌无效}
/internal/order/v1/pending-review-orders/batch:
post:
security: []
summary: Firstleg 按订单 ID 批量核验 Order 权威待审核订单
description: >-
仅接受内部服务令牌。只返回请求集合中未删除且 status=SUBMITTED 的订单,按请求顺序返回;
供订单列表创建同柜组前幂等准备 Firstleg PREPARING 入库投影,不返回已审核或失效订单。
parameters:
- name: X-Internal-Service-Token
in: header
required: true
schema: {type: string}
requestBody:
required: true
content:
application/json:
schema: {$ref: '#/components/schemas/PendingReviewOrderBatchRequest'}
responses:
'200':
description: Order 权威待审核订单集合
content:
application/json:
schema: {$ref: '#/components/schemas/PendingReviewOrderListEnvelope'}
'403': {description: 内部服务令牌无效}
/internal/exports/v1/DOMESTIC_WAREHOUSE_ORDER_LIST/batches:
post:
security: []
@@ -1293,6 +1317,23 @@ components:
size: {type: integer, format: int64, minimum: 1}
total: {type: integer, format: int64, minimum: 0}
pages: {type: integer, format: int64, minimum: 0}
PendingReviewOrderBatchRequest:
type: object
additionalProperties: false
required: [orderIds]
properties:
orderIds:
type: array
minItems: 1
maxItems: 100
uniqueItems: true
items: {type: string, pattern: '^[1-9][0-9]*$'}
PendingReviewOrderListEnvelope:
type: object
properties:
code: {type: string, example: '200'}
message: {type: string}
data: {type: array, items: {$ref: '#/components/schemas/PendingReviewOrderRow'}}
PendingReviewOrderRow:
type: object
required: [orderId, orderNo, inboundCode, customerId, customerName, warehouseId, channelCode, channelName, totalPackageCount, createdAt, expectedArrivalAt, mainStatus]