fix(finance): preserve container identity and source version order

This commit is contained in:
2026-09-09 10:14:42 +08:00
parent 4379b721bc
commit 7e2626513e
4 changed files with 113 additions and 2 deletions
@@ -81,6 +81,11 @@ public class BusinessFeeSourceEventService {
}
if ("VOIDED".equals(source.action()))
throw error("FIN-EVT-005", "作废事件对应的费用来源版本不存在");
List<Map<String, Object>> versions = jdbc.queryForList(
"SELECT source_fee_version FROM fin_fee_source WHERE source_system=? AND source_type=? AND source_fee_id=? FOR UPDATE",
system, source.sourceType(), feeId);
if (versions.stream().anyMatch(row -> ((Number) row.get("source_fee_version")).intValue() > source.sourceVersion()))
throw error("FIN-EVT-008", "费用来源版本已过期");
requireSourceNotFrozen(system, source.sourceType(), feeId);
jdbc.update("UPDATE fin_fee_source SET status='SUPERSEDED' WHERE source_system=? AND source_type=? AND source_fee_id=? AND status='AVAILABLE'",
system, source.sourceType(), feeId);
@@ -115,6 +120,11 @@ public class BusinessFeeSourceEventService {
}
positive(value.sourceFeeId(), "sourceFeeId");
positive(value.customerId(), "customerId");
if ("OVERSEAS_CONTAINER_FEE".equals(value.sourceType())) {
if (!"LASTLEG".equals(value.sourceSystem()) || !"OVERSEAS_CONTAINER".equals(value.businessType()))
throw error("FIN-EVT-012", "海外柜费来源不一致");
positive(value.containerBookingId(), "containerBookingId");
}
if (!"VOIDED".equals(value.action()) && (!"PUBLISHED".equals(value.publicationStatus())
|| !"ACTIVE".equals(value.sourceStatus()))) {
throw error("FIN-EVT-015", "费用来源尚未发布或已失效");
@@ -125,7 +135,7 @@ public class BusinessFeeSourceEventService {
if (blank(value.supplierName()) || !value.supplierName().equals(supplier.name()))
throw error("FIN-EVT-012", "应付来源供应商快照不一致");
validateSettlement(value);
} else if (!blank(value.supplierId()) || !blank(value.supplierName())
} else if (!blank(value.supplierId()) || !blank(value.supplierName()) || !blank(value.supplierCategory())
|| !blank(value.settlementMode()) || value.paidAt() != null
|| !blank(value.paymentMethod()) || !blank(value.paymentReferenceNo())
|| (value.paymentVoucherFileIds() != null && !value.paymentVoucherFileIds().isEmpty())) {
@@ -169,7 +179,7 @@ public class BusinessFeeSourceEventService {
jdbc.update("INSERT INTO fin_cost(tenant_id,cost_no,cost_type,cost_origin,source_system,source_type,source_fee_id,source_fee_version,source_hash,order_id,inbound_id,container_id,warehouse_id,supplier_id,supplier_name_snapshot,fee_item_code,fee_item_name,currency_code,cost_amount,voucher_file_ids,paid_at,payment_method,payment_reference_no,status,confirmed_at,created_by,created_by_name,updated_by) VALUES(?,?,'SOURCE_DIRECT_PAID','BUSINESS_DIRECT_PAID',?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,'CONFIRMED',CURRENT_TIMESTAMP(3),0,'系统',0)",
positive(value.customerId(), "customerId"), "DIRECT-" + system + '-' + value.sourceType() + '-' + feeId + "-V" + value.sourceVersion(),
system, value.sourceType(), feeId, value.sourceVersion(), value.sourceHash(), number(value.orderId()),
number(value.inboundId()), number(value.containerId()), number(value.warehouseId()), positive(value.supplierId(), "supplierId"),
number(value.inboundId()), number(value.containerBookingId()), number(value.warehouseId()), positive(value.supplierId(), "supplierId"),
value.supplierName(), value.feeItemCode(), value.feeItemName(), value.currency(), value.totalAmount(),
json(value.paymentVoucherFileIds()), value.paidAt(), value.paymentMethod(), value.paymentReferenceNo());
}
@@ -81,6 +81,12 @@ public class FinanceFeeSourceEventService {
if ("FIRSTLEG_FEE_VOIDED".equals(event.eventType())) {
throw error("FIN-EVT-005", "作废事件对应的费用来源版本不存在");
}
List<Map<String, Object>> versions = jdbc.queryForList(
"SELECT source_fee_version FROM fin_fee_source WHERE source_system='FIRSTLEG' AND source_type=? AND source_fee_id=? FOR UPDATE",
snapshot.sourceType(), snapshot.feeId());
if (versions.stream().anyMatch(row -> ((Number) row.get("source_fee_version")).intValue() > snapshot.feeVersion())) {
throw error("FIN-EVT-008", "费用来源版本已过期");
}
requireSourceNotFrozen(snapshot.sourceType(), snapshot.feeId());
jdbc.update("UPDATE fin_fee_source SET status='SUPERSEDED' WHERE source_system='FIRSTLEG' AND source_type=? AND source_fee_id=? AND status='AVAILABLE'",
snapshot.sourceType(), snapshot.feeId());