feat(file-print): support ocean booking documents
This commit is contained in:
@@ -172,6 +172,11 @@ class InternalPdfControllerTest {
|
||||
.contains("application/pdf:")
|
||||
.contains("application/json:")
|
||||
.contains("name: X-Internal-Service-Token")
|
||||
.contains("SEA_FREIGHT_SHIPPING_INSTRUCTION_A4_V1:")
|
||||
.contains("BILL_OF_LADING_CONFIRMATION_A4_V1:")
|
||||
.contains("additionalProperties: false")
|
||||
.contains("minItems: 1")
|
||||
.contains("required: [marksAndNos, quantity, packaging, descriptionOfGoods, grossWeight, measurement]")
|
||||
.contains("maximum: 2000");
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.baiyue.print.renderer;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
class FreightA4ChineseLayoutContractTest {
|
||||
@Test
|
||||
void freezesChineseTitlesAndBilingualLayoutLabels() throws Exception {
|
||||
String source = Files.readString(Path.of(
|
||||
"src/main/java/com/baiyue/print/renderer/FreightA4Renderer.java"));
|
||||
|
||||
assertThat(source).contains(
|
||||
"出口货物托运单", "提单确认件",
|
||||
"Shipper(Full Name & Address)(托运人)", "Consignee(收货人)", "Notify Party(通知人)",
|
||||
"Ocean Vessel/Voy(船名航次)", "Port of Loading(起运港)",
|
||||
"Part of Discharge(卸货港)", "Place of Delivery(交货地)",
|
||||
"Marks & Nos\\n(标志和号码)", "Description of Goods(品名)",
|
||||
"Gross Weight(Kilos)\\n毛重(公斤)", "Measurement(CBM)\\n体积(立方米)",
|
||||
"截关日期", "预计开航日期", "SHIPPED ON BOARD");
|
||||
}
|
||||
}
|
||||
@@ -37,7 +37,8 @@ class FreightA4PdfServiceGenerationTest {
|
||||
assertA4(document);
|
||||
String text = new PDFTextStripper().getText(document);
|
||||
assertThat(text).contains("Sea Freight Shipping Instructions", "Job Nbr",
|
||||
"BYSE2607044", "CAR ACCESSORIES", "SAY SIX HUNDRED AND FIFTY NINE PACKAGES ONLY.");
|
||||
"BYSE2607044", "CAR ACCESSORIES",
|
||||
"SAY SIX HUNDRED AND FIFTY NINE PACKAGES ONLY.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+71
-6
@@ -25,7 +25,7 @@ class FreightA4PdfServiceValidationTest {
|
||||
@Test
|
||||
void rejectsUnsupportedTemplateCode() {
|
||||
assertValidationFailure(new FreightA4PdfDtos.Request("UNKNOWN",
|
||||
pageSpec(), "a4.pdf", List.of(document())), "templateCode");
|
||||
pageSpec(), "a4.pdf", List.of(shippingDocument())), "templateCode");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -33,18 +33,59 @@ class FreightA4PdfServiceValidationTest {
|
||||
assertValidationFailure(new FreightA4PdfDtos.Request(
|
||||
FreightA4PdfDtos.SHIPPING_INSTRUCTION_TEMPLATE,
|
||||
new FreightA4PdfDtos.PageSpec(new BigDecimal("100"), new BigDecimal("100")),
|
||||
"a4.pdf", List.of(document())), "pageSpec.widthMm");
|
||||
"a4.pdf", List.of(shippingDocument())), "pageSpec.widthMm");
|
||||
}
|
||||
|
||||
@Test
|
||||
void allowsMultilineDocumentFields() {
|
||||
FreightA4PdfDtos.Request request = new FreightA4PdfDtos.Request(
|
||||
FreightA4PdfDtos.SHIPPING_INSTRUCTION_TEMPLATE,
|
||||
pageSpec(), "a4.pdf", List.of(document()));
|
||||
pageSpec(), "a4.pdf", List.of(shippingDocument()));
|
||||
|
||||
assertThatCode(() -> service.generate(request)).doesNotThrowAnyException();
|
||||
}
|
||||
|
||||
@Test
|
||||
void rejectsMissingRequiredFieldForSelectedTemplate() {
|
||||
var fields = new java.util.HashMap<>(shippingDocument().fields());
|
||||
fields.remove("jobNumber");
|
||||
assertValidationFailure(request(FreightA4PdfDtos.SHIPPING_INSTRUCTION_TEMPLATE,
|
||||
new FreightA4PdfDtos.Document(fields, cargoRows())), "fields.jobNumber is required");
|
||||
}
|
||||
|
||||
@Test
|
||||
void rejectsUnknownFieldInsteadOfSilentlyIgnoringTypo() {
|
||||
var fields = new java.util.HashMap<>(shippingDocument().fields());
|
||||
fields.put("jobNubmer", "OB-260831-0001");
|
||||
assertValidationFailure(request(FreightA4PdfDtos.SHIPPING_INSTRUCTION_TEMPLATE,
|
||||
new FreightA4PdfDtos.Document(fields, cargoRows())), "fields.jobNubmer is not supported");
|
||||
}
|
||||
|
||||
@Test
|
||||
void requiresExactlyOneCompleteCargoRow() {
|
||||
assertValidationFailure(request(FreightA4PdfDtos.SHIPPING_INSTRUCTION_TEMPLATE,
|
||||
new FreightA4PdfDtos.Document(shippingDocument().fields(), List.of())),
|
||||
"cargoRows must contain exactly one item");
|
||||
assertValidationFailure(request(FreightA4PdfDtos.SHIPPING_INSTRUCTION_TEMPLATE,
|
||||
new FreightA4PdfDtos.Document(shippingDocument().fields(), List.of(cargo(), cargo()))),
|
||||
"cargoRows must contain exactly one item");
|
||||
assertValidationFailure(request(FreightA4PdfDtos.SHIPPING_INSTRUCTION_TEMPLATE,
|
||||
new FreightA4PdfDtos.Document(shippingDocument().fields(), List.of(
|
||||
new FreightA4PdfDtos.CargoRow("", "1", "PACKAGES", "GOODS", "1 KGS", "1 CBM")))),
|
||||
"marksAndNos must not be blank");
|
||||
}
|
||||
|
||||
@Test
|
||||
void derivesStableChineseFileNamesFromBusinessNumbers() {
|
||||
var shipping = service.generate(request(FreightA4PdfDtos.SHIPPING_INSTRUCTION_TEMPLATE,
|
||||
shippingDocument()));
|
||||
var bill = service.generate(request(FreightA4PdfDtos.BILL_CONFIRMATION_TEMPLATE,
|
||||
billDocument()));
|
||||
|
||||
assertThat(shipping.fileName()).isEqualTo("OB-260831-0001-出口货物托运单.pdf");
|
||||
assertThat(bill.fileName()).isEqualTo("BK-20260831-提单确认件.pdf");
|
||||
}
|
||||
|
||||
private void assertValidationFailure(FreightA4PdfDtos.Request request, String messagePart) {
|
||||
assertThatThrownBy(() -> service.generate(request))
|
||||
.isInstanceOfSatisfying(BizException.class, exception -> {
|
||||
@@ -53,12 +94,36 @@ class FreightA4PdfServiceValidationTest {
|
||||
});
|
||||
}
|
||||
|
||||
private FreightA4PdfDtos.Request request(String template, FreightA4PdfDtos.Document document) {
|
||||
return new FreightA4PdfDtos.Request(template, pageSpec(), null, List.of(document));
|
||||
}
|
||||
|
||||
private FreightA4PdfDtos.PageSpec pageSpec() {
|
||||
return new FreightA4PdfDtos.PageSpec(new BigDecimal("210"), new BigDecimal("297"));
|
||||
}
|
||||
|
||||
private FreightA4PdfDtos.Document document() {
|
||||
return new FreightA4PdfDtos.Document(Map.of("shipper", "A\nB"),
|
||||
List.of(new FreightA4PdfDtos.CargoRow("N/M", "1", "PACKAGES", "GOODS", "1 KGS", "1 CBM")));
|
||||
private FreightA4PdfDtos.Document shippingDocument() {
|
||||
return new FreightA4PdfDtos.Document(Map.of(
|
||||
"toCompany", "订舱代理", "shipper", "A\nB", "consignee", "C", "notifyParty", "N",
|
||||
"jobNumber", "OB-260831-0001", "cargoQuantity", "1*40HQ", "portOfLoading", "NINGBO",
|
||||
"portOfDischarge", "LOS ANGELES", "placeOfDelivery", "LOS ANGELES",
|
||||
"totalPackagesInWords", "SAY ONE PACKAGE ONLY."), cargoRows());
|
||||
}
|
||||
|
||||
private FreightA4PdfDtos.Document billDocument() {
|
||||
return new FreightA4PdfDtos.Document(Map.of(
|
||||
"shipper", "A", "consignee", "C", "notifyParty", "N", "bookingNumber", "BK-20260831",
|
||||
"portOfLoading", "NINGBO", "portOfDischarge", "LOS ANGELES",
|
||||
"placeOfDelivery", "LOS ANGELES", "serviceTerm", "CY-CY",
|
||||
"freightTerm", "FREIGHT PREPAID", "totalPackagesInWords", "SAY ONE PACKAGE ONLY."),
|
||||
cargoRows());
|
||||
}
|
||||
|
||||
private List<FreightA4PdfDtos.CargoRow> cargoRows() {
|
||||
return List.of(cargo());
|
||||
}
|
||||
|
||||
private FreightA4PdfDtos.CargoRow cargo() {
|
||||
return new FreightA4PdfDtos.CargoRow("N/M", "1", "PACKAGES", "GOODS", "1 KGS", "1 CBM");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user