调整配载、总单

This commit is contained in:
2026-08-22 21:11:12 +08:00
parent 3e265fc71e
commit 79f4c35235
5 changed files with 28 additions and 84 deletions
@@ -52,4 +52,7 @@ public class BusinessRemoveResultVO implements Serializable {
@Schema(description = "跳过编号") @Schema(description = "跳过编号")
private List<String> skippedCodes = new ArrayList<>(); private List<String> skippedCodes = new ArrayList<>();
@Schema(description = "跳过原因")
private List<String> skippedReasons = new ArrayList<>();
} }
@@ -56,10 +56,9 @@ public class LoadingManageController extends BladeController {
@GetMapping("/carrier-contracts") @GetMapping("/carrier-contracts")
@ApiOperationSupport(order = 13) @ApiOperationSupport(order = 13)
@Operation(summary = "可选承运商合同", description = "根据运单ID集合查询共同可用的承运商合同") @Operation(summary = "可选承运商合同", description = "查询已审核生效的承运商合同")
public R<List<LoadingCarrierContractVO>> carrierContracts( public R<List<LoadingCarrierContractVO>> carrierContracts() {
@Parameter(description = "运单ID集合", required = true) @RequestParam List<Long> waybillIds) { return R.data(loadingManageService.carrierContracts());
return R.data(loadingManageService.carrierContracts(waybillIds));
} }
@GetMapping("/list") @GetMapping("/list")
@@ -25,7 +25,7 @@ public interface ILoadingManageService extends BaseService<LoadingManage> {
LoadingManageVO detail(Long id); LoadingManageVO detail(Long id);
List<LoadingCarrierContractVO> carrierContracts(List<Long> waybillIds); List<LoadingCarrierContractVO> carrierContracts();
boolean saveDraft(LoadingManage loadingManage); boolean saveDraft(LoadingManage loadingManage);
@@ -8,6 +8,7 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springblade.core.log.exception.ServiceException; import org.springblade.core.log.exception.ServiceException;
import org.springblade.core.mp.base.BaseServiceImpl; import org.springblade.core.mp.base.BaseServiceImpl;
import org.springblade.core.tool.jackson.JsonUtil; import org.springblade.core.tool.jackson.JsonUtil;
@@ -39,10 +40,7 @@ import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatter;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.function.Function;
import java.util.stream.Collectors;
/** /**
* 配载管理 服务实现类 * 配载管理 服务实现类
@@ -50,6 +48,7 @@ import java.util.stream.Collectors;
* @author Chill * @author Chill
*/ */
@Service @Service
@Slf4j
public class LoadingManageServiceImpl extends BaseServiceImpl<LoadingManageMapper, LoadingManage> implements ILoadingManageService { public class LoadingManageServiceImpl extends BaseServiceImpl<LoadingManageMapper, LoadingManage> implements ILoadingManageService {
private static final String STATUS_DRAFT = "draft"; private static final String STATUS_DRAFT = "draft";
@@ -86,8 +85,8 @@ public class LoadingManageServiceImpl extends BaseServiceImpl<LoadingManageMappe
} }
@Override @Override
public List<LoadingCarrierContractVO> carrierContracts(List<Long> waybillIds) { public List<LoadingCarrierContractVO> carrierContracts() {
return findCarrierContracts(waybillIds).stream().map(contract -> { return availableCarrierContracts().stream().map(contract -> {
LoadingCarrierContractVO option = new LoadingCarrierContractVO(); LoadingCarrierContractVO option = new LoadingCarrierContractVO();
option.setId(contract.getId()); option.setId(contract.getId());
option.setContractName(contract.getContractName()); option.setContractName(contract.getContractName());
@@ -292,9 +291,8 @@ public class LoadingManageServiceImpl extends BaseServiceImpl<LoadingManageMappe
LoadingManage loadingManage = loadEditable(id, true); LoadingManage loadingManage = loadEditable(id, true);
validateCompletedCarrierContract(loadingManage); validateCompletedCarrierContract(loadingManage);
if (!Objects.equals(loadingManage.getBusinessStatus(), STATUS_RUNNING) if (!Objects.equals(loadingManage.getBusinessStatus(), STATUS_RUNNING)
&& !(Objects.equals(loadingManage.getBusinessStatus(), STATUS_PENDING) && !Objects.equals(loadingManage.getBusinessStatus(), STATUS_PENDING)) {
&& allAssociatedWaybillsCompletable(loadingManage))) { throw new ServiceException("仅待执行或进行中状态允许完成");
throw new ServiceException("仅进行中,或关联运单全部进行中/已完成的待执行配载单允许完成");
} }
loadingManage.setBusinessStatus(STATUS_COMPLETED); loadingManage.setBusinessStatus(STATUS_COMPLETED);
boolean result = updateById(loadingManage); boolean result = updateById(loadingManage);
@@ -358,28 +356,17 @@ public class LoadingManageServiceImpl extends BaseServiceImpl<LoadingManageMappe
complete(loadingManage.getId()); complete(loadingManage.getId());
result.setSuccessCount(result.getSuccessCount() + 1); result.setSuccessCount(result.getSuccessCount() + 1);
} catch (Exception exception) { } catch (Exception exception) {
String failureReason = Func.isEmpty(exception.getMessage()) ? "完成失败" : exception.getMessage();
log.error("批量完成配载单失败,loadingId:{}, loadingNo:{}, failureReason:{}",
loadingManage.getId(), loadingManage.getLoadingNo(), failureReason, exception);
result.setSkippedCount(result.getSkippedCount() + 1); result.setSkippedCount(result.getSkippedCount() + 1);
result.getSkippedCodes().add(loadingManage.getLoadingNo()); result.getSkippedCodes().add(loadingManage.getLoadingNo());
result.getSkippedReasons().add(loadingManage.getLoadingNo() + "" + failureReason);
} }
} }
return result; return result;
} }
private boolean allAssociatedWaybillsCompletable(LoadingManage loadingManage) {
List<Long> waybillIdList = waybillIds(loadingManage.getWaybillIdsJson());
if (Func.isEmpty(waybillIdList)) {
return false;
}
List<Waybill> waybillList = waybillMapper.selectList(Wrappers.<Waybill>lambdaQuery()
.eq(Waybill::getIsDeleted, 0)
.in(Waybill::getId, waybillIdList));
if (waybillList.size() != waybillIdList.size()) {
return false;
}
return waybillList.stream().allMatch(waybill -> Objects.equals(waybill.getBusinessStatus(), STATUS_RUNNING))
|| waybillList.stream().allMatch(waybill -> Objects.equals(waybill.getBusinessStatus(), STATUS_COMPLETED));
}
private LambdaQueryWrapper<LoadingManage> buildQuery(LoadingManageVO loadingManage) { private LambdaQueryWrapper<LoadingManage> buildQuery(LoadingManageVO loadingManage) {
TransportBusinessSupport.validateAllDept(loadingManage.getAllDept(), "配载管理"); TransportBusinessSupport.validateAllDept(loadingManage.getAllDept(), "配载管理");
LambdaQueryWrapper<LoadingManage> queryWrapper = Wrappers.<LoadingManage>lambdaQuery().eq(LoadingManage::getIsDeleted, 0); LambdaQueryWrapper<LoadingManage> queryWrapper = Wrappers.<LoadingManage>lambdaQuery().eq(LoadingManage::getIsDeleted, 0);
@@ -604,11 +591,10 @@ public class LoadingManageServiceImpl extends BaseServiceImpl<LoadingManageMappe
loadingManage.setCarrierName(null); loadingManage.setCarrierName(null);
return; return;
} }
ContractManage carrierContract = findCarrierContracts( ContractManage carrierContract = availableCarrierContracts().stream()
waybillIds(loadingManage.getWaybillIdsJson())).stream()
.filter(contract -> Objects.equals(contract.getId(), loadingManage.getCarrierContractId())) .filter(contract -> Objects.equals(contract.getId(), loadingManage.getCarrierContractId()))
.findFirst() .findFirst()
.orElseThrow(() -> new ServiceException("所选承运商合同与运单绑定的客户合同不匹配或已失效")); .orElseThrow(() -> new ServiceException("所选承运商合同不存在、未审核通过或已失效"));
loadingManage.setCarrierName(carrierContract.getPartyB()); loadingManage.setCarrierName(carrierContract.getPartyB());
} }
@@ -623,58 +609,10 @@ public class LoadingManageServiceImpl extends BaseServiceImpl<LoadingManageMappe
} }
} }
private List<ContractManage> findCarrierContracts(List<Long> waybillIds) { private List<ContractManage> availableCarrierContracts() {
if (Func.isEmpty(waybillIds)) {
return new ArrayList<>();
}
List<Long> distinctWaybillIds = waybillIds.stream()
.filter(Objects::nonNull)
.distinct()
.toList();
if (Func.isEmpty(distinctWaybillIds)) {
return new ArrayList<>();
}
List<Waybill> waybillList = waybillMapper.selectList(Wrappers.<Waybill>lambdaQuery()
.eq(Waybill::getIsDeleted, 0)
.in(Waybill::getId, distinctWaybillIds));
if (waybillList.size() != distinctWaybillIds.size()) {
throw new ServiceException("待配载运单不存在或已删除");
}
waybillList.forEach(waybill ->
TransportBusinessSupport.assertCurrentDept(waybill.getDeptId(), "运单管理"));
if (waybillList.stream().anyMatch(waybill -> Func.isEmpty(waybill.getContractId()))) {
throw new ServiceException("所选运单存在未绑定客户合同的数据");
}
List<Long> customerContractIds = waybillList.stream()
.map(Waybill::getContractId)
.distinct()
.toList();
Map<Long, ContractManage> customerContractMap = contractManageService.listByIds(customerContractIds)
.stream()
.filter(contract -> Objects.equals(contract.getIsDeleted(), 0))
.collect(Collectors.toMap(ContractManage::getId, Function.identity()));
if (customerContractMap.size() != customerContractIds.size()) {
throw new ServiceException("所选运单绑定的客户合同不存在或已删除");
}
Waybill firstWaybill = waybillList.get(0);
ContractManage firstCustomerContract = customerContractMap.get(firstWaybill.getContractId());
if (!Objects.equals(firstCustomerContract.getContractCategory(), "客户合同")
|| Func.isEmpty(firstCustomerContract.getPartyA())) {
throw new ServiceException("所选运单绑定的客户合同信息不完整");
}
boolean relationMismatch = waybillList.stream().anyMatch(waybill -> {
ContractManage customerContract = customerContractMap.get(waybill.getContractId());
return !Objects.equals(customerContract.getContractCategory(), "客户合同")
|| !Objects.equals(waybill.getProjectId(), firstWaybill.getProjectId())
|| !Objects.equals(customerContract.getPartyA(), firstCustomerContract.getPartyA());
});
if (relationMismatch) {
throw new ServiceException("所选运单的客户合同不属于同一项目和甲方,无法共用承运商合同");
}
return contractManageService.list(Wrappers.<ContractManage>lambdaQuery() return contractManageService.list(Wrappers.<ContractManage>lambdaQuery()
.eq(ContractManage::getIsDeleted, 0) .eq(ContractManage::getIsDeleted, 0)
.eq(ContractManage::getProjectId, firstWaybill.getProjectId()) .eq(ContractManage::getStatus, 1)
.eq(ContractManage::getPartyA, firstCustomerContract.getPartyA())
.eq(ContractManage::getContractCategory, "承运商合同") .eq(ContractManage::getContractCategory, "承运商合同")
.in(ContractManage::getApprovalStatus, "approved", "change_approved") .in(ContractManage::getApprovalStatus, "approved", "change_approved")
.and(wrapper -> wrapper.isNull(ContractManage::getContractStage) .and(wrapper -> wrapper.isNull(ContractManage::getContractStage)
@@ -697,6 +635,7 @@ public class LoadingManageServiceImpl extends BaseServiceImpl<LoadingManageMappe
.set(Waybill::getLoadingNo, loadingManage.getLoadingNo()) .set(Waybill::getLoadingNo, loadingManage.getLoadingNo())
.set(Waybill::getBusinessStatus, status) .set(Waybill::getBusinessStatus, status)
.set(Waybill::getCarrierType, loadingManage.getCarrierType()) .set(Waybill::getCarrierType, loadingManage.getCarrierType())
.set(Waybill::getCarrierContractId, loadingManage.getCarrierContractId())
.set(Waybill::getCarrierName, loadingManage.getCarrierName()) .set(Waybill::getCarrierName, loadingManage.getCarrierName())
.set(Waybill::getDriverName, loadingManage.getDriverName()) .set(Waybill::getDriverName, loadingManage.getDriverName())
.set(Waybill::getDriverPhone, loadingManage.getDriverPhone()) .set(Waybill::getDriverPhone, loadingManage.getDriverPhone())
@@ -719,6 +658,8 @@ public class LoadingManageServiceImpl extends BaseServiceImpl<LoadingManageMappe
waybillMapper.update(null, Wrappers.<Waybill>lambdaUpdate() waybillMapper.update(null, Wrappers.<Waybill>lambdaUpdate()
.in(Waybill::getId, waybillIds) .in(Waybill::getId, waybillIds)
.set(Waybill::getLoadingNo, null) .set(Waybill::getLoadingNo, null)
.set(Waybill::getCarrierContractId, null)
.set(Waybill::getCarrierName, null)
.set(Waybill::getBusinessStatus, status)); .set(Waybill::getBusinessStatus, status));
} }
@@ -428,18 +428,19 @@ public class MasterOrderServiceImpl extends BaseServiceImpl<MasterOrderMapper, M
throw new ServiceException("所选承运商不属于总单客户合同对应项目的有效承运商合同乙方"); throw new ServiceException("所选承运商不属于总单客户合同对应项目的有效承运商合同乙方");
} }
boolean road = string(dispatch, "transportType", "").toLowerCase().contains("road") || string(dispatch, "transportType", "").contains("公路"); boolean road = string(dispatch, "transportType", "").toLowerCase().contains("road") || string(dispatch, "transportType", "").contains("公路");
String mileage = string(dispatch, "mileage");
if (!road) { 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")))) { 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.isNotEmpty(mileage) && decimal(dispatch, "mileage").compareTo(BigDecimal.ZERO) <= 0) || ("承运商".equals(carrierType) && Func.isEmpty(string(dispatch, "carrierName")))) {
throw new ServiceException("非公路运输的承运信息不完整"); throw new ServiceException("非公路运输的承运信息不完整");
} }
return; return;
} }
if (Func.isEmpty(string(dispatch, "vehicleNo"))) throw new ServiceException("运单车牌号不能为空"); if (Func.isEmpty(string(dispatch, "vehicleNo"))) throw new ServiceException("运单车牌号不能为空");
if ("承运商".equals(carrierType)) { if ("承运商".equals(carrierType)) {
if (Func.isEmpty(string(dispatch, "carrierName")) || Func.isEmpty(string(dispatch, "mileage")) || decimal(dispatch, "mileage").compareTo(BigDecimal.ZERO) <= 0) throw new ServiceException("承运商、里程不能为空里程必须为正"); if (Func.isEmpty(string(dispatch, "carrierName")) || (Func.isNotEmpty(mileage) && decimal(dispatch, "mileage").compareTo(BigDecimal.ZERO) <= 0)) throw new ServiceException("承运商不能为空里程填写时必须为正数");
return; 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("自运或网货平台的车辆与人员信息不完整"); 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.isNotEmpty(mileage) && decimal(dispatch, "mileage").compareTo(BigDecimal.ZERO) < 0)) throw new ServiceException("自运或网货平台的车辆与人员信息不完整");
} }
private BigDecimal dispatchedQuantity(String masterNo, String segmentNo) { private BigDecimal dispatchedQuantity(String masterNo, String segmentNo) {
return dispatchedGoods(masterNo, segmentNo).values().stream().reduce(BigDecimal.ZERO, BigDecimal::add); return dispatchedGoods(masterNo, segmentNo).values().stream().reduce(BigDecimal.ZERO, BigDecimal::add);