diff --git a/print/AGENTS.md b/print/AGENTS.md index 28efab4c8..0e81b655c 100644 --- a/print/AGENTS.md +++ b/print/AGENTS.md @@ -5,7 +5,7 @@ - 本模块是无数据库的无状态 PDF 渲染服务;调用方传入完整 `labels[]` 或 `documents[]`,模块在内存中生成一次性多页 PDF 并同步返回。 - 不保存模板、任务、历史或文件,不连接数据库、File 服务或打印机,不反查或修正业务数据。 - `INBOUND_MARK_V1` 箱唛不接收或展示 SKU(包括一件代发箱唛),二维码仅编码稳定箱码;SKU 明细由一件代发 A4 托盘信息单展示,不能重新加入箱唛版面。 -- 当前支持 `INBOUND_MARK_V1`(100×100 mm)、`FBA_PALLET_A4_LANDSCAPE_V1`(297×210 mm),以及纵向 A4 的 `DROPSHIP_PALLET_A4_V2`、`SEA_FREIGHT_SHIPPING_INSTRUCTION_A4_V1`、`BILL_OF_LADING_CONFIRMATION_A4_V1`、`DISPATCH_BILL_OF_LADING_A4_V2`。FBA 模板由国内和海外统一使用,每托一页,只展示 SCK8 等 FBA 仓码、完整托盘号的 Code 128 条码和完整托盘号;141 等内部编号保留在托盘号中。一件代发每托一页,展示托盘 Code 128、目的仓、最多 10 行入仓码/客户昵称和最多 34 行 SKU,不展示状态、重量或体积。新尺寸或布局必须使用新模板编码。 +- 当前只有箱唛 `INBOUND_MARK_V1` 使用 100×100 mm;托盘标不得复用该模板。横向 A4 托盘模板包括 `FBA_PALLET_A4_LANDSCAPE_V1` 与 `PALLET_A4_LANDSCAPE_V1`,纵向 A4 包括 `DROPSHIP_PALLET_A4_V2`,其他 A4 单据为 `SEA_FREIGHT_SHIPPING_INSTRUCTION_A4_V1`、`BILL_OF_LADING_CONFIRMATION_A4_V1`、`DISPATCH_BILL_OF_LADING_A4_V2`。FBA 模板由国内和海外统一使用,每托一页,只展示 SCK8 等 FBA 仓码、完整托盘号的 Code 128 条码和完整托盘号;141 等内部编号保留在托盘号中。一件代发展示托盘 Code 128、目的仓、每页最多 10 行入仓码/客户昵称和 34 行 SKU,超量由调用方按同一托盘自动续页,不展示状态、重量或体积。新尺寸或布局必须使用新模板编码。 ## 快速索引 @@ -13,6 +13,7 @@ |---|---| | 调用方接入指南 | `README.md` | | 国内/海外统一 FBA 托盘标 | `dto/FbaPalletPdfDtos.java`、`service/FbaPalletPdfService.java`、`renderer/FbaPalletRenderer.java`;内部 `/internal/print/v1/pdfs/fba-pallet-labels`,回归 `src/test/java/com/baiyue/print/service/FbaPalletPdfServiceTest.java` | +| 非 FBA 通用托盘标 | `dto/GenericPalletPdfDtos.java`、`service/GenericPalletPdfService.java`、`renderer/GenericPalletRenderer.java`;内部 `/internal/print/v1/pdfs/pallet-a4-labels` | | 应用入口 | `src/main/java/com/baiyue/print/PrintServiceApplication.java` | | 健康状态 API | `controller/PrintHealthController.java`(`/api/platform/v1/print/status`) | | 内部 PDF API | `controller/InternalPdfController.java`(`/internal/print/v1/pdfs/inbound-marks`、`/internal/print/v1/pdfs/dropship-pallet-a4-documents`、`/internal/print/v1/pdfs/freight-a4-documents`) | diff --git a/print/src/main/java/com/baiyue/print/controller/InternalPdfController.java b/print/src/main/java/com/baiyue/print/controller/InternalPdfController.java index 73caf2a75..ec8cdeaa8 100644 --- a/print/src/main/java/com/baiyue/print/controller/InternalPdfController.java +++ b/print/src/main/java/com/baiyue/print/controller/InternalPdfController.java @@ -5,7 +5,9 @@ import jakarta.annotation.Resource; import com.baiyue.common.web.CorrelationContext; import com.baiyue.print.dto.FreightA4PdfDtos; import com.baiyue.print.dto.FbaPalletPdfDtos; +import com.baiyue.print.dto.GenericPalletPdfDtos; import com.baiyue.print.service.FbaPalletPdfService; +import com.baiyue.print.service.GenericPalletPdfService; import com.baiyue.print.dto.DispatchBolPdfDtos; import com.baiyue.print.dto.DropshipPalletA4PdfDtos; import com.baiyue.print.dto.InboundMarkPdfDtos; @@ -39,6 +41,7 @@ public class InternalPdfController { @Resource private DispatchBolPdfService dispatchBolPdfService; @Resource private DropshipPalletA4PdfService dropshipPalletA4PdfService; @Resource private FbaPalletPdfService fbaPalletPdfService; + @Resource private GenericPalletPdfService genericPalletPdfService; @Resource private InternalServiceTokenGuard tokenGuard; @PostMapping(value = "/fba-pallet-labels", consumes = MediaType.APPLICATION_JSON_VALUE) @@ -54,6 +57,19 @@ public class InternalPdfController { .contentType(MediaType.APPLICATION_PDF).contentLength(content.length).body(content); } + @PostMapping(value = "/pallet-a4-labels", consumes = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity generatePalletA4Labels( + @RequestHeader(value = INTERNAL_TOKEN_HEADER, required = false) String internalToken, + @Valid @RequestBody GenericPalletPdfDtos.Request request) { + tokenGuard.verify(internalToken); + GenericPalletPdfService.GeneratedPdf pdf = genericPalletPdfService.generate(request); + byte[] content = pdf.content(); + return ResponseEntity.ok().cacheControl(CacheControl.noStore()).header(HttpHeaders.PRAGMA, "no-cache") + .header(HttpHeaders.CONTENT_DISPOSITION, ContentDisposition.attachment().filename(pdf.fileName(), StandardCharsets.UTF_8).build().toString()) + .header("X-Content-Type-Options", "nosniff").header(PAGE_COUNT_HEADER, Integer.toString(pdf.pageCount())) + .contentType(MediaType.APPLICATION_PDF).contentLength(content.length).body(content); + } + @PostMapping(value = "/inbound-marks", consumes = MediaType.APPLICATION_JSON_VALUE) public ResponseEntity generateInboundMarks( @RequestHeader(value = INTERNAL_TOKEN_HEADER, required = false) String internalToken, 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 c6c4a9375..2d726108b 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/pallet-a4-labels", "/internal/print/v1/pdfs/dropship-pallet-a4-documents", "/internal/print/v1/pdfs/freight-a4-documents"); diff --git a/print/src/main/java/com/baiyue/print/dto/GenericPalletPdfDtos.java b/print/src/main/java/com/baiyue/print/dto/GenericPalletPdfDtos.java new file mode 100644 index 000000000..c990eecef --- /dev/null +++ b/print/src/main/java/com/baiyue/print/dto/GenericPalletPdfDtos.java @@ -0,0 +1,13 @@ +package com.baiyue.print.dto; + +import java.math.BigDecimal; +import java.util.List; + +public final class GenericPalletPdfDtos { + public static final String TEMPLATE = "PALLET_A4_LANDSCAPE_V1"; + private GenericPalletPdfDtos() {} + + public record Request(String templateCode, PageSpec pageSpec, String downloadFileName, List