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
@@ -4,6 +4,8 @@ import com.baiyue.common.core.api.ApiResponse;
import com.baiyue.common.core.api.PageResult;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
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.RequestParam;
@@ -29,6 +31,13 @@ public interface PendingReviewOrderClient {
@RequestParam long page,
@RequestParam long size);
@PostMapping("/batch")
ApiResponse<List<Row>> batch(
@RequestHeader("X-Internal-Service-Token") String token,
@RequestBody BatchRequest request);
record BatchRequest(List<Long> orderIds) {}
record Row(Long orderId, String orderNo, String inboundCode, Long customerId,
String customerName, Long warehouseId, String channelCode, String channelName,
int totalPackageCount, LocalDateTime createdAt, LocalDateTime expectedArrivalAt,
@@ -13,6 +13,11 @@ import static com.baiyue.firstleg.loading.coload.persistence.ColoadPersistenceRo
/** 同柜不可拆组在 Firstleg 单库内的唯一持久化入口。 */
@Mapper
public interface ColoadGroupMapper {
@Select({"<script>", "SELECT DISTINCT order_id FROM fl_inbound_order WHERE deleted=0 AND order_id IN",
"<foreach collection='orderIds' item='orderId' open='(' separator=',' close=')'>",
"#{orderId}", "</foreach>", "</script>"})
List<Long> existingOrderIds(@Param("orderIds") List<Long> orderIds);
@Select({"<script>", """
SELECT o.tenant_id tenantId,o.order_id orderId,o.order_no orderNo,
o.id inboundId,o.inbound_code inboundCode,o.process_status processStatus,
@@ -13,6 +13,10 @@ import com.baiyue.firstleg.loading.coload.persistence.ColoadPersistenceRows.Comm
import com.baiyue.firstleg.loading.coload.persistence.ColoadPersistenceRows.GroupRow;
import com.baiyue.firstleg.loading.coload.persistence.ColoadPersistenceRows.InboundCandidateRow;
import com.baiyue.firstleg.loading.coload.port.ColoadGroupAssignmentPort;
import com.baiyue.firstleg.client.OrderCargoClient;
import com.baiyue.firstleg.client.PendingReviewOrderClient;
import com.baiyue.firstleg.service.InboundOrderCreationService;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@@ -41,6 +45,10 @@ public class ColoadGroupService implements ColoadGroupAssignmentPort {
@Resource
private ColoadGroupMapper mapper;
@Resource private PendingReviewOrderClient pendingReviewOrders;
@Resource private OrderCargoClient orderCargoClient;
@Resource private InboundOrderCreationService inboundOrderCreationService;
@Value("${baiyue.security.internal-service-token:}") private String internalToken;
@Transactional
public GroupSnapshot create(List<Long> requestedOrderIds, String idempotencyKey,
@@ -51,6 +59,7 @@ public class ColoadGroupService implements ColoadGroupAssignmentPort {
CommandClaim claim = claim(operatorId, "CREATE", key, requestHash);
if (claim.replayGroupId() != null) return requiredSnapshot(claim.replayGroupId());
preparePendingReviewInbounds(orderIds);
List<InboundCandidateRow> candidates = authoritativeCandidates(orderIds, null);
validateSameRoute(candidates);
Long lockedPlanId = validateAllocationState(candidates);
@@ -265,6 +274,37 @@ public class ColoadGroupService implements ColoadGroupAssignmentPort {
return resolved;
}
private void preparePendingReviewInbounds(List<Long> orderIds) {
Set<Long> existing = Set.copyOf(mapper.existingOrderIds(orderIds));
List<Long> missing = orderIds.stream().filter(orderId -> !existing.contains(orderId)).toList();
if (missing.isEmpty()) return;
try {
var response = pendingReviewOrders.batch(internalToken,
new PendingReviewOrderClient.BatchRequest(missing));
if (response == null || !response.successful() || response.data() == null) throw unavailable();
for (PendingReviewOrderClient.Row row : response.data()) {
if (row == null || row.orderId() == null || !missing.contains(row.orderId())
|| row.customerId() == null || !"PENDING_REVIEW".equals(row.mainStatus())) {
throw conflict("待审核订单权威快照已变化,请刷新后重试");
}
var snapshotResponse = orderCargoClient.inboundSnapshot(
internalToken, row.customerId(), row.orderId());
if (snapshotResponse == null || !snapshotResponse.successful()
|| snapshotResponse.data() == null
|| snapshotResponse.data().tenantId() != row.customerId()
|| snapshotResponse.data().orderId() != row.orderId()
|| !Objects.equals(snapshotResponse.data().inboundCode(), row.inboundCode())) {
throw conflict("待审核订单履约快照已变化,请刷新后重试");
}
inboundOrderCreationService.prepareFromDraft(snapshotResponse.data());
}
} catch (BizException exception) {
throw exception;
} catch (RuntimeException exception) {
throw unavailable();
}
}
private String unavailableReason(InboundCandidateRow row, Long allowedGroupId) {
if (row.getTenantId() == null || row.getTenantId() <= 0
|| row.getInboundId() == null || row.getInboundId() <= 0
@@ -470,6 +510,10 @@ public class ColoadGroupService implements ColoadGroupAssignmentPort {
return new BizException(ResultCode.CONFLICT, message);
}
private static BizException unavailable() {
return new BizException(ResultCode.INTERNAL_ERROR, "待审核订单权威服务暂不可用");
}
private record CommandClaim(long commandId, Long replayGroupId) {
}
}