1、修复业务模块bug

2、完善凭证管理
This commit is contained in:
2026-08-13 20:58:52 +08:00
parent 323ce61136
commit 8e06aa3f68
7 changed files with 193 additions and 37 deletions
@@ -10,6 +10,7 @@ import org.springframework.amqp.core.DirectExchange;
import org.springframework.amqp.core.Queue;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.beans.factory.annotation.Value;
/**
* 凭证导入消息队列配置。
@@ -18,22 +19,35 @@ import org.springframework.context.annotation.Configuration;
@Configuration
public class VoucherImportRabbitConfig {
public static final String EXCHANGE = "tms.voucher.import.exchange";
public static final String QUEUE = "tms.voucher.import.queue";
public static final String ROUTING_KEY = "tms.voucher.import";
private final String exchange;
private final String queue;
private final String routingKey;
public VoucherImportRabbitConfig(
@Value("${voucher.import.rabbit.exchange:tms.voucher.import.exchange}") String exchange,
@Value("${voucher.import.rabbit.queue:tms.voucher.import.queue}") String queue,
@Value("${voucher.import.rabbit.routing-key:tms.voucher.import}") String routingKey) {
this.exchange = exchange;
this.queue = queue;
this.routingKey = routingKey;
}
public String getExchange() { return exchange; }
public String getQueue() { return queue; }
public String getRoutingKey() { return routingKey; }
@Bean
public DirectExchange voucherImportExchange() {
return new DirectExchange(EXCHANGE, true, false);
return new DirectExchange(exchange, true, false);
}
@Bean
public Queue voucherImportQueue() {
return new Queue(QUEUE, true);
return new Queue(queue, true);
}
@Bean
public Binding voucherImportBinding(Queue voucherImportQueue, DirectExchange voucherImportExchange) {
return BindingBuilder.bind(voucherImportQueue).to(voucherImportExchange).with(ROUTING_KEY);
return BindingBuilder.bind(voucherImportQueue).to(voucherImportExchange).with(routingKey);
}
}
@@ -5,22 +5,41 @@
package org.springblade.transport.listener;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springblade.transport.config.VoucherImportRabbitConfig;
import org.springblade.transport.service.IVoucherManageService;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.rabbit.listener.MessageListenerContainer;
import org.springframework.amqp.rabbit.listener.RabbitListenerEndpointRegistry;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.stereotype.Component;
import org.springframework.context.event.EventListener;
/**
* 凭证压缩包后台处理消费者。
*/
@Component
@RequiredArgsConstructor
@Slf4j
public class VoucherImportMessageListener {
private final IVoucherManageService voucherManageService;
private static final String LISTENER_ID = "voucherImportMessageListener";
@RabbitListener(queues = VoucherImportRabbitConfig.QUEUE)
private final IVoucherManageService voucherManageService;
private final VoucherImportRabbitConfig voucherImportRabbitConfig;
private final RabbitListenerEndpointRegistry rabbitListenerEndpointRegistry;
@EventListener(ApplicationReadyEvent.class)
public void logConsumerStatus() {
MessageListenerContainer container = rabbitListenerEndpointRegistry.getListenerContainer(LISTENER_ID);
log.info("[凭证MQ] 消费者状态 listenerId={}, queue={}, registered={}, running={}",
LISTENER_ID, voucherImportRabbitConfig.getQueue(), container != null, container != null && container.isRunning());
}
@RabbitListener(id = LISTENER_ID, queues = "${voucher.import.rabbit.queue:tms.voucher.import.queue}")
public void processVoucher(Long voucherId) {
log.info("[凭证MQ] 收到处理任务 queue={}, voucherId={}", voucherImportRabbitConfig.getQueue(), voucherId);
voucherManageService.processUploadedVoucher(voucherId);
log.info("[凭证MQ] 处理任务完成 voucherId={}", voucherId);
}
}
@@ -5,6 +5,7 @@
package org.springblade.transport.listener;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springblade.transport.config.VoucherImportRabbitConfig;
import org.springblade.transport.event.VoucherUploadCompletedEvent;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
@@ -17,13 +18,17 @@ import org.springframework.transaction.event.TransactionalEventListener;
*/
@Component
@RequiredArgsConstructor
@Slf4j
public class VoucherUploadCompletedListener {
private final RabbitTemplate rabbitTemplate;
private final VoucherImportRabbitConfig voucherImportRabbitConfig;
@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
public void publish(VoucherUploadCompletedEvent event) {
rabbitTemplate.convertAndSend(VoucherImportRabbitConfig.EXCHANGE,
VoucherImportRabbitConfig.ROUTING_KEY, event.getVoucherId());
log.info("[凭证MQ] 投递处理任务 exchange={}, routingKey={}, voucherId={}",
voucherImportRabbitConfig.getExchange(), voucherImportRabbitConfig.getRoutingKey(), event.getVoucherId());
rabbitTemplate.convertAndSend(voucherImportRabbitConfig.getExchange(),
voucherImportRabbitConfig.getRoutingKey(), event.getVoucherId());
}
}
@@ -78,7 +78,7 @@ public class MasterOrderServiceImpl extends BaseServiceImpl<MasterOrderMapper, M
public MasterOrderVO submit(MasterOrderVO request, boolean draft) {
boolean created = Func.isEmpty(request.getId());
MasterOrder target = created ? new MasterOrder() : getRequired(request.getId());
if (!created && ("dispatching".equals(target.getBusinessStatus()) || "completed".equals(target.getBusinessStatus()))) {
if (!created && "completed".equals(target.getBusinessStatus())) {
assertRestrictedEdit(target, request);
}
if (!created && "closed".equals(target.getBusinessStatus())) throw new ServiceException("调度关闭的总单不能编辑");
@@ -175,7 +175,8 @@ public class MasterOrderServiceImpl extends BaseServiceImpl<MasterOrderMapper, M
waybill.setTransportType(string(dispatch, "transportType")); waybill.setCarrierType(string(dispatch, "carrierType"));
waybill.setCarrierName(string(dispatch, "carrierName")); waybill.setDriverName(string(dispatch, "driverName"));
waybill.setDriverPhone(string(dispatch, "driverPhone")); waybill.setVehicleNo(string(dispatch, "vehicleNo")); waybill.setTrailerVehicleNo(string(dispatch, "trailerVehicleNo"));
waybill.setEscortName(string(dispatch, "escortName")); waybill.setEscortPhone(string(dispatch, "escortPhone")); waybill.setMileage(decimal(dispatch, "mileage"));
waybill.setCaptainName(string(dispatch, "captainName")); waybill.setCabinNo(string(dispatch, "cabinNo")); waybill.setContainerNo(string(dispatch, "containerNo"));
waybill.setEscortName(string(dispatch, "escortName")); waybill.setEscortPhone(string(dispatch, "escortPhone")); waybill.setMileage(nullableDecimal(dispatch, "mileage"));
waybill.setDepartureName(string(dispatch, "departureName")); waybill.setDepartureAddress(string(dispatch, "departureAddress"));
waybill.setArrivalName(string(dispatch, "arrivalName")); waybill.setArrivalAddress(string(dispatch, "arrivalAddress"));
waybill.setCargoName(joinGoodsField(dispatches, "cargoName")); waybill.setCargoType(joinGoodsField(dispatches, "cargoType"));
@@ -244,7 +245,9 @@ public class MasterOrderServiceImpl extends BaseServiceImpl<MasterOrderMapper, M
ContractManage contract = resolveContract(entity);
vo.setContractNo(contract == null ? null : contract.getContractNo());
vo.setRoutes(parseArray(entity.getRouteJson())); vo.setGoods(parseArray(entity.getGoodsJson())); vo.setTotalQuantity(totalQuantity(vo.getGoods()));
vo.setRouteProgress(buildProgress(entity, vo.getRoutes()));
List<Waybill> boundWaybills = waybillsByMasterNo(entity.getMasterNo());
vo.setBoundWaybills(boundWaybills);
vo.setRouteProgress(buildProgress(entity, vo.getRoutes(), boundWaybills));
vo.setCreateUserName(UserCache.getUserRealName(entity.getCreateUser())); vo.setUpdateUserName(UserCache.getUserRealName(entity.getUpdateUser()));
return vo;
}
@@ -260,16 +263,18 @@ public class MasterOrderServiceImpl extends BaseServiceImpl<MasterOrderMapper, M
return contractManageService.getOne(query, false);
}
private List<Map<String, Object>> buildProgress(MasterOrder masterOrder, List<Map<String, Object>> routes) {
List<Waybill> waybills = waybillService.list(new LambdaQueryWrapper<Waybill>().eq(Waybill::getMasterNo, masterOrder.getMasterNo()));
private List<Map<String, Object>> buildProgress(MasterOrder masterOrder, List<Map<String, Object>> routes, List<Waybill> waybills) {
List<TransportPlan> plans = transportPlanService.list(new LambdaQueryWrapper<TransportPlan>().eq(TransportPlan::getMasterNo, masterOrder.getMasterNo()));
for (Map<String, Object> route : routes) {
String segmentNo = string(route, "segmentNo");
route.put("dispatchedQuantity", dispatchedQuantity(masterOrder.getMasterNo(), segmentNo));
route.put("dispatchedGoods", dispatchedGoods(masterOrder.getMasterNo(), segmentNo));
route.put("arrivedQuantity", waybills.stream().filter(item -> Objects.equals(segmentNo, item.getRelationNo()) && "completed".equals(item.getBusinessStatus())).map(Waybill::getQuantity).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add));
route.put("waybills", waybills.stream().filter(item -> Objects.equals(segmentNo, item.getRelationNo())).toList());
route.put("transportPlans", plans.stream().filter(item -> Objects.equals(segmentNo, item.getRelationNo())).toList());
List<Waybill> routeWaybills = waybills.stream().filter(item -> belongsToRoute(item, route)).toList();
List<TransportPlan> routePlans = plans.stream().filter(item -> belongsToRoute(item, route)).toList();
Map<String, BigDecimal> dispatchedGoods = dispatchedGoods(routeWaybills, routePlans);
route.put("dispatchedQuantity", dispatchedGoods.values().stream().reduce(BigDecimal.ZERO, BigDecimal::add));
route.put("dispatchedGoods", dispatchedGoods);
route.put("arrivedQuantity", routeWaybills.stream().filter(item -> "completed".equals(item.getBusinessStatus())).flatMap(item -> waybillGoods(item).stream()).map(item -> decimal(item, "quantity")).reduce(BigDecimal.ZERO, BigDecimal::add));
route.put("waybills", routeWaybills);
route.put("transportPlans", routePlans);
}
return routes;
}
@@ -282,7 +287,7 @@ public class MasterOrderServiceImpl extends BaseServiceImpl<MasterOrderMapper, M
}
private void assertRestrictedEdit(MasterOrder oldRecord, MasterOrderVO request) {
if (!Objects.equals(oldRecord.getProjectId(), request.getProjectId()) || !Objects.equals(oldRecord.getRouteJson(), JsonUtil.toJson(request.getRoutes()))) throw new ServiceException("调度中或调度完成的总单不能修改基本信息和路线");
if (!Objects.equals(oldRecord.getProjectId(), request.getProjectId()) || !Objects.equals(oldRecord.getRouteJson(), JsonUtil.toJson(request.getRoutes()))) throw new ServiceException("调度完成的总单不能修改基本信息和路线");
}
private void validate(MasterOrder masterOrder, boolean draft) {
@@ -339,9 +344,16 @@ public class MasterOrderServiceImpl extends BaseServiceImpl<MasterOrderMapper, M
}
private void validateCarrier(Map<String, Object> dispatch) {
String carrierType = string(dispatch, "carrierType", "承运商");
boolean road = string(dispatch, "transportType", "").toLowerCase().contains("road") || string(dispatch, "transportType", "").contains("公路");
if (!road) {
if (Func.isEmpty(string(dispatch, "vehicleNo")) || Func.isEmpty(string(dispatch, "captainName")) || Func.isEmpty(string(dispatch, "driverPhone")) || Func.isEmpty(string(dispatch, "containerNo")) || Func.isEmpty(string(dispatch, "cabinNo")) || Func.isEmpty(string(dispatch, "mileage")) || decimal(dispatch, "mileage").compareTo(BigDecimal.ZERO) <= 0 || ("承运商".equals(carrierType) && Func.isEmpty(string(dispatch, "carrierName")))) {
throw new ServiceException("非公路运输的承运信息不完整");
}
return;
}
if (Func.isEmpty(string(dispatch, "vehicleNo"))) throw new ServiceException("运单车牌号不能为空");
if ("承运商".equals(carrierType)) {
if (Func.isEmpty(string(dispatch, "carrierName"))) throw new ServiceException("运单承运商不能为空");
if (Func.isEmpty(string(dispatch, "carrierName")) || Func.isEmpty(string(dispatch, "mileage")) || decimal(dispatch, "mileage").compareTo(BigDecimal.ZERO) <= 0) throw new ServiceException("承运商、里程不能为空且里程必须为正整数");
return;
}
if (Func.isEmpty(string(dispatch, "driverName")) || Func.isEmpty(string(dispatch, "driverPhone")) || Func.isEmpty(string(dispatch, "trailerVehicleNo")) || Func.isEmpty(string(dispatch, "escortName")) || Func.isEmpty(string(dispatch, "escortPhone")) || Func.isEmpty(string(dispatch, "mileage")) || decimal(dispatch, "mileage").compareTo(BigDecimal.ZERO) < 0) throw new ServiceException("自运或网货平台的车辆与人员信息不完整");
@@ -350,19 +362,57 @@ public class MasterOrderServiceImpl extends BaseServiceImpl<MasterOrderMapper, M
return dispatchedGoods(masterNo, segmentNo).values().stream().reduce(BigDecimal.ZERO, BigDecimal::add);
}
private Map<String, BigDecimal> dispatchedGoods(String masterNo, String segmentNo) {
Map<String, BigDecimal> result = new LinkedHashMap<>();
LambdaQueryWrapper<Waybill> billQuery = new LambdaQueryWrapper<Waybill>().eq(Waybill::getMasterNo, masterNo);
if (Func.isNotEmpty(segmentNo)) billQuery.eq(Waybill::getRelationNo, segmentNo);
for (Waybill bill : waybillService.list(billQuery)) {
List<Map<String, Object>> goods = parseArray(bill.getGoodsJson());
if (goods.isEmpty()) goods = List.of(Map.of("cargoName", bill.getCargoName(), "cargoType", bill.getCargoType(), "quantity", bill.getQuantity()));
for (Map<String, Object> goodsItem : goods) result.merge(goodsKey(goodsItem), decimal(goodsItem, "quantity"), BigDecimal::add);
}
List<Waybill> waybills = waybillsByMasterNo(masterNo).stream().filter(item -> Func.isEmpty(segmentNo) || Objects.equals(segmentNo, item.getRelationNo())).toList();
LambdaQueryWrapper<TransportPlan> planQuery = new LambdaQueryWrapper<TransportPlan>().eq(TransportPlan::getMasterNo, masterNo);
if (Func.isNotEmpty(segmentNo)) planQuery.eq(TransportPlan::getRelationNo, segmentNo);
for (TransportPlan plan : transportPlanService.list(planQuery)) for (Map<String, Object> goods : parseArray(plan.getGoodsJson())) result.merge(goodsKey(goods), decimal(goods, "quantity"), BigDecimal::add);
return dispatchedGoods(waybills, transportPlanService.list(planQuery));
}
private List<Waybill> waybillsByMasterNo(String masterNo) {
if (Func.isEmpty(masterNo)) return List.of();
return waybillService.list(new LambdaQueryWrapper<Waybill>().eq(Waybill::getMasterNo, masterNo));
}
private Map<String, BigDecimal> dispatchedGoods(List<Waybill> waybills, List<TransportPlan> plans) {
Map<String, BigDecimal> result = new LinkedHashMap<>();
for (Waybill bill : waybills) for (Map<String, Object> goods : waybillGoods(bill)) result.merge(goodsKey(goods), decimal(goods, "quantity"), BigDecimal::add);
for (TransportPlan plan : plans) for (Map<String, Object> goods : parseArray(plan.getGoodsJson())) result.merge(goodsKey(goods), decimal(goods, "quantity"), BigDecimal::add);
return result;
}
private List<Map<String, Object>> waybillGoods(Waybill waybill) {
List<Map<String, Object>> goods = parseArray(waybill.getGoodsJson());
if (!goods.isEmpty()) return goods;
Map<String, Object> fallback = new LinkedHashMap<>();
fallback.put("cargoName", waybill.getCargoName()); fallback.put("cargoType", waybill.getCargoType()); fallback.put("quantity", waybill.getQuantity());
return List.of(fallback);
}
private boolean belongsToRoute(Waybill waybill, Map<String, Object> route) {
return belongsToRoute(waybill.getRelationNo(), waybill.getTransportType(), waybill.getDepartureName(), waybill.getDepartureAddress(), waybill.getArrivalName(), waybill.getArrivalAddress(), route);
}
private boolean belongsToRoute(TransportPlan plan, Map<String, Object> route) {
return belongsToRoute(plan.getRelationNo(), plan.getTransportType(), plan.getDepartureName(), plan.getDepartureAddress(), plan.getArrivalName(), plan.getArrivalAddress(), route);
}
private boolean belongsToRoute(String relationNo, String transportType, String departureName, String departureAddress, String arrivalName, String arrivalAddress, Map<String, Object> route) {
if (Func.isNotEmpty(relationNo)) return Objects.equals(relationNo, string(route, "segmentNo"));
return sameTransportType(transportType, string(route, "transportType"))
&& sameLocation(departureName, departureAddress, string(route, "departureName"), string(route, "departureAddress"))
&& sameLocation(arrivalName, arrivalAddress, string(route, "arrivalName"), string(route, "arrivalAddress"));
}
private boolean sameLocation(String name, String address, String routeName, String routeAddress) {
return (Func.isNotEmpty(address) && Objects.equals(address, routeAddress)) || (Func.isNotEmpty(name) && Objects.equals(name, routeName));
}
private boolean sameTransportType(String left, String right) {
if (Objects.equals(left, right)) return true;
return transportTypeName(left).equals(transportTypeName(right));
}
private String transportTypeName(String value) {
String normalized = value == null ? "" : value.toLowerCase();
return switch (normalized) {
case "road" -> "公路运输";
case "railway" -> "铁路运输";
case "river" -> "水路运输";
case "air" -> "航空运输";
default -> value == null ? "" : value;
};
}
private BigDecimal totalQuantity(List<Map<String, Object>> goods) { return goods.stream().map(item -> decimal(item, "quantity")).reduce(BigDecimal.ZERO, BigDecimal::add); }
private String buildFreightJson(BigDecimal quantity, BigDecimal freightTotal, Map<String, Object> dispatch) {
Map<String, Object> freight = new LinkedHashMap<>();
@@ -373,7 +423,7 @@ public class MasterOrderServiceImpl extends BaseServiceImpl<MasterOrderMapper, M
freight.put("currency", string(dispatch, "currency", "CNY"));
return JsonUtil.toJson(freight);
}
private String waybillGroupKey(Map<String, Object> dispatch) { return String.join("\u0000", string(dispatch, "segmentNo", ""), string(dispatch, "carrierType", ""), string(dispatch, "carrierName", ""), string(dispatch, "driverName", ""), string(dispatch, "vehicleNo", "")); }
private String waybillGroupKey(Map<String, Object> dispatch) { return String.join("\u0000", string(dispatch, "segmentNo", ""), string(dispatch, "carrierType", ""), string(dispatch, "carrierName", ""), string(dispatch, "driverName", ""), string(dispatch, "driverPhone", ""), string(dispatch, "vehicleNo", ""), string(dispatch, "captainName", ""), string(dispatch, "containerNo", ""), string(dispatch, "cabinNo", "")); }
private String joinGoodsField(List<Map<String, Object>> dispatches, String field) { return dispatches.stream().map(item -> string(item, field, "")).filter(Func::isNotEmpty).distinct().reduce((left, right) -> left + "" + right).orElse(""); }
private BigDecimal decimal(Map<String, Object> values, String key) { try { return new BigDecimal(string(values, key, "0")); } catch (Exception exception) { return BigDecimal.ZERO; } }
private BigDecimal nullableDecimal(Map<String, Object> values, String key) { String value = string(values, key); if (Func.isEmpty(value)) return null; try { return new BigDecimal(value); } catch (Exception exception) { return null; } }
@@ -154,9 +154,13 @@ public class VoucherManageServiceImpl extends BaseServiceImpl<VoucherManageMappe
voucher.setWaybillBatchNo(relations.stream().map(VoucherWaybillBatch::getWaybillBatchNo).distinct().collect(Collectors.joining(",")));
voucher.setRelatedWaybillCount(0);
voucher.setUnRelatedWaybillCount(0);
voucher.setProcessStatus("处理");
voucher.setProcessStatus(Func.isNotEmpty(voucher.getFileUrl()) ? "处理中" : "上传");
updateById(voucher);
eventPublisher.publishEvent(new VoucherUploadCompletedEvent(voucher.getId()));
if (Func.isNotEmpty(voucher.getFileUrl())) {
eventPublisher.publishEvent(new VoucherUploadCompletedEvent(voucher.getId()));
} else {
log.info("[凭证MQ] 暂不投递处理任务,等待文件上传完成 voucherId={}, fileTaskId={}", voucher.getId(), voucher.getFileTaskId());
}
}
@Override
@@ -172,8 +176,10 @@ public class VoucherManageServiceImpl extends BaseServiceImpl<VoucherManageMappe
voucher.setFileTaskId(request.getFileTaskId());
voucher.setFileName(request.getFileName());
voucher.setFileUrl(request.getFileUrl());
voucher.setProcessStatus("处理中");
voucher.setProcessStatus("上传完成");
updateById(voucher);
log.info("[凭证MQ] 文件上传完成,等待确认关联运输批次后投递任务 voucherId={}, voucherBatchNo={}, fileTaskId={}",
voucher.getId(), voucher.getVoucherBatchNo(), voucher.getFileTaskId());
}
@Override
@@ -195,17 +201,32 @@ public class VoucherManageServiceImpl extends BaseServiceImpl<VoucherManageMappe
return;
}
if (!force && "处理完成".equals(voucher.getProcessStatus())) {
log.info("[凭证处理] 跳过已完成任务 voucherId={}, voucherBatchNo={}", voucherId, voucher.getVoucherBatchNo());
return;
}
try {
if (Func.isEmpty(voucher.getFileUrl())) {
throw new ServiceException("凭证文件地址为空,请在上传完成后重新提交");
}
log.info("[凭证处理] 进度 0%:开始处理 voucherId={}, voucherBatchNo={}, fileName={}, force={}",
voucherId, voucher.getVoucherBatchNo(), voucher.getFileName(), force);
validateMinioConfig();
List<Waybill> waybills = listRelatedWaybills(voucher);
log.info("[凭证处理] 进度 10%:已查询关联运单 voucherId={}, waybillCount={}", voucherId, waybills.size());
Map<String, Waybill> waybillByPlate = new HashMap<>();
for (Waybill waybill : waybills) {
waybillPlateNumbers(waybill).forEach(plateNo -> waybillByPlate.putIfAbsent(plateNo, waybill));
for (String plateNo : waybillPlateNumbers(waybill)) {
Waybill existing = waybillByPlate.putIfAbsent(plateNo, waybill);
if (existing != null && !Objects.equals(existing.getId(), waybill.getId())) {
log.warn("[凭证处理] 车牌对应多个关联运单 voucherId={}, plateNo={}, firstWaybillNo={}, duplicateWaybillNo={}",
voucherId, plateNo, existing.getWaybillNo(), waybill.getWaybillNo());
}
}
}
log.info("[凭证处理] 进度 20%:已建立车牌匹配索引 voucherId={}, plateCount={}", voucherId, waybillByPlate.size());
voucherImageMapper.deleteByVoucherId(voucher.getId());
int imageCount = 0;
int matchedImageCount = 0;
Set<Long> relatedWaybillIds = new HashSet<>();
try (InputStream source = openSourceFile(voucher.getFileUrl());
ZipInputStream zipInputStream = new ZipInputStream(new BufferedInputStream(source), StandardCharsets.UTF_8)) {
@@ -214,7 +235,11 @@ public class VoucherManageServiceImpl extends BaseServiceImpl<VoucherManageMappe
if (entry.isDirectory()) {
continue;
}
String[] pathParts = entry.getName().replace('\\', '/').split("/");
String entryName = entry.getName().replace('\\', '/');
if (entryName.equals("__MACOSX") || entryName.startsWith("__MACOSX/")) {
continue;
}
String[] pathParts = entryName.split("/");
if (pathParts.length < 2 || !isImageFile(pathParts[pathParts.length - 1])) {
continue;
}
@@ -224,6 +249,13 @@ public class VoucherManageServiceImpl extends BaseServiceImpl<VoucherManageMappe
continue;
}
Waybill waybill = waybillByPlate.get(plateNo);
if (waybill == null) {
log.warn("[凭证处理] 图片未匹配运单 voucherId={}, plateNo={}, indexedPlates={}",
voucherId, plateNo, waybillByPlate.keySet());
} else {
log.info("[凭证处理] 图片匹配运单 voucherId={}, plateNo={}, waybillId={}, waybillNo={}",
voucherId, plateNo, waybill.getId(), waybill.getWaybillNo());
}
String waybillNo = waybill == null ? "unmatched" : safePathPart(waybill.getWaybillNo());
String objectKey = buildObjectKey(voucher.getId(), waybillNo, plateNo, imageName);
minioClient.putObject(PutObjectArgs.builder().bucket(minioBucketName).object(objectKey)
@@ -241,10 +273,17 @@ public class VoucherManageServiceImpl extends BaseServiceImpl<VoucherManageMappe
voucherImageMapper.insert(image);
imageCount++;
if (waybill != null) {
matchedImageCount++;
relatedWaybillIds.add(waybill.getId());
}
if (imageCount % 10 == 0) {
log.info("[凭证处理] 图片处理中 voucherId={}, processedImages={}, matchedImages={}, relatedWaybills={}",
voucherId, imageCount, matchedImageCount, relatedWaybillIds.size());
}
}
}
log.info("[凭证处理] 进度 90%:图片解压上传完成 voucherId={}, imageCount={}, matchedImageCount={}",
voucherId, imageCount, matchedImageCount);
VoucherManage update = new VoucherManage();
update.setId(voucher.getId());
update.setVoucherCount(imageCount);
@@ -252,6 +291,8 @@ public class VoucherManageServiceImpl extends BaseServiceImpl<VoucherManageMappe
update.setUnRelatedWaybillCount(Math.max(waybills.size() - relatedWaybillIds.size(), 0));
update.setProcessStatus("处理完成");
updateById(update);
log.info("[凭证处理] 进度 100%:处理完成 voucherId={}, voucherBatchNo={}, imageCount={}, relatedWaybillCount={}, unrelatedWaybillCount={}",
voucherId, voucher.getVoucherBatchNo(), imageCount, relatedWaybillIds.size(), Math.max(waybills.size() - relatedWaybillIds.size(), 0));
} catch (Exception exception) {
VoucherManage update = new VoucherManage();
update.setId(voucher.getId());