Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1d95298e5d |
@@ -64,6 +64,7 @@ public class DispatchBolPdfService {
|
|||||||
return new DispatchBolPdfDtos.Request(DispatchBolPdfDtos.TEMPLATE, request.pageSpec(), fileName, List.copyOf(documents));
|
return new DispatchBolPdfDtos.Request(DispatchBolPdfDtos.TEMPLATE, request.pageSpec(), fileName, List.copyOf(documents));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 核对页面容量并规范化打印字段,预约号缺失时保持空白。 */
|
||||||
private DispatchBolPdfDtos.Document normalizeDocument(DispatchBolPdfDtos.Document value, int index) {
|
private DispatchBolPdfDtos.Document normalizeDocument(DispatchBolPdfDtos.Document value, int index) {
|
||||||
int maxRows = value != null && value.pageNumber() == 1 ? MAX_FIRST_PAGE_ROWS : MAX_CONTINUATION_PAGE_ROWS;
|
int maxRows = value != null && value.pageNumber() == 1 ? MAX_FIRST_PAGE_ROWS : MAX_CONTINUATION_PAGE_ROWS;
|
||||||
if (value == null || value.cargoRows() == null || value.cargoRows().isEmpty() || value.cargoRows().size() > maxRows) {
|
if (value == null || value.cargoRows() == null || value.cargoRows().isEmpty() || value.cargoRows().size() > maxRows) {
|
||||||
@@ -77,15 +78,22 @@ public class DispatchBolPdfService {
|
|||||||
text(row.warehouseNo()), text(row.fbaShipmentId()), text(row.poReferenceNo()), row.packageCount()));
|
text(row.warehouseNo()), text(row.fbaShipmentId()), text(row.poReferenceNo()), row.packageCount()));
|
||||||
}
|
}
|
||||||
return new DispatchBolPdfDtos.Document(text(value.shipFromName()), text(value.shipFromAddress()), text(value.carrierName()),
|
return new DispatchBolPdfDtos.Document(text(value.shipFromName()), text(value.shipFromAddress()), text(value.carrierName()),
|
||||||
text(value.isaNumber()), text(value.appointmentTime()), text(value.trailerNumber()), text(value.sealNumber()),
|
optionalText(value.isaNumber()), text(value.appointmentTime()), text(value.trailerNumber()), text(value.sealNumber()),
|
||||||
text(value.fbaWarehouseCode()), text(value.shipToName()), text(value.shipToAddress()), text(value.dispatchNo()),
|
text(value.fbaWarehouseCode()), text(value.shipToName()), text(value.shipToAddress()), text(value.dispatchNo()),
|
||||||
text(value.fbaShipmentIds()), text(value.poReferenceNos()), value.totalPackages(), value.pageNumber(), value.pageCount(), List.copyOf(rows));
|
text(value.fbaShipmentIds()), text(value.poReferenceNos()), value.totalPackages(), value.pageNumber(), value.pageCount(), List.copyOf(rows));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 普通缺失字段沿用占位符,预约号通过可空文本单独处理。 */
|
||||||
private String text(String value) {
|
private String text(String value) {
|
||||||
|
String normalized = optionalText(value);
|
||||||
|
return normalized.isBlank() ? "—" : normalized;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 保留空白语义,同时复用长度、规范化和控制字符校验。 */
|
||||||
|
private String optionalText(String value) {
|
||||||
String normalized = line(value);
|
String normalized = line(value);
|
||||||
if (normalized.codePointCount(0, normalized.length()) > 300 || normalized.codePoints().anyMatch(c -> Character.isISOControl(c))) invalid("document text is invalid");
|
if (normalized.codePointCount(0, normalized.length()) > 300 || normalized.codePoints().anyMatch(c -> Character.isISOControl(c))) invalid("document text is invalid");
|
||||||
return normalized.isBlank() ? "—" : normalized;
|
return normalized;
|
||||||
}
|
}
|
||||||
private String line(String value) { return value == null ? "" : Normalizer.normalize(value, Normalizer.Form.NFC).strip(); }
|
private String line(String value) { return value == null ? "" : Normalizer.normalize(value, Normalizer.Form.NFC).strip(); }
|
||||||
private void invalid(String message) { throw new BizException(ResultCode.VALIDATION_FAILED, message); }
|
private void invalid(String message) { throw new BizException(ResultCode.VALIDATION_FAILED, message); }
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package com.baiyue.print.service;
|
package com.baiyue.print.service;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||||
|
|
||||||
import com.baiyue.print.config.PrintPdfProperties;
|
import com.baiyue.print.config.PrintPdfProperties;
|
||||||
import com.baiyue.print.dto.DispatchBolPdfDtos;
|
import com.baiyue.print.dto.DispatchBolPdfDtos;
|
||||||
@@ -73,6 +74,45 @@ class DispatchBolPdfServiceGenerationTest {
|
|||||||
"FBA19TEST", "PO-TEST", 44, pageNumber, pageCount, rows);
|
"FBA19TEST", "PO-TEST", 44, pageNumber, pageCount, rows);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 未预约仍能生成真实PDF,预约栏不打印占位符或null。 */
|
||||||
|
@Test
|
||||||
|
void leavesMissingAppointmentNumbersBlankInTheRenderedPdf() throws Exception {
|
||||||
|
for (String appointment : new String[] { null, "", " " }) {
|
||||||
|
var generated = service.generate(appointmentRequest(appointment));
|
||||||
|
try (PDDocument pdf = Loader.loadPDF(generated.content())) {
|
||||||
|
assertThat(pdf.getNumberOfPages()).isEqualTo(1);
|
||||||
|
assertThat(new PDFTextStripper().getText(pdf)).contains("ISA #:", "BILL OF LADING", "PALLET-01")
|
||||||
|
.doesNotContain("ISA #: —", "ISA #: null");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 空值放开不削弱预约文本的长度和控制字符边界。 */
|
||||||
|
@Test
|
||||||
|
void keepsAppointmentTextValidationAndTrimsPresentNumbers() throws Exception {
|
||||||
|
assertThatThrownBy(() -> service.generate(appointmentRequest("ISA\u0000BAD")))
|
||||||
|
.isInstanceOf(com.baiyue.common.core.exception.BizException.class);
|
||||||
|
assertThatThrownBy(() -> service.generate(appointmentRequest("A".repeat(301))))
|
||||||
|
.isInstanceOf(com.baiyue.common.core.exception.BizException.class);
|
||||||
|
var generated = service.generate(appointmentRequest(" ISA-ONE "));
|
||||||
|
try (PDDocument pdf = Loader.loadPDF(generated.content())) {
|
||||||
|
assertThat(new PDFTextStripper().getText(pdf)).contains("ISA #: ISA-ONE");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 只替换预约字段,其他页面参数使用既有真实渲染夹具。 */
|
||||||
|
private DispatchBolPdfDtos.Request appointmentRequest(String appointment) {
|
||||||
|
var original = page(1, 1, rows(1, 1));
|
||||||
|
var document = new DispatchBolPdfDtos.Document(original.shipFromName(), original.shipFromAddress(),
|
||||||
|
original.carrierName(), appointment, original.appointmentTime(), original.trailerNumber(),
|
||||||
|
original.sealNumber(), original.fbaWarehouseCode(), original.shipToName(), original.shipToAddress(),
|
||||||
|
original.dispatchNo(), original.fbaShipmentIds(), original.poReferenceNos(), original.totalPackages(),
|
||||||
|
original.pageNumber(), original.pageCount(), original.cargoRows());
|
||||||
|
return new DispatchBolPdfDtos.Request(DispatchBolPdfDtos.TEMPLATE,
|
||||||
|
new DispatchBolPdfDtos.PageSpec(new BigDecimal("210"), new BigDecimal("297")),
|
||||||
|
"appointment-bol.pdf", List.of(document));
|
||||||
|
}
|
||||||
|
|
||||||
private List<DispatchBolPdfDtos.CargoRow> rows(int start, int end) {
|
private List<DispatchBolPdfDtos.CargoRow> rows(int start, int end) {
|
||||||
List<DispatchBolPdfDtos.CargoRow> rows = new ArrayList<>();
|
List<DispatchBolPdfDtos.CargoRow> rows = new ArrayList<>();
|
||||||
for (int index = start; index <= end; index++) {
|
for (int index = start; index <= end; index++) {
|
||||||
|
|||||||
Reference in New Issue
Block a user