完善退税报关回执确认流程

This commit is contained in:
2026-09-24 16:28:58 +08:00
parent bcf44affd7
commit 2486a01225
8 changed files with 154 additions and 46 deletions
@@ -88,11 +88,13 @@ class ContainerCustomsServiceTest {
when(mapper.completedPlanForOrder(7L,21L)).thenReturn(9L);
when(mapper.planInbounds(9L)).thenReturn(List.of(row));
when(mapper.container(9L)).thenReturn(container(ContainerCustomsService.READY,2));
when(mapper.actualBoxCount(9L,7L,"TAX_REFUND")).thenReturn(3L);
var view=service.merchantOrderView(7L,21L);
assertThat(view.loadingPlanId()).isEqualTo(9L);
assertThat(view.taxRefundCount()).isEqualTo(1);
assertThat(view.actualBoxCount()).isEqualTo(3L);
assertThat(view.inbounds()).extracting(value->value.orderId()).containsExactly(21L);
}
@@ -241,16 +243,24 @@ class ContainerCustomsServiceTest {
verify(mapper,times(1)).completeCommand(5L,"START_CONTAINER_CUSTOMS_9","start-key",2L);
}
@Test void lastCompletionRequiresConfirmationBeforeCallingFile(){
@Test void receiptUploadDoesNotRequireFinalConfirmation(){
var source=document(1L);var container=container(ContainerCustomsService.DECLARING,3);
when(mapper.claimCommand(anyLong(),eq(5L),eq("UPLOAD_COMPLETION_1"),eq("k"),anyString())).thenReturn(1);
when(mapper.document(1L)).thenReturn(source);when(mapper.lockContainerById(2L)).thenReturn(container);
when(mapper.lockDocument(1L)).thenReturn(source);when(mapper.lockCompletion(1L)).thenReturn(null);
when(mapper.missingCompletionCount(2L)).thenReturn(1);
when(files.upload(any(),eq(5L),eq(7L),eq("LOADING_LIST_CUSTOMS_RESULT"),eq("9"),any()))
.thenReturn(com.baiyue.common.core.api.ApiResponse.success(new CustomsFileClient.Metadata(99L,7L,
"LOADING_LIST_CUSTOMS_RESULT","9","result.bin","b".repeat(64),"application/octet-stream",1L)));
when(mapper.insertCompletion(anyLong(),eq(1L),eq(99L),anyString(),anyString(),anyString(),eq(1L),eq(5L),eq("admin"))).thenReturn(1);
when(mapper.insertCompletionVersion(anyLong(),anyLong(),eq(1),eq(99L),anyString(),anyString(),anyString(),eq(1L),eq(5L),eq("admin"))).thenReturn(1);
when(mapper.frozenScopes(1L)).thenReturn(List.of(new ContainerCustomsMapper.ScopeRow(1L,11L,21L,"I")));
when(mapper.completion(1L)).thenReturn(null);when(mapper.containerById(2L)).thenReturn(container);
when(mapper.completeCommand(anyLong(),eq("UPLOAD_COMPLETION_1"),eq("k"),anyLong())).thenReturn(1);
var file=new MockMultipartFile("file","result.bin","application/octet-stream",new byte[]{1});
assertThatThrownBy(()->service.uploadCompletion(1L,5L,"admin","k",0,false,file))
.isInstanceOf(BizException.class).hasMessageContaining("最后一份");
verifyNoInteractions(files);
var result=service.uploadCompletion(1L,5L,"admin","k",0,file);
assertThat(result).isNotNull();
verify(files).upload(any(),eq(5L),eq(7L),eq("LOADING_LIST_CUSTOMS_RESULT"),eq("9"),same(file));
verify(mapper,never()).complete(anyLong(),anyInt(),anyLong(),anyString());
}
@Test void completedContainerLocksCompletionReplacement(){
@@ -259,15 +269,14 @@ class ContainerCustomsServiceTest {
when(mapper.lockContainerById(2L)).thenReturn(container(ContainerCustomsService.COMPLETED,4));
when(mapper.lockDocument(1L)).thenReturn(source);
var file=new MockMultipartFile("file","result.bin","application/octet-stream",new byte[]{1});
assertThatThrownBy(()->service.uploadCompletion(1L,5L,"admin","k",0,false,file))
assertThatThrownBy(()->service.uploadCompletion(1L,5L,"admin","k",0,file))
.isInstanceOf(BizException.class).hasMessageContaining("不在报关中");
verifyNoInteractions(files);
}
@Test void finalCompletionReplaySucceedsAfterContainerCompletedAndRejectsChangedPayload(){
@Test void receiptReplaySucceedsAndDoesNotCompleteContainer(){
var source=document(1L);
var declaring=container(ContainerCustomsService.DECLARING,3);
var completed=container(ContainerCustomsService.COMPLETED,4);
var containerState=new AtomicReference<>(declaring);
var completionState=new AtomicReference<ContainerCustomsMapper.CompletionRow>();
var commandState=new AtomicReference<ContainerCustomsMapper.CommandRow>();
@@ -293,10 +302,10 @@ class ContainerCustomsServiceTest {
when(mapper.insertCompletion(anyLong(),eq(1L),eq(99L),eq("result.pdf"),eq("b".repeat(64)),
eq("application/pdf"),eq(1L),eq(5L),eq("admin"))).thenAnswer(invocation->{
completionState.set(new ContainerCustomsMapper.CompletionRow(invocation.getArgument(0),1L,99L,
"result.pdf","b".repeat(64),"application/pdf",1L,5L,"admin",java.time.LocalDateTime.now(),1));
"result.pdf","b".repeat(64),"application/pdf",1L,5L,"admin",java.time.LocalDateTime.now(),1,
"PENDING",null));
return 1;
});
when(mapper.complete(2L,3,5L,"admin")).thenAnswer(invocation->{containerState.set(completed);return 1;});
when(mapper.completeCommand(eq(5L),eq("UPLOAD_COMPLETION_1"),eq("completion-key"),anyLong()))
.thenAnswer(invocation->{
var current=commandState.get();
@@ -308,19 +317,19 @@ class ContainerCustomsServiceTest {
when(mapper.completion(1L)).thenAnswer(invocation->completionState.get());
when(mapper.containerById(2L)).thenAnswer(invocation->containerState.get());
var first=service.uploadCompletion(1L,5L,"admin","completion-key",0,true,file);
var replay=service.uploadCompletion(1L,5L,"admin","completion-key",0,true,file);
var first=service.uploadCompletion(1L,5L,"admin","completion-key",0,file);
var replay=service.uploadCompletion(1L,5L,"admin","completion-key",0,file);
assertThat(first.completion().fileId()).isEqualTo(99L);
assertThat(replay.completion().fileId()).isEqualTo(99L);
assertThatThrownBy(()->service.uploadCompletion(1L,5L,"admin","completion-key",0,true,changedFile))
assertThatThrownBy(()->service.uploadCompletion(1L,5L,"admin","completion-key",0,changedFile))
.isInstanceOfSatisfying(BizException.class,
error->assertThat(error.getResultCode()).isEqualTo(ResultCode.CONFLICT));
verify(files,times(1)).upload(any(),eq(5L),eq(7L),eq("LOADING_LIST_CUSTOMS_RESULT"),eq("9"),same(file));
verify(mapper,times(1)).lockContainerById(2L);
verify(mapper,times(1)).insertCompletion(anyLong(),eq(1L),eq(99L),anyString(),anyString(),anyString(),
eq(1L),eq(5L),eq("admin"));
verify(mapper,times(1)).complete(2L,3,5L,"admin");
verify(mapper,never()).complete(anyLong(),anyInt(),anyLong(),anyString());
}
@Test void merchantCannotDownloadCompletionBeforeWholeContainerCompletes(){