feat(fleet): enforce reviewed trips and original fee coverage for dispatch

This commit is contained in:
2026-10-03 04:18:52 +08:00
parent c50e9f97d1
commit 5e683da3b9
162 changed files with 9642 additions and 218 deletions
@@ -0,0 +1,32 @@
package com.baiyue.finance.controller;
import com.baiyue.finance.dto.DeliveryFeeCoverageModels;
import com.baiyue.finance.service.DeliveryFeeCoverageQueryService;
import com.baiyue.finance.service.FinanceEventException;
import jakarta.validation.Validation;
import org.junit.jupiter.api.Test;
import org.springframework.test.util.ReflectionTestUtils;
import java.util.List;
import static org.assertj.core.api.Assertions.*;
import static org.mockito.Mockito.*;
class InternalDeliveryFeeCoverageControllerTest {
@Test void requiresTheInternalIdentityBeforeQueryingFinancialData() {
var service = mock(DeliveryFeeCoverageQueryService.class);
var controller = new InternalDeliveryFeeCoverageController(service);
ReflectionTestUtils.setField(controller, "expectedToken", "coverage-test-token");
var query = new DeliveryFeeCoverageModels.Query(101L, List.of(11L));
assertThatThrownBy(() -> controller.sources(null, query)).isInstanceOf(FinanceEventException.class);
assertThatThrownBy(() -> controller.sources("wrong-token", query)).isInstanceOf(FinanceEventException.class);
verifyNoInteractions(service);
when(service.query(query)).thenReturn(List.of());
assertThat(controller.sources("coverage-test-token", query).successful()).isTrue();
verify(service).query(query);
}
@Test void validatesCustomerAndInboundScope() {
try (var factory = Validation.buildDefaultValidatorFactory()) {
assertThat(factory.getValidator().validate(new DeliveryFeeCoverageModels.Query(0L, List.of()))).hasSize(2);
assertThat(factory.getValidator().validate(new DeliveryFeeCoverageModels.Query(101L, List.of(-1L)))).hasSize(1);
}
}
}
@@ -0,0 +1,50 @@
package com.baiyue.finance.service;
import com.baiyue.finance.dto.DeliveryFeeCoverageModels;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import java.util.List;
import java.util.UUID;
import static org.assertj.core.api.Assertions.*;
class DeliveryFeeCoverageQueryServiceTest {
JdbcTemplate jdbc;
DeliveryFeeCoverageQueryService service;
@BeforeEach void setup() {
jdbc = new JdbcTemplate(new DriverManagerDataSource("jdbc:h2:mem:" + UUID.randomUUID() + ";MODE=MySQL;DB_CLOSE_DELAY=-1", "sa", ""));
jdbc.execute("CREATE TABLE fin_fee_source(id BIGINT PRIMARY KEY,source_system VARCHAR(32),source_fee_id BIGINT,source_type VARCHAR(32),source_fee_version INT,customer_id BIGINT,inbound_id BIGINT,source_no VARCHAR(64),direction VARCHAR(16),review_status VARCHAR(16),status VARCHAR(16),fee_item_code VARCHAR(64),fee_item_name VARCHAR(128),currency_code VARCHAR(3),amount DECIMAL(20,6),source_hash VARCHAR(71),inbound_code VARCHAR(64))");
service = new DeliveryFeeCoverageQueryService(jdbc);
}
@Test void returnsOnlyThisCustomersActualInboundLatestApprovedReceivables() {
insert(1, 701, 1, 101, 11, "FIRSTLEG", "RECEIVABLE", "APPROVED", "AVAILABLE");
insert(2, 701, 2, 101, 11, "FIRSTLEG", "RECEIVABLE", "APPROVED", "AVAILABLE");
insert(3, 702, 1, 202, 11, "FIRSTLEG", "RECEIVABLE", "APPROVED", "AVAILABLE");
insert(4, 703, 1, 101, 11, "FIRSTLEG", "PAYABLE", "APPROVED", "AVAILABLE");
insert(5, 704, 1, 101, 11, "LASTLEG", "RECEIVABLE", "APPROVED", "AVAILABLE");
insert(6, 705, 1, 101, 11, "FIRSTLEG", "RECEIVABLE", "PENDING", "AVAILABLE");
insert(7, 706, 1, 101, 11, "FIRSTLEG", "RECEIVABLE", "APPROVED", "VOIDED");
insert(8, 707, 1, 101, 11, "FIRSTLEG", "RECEIVABLE", "APPROVED", "SUPERSEDED");
insert(9, 708, 1, 101, 11, "FIRSTLEG", "RECEIVABLE", "APPROVED", "SETTLED");
insert(10, 709, 1, 101, 12, "FIRSTLEG", "RECEIVABLE", "APPROVED", "AVAILABLE");
var rows = service.query(new DeliveryFeeCoverageModels.Query(101L, List.of(11L, 11L)));
assertThat(rows).extracting(DeliveryFeeCoverageModels.Fee::financeFeeId).containsExactly(2L, 9L);
assertThat(rows).allSatisfy(row -> { assertThat(row.customerId()).isEqualTo(101); assertThat(row.sourceInboundId()).isEqualTo(11); assertThat(row.sourceHash()).startsWith("sha256:"); });
assertThat(service.query(new DeliveryFeeCoverageModels.Query(101L, List.of(999L)))).isEmpty();
}
@Test void aVoidedLatestVersionCannotFallBackToAnOlderActiveVersion() {
insert(1, 701, 1, 101, 11, "FIRSTLEG", "RECEIVABLE", "APPROVED", "AVAILABLE");
insert(2, 701, 2, 101, 11, "FIRSTLEG", "RECEIVABLE", "APPROVED", "VOIDED");
assertThat(service.query(new DeliveryFeeCoverageModels.Query(101L, List.of(11L)))).isEmpty();
}
@Test void aContainerBusinessNumberIsNotMislabelledAsAnInboundCode() {
insert(1, 701, 1, 101, 11, "FIRSTLEG", "RECEIVABLE", "APPROVED", "AVAILABLE");
jdbc.update("UPDATE fin_fee_source SET source_type='CONTAINER_FEE',source_no='MSCU1234567'");
assertThat(service.query(new DeliveryFeeCoverageModels.Query(101L, List.of(11L))).get(0).inboundCode()).isNull();
}
void insert(long id, long fee, int version, long customer, long inbound, String system, String direction, String review, String status) {
jdbc.update("INSERT INTO fin_fee_source VALUES(?, ?, ?, 'INBOUND_FEE', ?, ?, ?, ?, ?, ?, ?, 'FREIGHT', '原运费', 'CNY', 100, ?, NULL)",
id, system, fee, version, customer, inbound, "IN-" + inbound, direction, review, status, "sha256:" + "a".repeat(64));
}
}