diff --git a/blade-service-api/blade-transport-api/src/main/java/org/springblade/transport/pojo/dto/WaybillImportBatchRequest.java b/blade-service-api/blade-transport-api/src/main/java/org/springblade/transport/pojo/dto/WaybillImportBatchRequest.java index dadc790..c346165 100644 --- a/blade-service-api/blade-transport-api/src/main/java/org/springblade/transport/pojo/dto/WaybillImportBatchRequest.java +++ b/blade-service-api/blade-transport-api/src/main/java/org/springblade/transport/pojo/dto/WaybillImportBatchRequest.java @@ -25,6 +25,7 @@ public class WaybillImportBatchRequest { private Long carrierId; private List carrierIds; private String carrierName; + private Long carrierContractId; private String status; private String importStatus; private String importType; diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/MasterOrderServiceImpl.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/MasterOrderServiceImpl.java index 99200a6..11f7195 100644 --- a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/MasterOrderServiceImpl.java +++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/MasterOrderServiceImpl.java @@ -261,7 +261,7 @@ public class MasterOrderServiceImpl extends BaseServiceImpl decimal(item, "quantity").multiply(decimal(item, "unitPrice"))).reduce(BigDecimal.ZERO, BigDecimal::add); plan.setFreightJson(Func.isNotEmpty(freightJson) ? freightJson : buildFreightJson(null, freightTotal, first)); plan.setDataSource("多联总单调度"); plan.setBusinessStatus("waiting_dispatch"); - plan.setRemark(string(first, "remark")); + plan.setRemark(string(first, "routeRemark", string(first, "remark"))); transportPlanService.submit(plan); } diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/ReceivablePayableDetailServiceImpl.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/ReceivablePayableDetailServiceImpl.java index c25ff7a..0e4cec3 100644 --- a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/ReceivablePayableDetailServiceImpl.java +++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/ReceivablePayableDetailServiceImpl.java @@ -103,6 +103,7 @@ public class ReceivablePayableDetailServiceImpl private static final String SOURCE_MASTER_ORDER = "总单系统生成"; private static final String SOURCE_LOADING_ORDER = "配载单系统生成"; private static final String SOURCE_MANUAL_GENERATION = "手动生成"; + private static final String TRANSPORT_TYPE_SELF = "自运"; private static final String FEE_SOURCE_AUTO = "自动生成"; private static final String FEE_SOURCE_MANUAL = "手动录入"; private static final Set FEE_SOURCE_MANUAL_LEGACY = Set.of("手工录入", "手动添加"); @@ -604,11 +605,15 @@ public class ReceivablePayableDetailServiceImpl Long currentUserId = AuthUtil.getUserId(); Date generateTime = new Date(); ContractManage contract = contractManageService.getById(request.getContractId()); + String targetSettlementType = settlementType(request.getSettlementType()); for (Waybill waybill : waybills) { - if (existsByWaybill(waybill.getId(), settlementType(request.getSettlementType()))) { + if ("payable".equals(targetSettlementType) && isSelfTransport(waybill)) { continue; } - ReceivablePayableDetail detail = buildDetail(waybill, contract, request.getBillingPlanId(), settlementType(request.getSettlementType())); + if (existsByWaybill(waybill.getId(), targetSettlementType)) { + continue; + } + ReceivablePayableDetail detail = buildDetail(waybill, contract, request.getBillingPlanId(), targetSettlementType); detail.setSourceType(SOURCE_MANUAL_GENERATION); save(detail); calculatedFees(waybill, contract, request.getBillingPlanId()).forEach(fee -> { @@ -645,11 +650,14 @@ public class ReceivablePayableDetailServiceImpl Long currentUserId = AuthUtil.getUserId(); Date generateTime = new Date(); generateAutomaticWaybillDetails(waybills, true, waybill -> null, currentUserId, generateTime); + List payableWaybills = waybills.stream() + .filter(waybill -> !isSelfTransport(waybill)).toList(); + if (payableWaybills.isEmpty()) return; generateAutomaticDetail(carrierContract, "payable", - () -> existsByLoading(loadingNo, "payable"), waybills, + () -> existsByLoading(loadingNo, "payable"), payableWaybills, (fees, unitPrice) -> { normalizeWaybillFeeLines(fees); - return buildLoadingDetail(loadingNo, carrierContract, waybills, fees, unitPrice); + return buildLoadingDetail(loadingNo, carrierContract, payableWaybills, fees, unitPrice); }, false, currentUserId, generateTime); } @@ -672,10 +680,12 @@ public class ReceivablePayableDetailServiceImpl generateAutomaticWaybillDetail(waybill, receivableContract, "receivable", currentUserId, generateTime); } - ContractManage payableContract = payableContractResolver == null - ? null : payableContractResolver.apply(waybill); - generateAutomaticWaybillDetail(waybill, payableContract, "payable", - currentUserId, generateTime); + if (!isSelfTransport(waybill)) { + ContractManage payableContract = payableContractResolver == null + ? null : payableContractResolver.apply(waybill); + generateAutomaticWaybillDetail(waybill, payableContract, "payable", + currentUserId, generateTime); + } } catch (Exception exception) { log.error("自动生成运单费用明细失败,waybillId:{}, waybillNo:{}, receivableContractId:{}, failureReason:{}", waybill.getId(), waybill.getWaybillNo(), waybill.getContractId(), exception.getMessage(), exception); @@ -766,11 +776,14 @@ public class ReceivablePayableDetailServiceImpl } private void generateClosedMasterOrderPayables(MasterOrder masterOrder, Long currentUserId, - Date generateTime) { + Date generateTime) { + if (isSelfTransport(masterOrder.getTransportOrganizationType())) return; List waybills = waybillService.list(Wrappers.lambdaQuery() .eq(Waybill::getIsDeleted, 0) .eq(Waybill::getMasterNo, masterOrder.getMasterNo()) .isNotNull(Waybill::getCarrierContractId)); + waybills = waybills.stream() + .filter(waybill -> !isSelfTransport(waybill)).toList(); if (waybills.isEmpty()) return; Map carrierContracts = contractManageService.listByIds(waybills.stream() .map(Waybill::getCarrierContractId).distinct().toList()).stream() @@ -800,13 +813,21 @@ public class ReceivablePayableDetailServiceImpl return Objects.equals(expectedCategory, contract.getContractCategory()) && isSystemGeneration(contract); } + private boolean isSelfTransport(String transportType) { + return TRANSPORT_TYPE_SELF.equals(transportType == null ? null : transportType.trim()); + } + + private boolean isSelfTransport(Waybill waybill) { + return isSelfTransport(waybill.getTransportType()) || isSelfTransport(waybill.getCarrierType()); + } + private List calculateAutomaticFees(List waybills, ContractManage contract) { List matchedFees = new ArrayList<>(); for (Waybill waybill : waybills) { String planId = matchedPlanId(waybill, contract); if (Func.isEmpty(planId)) continue; - // 自动生成统一使用合同默认计费方案,且禁止回退读取运单自身其他费用。 + // 自动生成使用选定合同计费方案,且禁止回退读取运单自身其他费用。 matchedFees.addAll(calculatedFees(waybill, contract, planId, true)); } return matchedFees; @@ -1088,6 +1109,10 @@ public class ReceivablePayableDetailServiceImpl .eq(Waybill::getProjectId, contract.getProjectId()) .eq(Waybill::getCarrierName, contract.getPartyB()); } + wrapper.and(item -> item.isNull(Waybill::getTransportType) + .or().ne(Waybill::getTransportType, TRANSPORT_TYPE_SELF)); + wrapper.and(item -> item.isNull(Waybill::getCarrierType) + .or().ne(Waybill::getCarrierType, TRANSPORT_TYPE_SELF)); } wrapper.notInSql(Waybill::getId, "select waybill_id from blade_receivable_payable_detail" @@ -1494,13 +1519,19 @@ public class ReceivablePayableDetailServiceImpl } private Map resolveDefaultBillingPlan(List> plans, String transportType) { - return plans.stream().filter(this::isDefaultPlan) + if (plans.isEmpty()) return null; + if (plans.size() == 1) return plans.get(0); + Optional> matchedDefaultPlan = plans.stream().filter(this::isDefaultPlan) .filter(plan -> !isBlank(plan.get("transportMode"))) .filter(plan -> matchesCondition(plan.get("transportMode"), transportType)) - .findFirst() - .orElseGet(() -> plans.stream().filter(this::isDefaultPlan) - .filter(plan -> isBlank(plan.get("transportMode"))) - .findFirst().orElse(null)); + .findFirst(); + if (matchedDefaultPlan.isPresent()) return matchedDefaultPlan.get(); + Optional> defaultPlanWithoutTransportMode = plans.stream() + .filter(this::isDefaultPlan) + .filter(plan -> isBlank(plan.get("transportMode"))) + .findFirst(); + if (defaultPlanWithoutTransportMode.isPresent()) return defaultPlanWithoutTransportMode.get(); + return plans.stream().noneMatch(this::isDefaultPlan) ? plans.get(plans.size() - 1) : null; } private BigDecimal calculateRule(Map rule, Waybill waybill) { diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/WaybillImportBatchServiceImpl.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/WaybillImportBatchServiceImpl.java index 1a2f5ff..690c4bd 100644 --- a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/WaybillImportBatchServiceImpl.java +++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/WaybillImportBatchServiceImpl.java @@ -86,7 +86,7 @@ public class WaybillImportBatchServiceImpl extends BaseServiceImpl row, WaybillImportBatch batch) { - Waybill waybill = BeanUtil.copyProperties(row, Waybill.class); - if (waybill == null) throw new ServiceException("运单数据不正确"); + private Waybill buildWaybill(Map row, WaybillImportBatch batch, Long carrierContractId) { + if (row == null) throw new ServiceException("运单数据不正确"); + Waybill waybill = new Waybill(); + waybill.setOriginalNo(stringValue(row, "originalNo")); + waybill.setVehicleNo(stringValue(row, "vehicleNo")); + waybill.setDriverId(longValue(row, "driverId", "司机ID")); + waybill.setDriverName(stringValue(row, "driverName")); + waybill.setDriverPhone(stringValue(row, "driverPhone")); + waybill.setTransportType(stringValue(row, "transportType", "运输类型", "*运输类型", "运输方式", "*运输方式")); + waybill.setCargoName(stringValue(row, "cargoName")); + waybill.setCargoType(stringValue(row, "cargoType")); + waybill.setSpecification(stringValue(row, "specification")); + waybill.setModel(stringValue(row, "model")); + waybill.setQuantity(decimalValue(row, "quantity", "重量")); + waybill.setQuantityUnit(stringValue(row, "quantityUnit")); + waybill.setDepartureAddressId(longValue(row, "departureAddressId", "发货地址ID")); + waybill.setDepartureName(stringValue(row, "departureName")); + waybill.setDepartureAddress(stringValue(row, "departureAddress")); + waybill.setDepartureContact(stringValue(row, "departureContact")); + waybill.setDeparturePhone(stringValue(row, "departurePhone")); + waybill.setArrivalAddressId(longValue(row, "arrivalAddressId", "收货地址ID")); + waybill.setArrivalName(stringValue(row, "arrivalName")); + waybill.setArrivalAddress(stringValue(row, "arrivalAddress")); + waybill.setArrivalContact(stringValue(row, "arrivalContact")); + waybill.setArrivalPhone(stringValue(row, "arrivalPhone")); + waybill.setCaptainName(stringValue(row, "captainName")); + waybill.setCabinNo(stringValue(row, "cabinNo")); + waybill.setContainerNo(stringValue(row, "containerNo")); + waybill.setTrailerVehicleNo(stringValue(row, "trailerVehicleNo")); + waybill.setEscortName(stringValue(row, "escortName")); + waybill.setEscortPhone(stringValue(row, "escortPhone")); + waybill.setMileage(normalizeImportMileage(decimalValue( + row, "mileage", "里程", "里程", "里程(km)", "里程(公里)" + ))); + waybill.setUnitPrice(decimalValue(row, "unitPrice", "单价")); + waybill.setPriceUnit(stringValue(row, "priceUnit")); + waybill.setOtherFeeTotal(decimalValue(row, "otherFeeTotal", "其他费用合计", "其他费用合计")); + waybill.setRemark(stringValue(row, "remark")); waybill.setProjectId(batch.getProjectId()); waybill.setProjectName(batch.getProjectName()); waybill.setCustomerName(batch.getCustomerName()); @@ -166,6 +201,7 @@ public class WaybillImportBatchServiceImpl extends BaseServiceImpl row, String field, String... aliases) { + Object value = row.get(field); + if (value != null && !String.valueOf(value).trim().isEmpty()) { + return String.valueOf(value).trim(); + } + for (String alias : aliases) { + Object aliasValue = row.get(alias); + if (aliasValue != null && !String.valueOf(aliasValue).trim().isEmpty()) { + return String.valueOf(aliasValue).trim(); + } + } + return null; + } + + private Long longValue(Map row, String field, String fieldName) { + String value = stringValue(row, field); + if (Func.isEmpty(value)) return null; + try { + return Long.valueOf(value); + } catch (NumberFormatException exception) { + throw new ServiceException(fieldName + "格式不正确"); + } + } + + private BigDecimal decimalValue(Map row, String field, String fieldName, String... aliases) { + String value = stringValue(row, field, aliases); + if (Func.isEmpty(value)) return null; + try { + return new BigDecimal(value); + } catch (NumberFormatException exception) { + throw new ServiceException(fieldName + "格式不正确"); + } + } + + private BigDecimal normalizeImportMileage(BigDecimal mileage) { + return mileage != null && mileage.compareTo(BigDecimal.ONE.negate()) == 0 ? null : mileage; + } + private LocalDate parseDate(Object value, String fieldName) { if (value == null || String.valueOf(value).isBlank()) throw new ServiceException(fieldName + "不能为空"); String text = String.valueOf(value).trim(); diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/WaybillServiceImpl.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/WaybillServiceImpl.java index 5497b7e..9ce23b4 100644 --- a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/WaybillServiceImpl.java +++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/WaybillServiceImpl.java @@ -35,6 +35,7 @@ import org.springblade.system.pojo.entity.Dept; import org.springblade.transport.excel.WaybillExcel; import java.time.LocalDate; import java.time.format.DateTimeFormatter; +import java.util.Arrays; import org.springblade.transport.mapper.WaybillMapper; import org.springblade.transport.pojo.entity.LoadingManage; import org.springblade.transport.pojo.entity.ContractManage; @@ -504,7 +505,21 @@ public class WaybillServiceImpl extends BaseServiceImpl queryWrapper.like(Waybill::getCustomerName, waybill.getCustomerName()); } if (Func.isNotEmpty(waybill.getTransportType())) { - queryWrapper.eq(Waybill::getTransportType, waybill.getTransportType()); + List transportTypes = Arrays.stream(waybill.getTransportType().split("[,,]")) + .map(String::trim) + .filter(Func::isNotEmpty) + .distinct() + .toList(); + if (transportTypes.size() == 1) { + queryWrapper.eq(Waybill::getTransportType, transportTypes.get(0)); + } else if (!transportTypes.isEmpty()) { + queryWrapper.and(wrapper -> { + wrapper.eq(Waybill::getTransportType, transportTypes.get(0)); + for (int i = 1; i < transportTypes.size(); i++) { + wrapper.or().eq(Waybill::getTransportType, transportTypes.get(i)); + } + }); + } } if (Func.isNotEmpty(waybill.getCargoName())) { queryWrapper.like(Waybill::getCargoName, waybill.getCargoName()); @@ -667,7 +682,6 @@ public class WaybillServiceImpl extends BaseServiceImpl TransportBusinessSupport.validateRequired(waybill.getCarrierName(), "承运商不能为空"); } else { TransportBusinessSupport.validateRequired(waybill.getDriverName(), "司机不能为空"); - TransportBusinessSupport.validateRequired(waybill.getDriverPhone(), "司机手机号不能为空"); } } TransportBusinessSupport.validateRequired(waybill.getCarrierJson(), "承运信息不能为空"); @@ -744,7 +758,7 @@ public class WaybillServiceImpl extends BaseServiceImpl } private void validateCarrierContract(Waybill waybill) { - if (!"承运商".equals(waybill.getCarrierType())) { + if ("自运".equals(waybill.getCarrierType())) { waybill.setCarrierContractId(null); return; }