Files
baiyue-firstleg/warehouse-overseas-service/src/main/java/com/baiyue/warehouse/service/PalletLabelPrintService.java
T
2026-09-17 17:37:29 +08:00

76 lines
4.4 KiB
Java

package com.baiyue.warehouse.service;
import com.baiyue.common.core.api.ResultCode;
import com.baiyue.common.core.exception.BizException;
import com.baiyue.warehouse.client.PrintPdfClient;
import feign.FeignException;
import jakarta.annotation.Resource;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.util.List;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.client.circuitbreaker.NoFallbackAvailableException;
import org.springframework.http.ContentDisposition;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
@Service
public class PalletLabelPrintService {
@Resource private WarehouseResourceService resources;
@Resource private DomesticWarehouseDirectory warehouses;
@Resource private PrintPdfClient print;
@Value("${baiyue.security.internal-service-token:${baiyue.internal-service.token}}")
private String internalToken;
public ResponseEntity<byte[]> print(long warehouseId, long palletId, String requestId) {
return print(warehouseId, palletId, requestId, "PALLET");
}
public ResponseEntity<byte[]> printTransfer(long warehouseId, long palletId, String transferNo,
String requestId) {
String reference = transferNo == null || transferNo.isBlank() ? "转运单" : "转运单 " + transferNo.trim();
return print(warehouseId, palletId, requestId, reference);
}
private ResponseEntity<byte[]> print(long warehouseId, long palletId, String requestId, String reference) {
var pallet = resources.pallet(WarehouseResourceService.PUBLIC_RESOURCE_SCOPE, warehouseId, palletId);
String code = pallet.getPalletCode();
String fbaCode = pallet.getFbaWarehouseCode();
boolean fba = fbaCode != null && !fbaCode.isBlank();
int maxCodeLength = fba ? 80 : 34;
// Preserve the authoritative pallet identity on both the barcode and visible text.
if (code == null || !code.matches("[\\x20-\\x7E]{1," + maxCodeLength + "}") || code.isBlank()
|| !code.equals(code.strip())) {
throw new BizException(ResultCode.VALIDATION_FAILED, "当前标签模板要求托盘编码为 1–" + maxCodeLength + " 位可打印 ASCII 字符,且无首尾空格,请核对托盘编码");
}
var warehouse = warehouses.required(warehouseId);
String fileName = code.replaceAll("[\\\\/:*?\"<>|]", "-") + "-托盘码.pdf";
var label = new PrintPdfClient.Label(code,
fbaCode == null || fbaCode.isBlank() ? "目的仓待定" : fbaCode,
reference, warehouse.warehouseName(), code);
var request = new PrintPdfClient.Request("INBOUND_MARK_V1",
new PrintPdfClient.PageSpec(new BigDecimal("100"), new BigDecimal("100")), fileName, List.of(label));
try {
var response = fba
? print.generateFbaPalletLabels(internalToken, requestId, new PrintPdfClient.FbaPalletRequest(
"FBA_PALLET_A4_LANDSCAPE_V1", new PrintPdfClient.PageSpec(new BigDecimal("297"), new BigDecimal("210")),
fileName, List.of(new PrintPdfClient.FbaPalletLabel(fbaCode, code))))
: print.generateInboundMarks(internalToken, requestId, request);
byte[] body = response == null ? null : response.getBody();
MediaType type = response == null ? null : response.getHeaders().getContentType();
if (response == null || !response.getStatusCode().is2xxSuccessful() || body == null || body.length == 0
|| type == null || !MediaType.APPLICATION_PDF.isCompatibleWith(type)) {
throw new BizException(ResultCode.SERVICE_UNAVAILABLE, "打印服务未返回有效 PDF,请稍后重试");
}
return ResponseEntity.ok().contentType(MediaType.APPLICATION_PDF).contentLength(body.length)
.header(HttpHeaders.CONTENT_DISPOSITION,
ContentDisposition.attachment().filename(fileName, StandardCharsets.UTF_8).build().toString())
.header(HttpHeaders.CACHE_CONTROL, "no-store").body(body);
} catch (FeignException | NoFallbackAvailableException exception) {
throw new BizException(ResultCode.SERVICE_UNAVAILABLE, "打印服务暂不可用,请稍后重试");
}
}
}