test(firstleg): extend shipment demo regression
This commit is contained in:
+51
@@ -3,6 +3,7 @@ package com.baiyue.firstleg.customs.container;
|
||||
import com.baiyue.common.core.api.ResultCode;
|
||||
import com.baiyue.common.core.exception.BizException;
|
||||
import com.baiyue.firstleg.customs.container.dto.ContainerCustomsDtos.ActionRequest;
|
||||
import com.baiyue.firstleg.customs.container.dto.ContainerCustomsDtos.ScopeRequest;
|
||||
import com.baiyue.firstleg.customs.container.mapper.ContainerCustomsMapper;
|
||||
import com.baiyue.firstleg.customs.container.service.ContainerCustomsService;
|
||||
import com.baiyue.firstleg.customs.client.CustomsFileClient;
|
||||
@@ -108,6 +109,35 @@ class ContainerCustomsServiceTest {
|
||||
verify(mapper,never()).freezeScopes(anyLong());
|
||||
}
|
||||
|
||||
@Test void declaringContainerFreezesUploadReplacementScopeAndDeletionWithoutDrift(){
|
||||
var inbound=new ContainerCustomsMapper.InboundRow(9L,"LP9",8L,"COMPLETED","CAB","C",11L,21L,"O","I",7L,"客户","TAX_REFUND");
|
||||
var declaring=container(ContainerCustomsService.DECLARING,3);
|
||||
var source=document(1L);
|
||||
var file=new MockMultipartFile("file","source.bin","application/octet-stream",new byte[]{1});
|
||||
when(mapper.planInbounds(9L)).thenReturn(List.of(inbound));
|
||||
when(mapper.container(9L)).thenReturn(declaring);
|
||||
when(mapper.document(1L)).thenReturn(source);
|
||||
when(mapper.lockContainerById(2L)).thenReturn(declaring);
|
||||
|
||||
assertThatThrownBy(()->service.uploadSource(7L,9L,5L,"upload-after-start",List.of(11L),file))
|
||||
.isInstanceOf(BizException.class).hasMessageContaining("资料已锁定");
|
||||
assertThatThrownBy(()->service.replaceSource(7L,1L,5L,"replace-after-start",new ScopeRequest(List.of(11L),1),file))
|
||||
.isInstanceOf(BizException.class).hasMessageContaining("资料已锁定");
|
||||
assertThatThrownBy(()->service.updateScope(7L,1L,5L,"scope-after-start",new ScopeRequest(List.of(11L),1)))
|
||||
.isInstanceOf(BizException.class).hasMessageContaining("资料已锁定");
|
||||
assertThatThrownBy(()->service.deleteSource(7L,1L,5L,"delete-after-start",1))
|
||||
.isInstanceOf(BizException.class).hasMessageContaining("资料已锁定");
|
||||
|
||||
verifyNoInteractions(files);
|
||||
verify(mapper,never()).insertDocument(anyLong(),anyLong(),anyLong(),anyLong(),anyString(),anyString(),anyString(),anyLong(),anyLong());
|
||||
verify(mapper,never()).replaceDocument(anyLong(),anyLong(),anyInt(),anyLong(),anyString(),anyString(),anyString(),anyLong(),anyLong());
|
||||
verify(mapper,never()).touchScope(anyLong(),anyLong(),anyInt());
|
||||
verify(mapper,never()).deleteDocument(anyLong(),anyLong(),anyInt(),anyLong());
|
||||
verify(mapper,never()).insertDocumentVersion(anyLong(),anyLong(),anyInt(),anyLong(),anyString(),anyString(),anyString(),anyLong(),anyString(),anyString(),anyLong());
|
||||
assertThat(source.version()).isEqualTo(1);
|
||||
assertThat(source.status()).isEqualTo("ACTIVE");
|
||||
}
|
||||
|
||||
@Test void concurrentStartWithSameKeyReplaysOneAggregateAndDifferentPayloadConflicts() throws Exception {
|
||||
var row=new ContainerCustomsMapper.InboundRow(9L,"LP9",8L,"COMPLETED","CAB","C",11L,21L,"O","I",7L,"客户","TAX_REFUND");
|
||||
var ready=container(ContainerCustomsService.READY,2);
|
||||
@@ -271,6 +301,27 @@ class ContainerCustomsServiceTest {
|
||||
verify(mapper,never()).complete(anyLong(),anyInt(),anyLong(),anyString());
|
||||
}
|
||||
|
||||
@Test void allBuyContainerCompletesOnceAndPublishesAutoDispatchTrigger(){
|
||||
var declaring=container(ContainerCustomsService.DECLARING,3);
|
||||
var completed=container(ContainerCustomsService.COMPLETED,4);
|
||||
var buy=new ContainerCustomsMapper.InboundRow(9L,"LP9",8L,"COMPLETED","CAB","C",11L,21L,"O","I",7L,"客户","BUY_DECLARATION");
|
||||
when(mapper.claimCommand(anyLong(),eq(5L),eq("COMPLETE_ALL_BUY_CUSTOMS_9"),eq("all-buy-key"),anyString())).thenReturn(1);
|
||||
when(mapper.lockContainer(9L)).thenReturn(declaring);
|
||||
when(mapper.planInbounds(9L)).thenReturn(List.of(buy));
|
||||
when(mapper.complete(2L,3,5L,"admin")).thenReturn(1);
|
||||
when(mapper.completeCommand(5L,"COMPLETE_ALL_BUY_CUSTOMS_9","all-buy-key",2L)).thenReturn(1);
|
||||
when(mapper.container(9L)).thenReturn(completed);
|
||||
when(mapper.documents(2L,null)).thenReturn(List.of());
|
||||
|
||||
var result=service.completeAllBuy(9L,5L,"admin","all-buy-key",new ActionRequest(3,true,"代理已完成"));
|
||||
|
||||
assertThat(result.status()).isEqualTo(ContainerCustomsService.COMPLETED);
|
||||
verify(mapper,times(1)).complete(2L,3,5L,"admin");
|
||||
verify(mapper,times(1)).insertHistory(anyLong(),eq(2L),eq("COMPLETE_CUSTOMS"),
|
||||
eq(ContainerCustomsService.DECLARING),eq(ContainerCustomsService.COMPLETED),eq("代理已完成"),eq(5L),eq("admin"));
|
||||
verify(events,times(1)).publishEvent(new ContainerCustomsService.CustomsCompletedEvent(8L));
|
||||
}
|
||||
|
||||
private static ContainerCustomsMapper.DocumentRow document(long id){return new ContainerCustomsMapper.DocumentRow(id,2L,7L,10L,"source.bin","a".repeat(64),"application/octet-stream",1L,"ACTIVE",5L,java.time.LocalDateTime.now(),1,java.time.LocalDateTime.now(),1);}
|
||||
private static ContainerCustomsMapper.ContainerRow container(String status,int version){return new ContainerCustomsMapper.ContainerRow(2L,9L,8L,status,null,null,null,null,null,null,null,null,version);}
|
||||
private void assertMerchantOrderNotFound(long tenantId,long orderId){
|
||||
|
||||
+52
@@ -67,6 +67,37 @@ class OceanBookingDocumentServiceTest {
|
||||
verify(repository, times(1)).insert(any(OceanBookingDocumentEntity.class));
|
||||
}
|
||||
|
||||
@Test void draftAcceptsBookingConfirmationAndBillOfLadingAsTwoVersionedFiles() {
|
||||
MockMultipartFile confirmation = new MockMultipartFile("file", "confirmation.pdf",
|
||||
"application/pdf", "confirmation".getBytes());
|
||||
MockMultipartFile bill = new MockMultipartFile("file", "bill.pdf",
|
||||
"application/pdf", "bill".getBytes());
|
||||
when(repository.claimOperation(anyLong(), eq(7L), eq("UPLOAD_DOCUMENT"), anyString(), anyString()))
|
||||
.thenReturn(true);
|
||||
when(repository.findForUpdate(10L)).thenReturn(draft(0), draft(1));
|
||||
when(files.upload("token", 7L, 9L, "OCEAN_BOOKING_DOCUMENT", "10", confirmation))
|
||||
.thenReturn(ApiResponse.success(metadata(91L)));
|
||||
when(files.upload("token", 7L, 9L, "OCEAN_BOOKING_DOCUMENT", "10", bill))
|
||||
.thenReturn(ApiResponse.success(metadata(92L)));
|
||||
when(repository.touchDraft(eq(10L), anyInt(), eq(7L), eq("admin"))).thenReturn(1);
|
||||
when(repository.completeOperation(eq(10L), eq(7L), eq("UPLOAD_DOCUMENT"), anyString(), anyString()))
|
||||
.thenReturn(1);
|
||||
|
||||
var first = service.upload(10L, 0, "BOOKING_CONFIRMATION", "confirmation-key",
|
||||
confirmation, 7L, "admin");
|
||||
var second = service.upload(10L, 1, "BILL_OF_LADING", "bill-key", bill, 7L, "admin");
|
||||
|
||||
assertThat(first.bookingVersion()).isEqualTo(1);
|
||||
assertThat(second.bookingVersion()).isEqualTo(2);
|
||||
ArgumentCaptor<OceanBookingDocumentEntity> documents =
|
||||
ArgumentCaptor.forClass(OceanBookingDocumentEntity.class);
|
||||
verify(repository, times(2)).insert(documents.capture());
|
||||
assertThat(documents.getAllValues()).extracting(OceanBookingDocumentEntity::getDocumentType)
|
||||
.containsExactly("BOOKING_CONFIRMATION", "BILL_OF_LADING");
|
||||
assertThat(documents.getAllValues()).extracting(OceanBookingDocumentEntity::getFileId)
|
||||
.containsExactly(91L, 92L);
|
||||
}
|
||||
|
||||
@Test void attachRejectsCrossScopeFileBeforePersisting() {
|
||||
when(repository.claimOperation(any(), anyLong(), anyString(), anyString(), anyString())).thenReturn(true);
|
||||
when(repository.findForUpdate(10L)).thenReturn(draft(1));
|
||||
@@ -121,6 +152,27 @@ class OceanBookingDocumentServiceTest {
|
||||
verify(files).metadata("token", 9L, "OCEAN_BOOKING_DOCUMENT", "10", 91L);
|
||||
}
|
||||
|
||||
@Test void releaseGateRejectsWhenBothActiveFileReferencesNoLongerExist() {
|
||||
OceanBookingEntity booking = draft(3);
|
||||
OceanBookingDocumentEntity confirmation = activeDocument(20L, 91L, "BOOKING_CONFIRMATION");
|
||||
OceanBookingDocumentEntity bill = activeDocument(21L, 92L, "BILL_OF_LADING");
|
||||
when(repository.activeDocuments(10L)).thenReturn(List.of(confirmation, bill));
|
||||
|
||||
assertThatThrownBy(() -> service.requireActiveValidDocument(booking))
|
||||
.isInstanceOf(BizException.class).hasMessageContaining("有效订舱确认或提单文件");
|
||||
|
||||
verify(files).metadata("token", 9L, "OCEAN_BOOKING_DOCUMENT", "10", 91L);
|
||||
verify(files).metadata("token", 9L, "OCEAN_BOOKING_DOCUMENT", "10", 92L);
|
||||
verify(repository, never()).touchDraft(anyLong(), anyInt(), anyLong(), anyString());
|
||||
}
|
||||
|
||||
private static OceanBookingDocumentEntity activeDocument(long id, long fileId, String type) {
|
||||
OceanBookingDocumentEntity document = new OceanBookingDocumentEntity();
|
||||
document.setId(id); document.setOceanBookingId(10L); document.setFileId(fileId);
|
||||
document.setDocumentType(type); document.setValid(true);
|
||||
return document;
|
||||
}
|
||||
|
||||
private static OceanBookingEntity draft(int version) {
|
||||
OceanBookingEntity booking = new OceanBookingEntity();
|
||||
booking.setId(10L); booking.setCustomerId(9L); booking.setStatus("DRAFT"); booking.setVersion(version);
|
||||
|
||||
Reference in New Issue
Block a user