feat(firstleg): model declaration batches and customs results

This commit is contained in:
2026-09-27 20:23:53 +08:00
parent 69f2a18a44
commit ed692ee3bb
11 changed files with 480 additions and 3 deletions
@@ -19,6 +19,11 @@ class ContainerCustomsControllerContractTest {
assertPermission(PlatformContainerCustomsController.class,"start","platform:firstleg:customs:manage");
assertPermission(PlatformContainerCustomsController.class,"uploadCompletion","platform:firstleg:customs:manage");
assertPermission(PlatformContainerCustomsController.class,"completeAllBuy","platform:firstleg:customs:manage");
assertPermission(PlatformContainerCustomsController.class,"declarationBatches","platform:firstleg:customs:list");
assertPermission(PlatformContainerCustomsController.class,"createDeclarationBatch","platform:firstleg:customs:manage");
assertPermission(PlatformContainerCustomsController.class,"submitDeclarationBatch","platform:firstleg:customs:manage");
assertPermission(PlatformContainerCustomsController.class,"addClearanceResult","platform:firstleg:customs:manage");
assertPermission(PlatformContainerCustomsController.class,"resolveClearanceResult","platform:firstleg:customs:manage");
}
@Test void merchantUsesOrderViewAndEditWithoutTrustingTenantInput() {
assertThat(MerchantContainerCustomsController.class.getAnnotation(RequestMapping.class).value())
@@ -28,11 +33,13 @@ class ContainerCustomsControllerContractTest {
assertPermission(MerchantContainerCustomsController.class,"replace","merchant:order:edit");
assertPermission(MerchantContainerCustomsController.class,"scope","merchant:order:edit");
assertPermission(MerchantContainerCustomsController.class,"delete","merchant:order:edit");
assertPermission(MerchantContainerCustomsController.class,"clearanceResults","merchant:order:view");
}
@Test void openApiPublishesEveryPathParameterAndGeneratableDtos()throws Exception{
String yaml=new ClassPathResource("openapi/customs-v1.yaml").getContentAsString(java.nio.charset.StandardCharsets.UTF_8);
new Yaml().load(yaml);
assertThat(yaml).contains("ContainerView:","DocumentView:","FileView:","InboundView:","ActionRequest:","ScopeRequest:")
assertThat(yaml).contains("ContainerView:","DocumentView:","FileView:","InboundView:","ActionRequest:","ScopeRequest:",
"DeclarationBatch:","ClearanceResult:","declaration-batches","clearance-results")
.contains("merchantStatus:","WAITING_UPLOAD","CUSTOMS_COMPLETED","loadingPlanId:","hasActualCargo:","nullable: true")
.contains("LOADING_LIST_BUY_DECLARATION_ITEMS")
.doesNotContain("/cases/","CUSTOMS_DECLARATION");
@@ -47,7 +47,24 @@ class ContainerCustomsMapperContractTest {
assertRecordProjection("lockCompletion", ContainerCustomsMapper.CompletionRow.class, long.class);
}
@Test void declarationAndClearanceQueriesMapExplicitHistoricalFacts() throws Exception {
assertRecordProjection("declarationBatches", ContainerCustomsMapper.DeclarationBatchRow.class, long.class);
assertRecordProjection("declarationBatch", ContainerCustomsMapper.DeclarationBatchRow.class, long.class);
assertRecordProjection("lockDeclarationBatch", ContainerCustomsMapper.DeclarationBatchRow.class, long.class);
assertRecordProjectionWithoutVersion("clearanceResults", ContainerCustomsMapper.ClearanceResultRow.class, long.class);
assertRecordProjectionWithoutVersion("clearanceResult", ContainerCustomsMapper.ClearanceResultRow.class, long.class);
assertRecordProjectionWithoutVersion("lockClearanceResult", ContainerCustomsMapper.ClearanceResultRow.class, long.class);
}
private static void assertRecordProjection(String method,Class<?> recordType,Class<?>... parameterTypes) throws Exception {
assertProjection(method, recordType, true, parameterTypes);
}
private static void assertRecordProjectionWithoutVersion(String method,Class<?> recordType,Class<?>... parameterTypes) throws Exception {
assertProjection(method, recordType, false, parameterTypes);
}
private static void assertProjection(String method,Class<?> recordType,boolean requireVersion,Class<?>... parameterTypes) throws Exception {
String value=sql(method,parameterTypes).replaceAll("\\s+"," ").trim();
assertThat(value).doesNotContainIgnoringCase("SELECT *");
String projection=value.substring(value.indexOf("SELECT ")+7,value.indexOf(" FROM "));
@@ -56,7 +73,8 @@ class ContainerCustomsMapperContractTest {
.map(column->column.substring(column.lastIndexOf(' ')+1))
.toList();
List<String> components=Arrays.stream(recordType.getRecordComponents()).map(RecordComponent::getName).toList();
assertThat(aliases).containsExactlyElementsOf(components).contains("version");
assertThat(aliases).containsExactlyElementsOf(components);
if (requireVersion) assertThat(aliases).contains("version");
}
private static String sql(String name,Class<?>... types) throws Exception {
@@ -21,6 +21,9 @@ class CustomsSqlContractTest {
"fl_customs_frozen_document_inbound",
"fl_customs_completion_document",
"fl_customs_completion_document_version",
"fl_customs_final_document",
"fl_customs_declaration_batch",
"fl_customs_clearance_result",
"fl_customs_container_history",
"fl_customs_command");
private static final Pattern CREATE_TABLE = Pattern.compile(
@@ -38,6 +41,8 @@ class CustomsSqlContractTest {
.contains("fl_customs_customer_document_version", "scope_snapshot_json JSON NOT NULL")
.contains("fl_customs_frozen_document_inbound", "fl_customs_completion_document_version")
.contains("UNIQUE KEY uk_customs_completion_source(source_document_id)")
.contains("fl_customs_declaration_batch", "fl_customs_clearance_result", "customs_entry_no")
.contains("INSPECTION", "SUPPLEMENT_REQUIRED", "RELEASED", "DETAINED")
.contains("fl_customs_command", "uk_customs_command(actor_id,action,idempotency_key)")
.doesNotContain("platform:firstleg:loading-list:export");
}