391 lines
22 KiB
Java
391 lines
22 KiB
Java
package com.baiyue.finance;
|
|
|
|
import com.baiyue.common.core.api.ApiResponse;
|
|
import com.baiyue.common.security.AuthenticatedUser;
|
|
import com.baiyue.finance.client.FirstlegFeeSourceClient;
|
|
import com.baiyue.finance.controller.FinancePhase1OperationController;
|
|
import com.baiyue.finance.dto.FinancePhase1Dtos;
|
|
import com.baiyue.finance.dto.FinancePhase1Dtos.FeeSourceDetail;
|
|
import com.baiyue.finance.dto.FinancePhase1Dtos.PageEnvelope;
|
|
import com.baiyue.finance.service.FinanceEventException;
|
|
import com.baiyue.finance.service.FinancePhase1OperationService;
|
|
import com.baiyue.finance.service.FinanceCustomerAccountService;
|
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
|
import org.junit.jupiter.api.Test;
|
|
import org.junit.jupiter.api.extension.ExtendWith;
|
|
import org.mockito.Mock;
|
|
import org.mockito.junit.jupiter.MockitoExtension;
|
|
import org.springframework.jdbc.core.JdbcTemplate;
|
|
import org.springframework.jdbc.core.RowMapper;
|
|
|
|
import java.math.BigDecimal;
|
|
import java.sql.ResultSet;
|
|
import java.sql.Timestamp;
|
|
import java.time.LocalDate;
|
|
import java.time.LocalDateTime;
|
|
import java.util.ArrayList;
|
|
import java.util.Arrays;
|
|
import java.util.List;
|
|
import java.util.Set;
|
|
import java.util.concurrent.atomic.AtomicInteger;
|
|
|
|
import static org.assertj.core.api.Assertions.assertThat;
|
|
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
|
import static org.mockito.ArgumentMatchers.any;
|
|
import static org.mockito.ArgumentMatchers.anyString;
|
|
import static org.mockito.ArgumentMatchers.eq;
|
|
import static org.mockito.ArgumentMatchers.startsWith;
|
|
import static org.mockito.Mockito.mock;
|
|
import static org.mockito.Mockito.lenient;
|
|
import static org.mockito.Mockito.never;
|
|
import static org.mockito.Mockito.verify;
|
|
import static org.mockito.Mockito.when;
|
|
|
|
@ExtendWith(MockitoExtension.class)
|
|
class FinancePhase1OperationBehaviorTest {
|
|
@Mock FinancePhase1OperationService operationService;
|
|
@Mock FinanceCustomerAccountService customerAccountService;
|
|
|
|
@Test
|
|
void controllerDelegatesFiveFrozenOperationsAndUsesAuthenticatedOperator() {
|
|
FinancePhase1OperationController controller = new FinancePhase1OperationController(operationService, customerAccountService);
|
|
AuthenticatedUser user = new AuthenticatedUser(71L, null, null, null, "finance", "ADMIN", "WEB", Set.of());
|
|
var review = new FinancePhase1Dtos.ReviewRequest("APPROVE", "核对无误", 0);
|
|
var action = new FinancePhase1Dtos.FeeSourceActionRequest("提交审核", 1);
|
|
|
|
controller.listDerivedCustomerAccounts(1, 20, "柏悦", "ACTIVE", 9L);
|
|
controller.listDerivedCustomerAccountLedger(9L, 2, 50, "RECEIPT", LocalDate.of(2026, 8, 1), LocalDate.of(2026, 8, 31));
|
|
controller.listFinanceFeeSources(1, 20, 9L, "RECEIVABLE", "AVAILABLE", "APPROVED",
|
|
false, LocalDate.of(2026, 8, 1), LocalDate.of(2026, 8, 31), "IN-9");
|
|
controller.getFinanceFeeSource(88L);
|
|
controller.reviewFinanceFeeSource(user, 88L, "review-key", review);
|
|
controller.submitFinanceFeeSource(user, 88L, "submit-key", action);
|
|
controller.voidFinanceFeeSource(user, 88L, "void-key", action);
|
|
|
|
verify(customerAccountService).list(1, 20, "柏悦", "ACTIVE", 9L);
|
|
verify(operationService).listDerivedCustomerAccountLedger(eq(9L), eq(2), eq(50), eq("RECEIPT"), any(), any());
|
|
verify(operationService).listFinanceFeeSources(eq(1), eq(20), eq(9L), eq("RECEIVABLE"),
|
|
eq("AVAILABLE"), eq("APPROVED"), eq(false), any(), any(), eq("IN-9"));
|
|
verify(operationService).getFinanceFeeSource(88L);
|
|
verify(operationService).reviewFinanceFeeSource(88L, 71L, "review-key", review);
|
|
verify(operationService).submitFinanceFeeSource(88L, 71L, "submit-key", action);
|
|
verify(operationService).voidFinanceFeeSource(88L, 71L, "finance", "void-key", action);
|
|
}
|
|
|
|
@Test
|
|
void pageEnvelopeAlwaysContainsTraceMetadata() {
|
|
PageEnvelope<String> response = PageEnvelope.success(List.of("row"), 1, 20, 1);
|
|
assertThat(response.code()).isEqualTo("200");
|
|
assertThat(response.requestId()).isNotBlank();
|
|
assertThat(response.traceId()).isNotBlank();
|
|
assertThat(response.page().total()).isEqualTo(1);
|
|
}
|
|
|
|
@Test
|
|
void ledgerRejectsInvalidCustomerBeforeAnyQuery() {
|
|
FinancePhase1OperationService service = new FinancePhase1OperationService(mock(JdbcTemplate.class), objectMapper());
|
|
assertThatThrownBy(() -> service.listDerivedCustomerAccountLedger(0, 1, 20, null, null, null))
|
|
.isInstanceOf(FinanceEventException.class)
|
|
.extracting(error -> ((FinanceEventException) error).code()).isEqualTo("FIN-REQ-400");
|
|
}
|
|
|
|
@Test
|
|
void accountListReturnsFixedPagedDto() {
|
|
AccountJdbc jdbc = new AccountJdbc();
|
|
FinancePhase1OperationService service = new FinancePhase1OperationService(jdbc, objectMapper());
|
|
|
|
PageEnvelope<FinancePhase1Dtos.AccountSummary> result =
|
|
service.listDerivedCustomerAccounts(1, 20, "客户9", "ACTIVE");
|
|
|
|
assertThat(result.data()).singleElement().satisfies(account -> {
|
|
assertThat(account.customerId()).isEqualTo(9L);
|
|
assertThat(account.customerName()).isEqualTo("客户9");
|
|
assertThat(account.outstandingReceivable()).isEqualByComparingTo("100.00");
|
|
});
|
|
assertThat(result.page().total()).isEqualTo(1);
|
|
assertThat(result.requestId()).isNotBlank();
|
|
assertThat(result.traceId()).isNotBlank();
|
|
assertThat(jdbc.accountListSql).contains("p.customer_name_snapshot");
|
|
assertThat(jdbc.accountListSql)
|
|
.contains("ar.direction='RECEIVABLE'", "cost_origin IN ('FIRSTLEG_DIRECT_PAID','BUSINESS_DIRECT_PAID')", "FROM fin_settlement_line sl")
|
|
.contains("sl.fee_source_id=f.id", "s.status<>'VOIDED'");
|
|
assertThat(jdbc.accountListSql).doesNotContain("CAST(c.customer_id AS CHAR)");
|
|
}
|
|
|
|
@Test
|
|
void ledgerQueriesEveryDerivedSourceWithinCustomerScope() {
|
|
AccountJdbc jdbc = new AccountJdbc();
|
|
FinancePhase1OperationService service = new FinancePhase1OperationService(jdbc, objectMapper());
|
|
|
|
PageEnvelope<FinancePhase1Dtos.LedgerEntry> result =
|
|
service.listDerivedCustomerAccountLedger(9L, 1, 20, null, null, null);
|
|
|
|
assertThat(result.data()).isEmpty();
|
|
assertThat(jdbc.ledgerCustomerIds).containsExactly(9L, 9L, 9L, 9L);
|
|
assertThat(jdbc.ledgerSql).anySatisfy(sql -> assertThat(sql)
|
|
.contains("cost_origin IN ('FIRSTLEG_DIRECT_PAID','BUSINESS_DIRECT_PAID')", "status='CONFIRMED'"));
|
|
assertThat(jdbc.ledgerSql).anySatisfy(sql -> assertThat(sql)
|
|
.contains("fin_settlement_payment", "transaction_type='PAYMENT'", "s.direction='PAYABLE'"));
|
|
}
|
|
|
|
@Test
|
|
void feeSourceListUsesFormalFieldsAndAllActiveFilters() throws Exception {
|
|
JdbcTemplate jdbc = mock(JdbcTemplate.class);
|
|
when(jdbc.queryForObject(startsWith("SELECT COUNT(*) FROM fin_fee_source"), eq(Long.class), any(Object[].class)))
|
|
.thenReturn(1L);
|
|
when(jdbc.query(startsWith("SELECT f.*"), any(RowMapper.class), any(Object[].class))).thenAnswer(invocation -> {
|
|
@SuppressWarnings("unchecked") RowMapper<Object> mapper = invocation.getArgument(1);
|
|
ResultSet rs = mock(ResultSet.class);
|
|
when(rs.getLong("id")).thenReturn(88L);
|
|
when(rs.getLong("source_fee_id")).thenReturn(9001L);
|
|
when(rs.getInt("source_fee_version")).thenReturn(3);
|
|
when(rs.getLong("customer_id")).thenReturn(9L);
|
|
when(rs.getLong("order_id")).thenReturn(19L);
|
|
when(rs.getLong("inbound_id")).thenReturn(29L);
|
|
when(rs.getLong("container_id")).thenReturn(39L);
|
|
when(rs.getString("source_system")).thenReturn("FIRSTLEG");
|
|
when(rs.getString("source_type")).thenReturn("INBOUND_FEE");
|
|
when(rs.getString("source_no")).thenReturn("IN-9");
|
|
when(rs.getString("direction")).thenReturn("RECEIVABLE");
|
|
when(rs.getString("fee_item_name")).thenReturn("入库操作费");
|
|
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\",\"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));
|
|
});
|
|
FinancePhase1OperationService service = new FinancePhase1OperationService(jdbc, objectMapper());
|
|
|
|
var result = service.listFinanceFeeSources(2, 50, 9L, "receivable", "available", "approved",
|
|
false, LocalDate.of(2026, 8, 1), LocalDate.of(2026, 8, 31), "IN-9");
|
|
|
|
assertThat(result.page()).satisfies(meta -> {
|
|
assertThat(meta.page()).isEqualTo(2);
|
|
assertThat(meta.pageSize()).isEqualTo(50);
|
|
assertThat(meta.total()).isEqualTo(1);
|
|
});
|
|
assertThat(result.data()).singleElement().satisfies(source -> {
|
|
assertThat(source.sourceSystem()).isEqualTo("FIRSTLEG");
|
|
assertThat(source.sourceBusinessId()).isEqualTo("IN-9");
|
|
assertThat(source.inboundCode()).isEqualTo("IN-9");
|
|
assertThat(source.containerNo()).isEqualTo("CONT-9");
|
|
assertThat(source.supplierId()).isEqualTo(79L);
|
|
assertThat(source.supplierName()).isEqualTo("供应商A");
|
|
assertThat(source.reviewStatus()).isEqualTo("APPROVED");
|
|
assertThat(source.businessDate()).isEqualTo(LocalDate.of(2026, 8, 11));
|
|
assertThat(source.statementGenerated()).isFalse();
|
|
});
|
|
verify(jdbc).query(startsWith("SELECT f.*"), any(RowMapper.class), any(Object[].class));
|
|
}
|
|
|
|
@Test
|
|
void ledgerReturnsStableBusinessTypeDocumentAndOperatorNameSnapshot() throws Exception {
|
|
JdbcTemplate jdbc = mock(JdbcTemplate.class);
|
|
when(jdbc.query(startsWith("SELECT id,bill_no"), any(RowMapper.class), eq(9L))).thenAnswer(invocation -> {
|
|
@SuppressWarnings("unchecked") RowMapper<Object> mapper = invocation.getArgument(1);
|
|
ResultSet rs = mock(ResultSet.class);
|
|
when(rs.getLong("id")).thenReturn(81L);
|
|
when(rs.getLong("created_by")).thenReturn(71L);
|
|
when(rs.getString("bill_no")).thenReturn("REC-81");
|
|
when(rs.getString("created_by_name")).thenReturn("platform_admin");
|
|
when(rs.getString("remark")).thenReturn("八月账单");
|
|
when(rs.getBigDecimal("total_amount")).thenReturn(new BigDecimal("5200.00"));
|
|
when(rs.getTimestamp("created_at")).thenReturn(Timestamp.valueOf("2026-08-17 13:00:00"));
|
|
return List.of(mapper.mapRow(rs, 0));
|
|
});
|
|
when(jdbc.query(startsWith("SELECT id,receipt_no"), any(RowMapper.class), eq(9L))).thenReturn(List.of());
|
|
when(jdbc.query(startsWith("SELECT id,cost_no"), any(RowMapper.class), eq(9L))).thenReturn(List.of());
|
|
FinancePhase1OperationService service = new FinancePhase1OperationService(jdbc, objectMapper());
|
|
|
|
PageEnvelope<FinancePhase1Dtos.LedgerEntry> result =
|
|
service.listDerivedCustomerAccountLedger(9L, 1, 20, null, null, null);
|
|
|
|
assertThat(result.data()).singleElement().satisfies(entry -> {
|
|
assertThat(entry.businessType()).isEqualTo("SETTLEMENT_ISSUED");
|
|
assertThat(entry.documentType()).isEqualTo("BILL");
|
|
assertThat(entry.documentNo()).isEqualTo("REC-81");
|
|
assertThat(entry.occurredAt()).isEqualTo(LocalDateTime.of(2026, 8, 17, 13, 0));
|
|
assertThat(entry.operatorName()).isEqualTo("platform_admin");
|
|
});
|
|
}
|
|
|
|
@Test
|
|
void approvedFeeCannotBeEditedAsDraft() throws Exception {
|
|
JdbcTemplate jdbc = feeSourceJdbc("REJECTED", false, 2);
|
|
FinancePhase1OperationService service = new FinancePhase1OperationService(jdbc, objectMapper());
|
|
|
|
assertThat(service.getFinanceFeeSource(88L).reviewStatus()).isEqualTo("REJECTED");
|
|
}
|
|
|
|
@Test
|
|
void feeSourceDetailUsesFixedDtoAndRealCustomerScope() throws Exception {
|
|
FinancePhase1OperationService service = new FinancePhase1OperationService(
|
|
feeSourceJdbc("APPROVED", true, 2), objectMapper());
|
|
|
|
FeeSourceDetail detail = service.getFinanceFeeSource(88L);
|
|
|
|
assertThat(detail.feeSourceId()).isEqualTo(88L);
|
|
assertThat(detail.customerId()).isEqualTo(9L);
|
|
assertThat(detail.currency()).isEqualTo("CNY");
|
|
assertThat(detail.reviewStatus()).isEqualTo("APPROVED");
|
|
}
|
|
|
|
@Test
|
|
void firstlegFeeEditAndAdjustAreBlockedInsteadOfMutatingFinanceCopy() throws Exception {
|
|
JdbcTemplate jdbc = feeSourceJdbc("REJECTED", false, 1);
|
|
FinancePhase1OperationService service = new FinancePhase1OperationService(jdbc, objectMapper());
|
|
|
|
var request = new FinancePhase1Dtos.FeeSourceEditRequest(
|
|
new BigDecimal("120.00"), "更正金额", 1);
|
|
assertThatThrownBy(() -> service.editFinanceFeeSource(88L, 71L, "edit-key", request, false))
|
|
.isInstanceOf(FinanceEventException.class).hasMessageContaining("业务费用必须回到对应业务费用明细调整");
|
|
assertThatThrownBy(() -> service.editFinanceFeeSource(88L, 71L, "adjust-key", request, true))
|
|
.isInstanceOf(FinanceEventException.class).hasMessageContaining("业务费用必须回到对应业务费用明细调整");
|
|
verify(jdbc, never()).update(startsWith("UPDATE fin_fee_source SET amount="),
|
|
(Object[]) any());
|
|
}
|
|
|
|
@Test
|
|
void voidingNyexx2608180003DelegatesToFirstlegAndWaitsForEvent() throws Exception {
|
|
JdbcTemplate jdbc = feeSourceJdbc("APPROVED", false, 2);
|
|
when(jdbc.queryForList(startsWith("SELECT request_hash"), eq(9L), eq(71L),
|
|
eq("FEE_SOURCE_VOID"), eq("void-key"))).thenReturn(List.of());
|
|
FirstlegFeeSourceClient firstleg = mock(FirstlegFeeSourceClient.class);
|
|
when(firstleg.voidSource(eq("internal-token"), eq("void-key"), anyString(), any()))
|
|
.thenReturn(ApiResponse.success(new FirstlegFeeSourceClient.CommandResult(
|
|
"INBOUND_FEE", 700L, 3, "VOIDED", false)));
|
|
FinancePhase1OperationService service = new FinancePhase1OperationService(
|
|
jdbc, objectMapper(), firstleg, "internal-token");
|
|
|
|
FeeSourceDetail result = service.voidFinanceFeeSource(88L, 71L, "finance",
|
|
"void-key", new FinancePhase1Dtos.FeeSourceActionRequest("测试作废", 2));
|
|
|
|
assertThat(result.sourceStatus()).isEqualTo("AVAILABLE");
|
|
var command = org.mockito.ArgumentCaptor.forClass(FirstlegFeeSourceClient.VoidCommand.class);
|
|
verify(firstleg).voidSource(eq("internal-token"), eq("void-key"), anyString(), command.capture());
|
|
assertThat(command.getValue()).satisfies(value -> {
|
|
assertThat(value.sourceType()).isEqualTo("INBOUND_FEE");
|
|
assertThat(value.sourceFeeId()).isEqualTo(700L);
|
|
assertThat(value.sourceVersion()).isEqualTo(3);
|
|
assertThat(value.customerId()).isEqualTo(9L);
|
|
assertThat(value.inboundId()).isEqualTo(100L);
|
|
assertThat(value.operatorName()).isEqualTo("finance");
|
|
assertThat(value.reason()).isEqualTo("测试作废");
|
|
});
|
|
verify(jdbc, never()).update(startsWith("UPDATE fin_fee_source SET status='VOIDED'"),
|
|
(Object[]) any());
|
|
}
|
|
|
|
@Test
|
|
void reviewUsesExpectedVersionAndReturnsUpdatedDetail() throws Exception {
|
|
JdbcTemplate jdbc = mock(JdbcTemplate.class);
|
|
AtomicInteger reads = new AtomicInteger();
|
|
when(jdbc.query(startsWith("SELECT * FROM fin_fee_source"), any(RowMapper.class), (Object[]) any())).thenAnswer(invocation -> {
|
|
@SuppressWarnings("unchecked") RowMapper<FeeSourceDetail> mapper = invocation.getArgument(1);
|
|
String review = reads.getAndIncrement() == 0 ? "PENDING" : "APPROVED";
|
|
int version = "PENDING".equals(review) ? 0 : 1;
|
|
return List.of(mapper.mapRow(resultSet(review, false, version), 0));
|
|
});
|
|
when(jdbc.queryForObject(startsWith("SELECT COUNT(*)>0"), eq(Boolean.class), eq(88L), eq(3))).thenReturn(false);
|
|
when(jdbc.query(startsWith("SELECT created_at,action"), any(RowMapper.class), eq(9L), eq(88L))).thenReturn(List.of());
|
|
when(jdbc.queryForList(startsWith("SELECT request_hash"), eq(9L), eq(71L),
|
|
eq("FEE_SOURCE_REVIEW"), eq("review-key"))).thenReturn(List.of());
|
|
when(jdbc.update(startsWith("INSERT INTO fin_idempotency_record"), eq(9L), eq(71L),
|
|
eq("FEE_SOURCE_REVIEW"), eq("review-key"), anyString())).thenReturn(1);
|
|
when(jdbc.update(startsWith("UPDATE fin_fee_source SET review_status="),
|
|
eq("APPROVED"), eq("核对无误"), eq(88L), eq(0))).thenReturn(1);
|
|
when(jdbc.update(startsWith("INSERT INTO fin_audit_log"), eq(9L), eq("FIN_FEE_SOURCE"),
|
|
eq(88L), eq("FEE_SOURCE_REVIEW_APPROVE"), eq("核对无误"), anyString(), anyString(),
|
|
eq(71L), eq("操作人 71"), any(), any())).thenReturn(1);
|
|
when(jdbc.update(startsWith("UPDATE fin_idempotency_record SET status='SUCCEEDED'"),
|
|
eq(88L), eq(9L), eq(71L), eq("FEE_SOURCE_REVIEW"), eq("review-key"))).thenReturn(1);
|
|
FinancePhase1OperationService service = new FinancePhase1OperationService(jdbc, objectMapper());
|
|
|
|
FeeSourceDetail result = service.reviewFinanceFeeSource(88L, 71L, "review-key",
|
|
new FinancePhase1Dtos.ReviewRequest("APPROVE", "核对无误", 0));
|
|
|
|
assertThat(result.reviewStatus()).isEqualTo("APPROVED");
|
|
assertThat(result.operationVersion()).isEqualTo(1);
|
|
verify(jdbc).update(startsWith("UPDATE fin_fee_source SET review_status="), eq("APPROVED"), eq("核对无误"), eq(88L), eq(0));
|
|
}
|
|
|
|
private static JdbcTemplate feeSourceJdbc(String reviewStatus, boolean included, int version) throws Exception {
|
|
JdbcTemplate jdbc = mock(JdbcTemplate.class);
|
|
when(jdbc.query(startsWith("SELECT * FROM fin_fee_source"), any(RowMapper.class), (Object[]) any())).thenAnswer(invocation -> {
|
|
@SuppressWarnings("unchecked") RowMapper<FeeSourceDetail> mapper = invocation.getArgument(1);
|
|
return List.of(mapper.mapRow(resultSet(reviewStatus, included, version), 0));
|
|
});
|
|
when(jdbc.queryForObject(startsWith("SELECT COUNT(*)>0"), eq(Boolean.class), eq(88L), eq(3))).thenReturn(false);
|
|
when(jdbc.query(startsWith("SELECT created_at,action"), any(RowMapper.class), eq(9L), eq(88L))).thenReturn(List.of());
|
|
lenient().when(jdbc.queryForList(startsWith("SELECT request_hash"), eq(9L), eq(71L),
|
|
eq("FEE_SOURCE_SETTLEMENT"), eq("include-key"))).thenReturn(List.of());
|
|
return jdbc;
|
|
}
|
|
|
|
private static ResultSet resultSet(String reviewStatus, boolean included, int version) throws Exception {
|
|
ResultSet rs = mock(ResultSet.class);
|
|
when(rs.getLong("id")).thenReturn(88L);
|
|
when(rs.getLong("source_fee_id")).thenReturn(700L);
|
|
when(rs.getLong("customer_id")).thenReturn(9L);
|
|
when(rs.getLong("order_id")).thenReturn(90L);
|
|
when(rs.getLong("inbound_id")).thenReturn(100L);
|
|
when(rs.getLong("container_id")).thenReturn(200L);
|
|
when(rs.wasNull()).thenReturn(false, false, true, false, false, true);
|
|
when(rs.getInt("source_fee_version")).thenReturn(3);
|
|
when(rs.getString("source_system")).thenReturn("FIRSTLEG");
|
|
when(rs.getString("source_no")).thenReturn("IN-100");
|
|
when(rs.getString("source_type")).thenReturn("INBOUND_FEE");
|
|
when(rs.getString("direction")).thenReturn("RECEIVABLE");
|
|
when(rs.getString("fee_item_name")).thenReturn("头程运费");
|
|
when(rs.getString("currency_code")).thenReturn("CNY");
|
|
when(rs.getString("status")).thenReturn("AVAILABLE");
|
|
when(rs.getString("source_hash")).thenReturn("a".repeat(64));
|
|
when(rs.getString("review_status")).thenReturn(reviewStatus);
|
|
when(rs.getString("review_reason")).thenReturn(null);
|
|
when(rs.getInt("operation_version")).thenReturn(version);
|
|
when(rs.getBigDecimal("amount")).thenReturn(new BigDecimal("100.00"));
|
|
when(rs.getString("source_snapshot")).thenReturn("{\"customerName\":\"客户9\",\"inboundCode\":\"NYEXX2608180003\",\"businessDate\":\"2026-08-11\",\"chargeableQuantity\":\"10\",\"reviewStatus\":\"" + reviewStatus + "\",\"publicationStatus\":\"PUBLISHED\",\"operationVersion\":" + version + "}");
|
|
return rs;
|
|
}
|
|
|
|
private static ObjectMapper objectMapper() {
|
|
return new ObjectMapper().findAndRegisterModules();
|
|
}
|
|
|
|
private static final class AccountJdbc extends JdbcTemplate {
|
|
private final List<Long> ledgerCustomerIds = new ArrayList<>();
|
|
private final List<String> ledgerSql = new ArrayList<>();
|
|
private String accountListSql = "";
|
|
|
|
@Override
|
|
public <T> T queryForObject(String sql, Class<T> requiredType, Object... args) {
|
|
if (sql.startsWith("SELECT COUNT(*)")) return requiredType.cast(1L);
|
|
return null;
|
|
}
|
|
|
|
@Override
|
|
@SuppressWarnings("unchecked")
|
|
public <T> List<T> query(String sql, RowMapper<T> rowMapper, Object... args) {
|
|
if (sql.startsWith("SELECT c.customer_id")) {
|
|
accountListSql = sql;
|
|
return (List<T>) List.of(new FinancePhase1Dtos.AccountSummary(
|
|
9L, "9", "客户9", null, null, new BigDecimal("100.00"),
|
|
new BigDecimal("20.00"), new BigDecimal("30.00"), BigDecimal.ZERO,
|
|
BigDecimal.ZERO, BigDecimal.ZERO,
|
|
BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.ZERO,
|
|
BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.ZERO, null, false, 0, 0,
|
|
"ACTIVE", LocalDateTime.of(2026, 8, 11, 10, 0)));
|
|
}
|
|
if (sql.startsWith("SELECT id,bill_no") || sql.startsWith("SELECT id,receipt_no")
|
|
|| sql.startsWith("SELECT id,cost_no") || sql.startsWith("SELECT p.id")) {
|
|
ledgerCustomerIds.add(((Number) Arrays.asList(args).get(0)).longValue());
|
|
ledgerSql.add(sql);
|
|
return List.of();
|
|
}
|
|
return List.of();
|
|
}
|
|
}
|
|
}
|