From ee97565f67e4cc9a986ebc8a3da19ceb6b7fda06 Mon Sep 17 00:00:00 2001 From: ouyangxq <775153912@qq.com> Date: Sun, 20 Sep 2026 13:51:06 +0800 Subject: [PATCH] fix: paginate dropship pallet print details --- .../InboundCartonLabelPrintService.java | 33 ++++++++++++++-- .../InboundCartonLabelPrintServiceTest.java | 38 +++++++++++++++++++ .../controller/PrintRequestSizeFilter.java | 1 + .../PrintRequestSizeFilterTest.java | 11 ++++++ 4 files changed, 79 insertions(+), 4 deletions(-) diff --git a/firstleg/src/main/java/com/baiyue/firstleg/service/InboundCartonLabelPrintService.java b/firstleg/src/main/java/com/baiyue/firstleg/service/InboundCartonLabelPrintService.java index 8b2e7c047..e3148d064 100644 --- a/firstleg/src/main/java/com/baiyue/firstleg/service/InboundCartonLabelPrintService.java +++ b/firstleg/src/main/java/com/baiyue/firstleg/service/InboundCartonLabelPrintService.java @@ -32,6 +32,8 @@ public class InboundCartonLabelPrintService { private static final BigDecimal PAGE_MM = new BigDecimal("100"); private static final BigDecimal A4_WIDTH_MM = new BigDecimal("210"); private static final BigDecimal A4_HEIGHT_MM = new BigDecimal("297"); + private static final int DROPSHIP_INBOUND_ROWS_PER_PAGE = 10; + private static final int DROPSHIP_SKU_ROWS_PER_PAGE = 34; private static final List SAFE_RESPONSE_HEADERS = List.of( HttpHeaders.CONTENT_DISPOSITION, HttpHeaders.CACHE_CONTROL, HttpHeaders.PRAGMA, "X-Print-Page-Count", "X-Request-Id", "X-Trace-Id"); @@ -134,7 +136,7 @@ public class InboundCartonLabelPrintService { } Map customerNicknameCache = new HashMap<>(); List documents = pallets.stream() - .map(pallet -> dropshipPalletDocument(pallet, customerNicknameCache)).toList(); + .flatMap(pallet -> dropshipPalletDocuments(pallet, customerNicknameCache).stream()).toList(); String fileName = pallets.size() == 1 ? pallets.get(0).palletNo() + "-A4托盘信息单.pdf" : inboundCode + "-" + pallets.size() + "托-A4托盘信息单.pdf"; @@ -148,7 +150,7 @@ public class InboundCartonLabelPrintService { } } - private PrintPdfClient.DropshipPalletDocument dropshipPalletDocument( + private List dropshipPalletDocuments( Pallet pallet, Map customerNicknameCache) { if (pallet == null || pallet.palletId() == null || !StringUtils.hasText(pallet.palletNo())) { throw new BizException(ResultCode.CONFLICT, "托盘码尚未生成,不能打印"); @@ -172,8 +174,31 @@ public class InboundCartonLabelPrintService { .stream().map(row -> new PrintPdfClient.DropshipPalletSkuRow( row.getSkuCode(), number(row.getCartonCount()), number(row.getItemQuantity()), unitsPerCarton(row))).toList(); - return new PrintPdfClient.DropshipPalletDocument( - pallet.palletNo(), destinationWarehouse, pallet.palletNo(), inboundRows, skuRows); + int pageCount = Math.max(1, Math.max(pageCount(inboundRows.size(), DROPSHIP_INBOUND_ROWS_PER_PAGE), + pageCount(skuRows.size(), DROPSHIP_SKU_ROWS_PER_PAGE))); + List documents = new ArrayList<>(pageCount); + for (int page = 0; page < pageCount; page++) { + documents.add(new PrintPdfClient.DropshipPalletDocument( + pallet.palletNo(), destinationWarehouse, pallet.palletNo(), + pageOrRepeat(inboundRows, page, DROPSHIP_INBOUND_ROWS_PER_PAGE), + page(skuRows, page, DROPSHIP_SKU_ROWS_PER_PAGE))); + } + return List.copyOf(documents); + } + + private int pageCount(int size, int pageSize) { + return size == 0 ? 0 : (size + pageSize - 1) / pageSize; + } + + private List page(List rows, int page, int pageSize) { + int from = Math.min(rows.size(), page * pageSize); + int to = Math.min(rows.size(), from + pageSize); + return rows.subList(from, to); + } + + private List pageOrRepeat(List rows, int page, int pageSize) { + List selected = page(rows, page, pageSize); + return selected.isEmpty() ? page(rows, 0, pageSize) : selected; } private String unitsPerCarton(DropshipPalletizationMapper.PrintSkuRow row) { diff --git a/firstleg/src/test/java/com/baiyue/firstleg/service/InboundCartonLabelPrintServiceTest.java b/firstleg/src/test/java/com/baiyue/firstleg/service/InboundCartonLabelPrintServiceTest.java index a9f25abe4..ec288a2f8 100644 --- a/firstleg/src/test/java/com/baiyue/firstleg/service/InboundCartonLabelPrintServiceTest.java +++ b/firstleg/src/test/java/com/baiyue/firstleg/service/InboundCartonLabelPrintServiceTest.java @@ -18,6 +18,7 @@ import org.springframework.http.ResponseEntity; import org.springframework.test.util.ReflectionTestUtils; import java.math.BigDecimal; +import java.util.ArrayList; import java.util.List; import static org.assertj.core.api.Assertions.assertThat; @@ -108,6 +109,43 @@ class InboundCartonLabelPrintServiceTest { assertThat(response.getBody()).containsExactly(4, 5, 6); } + @Test + void splitsLargeDropshipPalletDetailsAcrossPrintableA4Pages() { + Pallet pallet = dropshipPallet("OPEN"); + stubPalletFacts(90001L); + List skuRows = new ArrayList<>(); + for (int index = 1; index <= 35; index++) { + DropshipPalletizationMapper.PrintSkuRow row = new DropshipPalletizationMapper.PrintSkuRow(); + row.setSkuCode("SKU-" + index); + row.setCartonCount(1); + row.setItemQuantity(index); + row.setMinUnitsPerCarton(index); + row.setMaxUnitsPerCarton(index); + skuRows.add(row); + } + when(palletization.printSkuRows(90001L)).thenReturn(skuRows); + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_PDF); + when(print.generateDropshipPalletA4Documents(org.mockito.ArgumentMatchers.anyString(), + org.mockito.ArgumentMatchers.eq("request-large"), org.mockito.ArgumentMatchers.any())) + .thenReturn(new ResponseEntity<>(new byte[] {1}, headers, + org.springframework.http.HttpStatus.OK)); + + service.generateDropshipPallet(pallet, "PCHK2608040174", "request-large"); + + ArgumentCaptor request = + ArgumentCaptor.forClass(PrintPdfClient.DropshipPalletA4PdfRequest.class); + verify(print).generateDropshipPalletA4Documents(org.mockito.ArgumentMatchers.eq("internal-token"), + org.mockito.ArgumentMatchers.eq("request-large"), request.capture()); + assertThat(request.getValue().documents()).hasSize(2).allSatisfy(document -> { + assertThat(document.palletNo()).isEqualTo("DP-260911-0001"); + assertThat(document.inboundRows()).isNotEmpty().hasSizeLessThanOrEqualTo(10); + assertThat(document.skuRows()).hasSizeLessThanOrEqualTo(34); + }); + assertThat(request.getValue().documents().get(0).skuRows()).hasSize(34); + assertThat(request.getValue().documents().get(1).skuRows()).hasSize(1); + } + @Test void forwardsStableLabelsWithoutSkuAndOnlySafePdfHeaders() throws Exception { when(labels.list(10001L, 70001L, List.of(1))).thenReturn(batch()); diff --git a/print/src/main/java/com/baiyue/print/controller/PrintRequestSizeFilter.java b/print/src/main/java/com/baiyue/print/controller/PrintRequestSizeFilter.java index 00215973d..c6c4a9375 100644 --- a/print/src/main/java/com/baiyue/print/controller/PrintRequestSizeFilter.java +++ b/print/src/main/java/com/baiyue/print/controller/PrintRequestSizeFilter.java @@ -31,6 +31,7 @@ public class PrintRequestSizeFilter extends OncePerRequestFilter { private static final java.util.Set PATHS = java.util.Set.of( "/internal/print/v1/pdfs/inbound-marks", "/internal/print/v1/pdfs/fba-pallet-labels", + "/internal/print/v1/pdfs/dropship-pallet-a4-documents", "/internal/print/v1/pdfs/freight-a4-documents"); @Resource private PrintPdfProperties properties; diff --git a/print/src/test/java/com/baiyue/print/controller/PrintRequestSizeFilterTest.java b/print/src/test/java/com/baiyue/print/controller/PrintRequestSizeFilterTest.java index 2e24244e3..0ed8c97fc 100644 --- a/print/src/test/java/com/baiyue/print/controller/PrintRequestSizeFilterTest.java +++ b/print/src/test/java/com/baiyue/print/controller/PrintRequestSizeFilterTest.java @@ -62,6 +62,17 @@ class PrintRequestSizeFilterTest { assertTooLarge(response); } + @Test + void capsDropshipPalletRequestsBeforeDeserialization() throws Exception { + var response = new MockHttpServletResponse(); + AtomicReference called = new AtomicReference<>(false); + filter.doFilter(request("12345678901", true, + "/internal/print/v1/pdfs/dropship-pallet-a4-documents"), response, + (ignoredRequest, ignoredResponse) -> called.set(true)); + assertThat(called).hasValue(false); + assertTooLarge(response); + } + @Test void rejectsOversizedDeclaredContentLengthWithoutCallingDownstream() throws Exception { MockHttpServletRequest request = new MockHttpServletRequest() {