merge: sync test and stabilize full acceptance
This commit is contained in:
@@ -187,7 +187,10 @@ public class OrderApplicationService {
|
||||
if (target == OrderStatus.COMPLETED) order.setCompletedAt(LocalDateTime.now());
|
||||
if (repository.saveOrder(tenantId, order) != 1) throw new BizException("Concurrent order update");
|
||||
record(tenantId, id, from, target, target.name(), reason, userId, username);
|
||||
if (target == OrderStatus.APPROVED || target == OrderStatus.CANCELLED) writeOutbox(order, target);
|
||||
if (target == OrderStatus.SUBMITTED) prepareSubmittedInbound(order);
|
||||
if (target == OrderStatus.SUBMITTED || target == OrderStatus.APPROVED || target == OrderStatus.CANCELLED) {
|
||||
writeOutbox(order, target);
|
||||
}
|
||||
}
|
||||
|
||||
/** 提交订单的幂等入口。 */
|
||||
@@ -668,9 +671,13 @@ public class OrderApplicationService {
|
||||
private void writeOutbox(OrderEntity order, OrderStatus target) {
|
||||
OutboxEventEntity event = new OutboxEventEntity();
|
||||
event.setTenantId(order.getTenantId()); event.setAggregateType("FIRST_LEG_ORDER"); event.setAggregateId(order.getId());
|
||||
event.setEventType(target == OrderStatus.APPROVED ? "FIRST_LEG_ORDER_APPROVED" : "FIRST_LEG_ORDER_CANCELLED");
|
||||
event.setEventType(switch (target) {
|
||||
case SUBMITTED -> "FIRST_LEG_ORDER_PREPARED";
|
||||
case APPROVED -> "FIRST_LEG_ORDER_APPROVED";
|
||||
default -> "FIRST_LEG_ORDER_CANCELLED";
|
||||
});
|
||||
try {
|
||||
event.setPayloadJson(target == OrderStatus.APPROVED
|
||||
event.setPayloadJson(target == OrderStatus.SUBMITTED || target == OrderStatus.APPROVED
|
||||
? json.writeValueAsString(inboundCommand(order, totalPackageCount(order)))
|
||||
: json.writeValueAsString(Map.of("tenantId", order.getTenantId(), "orderId", order.getId(),
|
||||
"orderNo", order.getOrderNo(), "status", target.name())));
|
||||
@@ -699,10 +706,27 @@ public class OrderApplicationService {
|
||||
order.getFulfillmentType() == null ? "STANDARD" : order.getFulfillmentType(), order.getLxCode());
|
||||
}
|
||||
private void prepareDraftInbound(OrderEntity order, OrderRequests.SaveRequest request) {
|
||||
FirstlegInboundClient client = firstlegProvider == null ? null : firstlegProvider.getIfAvailable();
|
||||
if (client == null || !StringUtils.hasText(internalToken)) return;
|
||||
int packageCount = request.cargoes().stream().map(OrderRequests.Cargo::packageCount)
|
||||
.filter(java.util.Objects::nonNull).mapToInt(Integer::intValue).sum();
|
||||
prepareSubmittedInbound(order, packageCount);
|
||||
}
|
||||
|
||||
/**
|
||||
* 提交即准备稳定的预入库单,供货物提前到仓时采集称重和箱规;
|
||||
* 订单审核仍由 Order 独立控制,Firstleg 不得据此推进测量审核或后续履约。
|
||||
*/
|
||||
private void prepareSubmittedInbound(OrderEntity order) {
|
||||
long total = repository.findCargo(order.getTenantId(), order.getId()).stream()
|
||||
.map(OrderCargoEntity::getPackageCount)
|
||||
.filter(java.util.Objects::nonNull)
|
||||
.mapToLong(Integer::longValue)
|
||||
.sum();
|
||||
prepareSubmittedInbound(order, total > 0 && total <= 1_000_000 ? (int) total : null);
|
||||
}
|
||||
|
||||
private void prepareSubmittedInbound(OrderEntity order, Integer packageCount) {
|
||||
FirstlegInboundClient client = firstlegProvider == null ? null : firstlegProvider.getIfAvailable();
|
||||
if (client == null || !StringUtils.hasText(internalToken)) return;
|
||||
FirstlegInboundClient.OrderApprovedInboundCommand command = inboundCommand(order, packageCount);
|
||||
Runnable prepare = () -> {
|
||||
try {
|
||||
|
||||
@@ -17,7 +17,7 @@ import org.springframework.stereotype.Component;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/** 可靠投递订单审核事件;接收端以订单唯一键保证重复投递安全。 */
|
||||
/** 可靠投递订单预入库与审核事件;接收端以订单唯一键保证重复投递安全。 */
|
||||
@Component
|
||||
@Slf4j
|
||||
public class OrderInboundOutboxPublisher {
|
||||
@@ -38,7 +38,8 @@ public class OrderInboundOutboxPublisher {
|
||||
publishDeclarationUpdate(event);
|
||||
continue;
|
||||
}
|
||||
if (!"FIRST_LEG_ORDER_APPROVED".equals(event.getEventType())) {
|
||||
boolean preparing = "FIRST_LEG_ORDER_PREPARED".equals(event.getEventType());
|
||||
if (!preparing && !"FIRST_LEG_ORDER_APPROVED".equals(event.getEventType())) {
|
||||
failPermanently(event, "unsupported order event");
|
||||
continue;
|
||||
}
|
||||
@@ -73,7 +74,9 @@ public class OrderInboundOutboxPublisher {
|
||||
}
|
||||
}
|
||||
try {
|
||||
ApiResponse<Long> response = client.create(internalToken, command);
|
||||
ApiResponse<Long> response = preparing
|
||||
? client.prepare(internalToken, command)
|
||||
: client.create(internalToken, command);
|
||||
if (response == null || !response.successful()) {
|
||||
throw new IllegalStateException("头程入库服务返回失败");
|
||||
}
|
||||
|
||||
@@ -65,9 +65,7 @@ public class UnifiedOrderQueryService {
|
||||
.collect(Collectors.toMap(OrderEntity::getOrderNo, Function.identity(), (left, right) -> left));
|
||||
List<OrderEntity> selected = orderNos.stream().map(orderByNo::get).filter(Objects::nonNull).toList();
|
||||
List<Long> orderIds = selected.stream().map(OrderEntity::getId).toList();
|
||||
Map<Long, FirstlegUnifiedOrderClient.Summary> inboundByOrder = summaries(null,
|
||||
selected.stream().filter(order -> order.getStatus() != OrderStatus.SUBMITTED)
|
||||
.map(OrderEntity::getId).toList());
|
||||
Map<Long, FirstlegUnifiedOrderClient.Summary> inboundByOrder = summaries(null, orderIds);
|
||||
Map<Long, String> latestNotes = latestNotes(null, orderIds);
|
||||
Map<Long, CargoSummary> cargoSummaries = cargoSummaries(null, orderIds);
|
||||
Map<Long, Integer> childCounts = childCounts(selected);
|
||||
@@ -87,9 +85,10 @@ public class UnifiedOrderQueryService {
|
||||
List<OrderStatus> statuses = "PENDING_REVIEW".equals(query.mainStatus())
|
||||
? List.of(OrderStatus.SUBMITTED) : ACTIVE_ORDER_STATUSES;
|
||||
PageResult<OrderEntity> source = orders.unifiedPage(tenantId, query, statuses);
|
||||
List<Long> sourceOrderIds = source.records().stream().map(OrderEntity::getId).toList();
|
||||
Map<Long, FirstlegUnifiedOrderClient.Summary> inboundByOrder = "PENDING_REVIEW".equals(query.mainStatus())
|
||||
? Map.of()
|
||||
: summaries(tenantId, source.records().stream().map(OrderEntity::getId).toList());
|
||||
? optionalSummaries(tenantId, sourceOrderIds)
|
||||
: summaries(tenantId, sourceOrderIds);
|
||||
Map<Long, String> latestNotes = latestNotes(tenantId, source.records().stream().map(OrderEntity::getId).toList());
|
||||
Map<Long, CargoSummary> cargoSummaries = cargoSummaries(tenantId,
|
||||
source.records().stream().map(OrderEntity::getId).toList());
|
||||
@@ -118,7 +117,7 @@ public class UnifiedOrderQueryService {
|
||||
orders.findParties(tenantId, orderId), includeInternalNotes ? orders.findNotes(tenantId, orderId) : List.of(),
|
||||
orders.findHistory(tenantId, orderId));
|
||||
FirstlegUnifiedOrderClient.Detail inbound = order.getStatus() == OrderStatus.SUBMITTED
|
||||
? null : firstlegDetail(tenantId, orderId);
|
||||
? optionalFirstlegDetail(tenantId, orderId) : firstlegDetail(tenantId, orderId);
|
||||
String latestNote = orderDetail.internalNotes().isEmpty() ? null : orderDetail.internalNotes().get(0).getContent();
|
||||
String creatorName = orderDetail.statusHistory().stream()
|
||||
.filter(item -> "CREATE".equals(item.getAction()))
|
||||
@@ -193,6 +192,15 @@ public class UnifiedOrderQueryService {
|
||||
Function.identity(), (left, right) -> left));
|
||||
}
|
||||
|
||||
private Map<Long, FirstlegUnifiedOrderClient.Summary> optionalSummaries(Long tenantId, List<Long> orderIds) {
|
||||
try {
|
||||
return summaries(tenantId, orderIds);
|
||||
} catch (BizException ignored) {
|
||||
// Order 待审核列表仍可独立使用;Firstleg 预入库投影恢复后再开放提前测量入口。
|
||||
return Map.of();
|
||||
}
|
||||
}
|
||||
|
||||
private FirstlegUnifiedOrderClient.Detail firstlegDetail(long tenantId, long orderId) {
|
||||
FirstlegUnifiedOrderClient.Detail detail = requireNullable(call(() -> firstleg.detail(internalToken,
|
||||
new FirstlegUnifiedOrderClient.DetailRequest(tenantId, orderId))), "统一订单履约详情响应无效");
|
||||
@@ -200,6 +208,15 @@ public class UnifiedOrderQueryService {
|
||||
return detail;
|
||||
}
|
||||
|
||||
|
||||
private FirstlegUnifiedOrderClient.Detail optionalFirstlegDetail(long tenantId, long orderId) {
|
||||
try {
|
||||
return firstlegDetail(tenantId, orderId);
|
||||
} catch (BizException ignored) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private List<FirstlegUnifiedOrderClient.Summary> validateSummaries(
|
||||
List<FirstlegUnifiedOrderClient.Summary> summaries, String message) {
|
||||
return summaries.stream().map(summary -> validateSummary(summary, message)).toList();
|
||||
|
||||
Reference in New Issue
Block a user