feat: support mixed-SKU dropship cartons
This commit is contained in:
+12
-5
@@ -3,12 +3,15 @@ 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.dto.DropshipPalletizationDtos.CountSkuLine;
|
||||
import com.baiyue.firstleg.entity.InboundOrderEntity;
|
||||
import com.baiyue.firstleg.mapper.DropshipPalletizationMapper;
|
||||
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 com.baiyue.firstleg.mapper.DropshipPalletizationMapper.LabelSkuRow;
|
||||
import com.baiyue.firstleg.mapper.DropshipPalletizationMapper.CartonSkuRow;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
|
||||
@@ -20,7 +23,7 @@ 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); }
|
||||
DropshipPalletizationServiceTest(){ ReflectionTestUtils.setField(service,"mapper",mapper); ReflectionTestUtils.setField(service,"documentNumbers",numbers); when(mapper.labelSkus(anyLong(),anyLong())).thenAnswer(call -> java.util.List.of(labelSku())); when(mapper.cartonSkus(anyLong())).thenAnswer(call -> java.util.List.of(cartonSku())); }
|
||||
|
||||
@Test void reviewCreatesExpectedNumberOfPrintablePalletCodes(){
|
||||
InboundOrderEntity inbound=dropshipInbound(); when(mapper.insertTask(anyLong(),eq(1L),eq(30L),eq(100L),eq(8))).thenReturn(1);
|
||||
@@ -38,20 +41,21 @@ class DropshipPalletizationServiceTest {
|
||||
@Test void resolvesUncountedCartonBeforeQuantityConfirmation(){
|
||||
when(mapper.task(10L,100L)).thenReturn(task()); when(mapper.palletCount(10L)).thenReturn(2); 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.expectedSkuQuantity()).isEqualTo(12); assertThat(result.canCount()).isTrue();
|
||||
assertThat(result.inboundCode()).isEqualTo("IN-1"); assertThat(result.skuLines()).extracting("expectedQuantity").containsExactly(12); assertThat(result.canCount()).isTrue();
|
||||
}
|
||||
|
||||
@Test void cartonCanBindDirectlyToAPreGeneratedPallet(){
|
||||
when(mapper.task(10L,100L)).thenReturn(task()); when(mapper.palletCount(10L)).thenReturn(2); 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,"张三");
|
||||
service.countCarton(10L,countRequest("DP-260911-0001"),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("张三"));
|
||||
verify(mapper).insertCartonSku(anyLong(),anyLong(),eq(40L),eq("SKU-1"),any(),eq(12),eq(12),eq("MATCH"),isNull(),eq(1));
|
||||
}
|
||||
|
||||
@Test void unknownPalletCodeCannotCreateAnAdHocPallet(){
|
||||
when(mapper.task(10L,100L)).thenReturn(task()); when(mapper.palletCount(10L)).thenReturn(2); when(mapper.label(10L,"BOX-1")).thenReturn(label());
|
||||
var request=new CountCartonRequest(100L,"BOX-1",12,DiscrepancyAction.MATCH,null,"DP-260911-9999","op-1");
|
||||
var request=countRequest("DP-260911-9999");
|
||||
assertThatThrownBy(()->service.countCarton(10L,request,7L,"张三")).isInstanceOf(BizException.class).hasMessageContaining("测量审核后生成");
|
||||
verify(mapper,never()).insertPallet(anyLong(),anyLong(),anyLong(),anyLong(),anyLong(),anyString(),anyString(),anyLong(),anyString());
|
||||
}
|
||||
@@ -61,12 +65,15 @@ class DropshipPalletizationServiceTest {
|
||||
when(mapper.task(10L,100L)).thenReturn(task()); when(mapper.palletCount(10L)).thenReturn(0); when(mapper.label(10L,"BOX-1")).thenReturn(label());
|
||||
var result=service.resolveCarton(10L,100L,"BOX-1",7L);
|
||||
assertThat(result.canCount()).isFalse(); assertThat(result.blockReason()).contains("预计 2 托").contains("当前仅生成 0 个托盘码");
|
||||
assertThatThrownBy(()->service.countCarton(10L,new CountCartonRequest(100L,"BOX-1",12,DiscrepancyAction.MATCH,null,null,"op-1"),7L,"张三"))
|
||||
assertThatThrownBy(()->service.countCarton(10L,countRequest(null),7L,"张三"))
|
||||
.isInstanceOf(BizException.class).hasMessageContaining("预计 2 托");
|
||||
}
|
||||
|
||||
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.setExpectedPalletCount(2);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 LabelSkuRow labelSku(){LabelSkuRow l=new LabelSkuRow();l.setInboundDetailId(40L);l.setSkuCode("SKU-1");l.setCargoName("货物");l.setExpectedQuantity(12);l.setLineNo(1);return l;}
|
||||
private static CartonSkuRow cartonSku(){CartonSkuRow l=new CartonSkuRow();l.setInboundDetailId(40L);l.setSkuCode("SKU-1");l.setCargoName("货物");l.setExpectedQuantity(12);l.setActualQuantity(12);l.setDiscrepancyStatus("MATCH");l.setLineNo(1);return l;}
|
||||
private static CountCartonRequest countRequest(String palletNo){return new CountCartonRequest(100L,"BOX-1",java.util.List.of(new CountSkuLine(40L,"SKU-1",12,DiscrepancyAction.MATCH,null)),palletNo,"op-1");}
|
||||
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;}
|
||||
}
|
||||
|
||||
+19
-1
@@ -42,13 +42,31 @@ class InboundCartonLabelPrintServiceTest {
|
||||
Pallet open = dropshipPallet("OPEN");
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setContentType(MediaType.APPLICATION_PDF);
|
||||
when(print.generateInboundMarks(org.mockito.ArgumentMatchers.anyString(),
|
||||
when(print.generateDropshipPalletA4Documents(org.mockito.ArgumentMatchers.anyString(),
|
||||
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(open, "PCHK2608040174", "request-open");
|
||||
assertThat(response.getBody()).containsExactly(7, 8, 9);
|
||||
|
||||
ArgumentCaptor<PrintPdfClient.DropshipPalletA4PdfRequest> request =
|
||||
ArgumentCaptor.forClass(PrintPdfClient.DropshipPalletA4PdfRequest.class);
|
||||
verify(print).generateDropshipPalletA4Documents(org.mockito.ArgumentMatchers.eq("internal-token"),
|
||||
org.mockito.ArgumentMatchers.eq("request-open"), request.capture());
|
||||
assertThat(request.getValue().templateCode()).isEqualTo("DROPSHIP_PALLET_A4_V1");
|
||||
assertThat(request.getValue().pageSpec().widthMm()).isEqualByComparingTo("210");
|
||||
assertThat(request.getValue().pageSpec().heightMm()).isEqualByComparingTo("297");
|
||||
assertThat(request.getValue().documents()).singleElement().satisfies(document -> {
|
||||
assertThat(document.palletNo()).isEqualTo("DP-260911-0001");
|
||||
assertThat(document.inboundCodes()).isEqualTo("PCHK2608040174");
|
||||
assertThat(document.skuRows()).singleElement().satisfies(row -> {
|
||||
assertThat(row.skuCode()).isEqualTo("SKU-1");
|
||||
assertThat(row.cargoName()).isEqualTo("音箱");
|
||||
assertThat(row.cartonCount()).isEqualTo(1);
|
||||
assertThat(row.skuQuantity()).isEqualTo(19);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -7,6 +7,7 @@ import com.baiyue.firstleg.client.PrintableOrderInboundClient;
|
||||
import com.baiyue.firstleg.entity.InboundCartonLabelEntity;
|
||||
import com.baiyue.firstleg.entity.InboundOrderEntity;
|
||||
import com.baiyue.firstleg.repository.InboundCartonLabelRepository;
|
||||
import com.baiyue.firstleg.mapper.InboundCartonLabelSkuMapper;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
@@ -32,6 +33,7 @@ class InboundCartonLabelServiceTest {
|
||||
@Mock private OrderCargoClient orderCargoClient;
|
||||
@Mock private PrintableOrderInboundClient printableOrderInboundClient;
|
||||
@Mock private InboundOrderCreationService inboundOrderCreationService;
|
||||
@Mock private InboundCartonLabelSkuMapper labelSkus;
|
||||
private InboundCartonLabelService service;
|
||||
|
||||
@BeforeEach
|
||||
@@ -41,6 +43,7 @@ class InboundCartonLabelServiceTest {
|
||||
ReflectionTestUtils.setField(service, "orderCargoClient", orderCargoClient);
|
||||
ReflectionTestUtils.setField(service, "printableOrderInboundClient", printableOrderInboundClient);
|
||||
ReflectionTestUtils.setField(service, "inboundOrderCreationService", inboundOrderCreationService);
|
||||
ReflectionTestUtils.setField(service, "labelSkus", labelSkus);
|
||||
ReflectionTestUtils.setField(service, "internalToken", "internal-token");
|
||||
}
|
||||
|
||||
@@ -75,6 +78,26 @@ class InboundCartonLabelServiceTest {
|
||||
verify(repository).updatePackageCount(10001L, 70001L, 5);
|
||||
}
|
||||
|
||||
@Test
|
||||
void mixedCartonGroupCreatesOnePhysicalBoxSeriesWithEverySkuLine() {
|
||||
InboundOrderEntity inbound = inbound();
|
||||
inbound.setFulfillmentType("ONE_CLICK_DROPSHIP");
|
||||
when(repository.lockInbound(10001L, 70001L)).thenReturn(inbound);
|
||||
when(repository.findActiveByInbound(10001L, 70001L)).thenReturn(new ArrayList<>());
|
||||
when(repository.findByInbound(10001L, 70001L)).thenReturn(new ArrayList<>());
|
||||
var skuA = mixedCargo(80001L, 1, "SKU-A", 2, 3, "A");
|
||||
var skuB = mixedCargo(80002L, 2, "SKU-B", 5, 3, "A");
|
||||
when(orderCargoClient.listForCartonLabels("internal-token", 10001L, 60001L))
|
||||
.thenReturn(ApiResponse.success(List.of(skuA, skuB)));
|
||||
|
||||
var batch = service.getOrCreate(10001L, 70001L);
|
||||
|
||||
assertThat(batch.totalCount()).isEqualTo(3);
|
||||
verify(labelSkus, org.mockito.Mockito.times(6)).insert(any(Long.class),
|
||||
org.mockito.ArgumentMatchers.eq(10001L), org.mockito.ArgumentMatchers.eq(70001L), any(Long.class),
|
||||
any(Long.class), any(String.class), any(), any(Integer.class), any(Integer.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void repeatedAndPartialPrintsReadFrozenMappingWithoutReallocation() {
|
||||
InboundOrderEntity inbound = inbound();
|
||||
@@ -283,6 +306,12 @@ class InboundCartonLabelServiceTest {
|
||||
new BigDecimal(length), new BigDecimal(width), new BigDecimal(height));
|
||||
}
|
||||
|
||||
private OrderCargoClient.CargoLabelBinding mixedCargo(long id, int itemNo, String sku,
|
||||
int units, int count, String group) {
|
||||
return new OrderCargoClient.CargoLabelBinding(id, 60001L, itemNo, "货物" + itemNo, sku, count,
|
||||
units, new BigDecimal("60"), new BigDecimal("40"), new BigDecimal("30"), null, group);
|
||||
}
|
||||
|
||||
private List<InboundCartonLabelEntity> labels(InboundOrderEntity inbound, int total) {
|
||||
List<InboundCartonLabelEntity> values = new ArrayList<>();
|
||||
for (int index = 1; index <= total; index++) {
|
||||
|
||||
Reference in New Issue
Block a user