This commit is contained in:
2026-08-14 16:06:27 +08:00
parent 87eb1aa72f
commit 87e919f3c4
54 changed files with 984 additions and 175 deletions
@@ -24,6 +24,9 @@ class FinanceContractTest {
assertTrue(service.contains("status='PROCESSING'") && service.contains("stableNo"));
assertTrue(service.contains("request_hash") && service.contains("result_resource_id") && service.contains("Idempotency-Key已用于其他请求"));
assertTrue(service.contains("status IN ('ISSUED','PARTIALLY_PAID','PAID')"));
assertTrue(service.contains("validateBillSources(tenantId, request.lines())"));
assertTrue(service.contains("账单金额必须等于费用来源金额"));
assertTrue(service.contains("source_fee_version") && service.contains("settlement_included"));
String controller = Files.readString(Path.of("src/main/java/com/baiyue/finance/controller/PlatformFinanceController.java"));
assertTrue(controller.contains("/vouchers") && controller.contains("MultipartFile"));
assertTrue(controller.contains("costSnapshotClient.loadingPlan") && controller.contains("createCost(request.customerId(), user.userId(), internal, volumes, key)"));
@@ -9,10 +9,13 @@ import com.baiyue.common.core.exception.BizException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.Test;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.test.util.ReflectionTestUtils;
import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.ArgumentMatchers.any;
@@ -21,6 +24,45 @@ import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.*;
class FinanceServiceValidationTest {
@Test
void acceptsOnlyApprovedIncludedReceivableSourceAtItsRecordedAmount() {
JdbcTemplate jdbc = mock(JdbcTemplate.class);
when(jdbc.queryForList(startsWith("SELECT customer_id,source_fee_version"), eq(81L)))
.thenReturn(List.of(source(9L, 3, "AVAILABLE", "APPROVED", true, "125.50")));
when(jdbc.queryForObject(startsWith("SELECT COUNT(*) FROM fin_bill_line"), eq(Integer.class),
eq(9L), eq(81L), eq(3))).thenReturn(0);
FinanceService service = service(jdbc);
assertDoesNotThrow(() -> ReflectionTestUtils.invokeMethod(service, "validateBillSources", 9L,
List.of(billLine(81L, 3, "125.50"))));
}
@Test
void rejectsClientAmountThatDiffersFromFinanceSourceSnapshot() {
JdbcTemplate jdbc = mock(JdbcTemplate.class);
when(jdbc.queryForList(startsWith("SELECT customer_id,source_fee_version"), eq(81L)))
.thenReturn(List.of(source(9L, 3, "AVAILABLE", "APPROVED", true, "125.50")));
FinanceService service = service(jdbc);
BizException error = assertThrows(BizException.class, () -> ReflectionTestUtils.invokeMethod(service,
"validateBillSources", 9L, List.of(billLine(81L, 3, "99.00"))));
assertEquals("账单金额必须等于费用来源金额", error.getMessage());
verify(jdbc, never()).queryForObject(startsWith("SELECT COUNT(*) FROM fin_bill_line"),
eq(Integer.class), any(), any(), any());
}
@Test
void rejectsSourceThatIsNotApprovedAndIncludedForSettlement() {
JdbcTemplate jdbc = mock(JdbcTemplate.class);
when(jdbc.queryForList(startsWith("SELECT customer_id,source_fee_version"), eq(81L)))
.thenReturn(List.of(source(9L, 3, "AVAILABLE", "PENDING", false, "125.50")));
FinanceService service = service(jdbc);
assertThrows(BizException.class, () -> ReflectionTestUtils.invokeMethod(service,
"validateBillSources", 9L, List.of(billLine(81L, 3, "125.50"))));
}
@Test
void containerCostAllocatesByVolumeAndPutsRoundingOnLastOrder() {
var rows = List.of(
@@ -240,4 +282,16 @@ class FinanceServiceValidationTest {
return new FinanceService(jdbc, new ObjectMapper().findAndRegisterModules(),
mock(FinanceVoucherValidator.class));
}
private static FinanceService.BillLine billLine(long sourceId, int version, String amount) {
return new FinanceService.BillLine("FIRSTLEG_FEE", sourceId, version, null, 31L, 41L,
"FREIGHT", "运费", new BigDecimal(amount));
}
private static Map<String, Object> source(long customerId, int version, String status,
String reviewStatus, boolean included, String amount) {
return Map.of("customer_id", customerId, "source_fee_version", version,
"direction", "RECEIVABLE", "currency_code", "CNY", "amount", new BigDecimal(amount),
"status", status, "review_status", reviewStatus, "settlement_included", included);
}
}