优化
This commit is contained in:
@@ -0,0 +1,50 @@
|
||||
package com.baiyue.finance;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.yaml.snakeyaml.Yaml;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
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");
|
||||
|
||||
@Test
|
||||
void keepsOpenApiAndAllFileDefinitionsOnTheSameEightTypes() 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);
|
||||
String cn = Files.readString(resolve("baiyue-firstleg", "config", "nacos", "cn", "file-service.yml"), StandardCharsets.UTF_8);
|
||||
|
||||
Yaml yaml = new Yaml();
|
||||
assertThat((Object) yaml.load(openApi)).isNotNull();
|
||||
assertThat((Object) yaml.load(application)).isNotNull();
|
||||
assertThat((Object) yaml.load(local)).isNotNull();
|
||||
assertThat((Object) yaml.load(cn)).isNotNull();
|
||||
|
||||
assertThat(openApi).contains("/internal/exports/v1/{exportType}/batches:")
|
||||
.contains("customerId?, status?, settlementNo?")
|
||||
.contains("所有 DETAIL 仅 settlementId")
|
||||
.doesNotContain("DETAIL: settlementId, direction");
|
||||
for (String type : TYPES) {
|
||||
assertThat(openApi).contains("- " + type);
|
||||
assertThat(application).contains(type + ":").contains("provider-path: /internal/exports/v1/" + type + "/batches");
|
||||
assertThat(local).contains(type + ":").contains("provider-path: /internal/exports/v1/" + type + "/batches");
|
||||
assertThat(cn).contains(type + ":").contains("provider-path: /internal/exports/v1/" + type + "/batches");
|
||||
}
|
||||
}
|
||||
|
||||
private static Path resolve(String... segments) {
|
||||
Path repository = Path.of("").toAbsolutePath().normalize();
|
||||
while (repository != null && !Files.exists(repository.resolve("apps").resolve("admin-web"))) repository = repository.getParent();
|
||||
if (repository == null) throw new IllegalStateException("repository root not found");
|
||||
return repository.resolve(Path.of(segments[0], java.util.Arrays.copyOfRange(segments, 1, segments.length)));
|
||||
}
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
package com.baiyue.finance.controller;
|
||||
|
||||
import com.baiyue.common.core.exception.BizException;
|
||||
import com.baiyue.common.core.export.ExportContracts.ExportBatchRequest;
|
||||
import com.baiyue.common.core.export.ExportContracts.ExportBatchResponse;
|
||||
import com.baiyue.finance.service.FinanceExportProviderService;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
class FinanceExportProviderControllerTest {
|
||||
@Test
|
||||
void exposesOnlyTheInternalVersionedProviderAndRequiresTheServiceToken() {
|
||||
FinanceExportProviderService service = mock(FinanceExportProviderService.class);
|
||||
String token = "12345678901234567890123456789012";
|
||||
FinanceExportProviderController controller = new FinanceExportProviderController(service, token);
|
||||
controller.initializeToken();
|
||||
ExportBatchRequest request = new ExportBatchRequest("9", "0", "PLATFORM", "7", 1, Map.of(), null, null, 100);
|
||||
ExportBatchResponse response = new ExportBatchResponse(1, "sha256:test", "snapshot", List.of(), List.of(), "0", false, 0L);
|
||||
when(service.exportBatch(FinanceExportProviderService.CUSTOMER_ACCOUNT_LIST, request)).thenReturn(response);
|
||||
|
||||
assertThat(FinanceExportProviderController.class.getAnnotation(RequestMapping.class).value())
|
||||
.containsExactly("/internal/exports/v1");
|
||||
assertThat(controller.batch(token, FinanceExportProviderService.CUSTOMER_ACCOUNT_LIST, request).data()).isSameAs(response);
|
||||
verify(service).exportBatch(FinanceExportProviderService.CUSTOMER_ACCOUNT_LIST, request);
|
||||
assertThatThrownBy(() -> controller.batch("wrong", FinanceExportProviderService.CUSTOMER_ACCOUNT_LIST, request))
|
||||
.isInstanceOf(BizException.class);
|
||||
}
|
||||
}
|
||||
+93
@@ -0,0 +1,93 @@
|
||||
package com.baiyue.finance.service;
|
||||
|
||||
import com.baiyue.common.core.exception.BizException;
|
||||
import com.baiyue.common.core.export.ExportContracts.ExportBatchRequest;
|
||||
import com.baiyue.finance.dto.FinancePhase1Dtos.FeeSourceDetail;
|
||||
import com.baiyue.finance.dto.FinanceReadModels.Statement;
|
||||
import com.baiyue.finance.dto.ReconciliationStatementDtos.PaymentHistory;
|
||||
import com.baiyue.finance.dto.ReconciliationStatementDtos.ReconciliationDetail;
|
||||
import com.baiyue.finance.dto.ReconciliationStatementDtos.ReconciliationLine;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class FinanceExportProviderServiceTest {
|
||||
@Mock FinanceCustomerAccountService accountService;
|
||||
@Mock FinancePhase1OperationService operationService;
|
||||
@Mock FinanceQueryService queryService;
|
||||
@Mock ReconciliationStatementService reconciliationService;
|
||||
@Mock FinanceSettlementService settlementService;
|
||||
private FinanceExportProviderService service;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
service = new FinanceExportProviderService(accountService, operationService, queryService,
|
||||
reconciliationService, settlementService, new ObjectMapper(), "12345678901234567890123456789012");
|
||||
service.initializeSigningKey();
|
||||
}
|
||||
|
||||
@Test
|
||||
void exportsStatementRowsUsingBusinessContainerNumberAndStableSnapshot() {
|
||||
Statement summary = new Statement(501L, 10001L, "REC-501", "客户A", LocalDate.parse("2026-08-31"),
|
||||
null, new BigDecimal("300"), new BigDecimal("100"), new BigDecimal("200"), "CNY", "ISSUED", 3,
|
||||
7L, "创建人A", LocalDateTime.parse("2026-08-01T09:00:00"), 8L, "更新人B", LocalDateTime.parse("2026-08-20T11:00:00"));
|
||||
ReconciliationLine line = new ReconciliationLine(601L, 81L, 2, "hash", 21L, 31L, "运费",
|
||||
new BigDecimal("320"), new BigDecimal("300"), "CNY", "优惠调整");
|
||||
ReconciliationDetail detail = new ReconciliationDetail(501L, "REC-501", 10001L, "客户A",
|
||||
LocalDate.parse("2026-08-01"), LocalDate.parse("2026-08-31"), 30, "CNY", new BigDecimal("300"),
|
||||
new BigDecimal("100"), new BigDecimal("200"), false, "ISSUED", 3, 7L, "创建人A",
|
||||
LocalDateTime.parse("2026-08-01T09:00:00"), 8L, "更新人B", LocalDateTime.parse("2026-08-20T11:00:00"),
|
||||
"八月账单", List.of(line), List.of(new PaymentHistory(701L, "RECEIPT", LocalDate.parse("2026-08-20"),
|
||||
new BigDecimal("100"), "BANK_TRANSFER", "PAY-701", 9L, "财务员", LocalDateTime.parse("2026-08-20T10:00:00"), "")), List.of());
|
||||
FeeSourceDetail source = new FeeSourceDetail(81L, "CONTAINER_FEE", 9001L, 2, "RECEIVABLE", 10001L,
|
||||
"客户A", null, null, 21L, "IN-21", 31L, "CONT-31", LocalDate.parse("2026-08-15"), "运费",
|
||||
BigDecimal.TEN, new BigDecimal("30"), new BigDecimal("300"), "CNY", "APPROVED", true,
|
||||
"AVAILABLE", true, null, null, "hash", 2, List.of());
|
||||
when(queryService.statements(10001L, false)).thenReturn(List.of(summary));
|
||||
when(reconciliationService.detailForPlatform(501L)).thenReturn(detail);
|
||||
when(operationService.getFinanceFeeSource(81L)).thenReturn(source);
|
||||
|
||||
var first = service.exportBatch(FinanceExportProviderService.RECONCILIATION_STATEMENT_LIST,
|
||||
request(Map.of("customerId", "10001", "containerNo", "CONT-31"), null, null));
|
||||
var continued = service.exportBatch(FinanceExportProviderService.RECONCILIATION_STATEMENT_LIST,
|
||||
request(Map.of("customerId", "10001", "containerNo", "CONT-31"), first.nextCursor(), first.snapshotToken()));
|
||||
|
||||
assertThat(first.columns()).isNotEmpty();
|
||||
assertThat(first.rows()).hasSize(1);
|
||||
assertThat(first.rows().get(0)).containsEntry("statementNo", "REC-501").containsEntry("customerName", "客户A");
|
||||
assertThat(first.totalRows()).isEqualTo(1L);
|
||||
assertThat(continued.columns()).isEmpty();
|
||||
assertThat(continued.rows()).isEmpty();
|
||||
assertThat(continued.snapshotToken()).isEqualTo(first.snapshotToken());
|
||||
}
|
||||
|
||||
@Test
|
||||
void rejectsUnknownParametersAndSnapshotReuseAcrossFilters() {
|
||||
assertThatThrownBy(() -> service.exportBatch(FinanceExportProviderService.CUSTOMER_ACCOUNT_LIST,
|
||||
request(Map.of("page", 1), null, null))).isInstanceOf(BizException.class);
|
||||
|
||||
var first = service.exportBatch(FinanceExportProviderService.RECONCILIATION_STATEMENT_LIST,
|
||||
request(Map.of("status", "ISSUED"), null, null));
|
||||
assertThatThrownBy(() -> service.exportBatch(FinanceExportProviderService.RECONCILIATION_STATEMENT_LIST,
|
||||
request(Map.of("status", "VOIDED"), first.nextCursor(), first.snapshotToken())))
|
||||
.isInstanceOf(BizException.class).hasMessageContaining("snapshotToken");
|
||||
}
|
||||
|
||||
private ExportBatchRequest request(Map<String, Object> parameters, String cursor, String snapshot) {
|
||||
return new ExportBatchRequest("9001", "0", "PLATFORM", "7", 1, parameters, cursor, snapshot, 100);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user