fix(acceptance): enforce immutable confirmed fees

This commit is contained in:
2026-09-10 21:18:52 +08:00
parent 7b35373da3
commit 800ebb875f
14 changed files with 116 additions and 53 deletions
@@ -222,6 +222,7 @@ public class CarrierScheduleQueryService {
}
CarrierScheduleQueryEntity value = requiredLockedVersion(id, request.expectedVersion());
CarrierScheduleNode node = CarrierScheduleNode.require(request.standardNode());
requireManualActualAdvance(value, node, request.actualAt());
CarrierScheduleQueryEntity before = copy(value);
String providerEventId = sha256("MANUAL|" + id + '|' + key);
CarrierScheduleNodeFactEntity fact = addNode(value, "MANUAL", providerEventId, node.name(), node,
@@ -306,6 +307,16 @@ public class CarrierScheduleQueryService {
return false;
}
private void requireManualActualAdvance(CarrierScheduleQueryEntity value, CarrierScheduleNode node,
LocalDateTime actualAt) {
if (actualAt == null) return;
CarrierScheduleNode current = value.getLatestStandardNode() == null ? null
: CarrierScheduleNode.require(value.getLatestStandardNode());
if ("STOPPED".equals(value.getStatus()) || current != null && node.sequence() <= current.sequence()) {
throw conflict("实际船节点必须按业务顺序向后推进");
}
}
public boolean hasOutboundDepartureFact(long customerId, long oceanBookingId, long containerBookingId) {
CarrierScheduleQueryEntity query = repository.findByBusinessScope(customerId, oceanBookingId,
containerBookingId);
@@ -98,8 +98,8 @@ public class FbaPricingService {
if (published == null || !"SENT".equals(published.getFeeStatus())) {
throw conflict("费用状态已变化,请刷新后重试");
}
if (feeRevisionLocked(inbound, published)) {
throw conflict("客户已确认且该票已装柜完成,不允许再修改或重新发送费用");
if (feeRevisionLocked(published)) {
throw conflict("客户已确认,不允许再修改或重新发送费用");
}
}
var measurement = measurementRepository.findLatestMeasurement(tenantId, inboundId);
@@ -490,8 +490,8 @@ public class FbaPricingService {
if (current == null || !List.of("CALCULATED", "CONFIRMED", "SENT").contains(current.getFeeStatus())) {
throw conflict("入库单没有可修改的初算或已发布费用");
}
if (feeRevisionLocked(inbound, current)) {
throw conflict("客户已确认且该票已装柜完成,不允许再修改费用");
if (feeRevisionLocked(current)) {
throw conflict("客户已确认,不允许再修改费用");
}
if (!request.expectedFeeVersion().equals(current.getFeeVersion())) {
throw conflict("费用版本已变化,请刷新后重试");
@@ -613,9 +613,8 @@ public class FbaPricingService {
.contains(processStatus);
}
private static boolean feeRevisionLocked(InboundPricingEntity inbound, InboundFeeEntity fee) {
return fee != null && fee.getCustomerConfirmedAt() != null
&& List.of("LOADED", "DELIVERED").contains(inbound.getProcessStatus());
private static boolean feeRevisionLocked(InboundFeeEntity fee) {
return fee != null && fee.getCustomerConfirmedAt() != null;
}
private static PricingDestinationType destinationType(InboundPricingEntity inbound) {