修复海外散货托盘收货与短少入库闭环

This commit is contained in:
2026-11-04 09:57:14 +08:00
parent b95281bacb
commit 2eb0b65ba5
10 changed files with 273 additions and 71 deletions
@@ -7,12 +7,21 @@ import com.baiyue.print.dto.GenericPalletPdfDtos;
import com.baiyue.print.renderer.GenericPalletRenderer;
import com.baiyue.print.renderer.PdfBarcodeRenderer;
import com.baiyue.print.renderer.PdfUnits;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.BinaryBitmap;
import com.google.zxing.DecodeHintType;
import com.google.zxing.MultiFormatReader;
import com.google.zxing.RGBLuminanceSource;
import com.google.zxing.common.HybridBinarizer;
import java.math.BigDecimal;
import java.nio.file.Files;
import java.nio.file.Path;
import java.text.Normalizer;
import java.util.List;
import java.util.Map;
import org.apache.pdfbox.Loader;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.rendering.PDFRenderer;
import org.apache.pdfbox.text.PDFTextStripper;
import org.junit.jupiter.api.Test;
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
@@ -22,22 +31,43 @@ import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
class GenericPalletPdfServiceGenerationTest {
@jakarta.annotation.Resource private GenericPalletPdfService service;
/** 从真实横向 A4 PDF 反解短码和最长托盘码,同时核对中文、页序和字体嵌入。 */
@Test
void generatesLandscapeA4WithoutUsingTheCartonMarkTemplate() throws Exception {
var labels = List.of(
new GenericPalletPdfDtos.Label("Los Angeles Warehouse", "Transfer WTR-1", "PALLET-001"),
new GenericPalletPdfDtos.Label("洛杉矶收货仓", "入库单 IP-DEMO-1", "D0001-IN-DEMO-001"),
new GenericPalletPdfDtos.Label("Private warehouse", "入库单 IP-DEMO-2", "A".repeat(80)));
var generated = service.generate(new GenericPalletPdfDtos.Request(
GenericPalletPdfDtos.TEMPLATE,
new GenericPalletPdfDtos.PageSpec(new BigDecimal("297"), new BigDecimal("210")),
"pallet.pdf", List.of(new GenericPalletPdfDtos.Label(
"Los Angeles Warehouse", "Transfer WTR-1", "PALLET-001"))));
"pallet.pdf", labels));
Files.createDirectories(Path.of("target"));
Files.write(Path.of("target", "generic-pallet-a4-preview.pdf"), generated.content());
try (PDDocument pdf = Loader.loadPDF(generated.content())) {
assertThat(pdf.getNumberOfPages()).isEqualTo(1);
assertThat(pdf.getPage(0).getMediaBox().getWidth()).isCloseTo(PdfUnits.mmToPt(297), org.assertj.core.data.Offset.offset(.002f));
assertThat(pdf.getPage(0).getMediaBox().getHeight()).isCloseTo(PdfUnits.mmToPt(210), org.assertj.core.data.Offset.offset(.002f));
assertThat(new PDFTextStripper().getText(pdf)).contains(
"Los Angeles Warehouse", "Transfer WTR-1", "PALLET-001");
assertThat(pdf.getNumberOfPages()).isEqualTo(labels.size());
var renderer = new PDFRenderer(pdf);
for (int index = 0; index < labels.size(); index++) {
var page = pdf.getPage(index);
assertThat(page.getMediaBox().getWidth()).isCloseTo(PdfUnits.mmToPt(297), org.assertj.core.data.Offset.offset(.002f));
assertThat(page.getMediaBox().getHeight()).isCloseTo(PdfUnits.mmToPt(210), org.assertj.core.data.Offset.offset(.002f));
var stripper = new PDFTextStripper();
stripper.setStartPage(index + 1); stripper.setEndPage(index + 1);
var label = labels.get(index);
// 字体的共享字形可能反解为康熙部首,中文语义按 Unicode 兼容标准化核对。
assertThat(Normalizer.normalize(stripper.getText(pdf), Normalizer.Form.NFKC))
.contains(label.heading(), label.reference(), label.palletCode());
for (var name : page.getResources().getFontNames()) {
assertThat(page.getResources().getFont(name).isEmbedded()).isTrue();
}
var image = renderer.renderImageWithDPI(index, 300);
var source = new RGBLuminanceSource(image.getWidth(), image.getHeight(),
image.getRGB(0, 0, image.getWidth(), image.getHeight(), null, 0, image.getWidth()));
var decoded = new MultiFormatReader().decode(new BinaryBitmap(new HybridBinarizer(source)),
Map.of(DecodeHintType.POSSIBLE_FORMATS, List.of(BarcodeFormat.CODE_128)));
assertThat(decoded.getText()).isEqualTo(label.palletCode());
}
}
}
}