This commit is contained in:
2026-08-19 09:42:07 +08:00
parent ff1d330c2d
commit b5864bfcda
56 changed files with 497 additions and 306 deletions
@@ -14,7 +14,7 @@ public interface WarehouseSupplierClient {
ApiResponse<SupplierSnapshot> get(@RequestHeader("X-Internal-Service-Token") String token,
@PathVariable long supplierId,
@RequestParam(defaultValue = "true") boolean requireActive,
@RequestParam String category);
@RequestParam(required = false) String category);
record SupplierSnapshot(long supplierId, String name, String category, String status) {}
}
@@ -131,7 +131,7 @@ public class FinanceFeeSourceEventService {
if (!Set.of("INBOUND_FEE", "CONTAINER_FEE").contains(value.sourceType()) || blank(value.feeItemCode()) || blank(value.feeItemName()) || blank(value.sourceHash())) throw error("FIN-EVT-012", "费用来源快照字段不完整");
if ("PAYABLE".equals(value.direction())) {
if (value.supplierId() == null || value.supplierId() <= 0
|| blank(value.supplierName()) || blank(value.supplierCategory())) {
|| blank(value.supplierName())) {
throw error("FIN-EVT-012", "应付费用来源供应商快照不完整");
}
var supplier = supplierValidator.requireActive(value.supplierId(), value.supplierCategory());
@@ -177,7 +177,7 @@ public class FinanceService {
String supplierName = null;
if (request.supplierId() != null) {
if (request.supplierId() <= 0) throw bad("供应商ID无效");
throw bad("人工成本缺少显式供应商类别,无法校验供应商");
supplierName = supplierValidator.requireActive(request.supplierId(), null).name();
} else if (org.springframework.util.StringUtils.hasText(request.supplierName())) {
throw bad("供应商名称必须来自Warehouse供应商主数据");
}
@@ -164,13 +164,8 @@ public class FinanceSettlementService {
}
BigDecimal total = sources.stream().map(row -> decimal(row, "amount")).reduce(BigDecimal.ZERO, BigDecimal::add);
if (total.signum() <= 0) throw error("FIN_400", "应付结算金额必须大于0");
if (sources.stream().anyMatch(row -> !StringUtils.hasText(text(row, "supplier_category")))) {
throw error("FIN_409", "应付费用来源缺少供应商类别快照");
}
Set<String> supplierCategories = sources.stream().map(row -> text(row, "supplier_category"))
.collect(java.util.stream.Collectors.toSet());
if (supplierCategories.size() != 1) throw error("FIN_409", "应付结算费用来源必须属于同一供应商类别");
String supplierName = supplierValidator.requireActive(request.supplierId(), supplierCategories.iterator().next()).name();
String supplierCategory = supplierCategoryConstraint(sources);
String supplierName = supplierValidator.requireActive(request.supplierId(), supplierCategory).name();
String customerName = sources.stream().map(row -> jsonText(parseTree(text(row, "source_snapshot")), "customerName"))
.filter(StringUtils::hasText).findFirst().orElse("客户" + customerId);
LocalDate generatedDate = LocalDate.now();
@@ -384,15 +379,18 @@ public class FinanceSettlementService {
}
private String payableSupplierCategory(long customerId, long settlementId) {
Set<String> categories = jdbc.queryForList(
return supplierCategoryConstraint(jdbc.queryForList(
"SELECT JSON_UNQUOTE(JSON_EXTRACT(f.source_snapshot,'$.supplierCategory')) supplier_category FROM fin_settlement_line sl " +
"JOIN fin_fee_source f ON f.id=sl.fee_source_id AND f.customer_id=sl.tenant_id " +
"WHERE sl.tenant_id=? AND sl.settlement_id=?",
customerId, settlementId).stream()
.map(row -> text(row, "supplier_category"))
.collect(java.util.stream.Collectors.toSet());
if (categories.size() != 1) throw error("FIN_409", "结算单费用来源供应商类别不一致");
return categories.iterator().next();
customerId, settlementId));
}
private String supplierCategoryConstraint(List<Map<String, Object>> sources) {
Set<String> categories = sources.stream().map(row -> text(row, "supplier_category"))
.filter(StringUtils::hasText).collect(java.util.stream.Collectors.toSet());
if (categories.size() > 1) throw error("FIN_409", "应付费用来源供应商类别约束不一致");
return categories.isEmpty() ? null : categories.iterator().next();
}
private Long reserve(long customerId, long operatorId, String operation, String key,
@@ -29,7 +29,8 @@ public class FinanceSupplierValidator {
var supplier = response == null ? null : response.data();
if (response == null || !response.successful() || supplier == null
|| supplier.supplierId() != supplierId || !"ACTIVE".equals(supplier.status())
|| !normalizedCategory.equals(supplier.category()) || !StringUtils.hasText(supplier.name())) {
|| (normalizedCategory != null && !normalizedCategory.equals(supplier.category()))
|| !StringUtils.hasText(supplier.name())) {
throw new FinanceEventException("FIN_409", "供应商不存在、未启用或类别与费用来源不匹配");
}
return supplier;
@@ -42,7 +43,8 @@ public class FinanceSupplierValidator {
}
private static String normalizeCategory(String category) {
String normalized = category == null ? "" : category.trim().toUpperCase(Locale.ROOT);
if (!StringUtils.hasText(category)) return null;
String normalized = category.trim().toUpperCase(Locale.ROOT);
if (!CATEGORIES.contains(normalized)) {
throw new FinanceEventException("FIN_409", "费用来源供应商类别无效");
}