优化
This commit is contained in:
@@ -60,4 +60,5 @@ public interface PrintPdfClient {
|
||||
|
||||
record DropshipPalletSkuRow(String inboundCode, String skuCode, String cargoName,
|
||||
int cartonCount, int skuQuantity) {}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,12 +1,16 @@
|
||||
package com.baiyue.firstleg.domain;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
|
||||
/** 首版固定渠道目录;上传名称只能映射到这些稳定编码。 */
|
||||
public final class PriceBookChannelCatalog {
|
||||
private PriceBookChannelCatalog() {}
|
||||
|
||||
private static final Set<String> SEA_RAIL_CHANNEL_CODES = Set.of(
|
||||
"EXX_RAIL_NY", "NYEXX", "OA_CHICAGO_RAIL", "CPHT");
|
||||
|
||||
public static final List<ChannelDefinition> CHANNELS = List.of(
|
||||
fba("MATSON_CLX_TRUCK", "美森正班海卡", "美森正班海卡", "ZBYHK", "ZBYHWK"),
|
||||
fba("MATSON_MAX_TRUCK", "美森加班海卡", "美森加班海卡", "BYHK", "BYHWK"),
|
||||
@@ -37,6 +41,11 @@ public final class PriceBookChannelCatalog {
|
||||
inboundCodePrefix, overseasInboundCodePrefix);
|
||||
}
|
||||
|
||||
public static boolean isSeaRail(String channelCode) {
|
||||
return channelCode != null
|
||||
&& SEA_RAIL_CHANNEL_CODES.contains(channelCode.trim().toUpperCase(Locale.ROOT));
|
||||
}
|
||||
|
||||
public record ChannelDefinition(
|
||||
String channelCode,
|
||||
String displayName,
|
||||
|
||||
@@ -23,6 +23,7 @@ public interface LoadingListQueryMapper {
|
||||
p.id AS plan_id, p.plan_no, p.container_booking_id, p.plan_status, p.remark,
|
||||
p.created_by, p.created_by_name, p.created_at, p.version,
|
||||
b.container_no, b.cabinet_no, b.warehouse_id, b.warehouse_name,
|
||||
b.channel_code, b.outbound_confirmed_at, b.actual_empty_reported_at,
|
||||
b.vessel_name, b.voyage_no, b.container_type,
|
||||
(SELECT COUNT(*) FROM fl_preload_loading_plan_link preload_link
|
||||
WHERE preload_link.loading_plan_id = p.id) AS preload_link_count,
|
||||
@@ -51,6 +52,7 @@ public interface LoadingListQueryMapper {
|
||||
p.id, p.plan_no, p.container_booking_id, p.plan_status, p.remark,
|
||||
p.created_by, p.created_by_name, p.created_at, p.version,
|
||||
b.container_no, b.cabinet_no, b.warehouse_id, b.warehouse_name,
|
||||
b.channel_code, b.outbound_confirmed_at, b.actual_empty_reported_at,
|
||||
b.vessel_name, b.voyage_no, b.container_type
|
||||
""";
|
||||
|
||||
@@ -394,6 +396,9 @@ public interface LoadingListQueryMapper {
|
||||
private String cabinetNo;
|
||||
private Long warehouseId;
|
||||
private String warehouseName;
|
||||
private String channelCode;
|
||||
private LocalDateTime outboundConfirmedAt;
|
||||
private LocalDateTime actualEmptyReportedAt;
|
||||
private String vesselName;
|
||||
private String voyageNo;
|
||||
private String containerType;
|
||||
|
||||
+5
-19
@@ -15,7 +15,6 @@ import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
@@ -47,7 +46,7 @@ public class OceanBookingPrintService {
|
||||
String fileName = booking.getBookingNo() + "-" + suffix + ".pdf";
|
||||
PrintPdfClient.FreightA4PdfRequest request = new PrintPdfClient.FreightA4PdfRequest(
|
||||
template, A4, fileName, List.of(new PrintPdfClient.FreightDocument(
|
||||
fields(template, detail), List.of(cargo(detail.containerRequirements())))));
|
||||
fields(template, detail), List.of(emptyCargo()))));
|
||||
try {
|
||||
ResponseEntity<byte[]> response = print.generateFreightA4Documents(internalToken, requestId, request);
|
||||
MediaType contentType = response.getHeaders().getContentType();
|
||||
@@ -78,12 +77,12 @@ public class OceanBookingPrintService {
|
||||
fields.put("placeOfDelivery", text(booking.getPlaceOfDelivery()));
|
||||
fields.put("serviceTerm", text(booking.getServiceTerm()));
|
||||
fields.put("freightTerm", text(booking.getFreightTerm()));
|
||||
fields.put("totalPackagesInWords", Integer.toString(totalContainers(detail.containerRequirements())));
|
||||
fields.put("totalPackagesInWords", "");
|
||||
if (SHIPPING_INSTRUCTION.equals(template)) {
|
||||
fields.put("toCompany", text(booking.getBookingAgentName()));
|
||||
fields.put("jobNumber", text(booking.getBookingNo()));
|
||||
fields.put("etdDate", date(booking.getEstimatedSailingAt()));
|
||||
fields.put("cargoQuantity", Integer.toString(totalContainers(detail.containerRequirements())));
|
||||
fields.put("cargoQuantity", "");
|
||||
fields.put("carrier", text(booking.getShippingCompanyName()));
|
||||
fields.put("bookingAgent", text(booking.getBookingAgentName()));
|
||||
fields.put("remark", text(booking.getRemark()));
|
||||
@@ -99,18 +98,8 @@ public class OceanBookingPrintService {
|
||||
return fields;
|
||||
}
|
||||
|
||||
private static PrintPdfClient.CargoRow cargo(List<OceanBookingContainerRequirementEntity> requirements) {
|
||||
BigDecimal gross = requirements.stream().map(value -> value.getMaxWeightKg()
|
||||
.multiply(BigDecimal.valueOf(value.getQuantity()))).reduce(BigDecimal.ZERO, BigDecimal::add);
|
||||
BigDecimal volume = requirements.stream().map(value -> value.getCapacityCbm()
|
||||
.multiply(BigDecimal.valueOf(value.getQuantity()))).reduce(BigDecimal.ZERO, BigDecimal::add);
|
||||
return new PrintPdfClient.CargoRow("N/M", Integer.toString(totalContainers(requirements)),
|
||||
"CONTAINERS", requirementSummary(requirements), decimal(gross, 3) + " KGS",
|
||||
decimal(volume, 4) + " CBM");
|
||||
}
|
||||
|
||||
private static int totalContainers(List<OceanBookingContainerRequirementEntity> values) {
|
||||
return values.stream().mapToInt(OceanBookingContainerRequirementEntity::getQuantity).sum();
|
||||
private static PrintPdfClient.CargoRow emptyCargo() {
|
||||
return new PrintPdfClient.CargoRow("—", "—", "—", "—", "—", "—");
|
||||
}
|
||||
|
||||
private static String requirementSummary(List<OceanBookingContainerRequirementEntity> values) {
|
||||
@@ -128,9 +117,6 @@ public class OceanBookingPrintService {
|
||||
private static String date(java.time.LocalDateTime value) {
|
||||
return value == null ? "" : value.format(DateTimeFormatter.ISO_LOCAL_DATE);
|
||||
}
|
||||
private static String decimal(BigDecimal value, int scale) {
|
||||
return value.setScale(scale, RoundingMode.HALF_UP).toPlainString();
|
||||
}
|
||||
private static String first(String first, String fallback) { return !text(first).isEmpty() ? first.trim() : text(fallback); }
|
||||
private static String join(String first, String second) { return List.of(text(first), text(second)).stream().filter(value -> !value.isEmpty()).collect(Collectors.joining(" / ")); }
|
||||
private static String text(String value) { return value == null ? "" : value.trim(); }
|
||||
|
||||
@@ -261,7 +261,7 @@ public class InboundMeasurementService {
|
||||
ConfirmedWeightTotals confirmedTotals = confirmedWeightTotals(weights);
|
||||
if (confirmedTotals.palletCount() == 0) {
|
||||
throw new BizException(ResultCode.VALIDATION_FAILED,
|
||||
"请至少上传并确认一张称重图片后再提交测量审核");
|
||||
"即使只有一箱,也必须上传并确认至少一张称重图片后再提交测量审核");
|
||||
}
|
||||
|
||||
requireConfirmedPackageTotal(inbound, items);
|
||||
|
||||
@@ -26,6 +26,7 @@ import com.baiyue.firstleg.repository.LoadingListRepository;
|
||||
import com.baiyue.firstleg.repository.LoadingPickRepository;
|
||||
import com.baiyue.firstleg.repository.ContainerRepository;
|
||||
import com.baiyue.firstleg.domain.Iso6346ContainerNumber;
|
||||
import com.baiyue.firstleg.domain.PriceBookChannelCatalog;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
@@ -138,7 +139,9 @@ public class LoadingListService {
|
||||
}
|
||||
public BusinessDocument containerLogisticsDocument(long bookingId,String type){ requireLogisticsType(type); requireBookingPlan(bookingId); return document(repository.document(bookingId,type)); }
|
||||
public BusinessDocument uploadContainerLogisticsDocument(long bookingId,String type,long operatorId,String operatorName,String key,int expectedVersion,String reason,MultipartFile file){
|
||||
requireLogisticsType(type); String businessType=fileType(type); return uploadDocument(requireBookingPlan(bookingId),type,businessType,bookingId,Long.toString(bookingId),operatorId,operatorName,key,expectedVersion,reason,file);
|
||||
requireLogisticsType(type); String businessType=fileType(type); AggregateRow plan=requireBookingPlan(bookingId);
|
||||
requireDeliveryOrderUploadAllowed(plan);
|
||||
return uploadDocument(plan,type,businessType,bookingId,Long.toString(bookingId),operatorId,operatorName,key,expectedVersion,reason,file);
|
||||
}
|
||||
public DocumentDownload downloadContainerDocument(long bookingId,String type,long fileId){
|
||||
requireLogisticsType(type); String businessType=fileType(type); requireBookingPlan(bookingId); ContainerDocumentEntity d=requireDocumentEntity(bookingId,type); if(!Long.valueOf(fileId).equals(d.getFileId())) throw notFound("货柜资料不存在");
|
||||
@@ -190,6 +193,17 @@ public class LoadingListService {
|
||||
public record DocumentDownload(String fileName,MediaType contentType,byte[] content) {}
|
||||
private static void requireLogisticsType(String type){ if(!DELIVERY_ORDER.equals(type)) throw badRequest("documentType只能是DELIVERY_ORDER"); }
|
||||
private static String fileType(String type){ if (DELIVERY_ORDER.equals(type)) return DO_FILE_TYPE; throw badRequest("documentType只能是DELIVERY_ORDER"); }
|
||||
private static void requireDeliveryOrderUploadAllowed(AggregateRow plan) {
|
||||
if (!"COMPLETED".equals(plan.getPlanStatus()) || plan.getOutboundConfirmedAt() == null) {
|
||||
throw conflict("货柜进入海外履约后才可上传DO资料");
|
||||
}
|
||||
if (plan.getActualEmptyReportedAt() != null) {
|
||||
throw conflict("货柜已还柜,不可再上传DO资料");
|
||||
}
|
||||
if (PriceBookChannelCatalog.isSeaRail(plan.getChannelCode())) {
|
||||
throw conflict("海铁渠道不适用DO资料");
|
||||
}
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@BusinessAudit(event = "CONTAINER_CLEARANCE_DOCUMENT_ATTACH", resourceType = "CONTAINER",
|
||||
|
||||
@@ -92,14 +92,18 @@ public class MeasurementReviewService {
|
||||
"人工确认箱数合计与入库单总箱数不一致,不能审核通过");
|
||||
}
|
||||
var weights = measurements.listWeights(tenantId, inboundId);
|
||||
if (weights.isEmpty() || weights.stream().anyMatch(weight ->
|
||||
if (weights.isEmpty()) {
|
||||
throw new BizException(ResultCode.VALIDATION_FAILED,
|
||||
"该票测量已提交但没有称重图片;请先退回测量,上传并确认至少一张称重图片后重新提交(即使只有一箱也必须称重)");
|
||||
}
|
||||
if (weights.stream().anyMatch(weight ->
|
||||
!"CONFIRMED".equals(weight.getRecognitionStatus())
|
||||
|| weight.getGrossWeightKg() == null
|
||||
|| weight.getGrossWeightKg().signum() <= 0
|
||||
|| weight.getNetWeightKg() == null
|
||||
|| weight.getNetWeightKg().signum() <= 0)) {
|
||||
throw new BizException(ResultCode.VALIDATION_FAILED,
|
||||
"所有称重结果必须已确认且包含大于零的毛重和货物净重,才能审核通过");
|
||||
"该票存在未确认或重量无效的称重图片;请先在审核弹框逐张修正并确认后再审核");
|
||||
}
|
||||
BigDecimal grossWeight = weights.stream()
|
||||
.map(com.baiyue.firstleg.entity.InboundWeightResultEntity::getGrossWeightKg)
|
||||
|
||||
Reference in New Issue
Block a user