优化
This commit is contained in:
@@ -14,10 +14,11 @@ class FinanceExportContractTest {
|
||||
private static final List<String> TYPES = List.of(
|
||||
"FINANCE_CUSTOMER_ACCOUNT_LIST", "FINANCE_CUSTOMER_ACCOUNT_LEDGER", "FINANCE_FEE_SOURCE_LIST",
|
||||
"FINANCE_RECONCILIATION_STATEMENT_LIST", "FINANCE_RECEIVABLE_SETTLEMENT_LIST",
|
||||
"FINANCE_RECEIVABLE_SETTLEMENT_DETAIL", "FINANCE_PAYABLE_SETTLEMENT_LIST", "FINANCE_PAYABLE_SETTLEMENT_DETAIL");
|
||||
"FINANCE_RECEIVABLE_SETTLEMENT_DETAIL", "FINANCE_PAYABLE_SETTLEMENT_LIST", "FINANCE_PAYABLE_SETTLEMENT_DETAIL",
|
||||
"FINANCE_RECEIVABLE_STATISTICS");
|
||||
|
||||
@Test
|
||||
void keepsOpenApiAndAllFileDefinitionsOnTheSameEightTypes() throws Exception {
|
||||
void keepsOpenApiAndAllFileDefinitionsOnTheSameNineTypes() throws Exception {
|
||||
String openApi = Files.readString(resolve("docs", "财务管理", "openapi", "finance-phase1-five-pages-v1.yaml"), StandardCharsets.UTF_8);
|
||||
String application = Files.readString(resolve("baiyue-firstleg", "file", "src", "main", "resources", "application.yml"), StandardCharsets.UTF_8);
|
||||
String local = Files.readString(resolve("baiyue-firstleg", "config", "nacos", "local", "file-service.yml"), StandardCharsets.UTF_8);
|
||||
|
||||
@@ -46,10 +46,10 @@ class FinanceFeeSourceEventServiceTest {
|
||||
void importsApprovedSettlementInboundFee() {
|
||||
FinanceFeeSourceEvent event = inboundEvent("published-1", "FIRSTLEG_FEE_PUBLISHED", 1, 7);
|
||||
givenNewEvent();
|
||||
when(firstleg.inbound("test-token", 21, 31)).thenReturn(ApiResponse.success(snapshot("INBOUND_FEE", 7, 1, 21L, null)));
|
||||
when(firstleg.inbound("test-token", 21, 31, 1)).thenReturn(ApiResponse.success(snapshot("INBOUND_FEE", 7, 1, 21L, null)));
|
||||
|
||||
assertThat(service.consume(event)).isEqualTo(101L);
|
||||
verify(firstleg).inbound("test-token", 21, 31);
|
||||
verify(firstleg).inbound("test-token", 21, 31, 1);
|
||||
verify(jdbc).update(startsWith("INSERT INTO fin_fee_source"), any(Object[].class));
|
||||
}
|
||||
|
||||
@@ -57,10 +57,10 @@ class FinanceFeeSourceEventServiceTest {
|
||||
void importsApprovedSettlementContainerFeeWithCustomerOwnership() {
|
||||
FinanceFeeSourceEvent event = containerEvent("container-1", "FIRSTLEG_FEE_PUBLISHED", 1, 7);
|
||||
givenNewEvent();
|
||||
when(firstleg.container("test-token", 41, 31)).thenReturn(ApiResponse.success(snapshot("CONTAINER_FEE", 7, 1, null, 41L)));
|
||||
when(firstleg.container("test-token", 41, 31, 1)).thenReturn(ApiResponse.success(snapshot("CONTAINER_FEE", 7, 1, null, 41L)));
|
||||
|
||||
assertThat(service.consume(event)).isEqualTo(101L);
|
||||
verify(firstleg).container("test-token", 41, 31);
|
||||
verify(firstleg).container("test-token", 41, 31, 1);
|
||||
verify(jdbc).update(contains("status='SUPERSEDED'"), eq(31L));
|
||||
}
|
||||
|
||||
@@ -69,12 +69,12 @@ class FinanceFeeSourceEventServiceTest {
|
||||
FinanceFeeSourceEvent event = containerEvent("container-payable-1", "FIRSTLEG_FEE_PUBLISHED", 1, 7);
|
||||
givenNewEvent();
|
||||
var snapshot = new FirstlegFeeSourceClient.Snapshot(7, "CONTAINER_FEE", 31, 1,
|
||||
null, null, null, 41L, 61L, "C-41", 7, "客户", 71L, "现有往来单位",
|
||||
"TRUCKING", 61L, "拖车费", "PAYABLE", LocalDate.of(2026, 8, 11),
|
||||
null, null, null, 41L, 61L, "C-41", 7, "客户", 71L, "现有供应商",
|
||||
"TRUCKING", 61L, "TRUCKING", "拖车费", "PAYABLE", LocalDate.of(2026, 8, 11),
|
||||
"CNY", new BigDecimal("300.00"), "APPROVED", "PUBLISHED",
|
||||
LocalDateTime.of(2026, 8, 11, 1, 0), null, null, null, null,
|
||||
"source-hash-payable", 1);
|
||||
when(firstleg.container("test-token", 41, 31)).thenReturn(ApiResponse.success(snapshot));
|
||||
when(firstleg.container("test-token", 41, 31, 1)).thenReturn(ApiResponse.success(snapshot));
|
||||
|
||||
assertThat(service.consume(event)).isEqualTo(101L);
|
||||
|
||||
@@ -82,14 +82,30 @@ class FinanceFeeSourceEventServiceTest {
|
||||
ArgumentCaptor<Object[]> values = ArgumentCaptor.forClass(Object[].class);
|
||||
verify(jdbc).update(startsWith("INSERT INTO fin_fee_source"), values.capture());
|
||||
assertThat(values.getValue()[14].toString())
|
||||
.contains("\"supplierId\":71", "\"supplierName\":\"现有往来单位\"", "\"supplierCategory\":\"TRUCKING\"");
|
||||
.contains("\"supplierId\":71", "\"supplierName\":\"现有供应商\"", "\"supplierCategory\":\"TRUCKING\"");
|
||||
}
|
||||
|
||||
@Test
|
||||
void importsPayableWithUnrestrictedActiveSupplier() {
|
||||
FinanceFeeSourceEvent event = containerEvent("container-unrestricted-1", "FIRSTLEG_FEE_PUBLISHED", 1, 7);
|
||||
givenNewEvent();
|
||||
var snapshot = new FirstlegFeeSourceClient.Snapshot(7, "CONTAINER_FEE", 31, 1,
|
||||
null, null, null, 41L, 61L, "C-41", 7, "客户", 71L, "现有供应商",
|
||||
null, 61L, "STORAGE", "仓储费", "PAYABLE", LocalDate.of(2026, 8, 11),
|
||||
"CNY", new BigDecimal("300.00"), "APPROVED", "PUBLISHED",
|
||||
LocalDateTime.of(2026, 8, 11, 1, 0), null, null, null, null,
|
||||
"source-hash-unrestricted", 1);
|
||||
when(firstleg.container("test-token", 41, 31, 1)).thenReturn(ApiResponse.success(snapshot));
|
||||
|
||||
assertThat(service.consume(event)).isEqualTo(101L);
|
||||
verify(supplierValidator).requireActive(71L, null);
|
||||
}
|
||||
|
||||
@Test
|
||||
void adjustmentCreatesNewImmutableVersionAndSupersedesAvailableVersion() {
|
||||
FinanceFeeSourceEvent event = inboundEvent("adjusted-2", "FIRSTLEG_FEE_ADJUSTED", 2, 7);
|
||||
givenNewEvent();
|
||||
when(firstleg.inbound(anyString(), eq(21L), eq(31L))).thenReturn(ApiResponse.success(snapshot("INBOUND_FEE", 7, 2, 21L, null)));
|
||||
when(firstleg.inbound(anyString(), eq(21L), eq(31L), eq(2))).thenReturn(ApiResponse.success(snapshot("INBOUND_FEE", 7, 2, 21L, null)));
|
||||
|
||||
assertThat(service.consume(event)).isEqualTo(101L);
|
||||
verify(jdbc).update(contains("status='SUPERSEDED'"), eq(31L));
|
||||
@@ -100,7 +116,7 @@ class FinanceFeeSourceEventServiceTest {
|
||||
void voidMarksExistingVersionWithoutDeletingHistory() {
|
||||
FinanceFeeSourceEvent event = inboundEvent("voided-2", "FIRSTLEG_FEE_VOIDED", 2, 7);
|
||||
when(jdbc.queryForList(startsWith("SELECT payload_hash,status"), eq("FIRSTLEG"), eq("voided-2"))).thenReturn(List.of());
|
||||
when(firstleg.inbound(anyString(), eq(21L), eq(31L))).thenReturn(ApiResponse.success(snapshot("INBOUND_FEE", 7, 2, 21L, null)));
|
||||
when(firstleg.inbound(anyString(), eq(21L), eq(31L), eq(2))).thenReturn(ApiResponse.success(snapshot("INBOUND_FEE", 7, 2, 21L, null)));
|
||||
when(jdbc.queryForList(startsWith("SELECT id,source_hash,status"), eq(31L), eq(2)))
|
||||
.thenReturn(List.of(Map.of("id", 88L, "source_hash", "source-hash", "status", "AVAILABLE")));
|
||||
|
||||
@@ -135,7 +151,7 @@ class FinanceFeeSourceEventServiceTest {
|
||||
void rejectsSnapshotBelongingToAnotherCustomer() {
|
||||
FinanceFeeSourceEvent event = inboundEvent("tenant-1", "FIRSTLEG_FEE_PUBLISHED", 1, 7);
|
||||
when(jdbc.queryForList(startsWith("SELECT payload_hash,status"), eq("FIRSTLEG"), eq("tenant-1"))).thenReturn(List.of());
|
||||
when(firstleg.inbound(anyString(), eq(21L), eq(31L))).thenReturn(ApiResponse.success(snapshot("INBOUND_FEE", 8, 1, 21L, null)));
|
||||
when(firstleg.inbound(anyString(), eq(21L), eq(31L), eq(1))).thenReturn(ApiResponse.success(snapshot("INBOUND_FEE", 8, 1, 21L, null)));
|
||||
|
||||
assertThatThrownBy(() -> service.consume(event))
|
||||
.isInstanceOf(FinanceEventException.class)
|
||||
@@ -147,7 +163,7 @@ class FinanceFeeSourceEventServiceTest {
|
||||
void rejectsApprovedButUnpublishedNonVoidedFee() {
|
||||
FinanceFeeSourceEvent event = inboundEvent("draft-1", "FIRSTLEG_FEE_PUBLISHED", 1, 7);
|
||||
when(jdbc.queryForList(startsWith("SELECT payload_hash,status"), eq("FIRSTLEG"), eq("draft-1"))).thenReturn(List.of());
|
||||
when(firstleg.inbound(anyString(), eq(21L), eq(31L))).thenReturn(
|
||||
when(firstleg.inbound(anyString(), eq(21L), eq(31L), eq(1))).thenReturn(
|
||||
ApiResponse.success(snapshot("INBOUND_FEE", 7, 1, 21L, null, "DRAFT", new BigDecimal("100.00"))));
|
||||
|
||||
assertThatThrownBy(() -> service.consume(event))
|
||||
@@ -209,7 +225,7 @@ class FinanceFeeSourceEventServiceTest {
|
||||
private void assertInvalidAmount(String eventId, BigDecimal amount) {
|
||||
FinanceFeeSourceEvent event = inboundEvent(eventId, "FIRSTLEG_FEE_PUBLISHED", 1, 7);
|
||||
when(jdbc.queryForList(startsWith("SELECT payload_hash,status"), eq("FIRSTLEG"), eq(eventId))).thenReturn(List.of());
|
||||
when(firstleg.inbound(anyString(), eq(21L), eq(31L))).thenReturn(
|
||||
when(firstleg.inbound(anyString(), eq(21L), eq(31L), eq(1))).thenReturn(
|
||||
ApiResponse.success(snapshot("INBOUND_FEE", 7, 1, 21L, null, "PUBLISHED", amount)));
|
||||
|
||||
assertThatThrownBy(() -> service.consume(event))
|
||||
|
||||
@@ -139,7 +139,7 @@ class FinancePhase1OperationBehaviorTest {
|
||||
when(rs.getString("currency_code")).thenReturn("CNY");
|
||||
when(rs.getString("review_status")).thenReturn("APPROVED");
|
||||
when(rs.getString("effective_status")).thenReturn("AVAILABLE");
|
||||
when(rs.getString("source_snapshot")).thenReturn("{\"customerName\":\"客户9\",\"partnerId\":79,\"partnerName\":\"供应商A\",\"inboundCode\":\"IN-9\",\"containerNo\":\"CONT-9\",\"businessDate\":\"2026-08-11\",\"chargeableQuantity\":\"10\"}");
|
||||
when(rs.getString("source_snapshot")).thenReturn("{\"customerName\":\"客户9\",\"supplierId\":79,\"supplierName\":\"供应商A\",\"inboundCode\":\"IN-9\",\"containerNo\":\"CONT-9\",\"businessDate\":\"2026-08-11\",\"chargeableQuantity\":\"10\"}");
|
||||
when(rs.getBigDecimal("amount")).thenReturn(new BigDecimal("120.00"));
|
||||
when(rs.getBoolean("statement_generated")).thenReturn(false);
|
||||
return List.of(mapper.mapRow(rs, 0));
|
||||
|
||||
@@ -318,8 +318,7 @@ class FinanceSettlementBehaviorTest {
|
||||
assertThat(result.summary().direction()).isEqualTo("PAYABLE");
|
||||
assertThat(result.summary().supplierId()).isEqualTo(20L);
|
||||
assertThat(result.summary().totalAmount()).isEqualByComparingTo("100.00");
|
||||
verify(supplierValidator).categoryFor("FBA_HEAD_FREIGHT", "头程运费");
|
||||
verify(supplierValidator).requireActive(20L, "BOOKING");
|
||||
verify(supplierValidator).requireActive(20L, null);
|
||||
verify(jdbc).update(startsWith("INSERT INTO fin_settlement_line"), eq(10L), eq(88L), eq(31L),
|
||||
eq(new BigDecimal("100.00")), eq("CNY"));
|
||||
}
|
||||
@@ -541,8 +540,8 @@ class FinanceSettlementBehaviorTest {
|
||||
|
||||
private static FinanceSettlementService service(JdbcTemplate jdbc, FinanceFileClient fileClient,
|
||||
FinanceSupplierValidator supplierValidator) {
|
||||
org.mockito.Mockito.lenient().when(jdbc.queryForList(startsWith("SELECT f.fee_item_code"), anyLong(), anyLong()))
|
||||
.thenReturn(List.of(Map.of("fee_item_code", "FBA_HEAD_FREIGHT", "fee_item_name", "头程运费")));
|
||||
org.mockito.Mockito.lenient().when(jdbc.queryForList(startsWith("SELECT JSON_UNQUOTE"), anyLong(), anyLong()))
|
||||
.thenReturn(List.of(new java.util.HashMap<>(Map.of("supplier_category", "BOOKING"))));
|
||||
FinanceDocumentNumberGenerator documentNumbers = org.mockito.Mockito.mock(FinanceDocumentNumberGenerator.class);
|
||||
org.mockito.Mockito.lenient().when(documentNumbers.next("AR")).thenReturn("AR-260818-0001");
|
||||
org.mockito.Mockito.lenient().when(documentNumbers.next("AP")).thenReturn("AP-260818-0001");
|
||||
@@ -552,7 +551,6 @@ class FinanceSettlementBehaviorTest {
|
||||
|
||||
private static FinanceSupplierValidator supplierValidator() {
|
||||
FinanceSupplierValidator supplierValidator = org.mockito.Mockito.mock(FinanceSupplierValidator.class);
|
||||
org.mockito.Mockito.lenient().when(supplierValidator.categoryFor(any(), any())).thenReturn("BOOKING");
|
||||
org.mockito.Mockito.lenient().when(supplierValidator.requireActive(anyLong(), any()))
|
||||
.thenReturn(new com.baiyue.finance.client.WarehouseSupplierClient.SupplierSnapshot(
|
||||
20L, "供应商20", "BOOKING", "ACTIVE"));
|
||||
|
||||
@@ -44,7 +44,7 @@ class FinanceSqlCommentContractTest {
|
||||
}
|
||||
}
|
||||
assertThat(tableCount).isEqualTo(17);
|
||||
assertThat(columnCount).isEqualTo(239);
|
||||
assertThat(columnCount).isEqualTo(243);
|
||||
assertThat(missing).as("缺少中文业务注释的Finance字段").isEmpty();
|
||||
}
|
||||
|
||||
|
||||
@@ -18,8 +18,12 @@ class FinanceSupplierValidatorTest {
|
||||
private final FinanceSupplierValidator validator = new FinanceSupplierValidator(client, "internal-token");
|
||||
|
||||
@Test
|
||||
void rejectsMissingOrInvalidExplicitFeeCategory() {
|
||||
assertCode(() -> validator.requireActive(20L, null), "FIN_409");
|
||||
void acceptsMissingCategoryAndRejectsInvalidExplicitCategory() {
|
||||
var unrestricted = new WarehouseSupplierClient.SupplierSnapshot(
|
||||
20L, "任意启用供应商", "BOOKING", "ACTIVE");
|
||||
when(client.get("internal-token", 20L, true, null)).thenReturn(ApiResponse.success(unrestricted));
|
||||
assertThat(validator.requireActive(20L, null).name()).isEqualTo("任意启用供应商");
|
||||
verify(client).get("internal-token", 20L, true, null);
|
||||
assertCode(() -> validator.requireActive(20L, "UNKNOWN"), "FIN_409");
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user