This commit is contained in:
2026-08-14 10:09:46 +08:00
parent 0bc752a2be
commit 66089f9b99
31 changed files with 719 additions and 141 deletions
@@ -4,6 +4,8 @@ import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.core.io.ClassPathResource;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RequestPart;
import java.lang.reflect.Method;
import java.nio.charset.StandardCharsets;
@@ -62,6 +64,13 @@ class ContainerControllerContractTest {
.doesNotContain("accountId");
}
@Test
@DisplayName("multipart 文本字段使用请求参数绑定")
void multipartScalarFieldsUseRequestParameters() {
assertMultipartBinding("uploadLogisticsDocument", 4, 5, 6);
assertMultipartBinding("uploadClearance", 3, 4, 5);
}
private static void assertPermission(String methodName, String authority) {
Method method = Arrays.stream(PlatformContainerController.class.getDeclaredMethods())
.filter(candidate -> candidate.getName().equals(methodName))
@@ -70,4 +79,16 @@ class ContainerControllerContractTest {
.isEqualTo("hasAuthority('" + authority + "')");
}
private static void assertMultipartBinding(String methodName, int fileIndex,
int versionIndex, int reasonIndex) {
Method method = Arrays.stream(PlatformContainerController.class.getDeclaredMethods())
.filter(candidate -> candidate.getName().equals(methodName))
.findFirst().orElseThrow();
assertThat(method.getParameters()[fileIndex].getAnnotation(RequestPart.class)).isNotNull();
assertThat(method.getParameters()[versionIndex].getAnnotation(RequestParam.class)).isNotNull();
assertThat(method.getParameters()[versionIndex].getAnnotation(RequestPart.class)).isNull();
assertThat(method.getParameters()[reasonIndex].getAnnotation(RequestParam.class)).isNotNull();
assertThat(method.getParameters()[reasonIndex].getAnnotation(RequestPart.class)).isNull();
}
}
@@ -13,6 +13,8 @@ import org.junit.jupiter.api.Test;
import org.yaml.snakeyaml.Yaml;
import org.springframework.core.io.ClassPathResource;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.multipart.MultipartFile;
import java.lang.reflect.Method;
@@ -89,6 +91,18 @@ class LoadingListControllerContractTest {
assertThat(component(ConfirmedQuery.class, "warehouseId").getAnnotation(NotNull.class)).isNull();
}
@Test
void multipartScalarFieldsUseRequestParameters() throws Exception {
Method method = PlatformLoadingListController.class.getDeclaredMethod("uploadDeclaration",
AuthenticatedUser.class, long.class, long.class, String.class,
MultipartFile.class, int.class, String.class);
assertThat(method.getParameters()[4].getAnnotation(RequestPart.class)).isNotNull();
assertThat(method.getParameters()[5].getAnnotation(RequestParam.class)).isNotNull();
assertThat(method.getParameters()[5].getAnnotation(RequestPart.class)).isNull();
assertThat(method.getParameters()[6].getAnnotation(RequestParam.class)).isNotNull();
assertThat(method.getParameters()[6].getAnnotation(RequestPart.class)).isNull();
}
@Test
void yamlParses() throws Exception {
String yaml = new ClassPathResource("openapi/loading-lists-v1.yaml")
@@ -22,6 +22,9 @@ class FeeItemMigrationSqlContractTest {
.contains("LEFT JOIN tmp_fee_item_seed matched_seed")
.contains("matched_seed.fee_code = NULLIF(TRIM(f.fee_code), '')")
.contains("matched_seed.trade_scope = f.trade_scope")
.contains("193000000001000111, 0, 'FBA_HEAD_FREIGHT'")
.contains("fee_code = 'FBA_HEAD_FREIGHT'")
.contains("warehouse_receivable = 1")
.doesNotContain("LEFT JOIN tmp_fee_item_seed by_code")
.doesNotContain("LEFT JOIN tmp_fee_item_seed by_semantic")
.doesNotContain("OR (SELECT COUNT(*) FROM tmp_fee_item_seed")
@@ -183,13 +183,10 @@ class FeeManagementServiceTest {
inbound.setCompanyName("客户A有限公司");
when(repository.findInbound(10001L, 21L)).thenReturn(inbound);
when(repository.findBySourceFee(10001L, "FBA_PRICING", 501L)).thenReturn(null);
when(repository.findItemByCode("FBA_HEAD_FREIGHT")).thenReturn(null);
doAnswer(invocation -> {
FeeItemEntity value = invocation.getArgument(0);
assertThat(value.getTenantId()).isZero();
value.setId(11L);
return null;
}).when(repository).insertItem(any());
FeeItemEntity freightItem = item(true, false);
freightItem.setId(11L);
freightItem.setFeeCode("FBA_HEAD_FREIGHT");
when(repository.findItemByCode("FBA_HEAD_FREIGHT")).thenReturn(freightItem);
InboundFeeEntity fee = new InboundFeeEntity();
fee.setId(501L);
@@ -226,6 +223,26 @@ class FeeManagementServiceTest {
assertThat(saved.getSettlementIncluded()).isTrue();
}
@Test
@DisplayName("系统头程运费项目缺失时拒绝运行期补建")
void rejectsMissingSystemFreightItem() {
when(repository.findInbound(10001L, 21L)).thenReturn(inbound());
when(repository.findBySourceFee(10001L, "FBA_PRICING", 501L)).thenReturn(null);
when(repository.findItemByCode("FBA_HEAD_FREIGHT")).thenReturn(null);
InboundFeeEntity fee = new InboundFeeEntity();
fee.setId(501L);
fee.setInboundId(21L);
fee.setFeeStatus("SENT");
when(pricingRepository.findFee(10001L, 501L)).thenReturn(fee);
assertThatThrownBy(() -> details.publishFreight(
10001L, 21L, 501L, 9L, "admin", LocalDateTime.of(2026, 8, 5, 12, 0)))
.isInstanceOf(BizException.class)
.hasMessageContaining("FBA头程运费未初始化");
verify(repository, never()).insertItem(any());
}
@Test
@DisplayName("并发发布同一计费快照时返回已生成的运费明细")
void reusesConcurrentFreightDetail() {