feat: precreate dropship pallet codes after measurement
This commit is contained in:
+29
-77
@@ -3,9 +3,10 @@ package com.baiyue.firstleg.service;
|
||||
import com.baiyue.common.core.exception.BizException;
|
||||
import com.baiyue.firstleg.dto.DropshipPalletizationDtos.CountCartonRequest;
|
||||
import com.baiyue.firstleg.dto.DropshipPalletizationDtos.DiscrepancyAction;
|
||||
import com.baiyue.firstleg.entity.InboundOrderEntity;
|
||||
import com.baiyue.firstleg.mapper.DropshipPalletizationMapper;
|
||||
import com.baiyue.firstleg.mapper.DropshipPalletizationMapper.CartonRow;
|
||||
import com.baiyue.firstleg.mapper.DropshipPalletizationMapper.LabelRow;
|
||||
import com.baiyue.firstleg.mapper.DropshipPalletizationMapper.CartonRow;
|
||||
import com.baiyue.firstleg.mapper.DropshipPalletizationMapper.PalletRow;
|
||||
import com.baiyue.firstleg.mapper.DropshipPalletizationMapper.TaskRow;
|
||||
import org.junit.jupiter.api.Test;
|
||||
@@ -19,94 +20,45 @@ class DropshipPalletizationServiceTest {
|
||||
private final FirstlegDocumentNumberGenerator numbers=mock(FirstlegDocumentNumberGenerator.class);
|
||||
private final DropshipPalletizationMapper mapper=mock(DropshipPalletizationMapper.class);
|
||||
private final DropshipPalletizationService service=new DropshipPalletizationService();
|
||||
|
||||
DropshipPalletizationServiceTest(){ ReflectionTestUtils.setField(service,"mapper",mapper); ReflectionTestUtils.setField(service,"documentNumbers",numbers); }
|
||||
|
||||
@Test void generatesBindsSealsAndCompletesOnlyAfterEveryCartonIsCounted(){
|
||||
when(mapper.lockTask(10L,100L)).thenReturn(10L); when(mapper.task(10L,100L)).thenReturn(readyToComplete());
|
||||
when(mapper.unboundCount(10L)).thenReturn(2); when(numbers.next("DP")).thenReturn("DP-260909-0001");
|
||||
when(mapper.bindPending(eq(10L),anyLong(),eq("create-1"),eq(7L),eq("张三"))).thenReturn(2);
|
||||
when(mapper.adjustBound(10L,7L,2)).thenReturn(1);
|
||||
when(mapper.seal(eq(10L),anyLong(),eq(1),eq(100L),eq("create-1"),eq(7L),eq("张三"))).thenReturn(1);
|
||||
when(mapper.completeTask(10L)).thenReturn(1); when(mapper.completeInbound(10L,1L,30L,7L)).thenReturn(1);
|
||||
service.createAndBind(10L,new com.baiyue.firstleg.dto.DropshipPalletizationDtos.CreateAndBindRequest(100L,"create-1"),7L,"张三");
|
||||
verify(mapper).insertPallet(anyLong(),eq(10L),eq(1L),eq(30L),eq(100L),eq("DP-260909-0001"),eq("create-1"),eq(7L),eq("张三"));
|
||||
verify(numbers,times(1)).next("DP");
|
||||
@Test void reviewCreatesExpectedNumberOfPrintablePalletCodes(){
|
||||
InboundOrderEntity inbound=dropshipInbound(); when(mapper.insertTask(anyLong(),eq(1L),eq(30L),eq(100L),eq(8))).thenReturn(1);
|
||||
when(numbers.next("DP")).thenReturn("DP-260911-0001","DP-260911-0002");
|
||||
service.createTask(inbound,7L,"张三");
|
||||
verify(mapper,times(2)).insertPallet(anyLong(),anyLong(),eq(1L),eq(30L),eq(100L),startsWith("DP-"),startsWith("dropship-precreate-"),eq(7L),eq("张三"));
|
||||
}
|
||||
|
||||
@Test void incompleteCountingNeverAllocatesAPalletNumber(){
|
||||
when(mapper.lockTask(10L,100L)).thenReturn(10L); when(mapper.task(10L,100L)).thenReturn(task());
|
||||
assertThatThrownBy(()->service.createAndBind(10L,new com.baiyue.firstleg.dto.DropshipPalletizationDtos.CreateAndBindRequest(100L,"early"),7L,"张三"))
|
||||
.hasMessageContaining("完成全部箱码清点");
|
||||
verifyNoInteractions(numbers);
|
||||
}
|
||||
|
||||
@Test void noPendingCartonsNeverAllocatesNumberOrEmptyPallet(){
|
||||
when(mapper.lockTask(10L,100L)).thenReturn(10L); when(mapper.task(10L,100L)).thenReturn(readyToComplete());
|
||||
assertThatThrownBy(()->service.createAndBind(10L,new com.baiyue.firstleg.dto.DropshipPalletizationDtos.CreateAndBindRequest(100L,"empty"),7L,"张三")).hasMessageContaining("没有待绑托箱");
|
||||
verifyNoInteractions(numbers);
|
||||
verify(mapper,never()).insertPallet(anyLong(),anyLong(),anyLong(),anyLong(),anyLong(),anyString(),anyString(),anyLong(),anyString());
|
||||
}
|
||||
|
||||
@Test void replaysAfterCompletionWithoutGeneratingAnotherPallet(){
|
||||
TaskRow completed=task(); completed.setTaskStatus("COMPLETED"); completed.setProcessStatus("WAIT_SPLIT");
|
||||
when(mapper.lockTask(10L,100L)).thenReturn(10L); when(mapper.task(10L,100L)).thenReturn(completed);
|
||||
when(mapper.palletByOpenOperation("replay")).thenReturn(pallet());
|
||||
service.createAndBind(10L,new com.baiyue.firstleg.dto.DropshipPalletizationDtos.CreateAndBindRequest(100L,"replay"),7L,"张三");
|
||||
verifyNoInteractions(numbers); verify(mapper,never()).unboundCount(anyLong());
|
||||
}
|
||||
|
||||
@Test void rejectsOtherOperatorAndCrossTaskReplay(){
|
||||
when(mapper.lockTask(10L,100L)).thenReturn(10L); when(mapper.task(10L,100L)).thenReturn(readyToComplete());
|
||||
var request=new com.baiyue.firstleg.dto.DropshipPalletizationDtos.CreateAndBindRequest(100L,"replay");
|
||||
assertThatThrownBy(()->service.createAndBind(10L,request,8L,"李四")).hasMessageContaining("当前操作员");
|
||||
PalletRow other=pallet(); other.setTaskId(11L); when(mapper.palletByOpenOperation("replay")).thenReturn(other);
|
||||
assertThatThrownBy(()->service.createAndBind(10L,request,7L,"张三")).hasMessageContaining("不同任务");
|
||||
verifyNoInteractions(numbers);
|
||||
}
|
||||
|
||||
@Test void rejectsUnknownWarehouseAndChangedBindCount(){
|
||||
var request=new com.baiyue.firstleg.dto.DropshipPalletizationDtos.CreateAndBindRequest(100L,"new");
|
||||
assertThatThrownBy(()->service.createAndBind(10L,request,7L,"张三")).hasMessageContaining("当前仓库");
|
||||
when(mapper.lockTask(10L,100L)).thenReturn(10L); when(mapper.task(10L,100L)).thenReturn(readyToComplete());
|
||||
when(mapper.unboundCount(10L)).thenReturn(2); when(numbers.next("DP")).thenReturn("DP-260909-0002");
|
||||
assertThatThrownBy(()->service.createAndBind(10L,request,7L,"张三")).hasMessageContaining("待绑托箱已变化");
|
||||
verify(mapper,never()).adjustBound(anyLong(),anyLong(),anyInt());
|
||||
@Test void replayedReviewDoesNotGenerateDuplicatePalletCodes(){
|
||||
when(mapper.insertTask(anyLong(),anyLong(),anyLong(),anyLong(),anyInt())).thenReturn(0);
|
||||
service.createTask(dropshipInbound(),7L,"张三");
|
||||
verifyNoInteractions(numbers); verify(mapper,never()).insertPallet(anyLong(),anyLong(),anyLong(),anyLong(),anyLong(),anyString(),anyString(),anyLong(),anyString());
|
||||
}
|
||||
|
||||
@Test void resolvesUncountedCartonBeforeQuantityConfirmation(){
|
||||
TaskRow task=task(); LabelRow label=label();
|
||||
when(mapper.task(10L,100L)).thenReturn(task); when(mapper.label(10L,"BOX-1")).thenReturn(label);
|
||||
when(mapper.task(10L,100L)).thenReturn(task()); when(mapper.label(10L,"BOX-1")).thenReturn(label());
|
||||
var result=service.resolveCarton(10L,100L,"BOX-1",7L);
|
||||
assertThat(result.inboundCode()).isEqualTo("IN-1");
|
||||
assertThat(result.skuCode()).isEqualTo("SKU-1");
|
||||
assertThat(result.expectedSkuQuantity()).isEqualTo(12);
|
||||
assertThat(result.countStatus()).isEqualTo("UNCOUNTED");
|
||||
assertThat(result.canCount()).isTrue();
|
||||
assertThat(result.inboundCode()).isEqualTo("IN-1"); assertThat(result.expectedSkuQuantity()).isEqualTo(12); assertThat(result.canCount()).isTrue();
|
||||
}
|
||||
|
||||
@Test void mismatchCannotBeRecordedWithoutAcceptedVarianceAndRemark(){
|
||||
@Test void cartonCanBindDirectlyToAPreGeneratedPallet(){
|
||||
when(mapper.task(10L,100L)).thenReturn(task()); when(mapper.label(10L,"BOX-1")).thenReturn(label()); when(mapper.palletByNo("DP-260911-0001")).thenReturn(pallet());
|
||||
when(mapper.addCounted(10L,7L,1,0)).thenReturn(1); when(mapper.carton(eq(10L),anyLong())).thenReturn(carton());
|
||||
when(mapper.pallet(10L,20L,100L)).thenReturn(pallet()); when(mapper.cartons(20L)).thenReturn(java.util.List.of());
|
||||
service.countCarton(10L,new CountCartonRequest(100L,"BOX-1",12,DiscrepancyAction.MATCH,null,"DP-260911-0001","op-1"),7L,"张三");
|
||||
verify(mapper).insertCarton(anyLong(),eq(10L),eq(20L),eq(1L),eq(30L),eq(40L),eq(50L),eq("SKU-1"),any(),eq("BOX-1"),eq(12),eq(12),eq("MATCH"),isNull(),eq("op-1"),eq(7L),eq("张三"));
|
||||
}
|
||||
|
||||
@Test void unknownPalletCodeCannotCreateAnAdHocPallet(){
|
||||
when(mapper.task(10L,100L)).thenReturn(task()); when(mapper.label(10L,"BOX-1")).thenReturn(label());
|
||||
var wrongAction=new CountCartonRequest(100L,"BOX-1",11,DiscrepancyAction.MATCH,null,null,"op-1");
|
||||
assertThatThrownBy(()->service.countCarton(10L,wrongAction,7L,"张三"))
|
||||
.isInstanceOf(BizException.class).hasMessageContaining("确认差异处理结果");
|
||||
var noRemark=new CountCartonRequest(100L,"BOX-1",11,DiscrepancyAction.ACCEPT_VARIANCE,null,null,"op-2");
|
||||
assertThatThrownBy(()->service.countCarton(10L,noRemark,7L,"张三"))
|
||||
.isInstanceOf(BizException.class).hasMessageContaining("处理说明");
|
||||
verify(mapper,never()).insertCarton(anyLong(),anyLong(),any(),anyLong(),anyLong(),anyLong(),anyLong(),any(),any(),any(),anyInt(),anyInt(),any(),any(),any(),anyLong(),any());
|
||||
var request=new CountCartonRequest(100L,"BOX-1",12,DiscrepancyAction.MATCH,null,"DP-260911-9999","op-1");
|
||||
assertThatThrownBy(()->service.countCarton(10L,request,7L,"张三")).isInstanceOf(BizException.class).hasMessageContaining("测量审核后生成");
|
||||
verify(mapper,never()).insertPallet(anyLong(),anyLong(),anyLong(),anyLong(),anyLong(),anyString(),anyString(),anyLong(),anyString());
|
||||
}
|
||||
|
||||
@Test void countingCannotExposeOrBindAPalletNumberEarly(){
|
||||
when(mapper.task(10L,100L)).thenReturn(task()); when(mapper.label(10L,"BOX-1")).thenReturn(label());
|
||||
var request=new CountCartonRequest(100L,"BOX-1",12,DiscrepancyAction.MATCH,null,"DP-260908-0001","op-1");
|
||||
assertThatThrownBy(()->service.countCarton(10L,request,7L,"张三"))
|
||||
.hasMessageContaining("不能提前绑定托盘码");
|
||||
verify(mapper,never()).insertCarton(anyLong(),anyLong(),any(),anyLong(),anyLong(),anyLong(),anyLong(),any(),any(),any(),anyInt(),anyInt(),any(),any(),any(),anyLong(),any());
|
||||
}
|
||||
|
||||
private static TaskRow task(){ TaskRow t=new TaskRow();t.setId(10L);t.setTenantId(1L);t.setInboundId(30L);t.setWarehouseId(100L);t.setInboundCode("IN-1");t.setTaskStatus("CLAIMED");t.setAssigneeId(7L);t.setProcessStatus("WAIT_PALLETIZE");t.setTotalCartons(2);t.setCountedCartons(0);t.setAllocatedCartons(0);t.setDiscrepancyCartons(0);t.setVersion(1);return t; }
|
||||
private static TaskRow readyToComplete(){ TaskRow t=task();t.setCountedCartons(2);return t; }
|
||||
private static InboundOrderEntity dropshipInbound(){InboundOrderEntity i=new InboundOrderEntity();i.setId(30L);i.setTenantId(1L);i.setWarehouseId(100L);i.setFulfillmentType("ONE_CLICK_DROPSHIP");i.setTotalPackageCount(8);i.setPalletCount(2);return i;}
|
||||
private static TaskRow task(){TaskRow t=new TaskRow();t.setId(10L);t.setTenantId(1L);t.setInboundId(30L);t.setWarehouseId(100L);t.setInboundCode("IN-1");t.setTaskStatus("CLAIMED");t.setAssigneeId(7L);t.setProcessStatus("WAIT_PALLETIZE");t.setTotalCartons(2);t.setCountedCartons(0);t.setAllocatedCartons(0);t.setDiscrepancyCartons(0);t.setVersion(1);return t;}
|
||||
private static LabelRow label(){LabelRow l=new LabelRow();l.setCartonLabelId(50L);l.setInboundDetailId(40L);l.setSkuCode("SKU-1");l.setCargoName("货物");l.setUnitsPerCarton(12);l.setInboundCode("IN-1");l.setBoxCode("BOX-1");return l;}
|
||||
private static PalletRow pallet(){PalletRow p=new PalletRow();p.setId(20L);p.setTaskId(10L);p.setTenantId(1L);p.setInboundId(30L);p.setWarehouseId(100L);p.setPalletNo("DP-260908-0001");p.setPalletStatus("OPEN");p.setVersion(1);return p;}
|
||||
private static CartonRow carton(){CartonRow c=new CartonRow();c.setId(60L);c.setTaskId(10L);c.setPalletId(20L);c.setPalletNo("DP-260908-0001");c.setInboundId(30L);c.setInboundDetailId(40L);c.setSkuCode("SKU-1");c.setCargoName("货物");c.setBoxCode("BOX-1");c.setExpectedSkuQuantity(12);c.setActualSkuQuantity(12);c.setDiscrepancyStatus("MATCH");return c;}
|
||||
private static PalletRow pallet(){PalletRow p=new PalletRow();p.setId(20L);p.setTaskId(10L);p.setTenantId(1L);p.setInboundId(30L);p.setWarehouseId(100L);p.setPalletNo("DP-260911-0001");p.setPalletStatus("OPEN");p.setVersion(1);return p;}
|
||||
private static CartonRow carton(){CartonRow c=new CartonRow();c.setId(60L);c.setTaskId(10L);c.setPalletId(20L);c.setInboundId(30L);c.setInboundDetailId(40L);c.setPalletNo("DP-260911-0001");c.setSkuCode("SKU-1");c.setCargoName("货物");c.setBoxCode("BOX-1");c.setExpectedSkuQuantity(12);c.setActualSkuQuantity(12);c.setDiscrepancyStatus("MATCH");return c;}
|
||||
}
|
||||
|
||||
+3
-8
@@ -38,21 +38,16 @@ class InboundCartonLabelPrintServiceTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void dropshipPalletLabelIsAvailableOnlyAfterSeal() {
|
||||
void dropshipPalletLabelIsAvailableBeforeSeal() {
|
||||
Pallet open = dropshipPallet("OPEN");
|
||||
assertThatThrownBy(() -> service.generateDropshipPallet(open, "request-open"))
|
||||
.isInstanceOf(BizException.class)
|
||||
.hasMessageContaining("已完成");
|
||||
verifyNoInteractions(print);
|
||||
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setContentType(MediaType.APPLICATION_PDF);
|
||||
when(print.generateInboundMarks(org.mockito.ArgumentMatchers.anyString(),
|
||||
org.mockito.ArgumentMatchers.eq("request-sealed"), org.mockito.ArgumentMatchers.any()))
|
||||
org.mockito.ArgumentMatchers.eq("request-open"), org.mockito.ArgumentMatchers.any()))
|
||||
.thenReturn(new ResponseEntity<>(new byte[] {7, 8, 9}, headers,
|
||||
org.springframework.http.HttpStatus.OK));
|
||||
|
||||
ResponseEntity<byte[]> response = service.generateDropshipPallet(dropshipPallet("SEALED"), "request-sealed");
|
||||
ResponseEntity<byte[]> response = service.generateDropshipPallet(open, "PCHK2608040174", "request-open");
|
||||
assertThat(response.getBody()).containsExactly(7, 8, 9);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user