fix: paginate dropship pallet print details
This commit is contained in:
+29
-4
@@ -32,6 +32,8 @@ public class InboundCartonLabelPrintService {
|
|||||||
private static final BigDecimal PAGE_MM = new BigDecimal("100");
|
private static final BigDecimal PAGE_MM = new BigDecimal("100");
|
||||||
private static final BigDecimal A4_WIDTH_MM = new BigDecimal("210");
|
private static final BigDecimal A4_WIDTH_MM = new BigDecimal("210");
|
||||||
private static final BigDecimal A4_HEIGHT_MM = new BigDecimal("297");
|
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<String> SAFE_RESPONSE_HEADERS = List.of(
|
private static final List<String> SAFE_RESPONSE_HEADERS = List.of(
|
||||||
HttpHeaders.CONTENT_DISPOSITION, HttpHeaders.CACHE_CONTROL, HttpHeaders.PRAGMA,
|
HttpHeaders.CONTENT_DISPOSITION, HttpHeaders.CACHE_CONTROL, HttpHeaders.PRAGMA,
|
||||||
"X-Print-Page-Count", "X-Request-Id", "X-Trace-Id");
|
"X-Print-Page-Count", "X-Request-Id", "X-Trace-Id");
|
||||||
@@ -134,7 +136,7 @@ public class InboundCartonLabelPrintService {
|
|||||||
}
|
}
|
||||||
Map<Long, String> customerNicknameCache = new HashMap<>();
|
Map<Long, String> customerNicknameCache = new HashMap<>();
|
||||||
List<PrintPdfClient.DropshipPalletDocument> documents = pallets.stream()
|
List<PrintPdfClient.DropshipPalletDocument> documents = pallets.stream()
|
||||||
.map(pallet -> dropshipPalletDocument(pallet, customerNicknameCache)).toList();
|
.flatMap(pallet -> dropshipPalletDocuments(pallet, customerNicknameCache).stream()).toList();
|
||||||
String fileName = pallets.size() == 1
|
String fileName = pallets.size() == 1
|
||||||
? pallets.get(0).palletNo() + "-A4托盘信息单.pdf"
|
? pallets.get(0).palletNo() + "-A4托盘信息单.pdf"
|
||||||
: inboundCode + "-" + pallets.size() + "托-A4托盘信息单.pdf";
|
: inboundCode + "-" + pallets.size() + "托-A4托盘信息单.pdf";
|
||||||
@@ -148,7 +150,7 @@ public class InboundCartonLabelPrintService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private PrintPdfClient.DropshipPalletDocument dropshipPalletDocument(
|
private List<PrintPdfClient.DropshipPalletDocument> dropshipPalletDocuments(
|
||||||
Pallet pallet, Map<Long, String> customerNicknameCache) {
|
Pallet pallet, Map<Long, String> customerNicknameCache) {
|
||||||
if (pallet == null || pallet.palletId() == null || !StringUtils.hasText(pallet.palletNo())) {
|
if (pallet == null || pallet.palletId() == null || !StringUtils.hasText(pallet.palletNo())) {
|
||||||
throw new BizException(ResultCode.CONFLICT, "托盘码尚未生成,不能打印");
|
throw new BizException(ResultCode.CONFLICT, "托盘码尚未生成,不能打印");
|
||||||
@@ -172,8 +174,31 @@ public class InboundCartonLabelPrintService {
|
|||||||
.stream().map(row -> new PrintPdfClient.DropshipPalletSkuRow(
|
.stream().map(row -> new PrintPdfClient.DropshipPalletSkuRow(
|
||||||
row.getSkuCode(), number(row.getCartonCount()), number(row.getItemQuantity()),
|
row.getSkuCode(), number(row.getCartonCount()), number(row.getItemQuantity()),
|
||||||
unitsPerCarton(row))).toList();
|
unitsPerCarton(row))).toList();
|
||||||
return new PrintPdfClient.DropshipPalletDocument(
|
int pageCount = Math.max(1, Math.max(pageCount(inboundRows.size(), DROPSHIP_INBOUND_ROWS_PER_PAGE),
|
||||||
pallet.palletNo(), destinationWarehouse, pallet.palletNo(), inboundRows, skuRows);
|
pageCount(skuRows.size(), DROPSHIP_SKU_ROWS_PER_PAGE)));
|
||||||
|
List<PrintPdfClient.DropshipPalletDocument> 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 <T> List<T> page(List<T> 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 <T> List<T> pageOrRepeat(List<T> rows, int page, int pageSize) {
|
||||||
|
List<T> selected = page(rows, page, pageSize);
|
||||||
|
return selected.isEmpty() ? page(rows, 0, pageSize) : selected;
|
||||||
}
|
}
|
||||||
|
|
||||||
private String unitsPerCarton(DropshipPalletizationMapper.PrintSkuRow row) {
|
private String unitsPerCarton(DropshipPalletizationMapper.PrintSkuRow row) {
|
||||||
|
|||||||
+38
@@ -18,6 +18,7 @@ import org.springframework.http.ResponseEntity;
|
|||||||
import org.springframework.test.util.ReflectionTestUtils;
|
import org.springframework.test.util.ReflectionTestUtils;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
@@ -108,6 +109,43 @@ class InboundCartonLabelPrintServiceTest {
|
|||||||
assertThat(response.getBody()).containsExactly(4, 5, 6);
|
assertThat(response.getBody()).containsExactly(4, 5, 6);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void splitsLargeDropshipPalletDetailsAcrossPrintableA4Pages() {
|
||||||
|
Pallet pallet = dropshipPallet("OPEN");
|
||||||
|
stubPalletFacts(90001L);
|
||||||
|
List<DropshipPalletizationMapper.PrintSkuRow> 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<PrintPdfClient.DropshipPalletA4PdfRequest> 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
|
@Test
|
||||||
void forwardsStableLabelsWithoutSkuAndOnlySafePdfHeaders() throws Exception {
|
void forwardsStableLabelsWithoutSkuAndOnlySafePdfHeaders() throws Exception {
|
||||||
when(labels.list(10001L, 70001L, List.of(1))).thenReturn(batch());
|
when(labels.list(10001L, 70001L, List.of(1))).thenReturn(batch());
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ public class PrintRequestSizeFilter extends OncePerRequestFilter {
|
|||||||
private static final java.util.Set<String> PATHS = java.util.Set.of(
|
private static final java.util.Set<String> PATHS = java.util.Set.of(
|
||||||
"/internal/print/v1/pdfs/inbound-marks",
|
"/internal/print/v1/pdfs/inbound-marks",
|
||||||
"/internal/print/v1/pdfs/fba-pallet-labels",
|
"/internal/print/v1/pdfs/fba-pallet-labels",
|
||||||
|
"/internal/print/v1/pdfs/dropship-pallet-a4-documents",
|
||||||
"/internal/print/v1/pdfs/freight-a4-documents");
|
"/internal/print/v1/pdfs/freight-a4-documents");
|
||||||
|
|
||||||
@Resource private PrintPdfProperties properties;
|
@Resource private PrintPdfProperties properties;
|
||||||
|
|||||||
@@ -62,6 +62,17 @@ class PrintRequestSizeFilterTest {
|
|||||||
assertTooLarge(response);
|
assertTooLarge(response);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void capsDropshipPalletRequestsBeforeDeserialization() throws Exception {
|
||||||
|
var response = new MockHttpServletResponse();
|
||||||
|
AtomicReference<Boolean> 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
|
@Test
|
||||||
void rejectsOversizedDeclaredContentLengthWithoutCallingDownstream() throws Exception {
|
void rejectsOversizedDeclaredContentLengthWithoutCallingDownstream() throws Exception {
|
||||||
MockHttpServletRequest request = new MockHttpServletRequest() {
|
MockHttpServletRequest request = new MockHttpServletRequest() {
|
||||||
|
|||||||
Reference in New Issue
Block a user