🔀 合并票 07:代码复核修复
This commit is contained in:
+2
-3
@@ -35,10 +35,9 @@ import java.util.Set;
|
|||||||
* 运次查询条件
|
* 运次查询条件
|
||||||
* <p>
|
* <p>
|
||||||
* 司机端用 {@link #forDriver(Long)} 按司机档案 ID 收口;管理端用 {@link #forAdmin()} 不按司机收口。
|
* 司机端用 {@link #forDriver(Long)} 按司机档案 ID 收口;管理端用 {@link #forAdmin()} 不按司机收口。
|
||||||
* 两者都不给时收口为空集——收口一旦缺省就等于把别人的运次发出去,故缺省不放行。
|
* 两者都不给时收口为空集。
|
||||||
* <p>
|
* <p>
|
||||||
* 判据是司机档案 ID 而不是手机号:手机号在配载单/运单上只是派单时的快照,司机换号后并不跟随,
|
* 归属判据只有司机档案 ID;driver_phone 是派单时的号码快照,不参与判定。
|
||||||
* 按号收口会让改过号的司机看不到自己手上的运次,号码被回收给别人时还会反向串号。
|
|
||||||
*/
|
*/
|
||||||
@Data
|
@Data
|
||||||
@Schema(description = "运次查询条件")
|
@Schema(description = "运次查询条件")
|
||||||
|
|||||||
+1
-4
@@ -34,7 +34,6 @@ import org.springblade.core.tool.jackson.JsonUtil;
|
|||||||
import org.springblade.core.tool.utils.DateUtil;
|
import org.springblade.core.tool.utils.DateUtil;
|
||||||
import org.springblade.core.tool.constant.BladeConstant;
|
import org.springblade.core.tool.constant.BladeConstant;
|
||||||
import org.springblade.core.tool.utils.Func;
|
import org.springblade.core.tool.utils.Func;
|
||||||
import org.springblade.system.feign.IMpUserClient;
|
|
||||||
import org.springblade.transport.mapper.ExceptionDisposalMapper;
|
import org.springblade.transport.mapper.ExceptionDisposalMapper;
|
||||||
import org.springblade.transport.mapper.WaybillEnroutePunchMapper;
|
import org.springblade.transport.mapper.WaybillEnroutePunchMapper;
|
||||||
import org.springblade.transport.mapper.WaybillNodePunchMapper;
|
import org.springblade.transport.mapper.WaybillNodePunchMapper;
|
||||||
@@ -152,7 +151,6 @@ public class DriverWaybillServiceImpl implements IDriverWaybillService {
|
|||||||
|
|
||||||
private final IWaybillService waybillService;
|
private final IWaybillService waybillService;
|
||||||
private final IDriverService driverService;
|
private final IDriverService driverService;
|
||||||
private final IMpUserClient mpUserClient;
|
|
||||||
private final IProcessConfigService processConfigService;
|
private final IProcessConfigService processConfigService;
|
||||||
private final ITransportVehicleService transportVehicleService;
|
private final ITransportVehicleService transportVehicleService;
|
||||||
private final CertificationGate certificationGate;
|
private final CertificationGate certificationGate;
|
||||||
@@ -923,8 +921,7 @@ public class DriverWaybillServiceImpl implements IDriverWaybillService {
|
|||||||
/**
|
/**
|
||||||
* 当前登录司机:只按登录用户 ID 查司机档案,查不到即「无归属」。
|
* 当前登录司机:只按登录用户 ID 查司机档案,查不到即「无归属」。
|
||||||
* <p>
|
* <p>
|
||||||
* 曾经查不到档案时按手机号回退匹配 driver.mobile,这让两个同号档案可以互相冒充,
|
* 归属判据:driver_id = 当前登录人的司机档案 id;driver_phone 不参与判定。
|
||||||
* 已删除:手机号在归属链路上不再有任何作用。
|
|
||||||
*/
|
*/
|
||||||
private Driver currentDriver() {
|
private Driver currentDriver() {
|
||||||
Long userId = AuthUtil.getUserId();
|
Long userId = AuthUtil.getUserId();
|
||||||
|
|||||||
+41
-16
@@ -4,6 +4,7 @@
|
|||||||
*/
|
*/
|
||||||
package org.springblade.transport.service.impl;
|
package org.springblade.transport.service.impl;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.DesensitizedUtil;
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
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;
|
||||||
@@ -11,6 +12,7 @@ import jakarta.annotation.Resource;
|
|||||||
import lombok.extern.slf4j.Slf4j;
|
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.secure.utils.AuthUtil;
|
||||||
import org.springblade.core.tool.jackson.JsonUtil;
|
import org.springblade.core.tool.jackson.JsonUtil;
|
||||||
import org.springblade.core.tool.utils.BeanUtil;
|
import org.springblade.core.tool.utils.BeanUtil;
|
||||||
import org.springblade.core.tool.utils.Func;
|
import org.springblade.core.tool.utils.Func;
|
||||||
@@ -143,16 +145,17 @@ public class LoadingManageServiceImpl extends BaseServiceImpl<LoadingManageMappe
|
|||||||
List<Long> oldWaybillIds = new ArrayList<>();
|
List<Long> oldWaybillIds = new ArrayList<>();
|
||||||
// 新建暂存为草稿;编辑已有单据时保持原业务状态(如待执行),避免被改回草稿
|
// 新建暂存为草稿;编辑已有单据时保持原业务状态(如待执行),避免被改回草稿
|
||||||
String businessStatus = STATUS_DRAFT;
|
String businessStatus = STATUS_DRAFT;
|
||||||
if (Func.isNotEmpty(loadingManage.getId())) {
|
LoadingManage stored = Func.isEmpty(loadingManage.getId()) ? null : loadEditable(loadingManage.getId(), true);
|
||||||
LoadingManage oldRecord = loadEditable(loadingManage.getId(), true);
|
if (stored != null) {
|
||||||
oldWaybillIds = waybillIds(oldRecord.getWaybillIdsJson());
|
oldWaybillIds = waybillIds(stored.getWaybillIdsJson());
|
||||||
loadingManage.setLoadingNo(oldRecord.getLoadingNo());
|
loadingManage.setLoadingNo(stored.getLoadingNo());
|
||||||
loadingManage.setDeptId(oldRecord.getDeptId());
|
loadingManage.setDeptId(stored.getDeptId());
|
||||||
loadingManage.setDeptName(oldRecord.getDeptName());
|
loadingManage.setDeptName(stored.getDeptName());
|
||||||
if (Func.isNotEmpty(oldRecord.getBusinessStatus())) {
|
if (Func.isNotEmpty(stored.getBusinessStatus())) {
|
||||||
businessStatus = oldRecord.getBusinessStatus();
|
businessStatus = stored.getBusinessStatus();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
applyDriverOwnership(loadingManage, stored);
|
||||||
prepareCreateOrUpdate(loadingManage);
|
prepareCreateOrUpdate(loadingManage);
|
||||||
loadingManage.setBusinessStatus(businessStatus);
|
loadingManage.setBusinessStatus(businessStatus);
|
||||||
if (Func.isEmpty(loadingManage.getLoadingNo())) {
|
if (Func.isEmpty(loadingManage.getLoadingNo())) {
|
||||||
@@ -204,6 +207,7 @@ public class LoadingManageServiceImpl extends BaseServiceImpl<LoadingManageMappe
|
|||||||
loadingManage.setDeptId(oldRecord.getDeptId());
|
loadingManage.setDeptId(oldRecord.getDeptId());
|
||||||
loadingManage.setDeptName(oldRecord.getDeptName());
|
loadingManage.setDeptName(oldRecord.getDeptName());
|
||||||
}
|
}
|
||||||
|
applyDriverOwnership(loadingManage, oldRecord);
|
||||||
prepareCreateOrUpdate(loadingManage);
|
prepareCreateOrUpdate(loadingManage);
|
||||||
if (Func.isEmpty(loadingManage.getLoadingNo())) {
|
if (Func.isEmpty(loadingManage.getLoadingNo())) {
|
||||||
loadingManage.setLoadingNo(nextCode());
|
loadingManage.setLoadingNo(nextCode());
|
||||||
@@ -483,6 +487,7 @@ public class LoadingManageServiceImpl extends BaseServiceImpl<LoadingManageMappe
|
|||||||
target.setTrailerVehicleNo(source.getTrailerVehicleNo());
|
target.setTrailerVehicleNo(source.getTrailerVehicleNo());
|
||||||
target.setDriverName(source.getDriverName());
|
target.setDriverName(source.getDriverName());
|
||||||
target.setDriverPhone(source.getDriverPhone());
|
target.setDriverPhone(source.getDriverPhone());
|
||||||
|
target.setDriverId(source.getDriverId());
|
||||||
target.setEscortName(source.getEscortName());
|
target.setEscortName(source.getEscortName());
|
||||||
target.setEscortPhone(source.getEscortPhone());
|
target.setEscortPhone(source.getEscortPhone());
|
||||||
target.setCarrierType(source.getCarrierType());
|
target.setCarrierType(source.getCarrierType());
|
||||||
@@ -510,8 +515,7 @@ public class LoadingManageServiceImpl extends BaseServiceImpl<LoadingManageMappe
|
|||||||
target.setBusinessStatus(STATUS_DRAFT);
|
target.setBusinessStatus(STATUS_DRAFT);
|
||||||
target.setLoadingNo(nextCode());
|
target.setLoadingNo(nextCode());
|
||||||
prepare(target);
|
prepare(target);
|
||||||
// 源单已有归属就沿用(手机号可能已被改过);没有才用刚解析出的值
|
applyDriverOwnership(target, null);
|
||||||
target.setDriverId(source.getDriverId() != null ? source.getDriverId() : target.getDriverId());
|
|
||||||
validate(target, true);
|
validate(target, true);
|
||||||
save(target);
|
save(target);
|
||||||
return detail(target.getId());
|
return detail(target.getId());
|
||||||
@@ -528,6 +532,7 @@ public class LoadingManageServiceImpl extends BaseServiceImpl<LoadingManageMappe
|
|||||||
throw new ServiceException("仅司机拒绝接单后允许重新派单");
|
throw new ServiceException("仅司机拒绝接单后允许重新派单");
|
||||||
}
|
}
|
||||||
prepare(loadingManage);
|
prepare(loadingManage);
|
||||||
|
applyDriverOwnership(loadingManage, oldRecord);
|
||||||
validate(loadingManage, false);
|
validate(loadingManage, false);
|
||||||
List<Long> oldWaybillIds = waybillIds(oldRecord.getWaybillIdsJson());
|
List<Long> oldWaybillIds = waybillIds(oldRecord.getWaybillIdsJson());
|
||||||
loadingManage.setLoadingNo(oldRecord.getLoadingNo());
|
loadingManage.setLoadingNo(oldRecord.getLoadingNo());
|
||||||
@@ -756,12 +761,6 @@ public class LoadingManageServiceImpl extends BaseServiceImpl<LoadingManageMappe
|
|||||||
loadingManage.setTrailerVehicleNo(TransportBusinessSupport.trimToNull(loadingManage.getTrailerVehicleNo()));
|
loadingManage.setTrailerVehicleNo(TransportBusinessSupport.trimToNull(loadingManage.getTrailerVehicleNo()));
|
||||||
loadingManage.setDriverName(TransportBusinessSupport.trimToNull(loadingManage.getDriverName()));
|
loadingManage.setDriverName(TransportBusinessSupport.trimToNull(loadingManage.getDriverName()));
|
||||||
loadingManage.setDriverPhone(TransportBusinessSupport.trimToNull(loadingManage.getDriverPhone()));
|
loadingManage.setDriverPhone(TransportBusinessSupport.trimToNull(loadingManage.getDriverPhone()));
|
||||||
// 归属主键是档案 ID,手机号只是号码快照:每次保存都按手机号重解析,
|
|
||||||
// 避免改派后残留旧归属;解析不到(承运商司机)留空,不阻断保存
|
|
||||||
Long resolvedDriverId = driverService.resolveDriverIdByMobile(
|
|
||||||
loadingManage.getTenantId(), loadingManage.getDriverPhone());
|
|
||||||
// driver_id 只有 >0 才算有主,0 / -1 都是「无主」的哨兵写法,落库统一为 NULL
|
|
||||||
loadingManage.setDriverId(resolvedDriverId != null && resolvedDriverId > 0 ? resolvedDriverId : null);
|
|
||||||
loadingManage.setEscortName(TransportBusinessSupport.trimToNull(loadingManage.getEscortName()));
|
loadingManage.setEscortName(TransportBusinessSupport.trimToNull(loadingManage.getEscortName()));
|
||||||
loadingManage.setEscortPhone(TransportBusinessSupport.trimToNull(loadingManage.getEscortPhone()));
|
loadingManage.setEscortPhone(TransportBusinessSupport.trimToNull(loadingManage.getEscortPhone()));
|
||||||
loadingManage.setCarrierType(TransportBusinessSupport.trimToNull(loadingManage.getCarrierType()));
|
loadingManage.setCarrierType(TransportBusinessSupport.trimToNull(loadingManage.getCarrierType()));
|
||||||
@@ -794,6 +793,32 @@ public class LoadingManageServiceImpl extends BaseServiceImpl<LoadingManageMappe
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 写司机归属:档案 ID 只在需要时解析,已落在单据上的归属不会被无关保存抹掉。
|
||||||
|
* <p>
|
||||||
|
* 判定顺序:调用方带了正数档案 ID 就用它;更新时 driver_phone 与库中一致且库中 driver_id 非空就保留库中值;
|
||||||
|
* 其余情况(新建、换号、原本无主)按手机号在租户内唯一匹配司机档案,匹配不到落 null 并留 WARN,不阻断保存。
|
||||||
|
*/
|
||||||
|
private void applyDriverOwnership(LoadingManage loadingManage, LoadingManage stored) {
|
||||||
|
Long driverId = loadingManage.getDriverId();
|
||||||
|
if (driverId != null && driverId > 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (stored != null && Func.isNotEmpty(stored.getDriverId())
|
||||||
|
&& Objects.equals(TransportBusinessSupport.trimToNull(stored.getDriverPhone()), loadingManage.getDriverPhone())) {
|
||||||
|
loadingManage.setDriverId(stored.getDriverId());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String tenantId = Func.isNotEmpty(loadingManage.getTenantId()) ? loadingManage.getTenantId() : AuthUtil.getTenantId();
|
||||||
|
Long resolvedDriverId = driverService.resolveDriverIdByMobile(tenantId, loadingManage.getDriverPhone());
|
||||||
|
loadingManage.setDriverId(resolvedDriverId);
|
||||||
|
if (resolvedDriverId == null) {
|
||||||
|
log.warn("配载单 {} 的司机手机号未唯一匹配司机档案,driver_id 落空。租户={} 手机号={}",
|
||||||
|
Func.isEmpty(loadingManage.getLoadingNo()) ? "(未编号)" : loadingManage.getLoadingNo(),
|
||||||
|
tenantId, DesensitizedUtil.mobilePhone(loadingManage.getDriverPhone()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void validate(LoadingManage loadingManage, boolean draftMode) {
|
private void validate(LoadingManage loadingManage, boolean draftMode) {
|
||||||
TransportBusinessSupport.validateRequired(loadingManage.getLoadingSubNos(), "配载子单号不能为空");
|
TransportBusinessSupport.validateRequired(loadingManage.getLoadingSubNos(), "配载子单号不能为空");
|
||||||
TransportBusinessSupport.validateRequired(loadingManage.getTransportType(), "运输类型不能为空");
|
TransportBusinessSupport.validateRequired(loadingManage.getTransportType(), "运输类型不能为空");
|
||||||
|
|||||||
+10
-3
@@ -4,8 +4,10 @@
|
|||||||
*/
|
*/
|
||||||
package org.springblade.transport.service.impl;
|
package org.springblade.transport.service.impl;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.DesensitizedUtil;
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||||
|
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;
|
||||||
@@ -51,6 +53,7 @@ import java.util.Objects;
|
|||||||
* @author Chill
|
* @author Chill
|
||||||
*/
|
*/
|
||||||
@Service
|
@Service
|
||||||
|
@Slf4j
|
||||||
public class MasterOrderServiceImpl extends BaseServiceImpl<MasterOrderMapper, MasterOrder> implements IMasterOrderService {
|
public class MasterOrderServiceImpl extends BaseServiceImpl<MasterOrderMapper, MasterOrder> implements IMasterOrderService {
|
||||||
|
|
||||||
private static final String CARRIER_SELF = "自运";
|
private static final String CARRIER_SELF = "自运";
|
||||||
@@ -266,11 +269,15 @@ public class MasterOrderServiceImpl extends BaseServiceImpl<MasterOrderMapper, M
|
|||||||
waybill.setTransportType(string(dispatch, "transportType")); waybill.setCarrierType(string(dispatch, "carrierType"));
|
waybill.setTransportType(string(dispatch, "transportType")); waybill.setCarrierType(string(dispatch, "carrierType"));
|
||||||
waybill.setCarrierContractId(longValue(dispatch, "carrierContractId")); waybill.setCarrierName(string(dispatch, "carrierName")); waybill.setDriverName(string(dispatch, "driverName"));
|
waybill.setCarrierContractId(longValue(dispatch, "carrierContractId")); 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.setDriverPhone(string(dispatch, "driverPhone")); waybill.setVehicleNo(string(dispatch, "vehicleNo")); waybill.setTrailerVehicleNo(string(dispatch, "trailerVehicleNo"));
|
||||||
// 归属主键是档案 ID:调度带了就用它,否则按手机号解析;承运商司机解析为空也照常派单
|
// 归属主键是档案 ID:调度带了就用它,否则按手机号解析;解析入口只返回 null 或唯一命中的
|
||||||
|
// 档案 ID,承运商司机解析为空也照常派单,落空时留 WARN
|
||||||
Long driverId = longValue(dispatch, "driverId");
|
Long driverId = longValue(dispatch, "driverId");
|
||||||
if (driverId == null || driverId <= 0) {
|
if (driverId == null || driverId <= 0) {
|
||||||
Long resolvedDriverId = driverService.resolveDriverIdByMobile(waybill.getTenantId(), waybill.getDriverPhone());
|
driverId = driverService.resolveDriverIdByMobile(waybill.getTenantId(), waybill.getDriverPhone());
|
||||||
driverId = resolvedDriverId != null && resolvedDriverId > 0 ? resolvedDriverId : null;
|
if (driverId == null) {
|
||||||
|
log.warn("总单 {} 派单的司机手机号未唯一匹配司机档案,driver_id 落空(不阻断派单)。租户={} 手机号={}",
|
||||||
|
masterOrder.getMasterNo(), waybill.getTenantId(), DesensitizedUtil.mobilePhone(waybill.getDriverPhone()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
waybill.setDriverId(driverId);
|
waybill.setDriverId(driverId);
|
||||||
waybill.setCaptainName(string(dispatch, "captainName")); waybill.setCabinNo(string(dispatch, "cabinNo")); waybill.setContainerNo(string(dispatch, "containerNo"));
|
waybill.setCaptainName(string(dispatch, "captainName")); waybill.setCabinNo(string(dispatch, "cabinNo")); waybill.setContainerNo(string(dispatch, "containerNo"));
|
||||||
|
|||||||
+3
-5
@@ -389,12 +389,10 @@ public class TripQueryServiceImpl implements ITripQueryService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 运次可见范围:配载段按配载单的司机档案 ID 收口,未配载段按运单的司机档案 ID 收口。
|
* 运次可见范围:已配载段按配载单的 driver_id 收口,未配载段按运单的 driver_id 收口。
|
||||||
* <p>
|
* <p>
|
||||||
* 判据是司机档案 ID 而不是手机号:司机换号后档案 ID 不变,而派单时落在配载单/运单上的手机号
|
* 归属判据只有司机档案 ID(null 或非正数视为无主),driver_phone 不参与判定。
|
||||||
* 是快照,按号收口会让改过号的司机看不到自己手上的运次;号码被回收给别人时又会反向串号。
|
* 无主的运次由 {@link #scoped} 在外层挡掉。
|
||||||
* 两段必须同时切:只切一段,另一段就会把不属于该司机的运次放进来。
|
|
||||||
* 缺省收口(空、0、负数)不放行,由 {@link #scoped} 在外层挡掉。
|
|
||||||
*/
|
*/
|
||||||
private void applyScope(LambdaQueryWrapper<Waybill> wrapper, TripQueryVO condition) {
|
private void applyScope(LambdaQueryWrapper<Waybill> wrapper, TripQueryVO condition) {
|
||||||
if (condition.isAllDrivers()) {
|
if (condition.isAllDrivers()) {
|
||||||
|
|||||||
+2
-2
@@ -500,12 +500,12 @@ public class WaybillImportBatchServiceImpl extends BaseServiceImpl<WaybillImport
|
|||||||
if (driverId != null && driverId > 0) {
|
if (driverId != null && driverId > 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// 解析入口只返回 null 或唯一命中的档案 ID,不需要再按哨兵归一
|
||||||
Long resolvedDriverId = driverService.resolveDriverIdByMobile(waybill.getTenantId(), waybill.getDriverPhone());
|
Long resolvedDriverId = driverService.resolveDriverIdByMobile(waybill.getTenantId(), waybill.getDriverPhone());
|
||||||
if (resolvedDriverId != null && resolvedDriverId > 0) {
|
if (resolvedDriverId != null) {
|
||||||
waybill.setDriverId(resolvedDriverId);
|
waybill.setDriverId(resolvedDriverId);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// driver_id 只有 >0 才算有主,0 / -1 都按无主落空
|
|
||||||
waybill.setDriverId(null);
|
waybill.setDriverId(null);
|
||||||
log.warn("第{}行 运单 {} 的司机手机号未唯一匹配司机档案,driver_id 留空(不阻断导入)",
|
log.warn("第{}行 运单 {} 的司机手机号未唯一匹配司机档案,driver_id 留空(不阻断导入)",
|
||||||
rowNo, waybill.getWaybillNo());
|
rowNo, waybill.getWaybillNo());
|
||||||
|
|||||||
+8
-4
@@ -22,6 +22,7 @@
|
|||||||
*/
|
*/
|
||||||
package org.springblade.transport.service.impl;
|
package org.springblade.transport.service.impl;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.DesensitizedUtil;
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
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;
|
||||||
@@ -1615,12 +1616,15 @@ public class WaybillServiceImpl extends BaseServiceImpl<WaybillMapper, Waybill>
|
|||||||
TransportBusinessSupport.validateRequired(vehicleNo, "车牌号不能为空");
|
TransportBusinessSupport.validateRequired(vehicleNo, "车牌号不能为空");
|
||||||
|
|
||||||
// 归属主键是档案 ID,手机号只是派单时的号码快照:调用方带了档案 ID 就用它,
|
// 归属主键是档案 ID,手机号只是派单时的号码快照:调用方带了档案 ID 就用它,
|
||||||
// 否则按手机号解析;承运商司机、未建档司机解析为空,派单照旧成功,只留 WARN
|
// 否则按手机号解析;解析入口只返回 null 或唯一命中的档案 ID,承运商司机、未建档司机
|
||||||
|
// 解析为空,派单照旧成功,落空时留 WARN
|
||||||
Long driverId = request.getDriverId();
|
Long driverId = request.getDriverId();
|
||||||
if (driverId == null || driverId <= 0) {
|
if (driverId == null || driverId <= 0) {
|
||||||
Long resolvedDriverId = driverService.resolveDriverIdByMobile(waybill.getTenantId(), driverPhone);
|
driverId = driverService.resolveDriverIdByMobile(waybill.getTenantId(), driverPhone);
|
||||||
// driver_id 只有 >0 才算有主,0 / -1 都是「无主」的哨兵写法,落库统一为 NULL
|
if (driverId == null) {
|
||||||
driverId = resolvedDriverId != null && resolvedDriverId > 0 ? resolvedDriverId : null;
|
log.warn("运单 {} 的司机手机号未唯一匹配司机档案,driver_id 落空(不阻断派单)。租户={} 手机号={}",
|
||||||
|
waybill.getWaybillNo(), waybill.getTenantId(), DesensitizedUtil.mobilePhone(driverPhone));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
waybill.setDriverId(driverId);
|
waybill.setDriverId(driverId);
|
||||||
waybill.setDriverName(driverName);
|
waybill.setDriverName(driverName);
|
||||||
|
|||||||
-2
@@ -12,7 +12,6 @@ import org.mockito.MockedStatic;
|
|||||||
import org.springblade.core.log.exception.ServiceException;
|
import org.springblade.core.log.exception.ServiceException;
|
||||||
import org.springblade.core.secure.utils.AuthUtil;
|
import org.springblade.core.secure.utils.AuthUtil;
|
||||||
import org.springblade.core.tool.jackson.JsonUtil;
|
import org.springblade.core.tool.jackson.JsonUtil;
|
||||||
import org.springblade.system.feign.IMpUserClient;
|
|
||||||
import org.springblade.transport.mapper.ExceptionDisposalMapper;
|
import org.springblade.transport.mapper.ExceptionDisposalMapper;
|
||||||
import org.springblade.transport.mapper.WaybillEnroutePunchMapper;
|
import org.springblade.transport.mapper.WaybillEnroutePunchMapper;
|
||||||
import org.springblade.transport.mapper.WaybillNodePunchMapper;
|
import org.springblade.transport.mapper.WaybillNodePunchMapper;
|
||||||
@@ -95,7 +94,6 @@ class DriverNodePunchPhotoTest {
|
|||||||
service = new DriverWaybillServiceImpl(
|
service = new DriverWaybillServiceImpl(
|
||||||
waybillService,
|
waybillService,
|
||||||
driverService,
|
driverService,
|
||||||
mock(IMpUserClient.class),
|
|
||||||
mock(IProcessConfigService.class),
|
mock(IProcessConfigService.class),
|
||||||
mock(ITransportVehicleService.class),
|
mock(ITransportVehicleService.class),
|
||||||
mock(CertificationGate.class),
|
mock(CertificationGate.class),
|
||||||
|
|||||||
-2
@@ -7,7 +7,6 @@ import org.junit.jupiter.api.BeforeAll;
|
|||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.DisplayName;
|
import org.junit.jupiter.api.DisplayName;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.springblade.system.feign.IMpUserClient;
|
|
||||||
import org.springblade.transport.mapper.ExceptionDisposalMapper;
|
import org.springblade.transport.mapper.ExceptionDisposalMapper;
|
||||||
import org.springblade.transport.mapper.WaybillEnroutePunchMapper;
|
import org.springblade.transport.mapper.WaybillEnroutePunchMapper;
|
||||||
import org.springblade.transport.mapper.WaybillNodePunchMapper;
|
import org.springblade.transport.mapper.WaybillNodePunchMapper;
|
||||||
@@ -92,7 +91,6 @@ class DriverPunchFinishFlagTest {
|
|||||||
service = new DriverWaybillServiceImpl(
|
service = new DriverWaybillServiceImpl(
|
||||||
waybillService,
|
waybillService,
|
||||||
mock(IDriverService.class),
|
mock(IDriverService.class),
|
||||||
mock(IMpUserClient.class),
|
|
||||||
mock(IProcessConfigService.class),
|
mock(IProcessConfigService.class),
|
||||||
mock(ITransportVehicleService.class),
|
mock(ITransportVehicleService.class),
|
||||||
mock(CertificationGate.class),
|
mock(CertificationGate.class),
|
||||||
|
|||||||
-2
@@ -10,7 +10,6 @@ import org.junit.jupiter.api.DisplayName;
|
|||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.mockito.ArgumentCaptor;
|
import org.mockito.ArgumentCaptor;
|
||||||
import org.springblade.core.tool.jackson.JsonUtil;
|
import org.springblade.core.tool.jackson.JsonUtil;
|
||||||
import org.springblade.system.feign.IMpUserClient;
|
|
||||||
import org.springblade.transport.mapper.ExceptionDisposalMapper;
|
import org.springblade.transport.mapper.ExceptionDisposalMapper;
|
||||||
import org.springblade.transport.mapper.WaybillEnroutePunchMapper;
|
import org.springblade.transport.mapper.WaybillEnroutePunchMapper;
|
||||||
import org.springblade.transport.mapper.WaybillNodePunchMapper;
|
import org.springblade.transport.mapper.WaybillNodePunchMapper;
|
||||||
@@ -87,7 +86,6 @@ class DriverPunchNodeCardTest {
|
|||||||
service = new DriverWaybillServiceImpl(
|
service = new DriverWaybillServiceImpl(
|
||||||
waybillService,
|
waybillService,
|
||||||
mock(IDriverService.class),
|
mock(IDriverService.class),
|
||||||
mock(IMpUserClient.class),
|
|
||||||
mock(IProcessConfigService.class),
|
mock(IProcessConfigService.class),
|
||||||
mock(ITransportVehicleService.class),
|
mock(ITransportVehicleService.class),
|
||||||
mock(CertificationGate.class),
|
mock(CertificationGate.class),
|
||||||
|
|||||||
+3
-2
@@ -96,8 +96,9 @@ class DriverResolveMobileTest {
|
|||||||
when(driverMapper.selectList(any())).thenReturn(List.of(profile(9001L)));
|
when(driverMapper.selectList(any())).thenReturn(List.of(profile(9001L)));
|
||||||
|
|
||||||
Long driverId = null;
|
Long driverId = null;
|
||||||
try (var ignored = org.mockito.Mockito.mockStatic(org.springblade.core.secure.utils.AuthUtil.class)) {
|
try (org.mockito.MockedStatic<org.springblade.core.secure.utils.AuthUtil> authUtil
|
||||||
ignored.when(org.springblade.core.secure.utils.AuthUtil::getTenantId).thenReturn(TENANT_ID);
|
= org.mockito.Mockito.mockStatic(org.springblade.core.secure.utils.AuthUtil.class)) {
|
||||||
|
authUtil.when(org.springblade.core.secure.utils.AuthUtil::getTenantId).thenReturn(TENANT_ID);
|
||||||
driverId = service.resolveDriverIdByMobile(null, MOBILE);
|
driverId = service.resolveDriverIdByMobile(null, MOBILE);
|
||||||
}
|
}
|
||||||
assertEquals(9001L, driverId);
|
assertEquals(9001L, driverId);
|
||||||
|
|||||||
-2
@@ -14,7 +14,6 @@ import org.mockito.MockedStatic;
|
|||||||
import org.springblade.core.log.exception.ServiceException;
|
import org.springblade.core.log.exception.ServiceException;
|
||||||
import org.springblade.core.secure.BladeUser;
|
import org.springblade.core.secure.BladeUser;
|
||||||
import org.springblade.core.secure.utils.AuthUtil;
|
import org.springblade.core.secure.utils.AuthUtil;
|
||||||
import org.springblade.system.feign.IMpUserClient;
|
|
||||||
import org.springblade.transport.mapper.ExceptionDisposalMapper;
|
import org.springblade.transport.mapper.ExceptionDisposalMapper;
|
||||||
import org.springblade.transport.mapper.WaybillEnroutePunchMapper;
|
import org.springblade.transport.mapper.WaybillEnroutePunchMapper;
|
||||||
import org.springblade.transport.mapper.WaybillNodePunchMapper;
|
import org.springblade.transport.mapper.WaybillNodePunchMapper;
|
||||||
@@ -88,7 +87,6 @@ class DriverTripAcceptRejectTest {
|
|||||||
service = new DriverWaybillServiceImpl(
|
service = new DriverWaybillServiceImpl(
|
||||||
waybillService,
|
waybillService,
|
||||||
driverService,
|
driverService,
|
||||||
mock(IMpUserClient.class),
|
|
||||||
mock(IProcessConfigService.class),
|
mock(IProcessConfigService.class),
|
||||||
mock(ITransportVehicleService.class),
|
mock(ITransportVehicleService.class),
|
||||||
certificationGate,
|
certificationGate,
|
||||||
|
|||||||
-4
@@ -10,7 +10,6 @@ import org.mockito.ArgumentCaptor;
|
|||||||
import org.mockito.MockedStatic;
|
import org.mockito.MockedStatic;
|
||||||
import org.springblade.core.log.exception.ServiceException;
|
import org.springblade.core.log.exception.ServiceException;
|
||||||
import org.springblade.core.secure.utils.AuthUtil;
|
import org.springblade.core.secure.utils.AuthUtil;
|
||||||
import org.springblade.system.feign.IMpUserClient;
|
|
||||||
import org.springblade.transport.mapper.ExceptionDisposalMapper;
|
import org.springblade.transport.mapper.ExceptionDisposalMapper;
|
||||||
import org.springblade.transport.mapper.WaybillEnroutePunchMapper;
|
import org.springblade.transport.mapper.WaybillEnroutePunchMapper;
|
||||||
import org.springblade.transport.mapper.WaybillNodePunchMapper;
|
import org.springblade.transport.mapper.WaybillNodePunchMapper;
|
||||||
@@ -74,7 +73,6 @@ class DriverTripCardTest {
|
|||||||
|
|
||||||
private IWaybillService waybillService;
|
private IWaybillService waybillService;
|
||||||
private IDriverService driverService;
|
private IDriverService driverService;
|
||||||
private IMpUserClient mpUserClient;
|
|
||||||
private ITripQueryService tripQueryService;
|
private ITripQueryService tripQueryService;
|
||||||
private WaybillEnroutePunchMapper enroutePunchMapper;
|
private WaybillEnroutePunchMapper enroutePunchMapper;
|
||||||
private WaybillNodePunchMapper nodePunchMapper;
|
private WaybillNodePunchMapper nodePunchMapper;
|
||||||
@@ -94,14 +92,12 @@ class DriverTripCardTest {
|
|||||||
void setUp() {
|
void setUp() {
|
||||||
waybillService = mock(IWaybillService.class);
|
waybillService = mock(IWaybillService.class);
|
||||||
driverService = mock(IDriverService.class);
|
driverService = mock(IDriverService.class);
|
||||||
mpUserClient = mock(IMpUserClient.class);
|
|
||||||
tripQueryService = mock(ITripQueryService.class);
|
tripQueryService = mock(ITripQueryService.class);
|
||||||
enroutePunchMapper = mock(WaybillEnroutePunchMapper.class);
|
enroutePunchMapper = mock(WaybillEnroutePunchMapper.class);
|
||||||
nodePunchMapper = mock(WaybillNodePunchMapper.class);
|
nodePunchMapper = mock(WaybillNodePunchMapper.class);
|
||||||
service = new DriverWaybillServiceImpl(
|
service = new DriverWaybillServiceImpl(
|
||||||
waybillService,
|
waybillService,
|
||||||
driverService,
|
driverService,
|
||||||
mpUserClient,
|
|
||||||
mock(IProcessConfigService.class),
|
mock(IProcessConfigService.class),
|
||||||
mock(ITransportVehicleService.class),
|
mock(ITransportVehicleService.class),
|
||||||
mock(CertificationGate.class),
|
mock(CertificationGate.class),
|
||||||
|
|||||||
-2
@@ -11,7 +11,6 @@ import org.mockito.ArgumentCaptor;
|
|||||||
import org.mockito.MockedStatic;
|
import org.mockito.MockedStatic;
|
||||||
import org.springblade.core.log.exception.ServiceException;
|
import org.springblade.core.log.exception.ServiceException;
|
||||||
import org.springblade.core.secure.utils.AuthUtil;
|
import org.springblade.core.secure.utils.AuthUtil;
|
||||||
import org.springblade.system.feign.IMpUserClient;
|
|
||||||
import org.springblade.transport.mapper.ExceptionDisposalMapper;
|
import org.springblade.transport.mapper.ExceptionDisposalMapper;
|
||||||
import org.springblade.transport.mapper.WaybillEnroutePunchMapper;
|
import org.springblade.transport.mapper.WaybillEnroutePunchMapper;
|
||||||
import org.springblade.transport.mapper.WaybillNodePunchMapper;
|
import org.springblade.transport.mapper.WaybillNodePunchMapper;
|
||||||
@@ -116,7 +115,6 @@ class DriverWaybillAutoCompleteTest {
|
|||||||
service = new DriverWaybillServiceImpl(
|
service = new DriverWaybillServiceImpl(
|
||||||
waybillService,
|
waybillService,
|
||||||
driverService,
|
driverService,
|
||||||
mock(IMpUserClient.class),
|
|
||||||
mock(IProcessConfigService.class),
|
mock(IProcessConfigService.class),
|
||||||
mock(ITransportVehicleService.class),
|
mock(ITransportVehicleService.class),
|
||||||
mock(CertificationGate.class),
|
mock(CertificationGate.class),
|
||||||
|
|||||||
-2
@@ -7,7 +7,6 @@ import org.junit.jupiter.api.BeforeAll;
|
|||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.DisplayName;
|
import org.junit.jupiter.api.DisplayName;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.springblade.system.feign.IMpUserClient;
|
|
||||||
import org.springblade.transport.mapper.ExceptionDisposalMapper;
|
import org.springblade.transport.mapper.ExceptionDisposalMapper;
|
||||||
import org.springblade.transport.mapper.WaybillEnroutePunchMapper;
|
import org.springblade.transport.mapper.WaybillEnroutePunchMapper;
|
||||||
import org.springblade.transport.mapper.WaybillNodePunchMapper;
|
import org.springblade.transport.mapper.WaybillNodePunchMapper;
|
||||||
@@ -73,7 +72,6 @@ class DriverWaybillCardLocationTest {
|
|||||||
service = new DriverWaybillServiceImpl(
|
service = new DriverWaybillServiceImpl(
|
||||||
waybillService,
|
waybillService,
|
||||||
mock(IDriverService.class),
|
mock(IDriverService.class),
|
||||||
mock(IMpUserClient.class),
|
|
||||||
mock(IProcessConfigService.class),
|
mock(IProcessConfigService.class),
|
||||||
mock(ITransportVehicleService.class),
|
mock(ITransportVehicleService.class),
|
||||||
mock(CertificationGate.class),
|
mock(CertificationGate.class),
|
||||||
|
|||||||
-2
@@ -7,7 +7,6 @@ import org.junit.jupiter.api.BeforeAll;
|
|||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.DisplayName;
|
import org.junit.jupiter.api.DisplayName;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.springblade.system.feign.IMpUserClient;
|
|
||||||
import org.springblade.transport.mapper.ExceptionDisposalMapper;
|
import org.springblade.transport.mapper.ExceptionDisposalMapper;
|
||||||
import org.springblade.transport.mapper.WaybillEnroutePunchMapper;
|
import org.springblade.transport.mapper.WaybillEnroutePunchMapper;
|
||||||
import org.springblade.transport.mapper.WaybillNodePunchMapper;
|
import org.springblade.transport.mapper.WaybillNodePunchMapper;
|
||||||
@@ -55,7 +54,6 @@ class DriverWaybillNodePunchTest {
|
|||||||
service = new DriverWaybillServiceImpl(
|
service = new DriverWaybillServiceImpl(
|
||||||
mock(IWaybillService.class),
|
mock(IWaybillService.class),
|
||||||
mock(IDriverService.class),
|
mock(IDriverService.class),
|
||||||
mock(IMpUserClient.class),
|
|
||||||
mock(IProcessConfigService.class),
|
mock(IProcessConfigService.class),
|
||||||
mock(ITransportVehicleService.class),
|
mock(ITransportVehicleService.class),
|
||||||
mock(CertificationGate.class),
|
mock(CertificationGate.class),
|
||||||
|
|||||||
-2
@@ -12,7 +12,6 @@ import org.mockito.ArgumentCaptor;
|
|||||||
import org.mockito.MockedStatic;
|
import org.mockito.MockedStatic;
|
||||||
import org.springblade.core.log.exception.ServiceException;
|
import org.springblade.core.log.exception.ServiceException;
|
||||||
import org.springblade.core.secure.utils.AuthUtil;
|
import org.springblade.core.secure.utils.AuthUtil;
|
||||||
import org.springblade.system.feign.IMpUserClient;
|
|
||||||
import org.springblade.transport.mapper.ExceptionDisposalMapper;
|
import org.springblade.transport.mapper.ExceptionDisposalMapper;
|
||||||
import org.springblade.transport.mapper.WaybillEnroutePunchMapper;
|
import org.springblade.transport.mapper.WaybillEnroutePunchMapper;
|
||||||
import org.springblade.transport.mapper.WaybillNodePunchMapper;
|
import org.springblade.transport.mapper.WaybillNodePunchMapper;
|
||||||
@@ -76,7 +75,6 @@ class DriverWaybillOwnershipTest {
|
|||||||
service = new DriverWaybillServiceImpl(
|
service = new DriverWaybillServiceImpl(
|
||||||
waybillService,
|
waybillService,
|
||||||
driverService,
|
driverService,
|
||||||
mock(IMpUserClient.class),
|
|
||||||
mock(IProcessConfigService.class),
|
mock(IProcessConfigService.class),
|
||||||
mock(ITransportVehicleService.class),
|
mock(ITransportVehicleService.class),
|
||||||
mock(CertificationGate.class),
|
mock(CertificationGate.class),
|
||||||
|
|||||||
-2
@@ -15,7 +15,6 @@ import org.mockito.ArgumentMatchers;
|
|||||||
import org.mockito.MockedStatic;
|
import org.mockito.MockedStatic;
|
||||||
import org.springblade.core.log.exception.ServiceException;
|
import org.springblade.core.log.exception.ServiceException;
|
||||||
import org.springblade.core.secure.utils.AuthUtil;
|
import org.springblade.core.secure.utils.AuthUtil;
|
||||||
import org.springblade.system.feign.IMpUserClient;
|
|
||||||
import org.springblade.transport.mapper.ExceptionDisposalMapper;
|
import org.springblade.transport.mapper.ExceptionDisposalMapper;
|
||||||
import org.springblade.transport.mapper.WaybillEnroutePunchMapper;
|
import org.springblade.transport.mapper.WaybillEnroutePunchMapper;
|
||||||
import org.springblade.transport.mapper.WaybillNodePunchMapper;
|
import org.springblade.transport.mapper.WaybillNodePunchMapper;
|
||||||
@@ -87,7 +86,6 @@ class DriverWaybillRejectDetachTest {
|
|||||||
service = new DriverWaybillServiceImpl(
|
service = new DriverWaybillServiceImpl(
|
||||||
waybillService,
|
waybillService,
|
||||||
driverService,
|
driverService,
|
||||||
mock(IMpUserClient.class),
|
|
||||||
mock(IProcessConfigService.class),
|
mock(IProcessConfigService.class),
|
||||||
mock(ITransportVehicleService.class),
|
mock(ITransportVehicleService.class),
|
||||||
certificationGate,
|
certificationGate,
|
||||||
|
|||||||
-2
@@ -12,7 +12,6 @@ import org.junit.jupiter.api.DisplayName;
|
|||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.mockito.MockedStatic;
|
import org.mockito.MockedStatic;
|
||||||
import org.springblade.core.secure.utils.AuthUtil;
|
import org.springblade.core.secure.utils.AuthUtil;
|
||||||
import org.springblade.system.feign.IMpUserClient;
|
|
||||||
import org.springblade.transport.mapper.ExceptionDisposalMapper;
|
import org.springblade.transport.mapper.ExceptionDisposalMapper;
|
||||||
import org.springblade.transport.mapper.WaybillEnroutePunchMapper;
|
import org.springblade.transport.mapper.WaybillEnroutePunchMapper;
|
||||||
import org.springblade.transport.mapper.WaybillNodePunchMapper;
|
import org.springblade.transport.mapper.WaybillNodePunchMapper;
|
||||||
@@ -86,7 +85,6 @@ class DriverWaybillTabStatusTest {
|
|||||||
service = new DriverWaybillServiceImpl(
|
service = new DriverWaybillServiceImpl(
|
||||||
waybillService,
|
waybillService,
|
||||||
driverService,
|
driverService,
|
||||||
mock(IMpUserClient.class),
|
|
||||||
mock(IProcessConfigService.class),
|
mock(IProcessConfigService.class),
|
||||||
mock(ITransportVehicleService.class),
|
mock(ITransportVehicleService.class),
|
||||||
mock(CertificationGate.class),
|
mock(CertificationGate.class),
|
||||||
|
|||||||
+119
@@ -1,5 +1,7 @@
|
|||||||
package org.springblade.transport.service.impl;
|
package org.springblade.transport.service.impl;
|
||||||
|
|
||||||
|
import ch.qos.logback.classic.Level;
|
||||||
|
import ch.qos.logback.classic.spi.ILoggingEvent;
|
||||||
import com.baomidou.mybatisplus.core.MybatisConfiguration;
|
import com.baomidou.mybatisplus.core.MybatisConfiguration;
|
||||||
import com.baomidou.mybatisplus.core.conditions.Wrapper;
|
import com.baomidou.mybatisplus.core.conditions.Wrapper;
|
||||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||||
@@ -24,6 +26,7 @@ import org.springblade.transport.service.IContractManageService;
|
|||||||
import org.springblade.transport.service.IDriverService;
|
import org.springblade.transport.service.IDriverService;
|
||||||
import org.springblade.transport.service.IProcessConfigService;
|
import org.springblade.transport.service.IProcessConfigService;
|
||||||
import org.springblade.transport.service.IReceivablePayableDetailService;
|
import org.springblade.transport.service.IReceivablePayableDetailService;
|
||||||
|
import org.springblade.transport.support.LogCapture;
|
||||||
|
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
@@ -35,6 +38,7 @@ import java.util.Map;
|
|||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
@@ -66,6 +70,9 @@ class LoadingManageChildStatusWriteTest {
|
|||||||
private static final String DRIVER_PHONE = "13800138000";
|
private static final String DRIVER_PHONE = "13800138000";
|
||||||
private static final String TENANT_ID = "000000";
|
private static final String TENANT_ID = "000000";
|
||||||
private static final Long RESOLVED_DRIVER_ID = 9321L;
|
private static final Long RESOLVED_DRIVER_ID = 9321L;
|
||||||
|
private static final Long MANUAL_DRIVER_ID = 7001L;
|
||||||
|
private static final Long OTHER_PROFILE_ID = 8888L;
|
||||||
|
private static final String OTHER_DRIVER_PHONE = "13900139000";
|
||||||
private static final Long SOURCE_LOADING_ID = 1800000000000000002L;
|
private static final Long SOURCE_LOADING_ID = 1800000000000000002L;
|
||||||
|
|
||||||
private static final Long NEED_ACCEPT_WAYBILL_ID = 3101L;
|
private static final Long NEED_ACCEPT_WAYBILL_ID = 3101L;
|
||||||
@@ -394,6 +401,110 @@ class LoadingManageChildStatusWriteTest {
|
|||||||
assertEquals(RESOLVED_DRIVER_ID, capturedSaved().getDriverId());
|
assertEquals(RESOLVED_DRIVER_ID, capturedSaved().getDriverId());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("已归属的单子号码没变:无关字段的保存不重解析,归属原样保留")
|
||||||
|
void unrelatedEditKeepsStoredDriverId() {
|
||||||
|
LoadingManage record = runningRecord();
|
||||||
|
record.setDriverId(RESOLVED_DRIVER_ID);
|
||||||
|
stubLoadingRecord(record);
|
||||||
|
stubWaybills(waybill(NEED_ACCEPT_WAYBILL_ID, NEED_ACCEPT_PROJECT_ID));
|
||||||
|
// 这一次谁都解析不到:只要实现还按手机号重解析,归属就会被清空
|
||||||
|
when(driverService.resolveDriverIdByMobile(any(), any())).thenReturn(null);
|
||||||
|
|
||||||
|
assertTrue(service.submit(editForm(LOADING_ID, NEED_ACCEPT_WAYBILL_ID)));
|
||||||
|
|
||||||
|
assertEquals(RESOLVED_DRIVER_ID, capturedLoading().getDriverId());
|
||||||
|
assertEquals(RESOLVED_DRIVER_ID, statusSyncUpdates().get(0).setValue("driver_id"));
|
||||||
|
verify(driverService, never()).resolveDriverIdByMobile(any(), any());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("人工补过归属的单子:号码恰好命中别人的档案,保存也不改归属")
|
||||||
|
void unrelatedEditKeepsManualOwnership() {
|
||||||
|
LoadingManage record = runningRecord();
|
||||||
|
record.setDriverId(MANUAL_DRIVER_ID);
|
||||||
|
stubLoadingRecord(record);
|
||||||
|
stubWaybills(waybill(NEED_ACCEPT_WAYBILL_ID, NEED_ACCEPT_PROJECT_ID));
|
||||||
|
when(driverService.resolveDriverIdByMobile(any(), any())).thenReturn(OTHER_PROFILE_ID);
|
||||||
|
|
||||||
|
assertTrue(service.submit(editForm(LOADING_ID, NEED_ACCEPT_WAYBILL_ID)));
|
||||||
|
|
||||||
|
assertEquals(MANUAL_DRIVER_ID, capturedLoading().getDriverId(),
|
||||||
|
"人工归属不能被一次无关保存改到同号的另一个档案上");
|
||||||
|
assertEquals(MANUAL_DRIVER_ID, statusSyncUpdates().get(0).setValue("driver_id"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("-1 哨兵的归属:号码没变的保存原样保留,不抹成 NULL")
|
||||||
|
void sentinelDriverIdSurvivesUnrelatedEdit() {
|
||||||
|
LoadingManage record = runningRecord();
|
||||||
|
record.setDriverId(-1L);
|
||||||
|
stubLoadingRecord(record);
|
||||||
|
stubWaybills(waybill(NEED_ACCEPT_WAYBILL_ID, NEED_ACCEPT_PROJECT_ID));
|
||||||
|
when(driverService.resolveDriverIdByMobile(any(), any())).thenReturn(null);
|
||||||
|
|
||||||
|
assertTrue(service.submit(editForm(LOADING_ID, NEED_ACCEPT_WAYBILL_ID)));
|
||||||
|
|
||||||
|
assertEquals(-1L, capturedLoading().getDriverId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("换司机:号码变了就按新号码重新解析,归属跟着换")
|
||||||
|
void changingPhoneResolvesNewDriverId() {
|
||||||
|
LoadingManage record = pendingRecord();
|
||||||
|
record.setDriverId(RESOLVED_DRIVER_ID);
|
||||||
|
stubLoadingRecord(record);
|
||||||
|
stubWaybills(waybill(NEED_ACCEPT_WAYBILL_ID, NEED_ACCEPT_PROJECT_ID));
|
||||||
|
stubConfigs(config(NEED_ACCEPT_PROJECT_ID, NEED_ACCEPT_JSON));
|
||||||
|
when(driverService.resolveDriverIdByMobile(any(), eq(OTHER_DRIVER_PHONE))).thenReturn(OTHER_PROFILE_ID);
|
||||||
|
LoadingManage form = editForm(LOADING_ID, NEED_ACCEPT_WAYBILL_ID);
|
||||||
|
form.setDriverPhone(OTHER_DRIVER_PHONE);
|
||||||
|
|
||||||
|
assertTrue(service.submit(form));
|
||||||
|
|
||||||
|
assertEquals(OTHER_PROFILE_ID, capturedLoading().getDriverId());
|
||||||
|
assertEquals(OTHER_PROFILE_ID, statusSyncUpdates().get(0).setValue("driver_id"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("号码改成一个解析不到的号:归属落空,子单同步落空")
|
||||||
|
void changingPhoneToUnresolvedNumberClearsDriverId() {
|
||||||
|
LoadingManage record = pendingRecord();
|
||||||
|
record.setDriverId(RESOLVED_DRIVER_ID);
|
||||||
|
stubLoadingRecord(record);
|
||||||
|
stubWaybills(waybill(NEED_ACCEPT_WAYBILL_ID, NEED_ACCEPT_PROJECT_ID));
|
||||||
|
stubConfigs(config(NEED_ACCEPT_PROJECT_ID, NEED_ACCEPT_JSON));
|
||||||
|
when(driverService.resolveDriverIdByMobile(any(), eq(OTHER_DRIVER_PHONE))).thenReturn(null);
|
||||||
|
LoadingManage form = editForm(LOADING_ID, NEED_ACCEPT_WAYBILL_ID);
|
||||||
|
form.setDriverPhone(OTHER_DRIVER_PHONE);
|
||||||
|
|
||||||
|
assertTrue(service.submit(form));
|
||||||
|
|
||||||
|
assertNull(capturedLoading().getDriverId());
|
||||||
|
assertNull(statusSyncUpdates().get(0).setValue("driver_id"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("解析不到档案:留一条脱敏 WARN,保存照常成功")
|
||||||
|
void unresolvedPhoneLogsMaskedWarning() {
|
||||||
|
stubWaybills(waybill(NO_ACCEPT_WAYBILL_ID, NO_ACCEPT_PROJECT_ID));
|
||||||
|
stubConfigs(config(NO_ACCEPT_PROJECT_ID, NO_ACCEPT_JSON));
|
||||||
|
when(driverService.resolveDriverIdByMobile(any(), eq(DRIVER_PHONE))).thenReturn(null);
|
||||||
|
try (LogCapture logs = LogCapture.open(LoadingManageServiceImpl.class)) {
|
||||||
|
assertTrue(service.submit(loadingForm(NO_ACCEPT_WAYBILL_ID)));
|
||||||
|
|
||||||
|
String warning = logs.events().stream()
|
||||||
|
.filter(event -> event.getLevel() == Level.WARN)
|
||||||
|
.map(ILoggingEvent::getFormattedMessage)
|
||||||
|
.filter(message -> message.contains("司机档案"))
|
||||||
|
.findFirst()
|
||||||
|
.orElseThrow(() -> new AssertionError("解析失败必须留 WARN,实际日志:" + logs.messages()));
|
||||||
|
assertTrue(warning.contains("138****8000"), "WARN 里的号码必须脱敏,实际:" + warning);
|
||||||
|
assertFalse(warning.contains(DRIVER_PHONE), "WARN 里不能出现完整号码,实际:" + warning);
|
||||||
|
assertTrue(warning.contains(LOADING_NO), "WARN 要带业务标识(配载单号),实际:" + warning);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------ 夹具
|
// ------------------------------------------------------------ 夹具
|
||||||
|
|
||||||
private LoadingManage loadingForm(Long... waybillIds) {
|
private LoadingManage loadingForm(Long... waybillIds) {
|
||||||
@@ -468,6 +579,14 @@ class LoadingManageChildStatusWriteTest {
|
|||||||
return record;
|
return record;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private LoadingManage pendingRecord() {
|
||||||
|
LoadingManage record = loadingRecord("pending", NEED_ACCEPT_WAYBILL_ID);
|
||||||
|
record.setVehicleNo("桂A12345");
|
||||||
|
record.setDriverName("张三");
|
||||||
|
record.setDriverPhone(DRIVER_PHONE);
|
||||||
|
return record;
|
||||||
|
}
|
||||||
|
|
||||||
private LoadingManage copySource() {
|
private LoadingManage copySource() {
|
||||||
LoadingManage source = loadingRecord("pending", NEED_ACCEPT_WAYBILL_ID);
|
LoadingManage source = loadingRecord("pending", NEED_ACCEPT_WAYBILL_ID);
|
||||||
source.setLoadingSubNos("YD-" + NEED_ACCEPT_WAYBILL_ID);
|
source.setLoadingSubNos("YD-" + NEED_ACCEPT_WAYBILL_ID);
|
||||||
|
|||||||
+23
@@ -1,5 +1,7 @@
|
|||||||
package org.springblade.transport.service.impl;
|
package org.springblade.transport.service.impl;
|
||||||
|
|
||||||
|
import ch.qos.logback.classic.Level;
|
||||||
|
import ch.qos.logback.classic.spi.ILoggingEvent;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.DisplayName;
|
import org.junit.jupiter.api.DisplayName;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
@@ -11,6 +13,7 @@ import org.springblade.transport.service.IDriverService;
|
|||||||
import org.springblade.transport.service.IProjectApplyService;
|
import org.springblade.transport.service.IProjectApplyService;
|
||||||
import org.springblade.transport.service.ITransportPlanService;
|
import org.springblade.transport.service.ITransportPlanService;
|
||||||
import org.springblade.transport.service.IWaybillService;
|
import org.springblade.transport.service.IWaybillService;
|
||||||
|
import org.springblade.transport.support.LogCapture;
|
||||||
|
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
@@ -18,6 +21,7 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
@@ -84,6 +88,25 @@ class MasterOrderDriverIdTest {
|
|||||||
verify(waybillService).submit(any(Waybill.class));
|
verify(waybillService).submit(any(Waybill.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("解析不到档案:落空时留一条脱敏 WARN,派单照常成功")
|
||||||
|
void unresolvedProfileLogsMaskedWarning() throws Exception {
|
||||||
|
when(driverService.resolveDriverIdByMobile(any(), eq(DRIVER_PHONE))).thenReturn(null);
|
||||||
|
try (LogCapture logs = LogCapture.open(MasterOrderServiceImpl.class)) {
|
||||||
|
assertTrue(createWaybill(dispatch()));
|
||||||
|
|
||||||
|
String warning = logs.events().stream()
|
||||||
|
.filter(event -> event.getLevel() == Level.WARN)
|
||||||
|
.map(ILoggingEvent::getFormattedMessage)
|
||||||
|
.filter(message -> message.contains("司机档案"))
|
||||||
|
.findFirst()
|
||||||
|
.orElseThrow(() -> new AssertionError("解析失败必须留 WARN,实际日志:" + logs.messages()));
|
||||||
|
assertTrue(warning.contains("138****8000"), "WARN 里的号码必须脱敏,实际:" + warning);
|
||||||
|
assertFalse(warning.contains(DRIVER_PHONE), "WARN 里不能出现完整号码,实际:" + warning);
|
||||||
|
assertTrue(warning.contains("ZD-20261027-001"), "WARN 要带业务标识(总单号),实际:" + warning);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------ 夹具
|
// ------------------------------------------------------------ 夹具
|
||||||
|
|
||||||
private boolean createWaybill(Map<String, Object> dispatch) throws Exception {
|
private boolean createWaybill(Map<String, Object> dispatch) throws Exception {
|
||||||
|
|||||||
-11
@@ -86,17 +86,6 @@ class WaybillImportDriverIdTest {
|
|||||||
assertNull(waybill.getDriverId());
|
assertNull(waybill.getDriverId());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
@DisplayName("解析器返回 0(无主哨兵):按无主落空,不把 0 写进库")
|
|
||||||
void normalizesSentinelToNull() throws Exception {
|
|
||||||
when(driverService.resolveDriverIdByMobile(any(), eq(DRIVER_PHONE))).thenReturn(0L);
|
|
||||||
|
|
||||||
Waybill waybill = importedWaybill(0L);
|
|
||||||
fillDriverOwnership(waybill, 3);
|
|
||||||
|
|
||||||
assertNull(waybill.getDriverId());
|
|
||||||
}
|
|
||||||
|
|
||||||
// ------------------------------------------------------------ 夹具
|
// ------------------------------------------------------------ 夹具
|
||||||
|
|
||||||
private void fillDriverOwnership(Waybill waybill, int rowNo) throws Exception {
|
private void fillDriverOwnership(Waybill waybill, int rowNo) throws Exception {
|
||||||
|
|||||||
+24
@@ -1,5 +1,7 @@
|
|||||||
package org.springblade.transport.service.impl;
|
package org.springblade.transport.service.impl;
|
||||||
|
|
||||||
|
import ch.qos.logback.classic.Level;
|
||||||
|
import ch.qos.logback.classic.spi.ILoggingEvent;
|
||||||
import com.baomidou.mybatisplus.core.MybatisConfiguration;
|
import com.baomidou.mybatisplus.core.MybatisConfiguration;
|
||||||
import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
|
import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
|
||||||
import org.apache.ibatis.builder.MapperBuilderAssistant;
|
import org.apache.ibatis.builder.MapperBuilderAssistant;
|
||||||
@@ -12,11 +14,13 @@ import org.springblade.transport.mapper.WaybillMapper;
|
|||||||
import org.springblade.transport.pojo.entity.Waybill;
|
import org.springblade.transport.pojo.entity.Waybill;
|
||||||
import org.springblade.transport.service.IDriverService;
|
import org.springblade.transport.service.IDriverService;
|
||||||
import org.springblade.transport.service.IProcessConfigService;
|
import org.springblade.transport.service.IProcessConfigService;
|
||||||
|
import org.springblade.transport.support.LogCapture;
|
||||||
|
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
@@ -108,6 +112,25 @@ class WaybillReassignDriverIdTest {
|
|||||||
assertNull(capturedWaybill().getDriverId());
|
assertNull(capturedWaybill().getDriverId());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("解析不到档案:落空时留一条脱敏 WARN,派单照常成功")
|
||||||
|
void unresolvedProfileLogsMaskedWarning() {
|
||||||
|
when(driverService.resolveDriverIdByMobile(TENANT_ID, DRIVER_PHONE)).thenReturn(null);
|
||||||
|
try (LogCapture logs = LogCapture.open(WaybillServiceImpl.class)) {
|
||||||
|
assertTrue(service.reassignWithoutDeptCheck(reassignRequest(null)));
|
||||||
|
|
||||||
|
String warning = logs.events().stream()
|
||||||
|
.filter(event -> event.getLevel() == Level.WARN)
|
||||||
|
.map(ILoggingEvent::getFormattedMessage)
|
||||||
|
.filter(message -> message.contains("司机档案"))
|
||||||
|
.findFirst()
|
||||||
|
.orElseThrow(() -> new AssertionError("解析失败必须留 WARN,实际日志:" + logs.messages()));
|
||||||
|
assertTrue(warning.contains("138****8000"), "WARN 里的号码必须脱敏,实际:" + warning);
|
||||||
|
assertFalse(warning.contains(DRIVER_PHONE), "WARN 里不能出现完整号码,实际:" + warning);
|
||||||
|
assertTrue(warning.contains("YD-20261027-001"), "WARN 要带业务标识(运单号),实际:" + warning);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------ 夹具
|
// ------------------------------------------------------------ 夹具
|
||||||
|
|
||||||
private void setUpAgain() throws Exception {
|
private void setUpAgain() throws Exception {
|
||||||
@@ -131,6 +154,7 @@ class WaybillReassignDriverIdTest {
|
|||||||
waybill.setId(WAYBILL_ID);
|
waybill.setId(WAYBILL_ID);
|
||||||
waybill.setIsDeleted(0);
|
waybill.setIsDeleted(0);
|
||||||
waybill.setTenantId(TENANT_ID);
|
waybill.setTenantId(TENANT_ID);
|
||||||
|
waybill.setWaybillNo("YD-20261027-001");
|
||||||
waybill.setBusinessStatus("pending");
|
waybill.setBusinessStatus("pending");
|
||||||
waybill.setTransportType("road");
|
waybill.setTransportType("road");
|
||||||
waybill.setDriverName("张三");
|
waybill.setDriverName("张三");
|
||||||
|
|||||||
+48
@@ -0,0 +1,48 @@
|
|||||||
|
package org.springblade.transport.support;
|
||||||
|
|
||||||
|
import ch.qos.logback.classic.Logger;
|
||||||
|
import ch.qos.logback.classic.spi.ILoggingEvent;
|
||||||
|
import ch.qos.logback.core.read.ListAppender;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 抓取某个类的日志输出(logback ListAppender)。
|
||||||
|
* <p>
|
||||||
|
* 「解析失败时留一条脱敏 WARN」这类要求只看返回值验不出来,必须断言真实日志正文。
|
||||||
|
*/
|
||||||
|
public final class LogCapture implements AutoCloseable {
|
||||||
|
|
||||||
|
private final Logger logger;
|
||||||
|
private final ListAppender<ILoggingEvent> appender;
|
||||||
|
|
||||||
|
private LogCapture(Logger logger, ListAppender<ILoggingEvent> appender) {
|
||||||
|
this.logger = logger;
|
||||||
|
this.appender = appender;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static LogCapture open(Class<?> loggerType) {
|
||||||
|
Logger logger = (Logger) LoggerFactory.getLogger(loggerType);
|
||||||
|
ListAppender<ILoggingEvent> appender = new ListAppender<>();
|
||||||
|
appender.start();
|
||||||
|
logger.addAppender(appender);
|
||||||
|
return new LogCapture(logger, appender);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 已按占位符填充好的日志正文,按发生顺序 */
|
||||||
|
public List<String> messages() {
|
||||||
|
return appender.list.stream().map(ILoggingEvent::getFormattedMessage).toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<ILoggingEvent> events() {
|
||||||
|
return List.copyOf(appender.list);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() {
|
||||||
|
logger.detachAppender(appender);
|
||||||
|
appender.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -22,8 +22,9 @@
|
|||||||
-- ⑤ 逻辑删除的配载单同样回填:票面口径只有 driver_id IS NULL,不额外收窄范围;
|
-- ⑤ 逻辑删除的配载单同样回填:票面口径只有 driver_id IS NULL,不额外收窄范围;
|
||||||
-- 这些单不会回到列表,回填对它们无副作用。
|
-- 这些单不会回到列表,回填对它们无副作用。
|
||||||
-- ⑥ 跨表比较显式 COLLATE:blade_loading_manage.driver_phone / tenant_id 是 utf8mb4_0900_ai_ci,
|
-- ⑥ 跨表比较显式 COLLATE:blade_loading_manage.driver_phone / tenant_id 是 utf8mb4_0900_ai_ci,
|
||||||
-- blade_transport_driver.mobile / tenant_id 是 utf8mb4_general_ci;
|
-- blade_transport_driver.mobile / tenant_id 与存档表都是 utf8mb4_general_ci;
|
||||||
-- 不显式 COLLATE 会抛 ERROR 1267 Illegal mix of collations,只有真跑库才会暴露。
|
-- 不显式 COLLATE 会抛 ERROR 1267 Illegal mix of collations,只有真跑库才会暴露。
|
||||||
|
-- 第 2.4 节拿存档表比 driver_phone 同样要带 COLLATE utf8mb4_0900_ai_ci。
|
||||||
-- ⑦ 取数与写入全在 SQL 内完成,不经 JSON / 客户端中转:19 位雪花 ID 过 JSON 会丢精度。
|
-- ⑦ 取数与写入全在 SQL 内完成,不经 JSON / 客户端中转:19 位雪花 ID 过 JSON 会丢精度。
|
||||||
-- ⑧ 分批执行(默认每批 500 行),每批独立提交,中断后重跑从剩余 NULL 行继续。
|
-- ⑧ 分批执行(默认每批 500 行),每批独立提交,中断后重跑从剩余 NULL 行继续。
|
||||||
--
|
--
|
||||||
@@ -41,11 +42,11 @@ CREATE TABLE IF NOT EXISTS blade_loading_manage_driver_id_bak_20261028 (
|
|||||||
loading_id bigint NOT NULL COMMENT '配载单ID',
|
loading_id bigint NOT NULL COMMENT '配载单ID',
|
||||||
driver_id_before bigint DEFAULT NULL COMMENT '回填前的司机ID(本脚本只处理 NULL)',
|
driver_id_before bigint DEFAULT NULL COMMENT '回填前的司机ID(本脚本只处理 NULL)',
|
||||||
driver_id_after bigint DEFAULT NULL COMMENT '回填写入的司机档案ID(blade_transport_driver.id)',
|
driver_id_after bigint DEFAULT NULL COMMENT '回填写入的司机档案ID(blade_transport_driver.id)',
|
||||||
driver_phone varchar(50) COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '回填前的手机号快照,用来证明没有被改写',
|
driver_phone varchar(50) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '回填前的手机号快照,用来证明没有被改写',
|
||||||
update_time_before datetime DEFAULT NULL COMMENT '回填前的更新时间,用来证明没有被改写',
|
update_time_before datetime DEFAULT NULL COMMENT '回填前的更新时间,用来证明没有被改写',
|
||||||
PRIMARY KEY (loading_id),
|
PRIMARY KEY (loading_id),
|
||||||
KEY idx_driver_id_after (driver_id_after)
|
KEY idx_driver_id_after (driver_id_after)
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='20261028 配载单司机档案ID回填存档';
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='20261028 配载单司机档案ID回填存档';
|
||||||
|
|
||||||
-- 命中映射:只收「号码唯一命中一条未删除档案」的 NULL 行。
|
-- 命中映射:只收「号码唯一命中一条未删除档案」的 NULL 行。
|
||||||
-- INSERT IGNORE + WHERE driver_id IS NULL:第二次执行不会重复建映射,已经填过的行不会再进映射。
|
-- INSERT IGNORE + WHERE driver_id IS NULL:第二次执行不会重复建映射,已经填过的行不会再进映射。
|
||||||
@@ -151,7 +152,7 @@ SELECT COUNT(*) AS wrong_driver_id
|
|||||||
SELECT COUNT(*) AS snapshot_rewritten
|
SELECT COUNT(*) AS snapshot_rewritten
|
||||||
FROM blade_loading_manage_driver_id_bak_20261028 b
|
FROM blade_loading_manage_driver_id_bak_20261028 b
|
||||||
JOIN blade_loading_manage w ON w.id = b.loading_id
|
JOIN blade_loading_manage w ON w.id = b.loading_id
|
||||||
WHERE NOT (w.driver_phone <=> b.driver_phone)
|
WHERE NOT (w.driver_phone <=> b.driver_phone COLLATE utf8mb4_0900_ai_ci)
|
||||||
OR NOT (w.update_time <=> b.update_time_before);
|
OR NOT (w.update_time <=> b.update_time_before);
|
||||||
|
|
||||||
-- 2.5 冲突清单:同号多档案,这些行被跳过(期望 0 行;有输出就是「为什么没填」的答案)
|
-- 2.5 冲突清单:同号多档案,这些行被跳过(期望 0 行;有输出就是「为什么没填」的答案)
|
||||||
|
|||||||
@@ -300,7 +300,8 @@ CREATE TABLE `blade_waybill` (
|
|||||||
KEY `idx_waybill_dept` (`dept_id`) USING BTREE,
|
KEY `idx_waybill_dept` (`dept_id`) USING BTREE,
|
||||||
KEY `idx_waybill_plan_id` (`plan_id`) USING BTREE,
|
KEY `idx_waybill_plan_id` (`plan_id`) USING BTREE,
|
||||||
KEY `idx_waybill_carrier_contract_id` (`carrier_contract_id`) USING BTREE,
|
KEY `idx_waybill_carrier_contract_id` (`carrier_contract_id`) USING BTREE,
|
||||||
KEY `idx_waybill_create_time` (`create_time`) USING BTREE
|
KEY `idx_waybill_create_time` (`create_time`) USING BTREE,
|
||||||
|
KEY `idx_waybill_tenant_driver_id` (`tenant_id`,`driver_id`) USING BTREE
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='运单管理';
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='运单管理';
|
||||||
|
|
||||||
-- ----------------------------
|
-- ----------------------------
|
||||||
@@ -330,6 +331,7 @@ CREATE TABLE `blade_loading_manage` (
|
|||||||
`trailer_vehicle_no` varchar(100) DEFAULT NULL COMMENT '挂车车牌号',
|
`trailer_vehicle_no` varchar(100) DEFAULT NULL COMMENT '挂车车牌号',
|
||||||
`driver_name` varchar(100) DEFAULT NULL COMMENT '司机',
|
`driver_name` varchar(100) DEFAULT NULL COMMENT '司机',
|
||||||
`driver_phone` varchar(50) DEFAULT NULL COMMENT '联系电话',
|
`driver_phone` varchar(50) DEFAULT NULL COMMENT '联系电话',
|
||||||
|
`driver_id` bigint(20) DEFAULT NULL COMMENT '司机ID',
|
||||||
`escort_name` varchar(100) DEFAULT NULL COMMENT '押运人',
|
`escort_name` varchar(100) DEFAULT NULL COMMENT '押运人',
|
||||||
`escort_phone` varchar(50) DEFAULT NULL COMMENT '押运人手机号',
|
`escort_phone` varchar(50) DEFAULT NULL COMMENT '押运人手机号',
|
||||||
`carrier_type` varchar(50) DEFAULT NULL COMMENT '承运类型',
|
`carrier_type` varchar(50) DEFAULT NULL COMMENT '承运类型',
|
||||||
@@ -359,7 +361,8 @@ CREATE TABLE `blade_loading_manage` (
|
|||||||
UNIQUE KEY `uk_loading_manage_no` (`loading_no`) USING BTREE,
|
UNIQUE KEY `uk_loading_manage_no` (`loading_no`) USING BTREE,
|
||||||
KEY `idx_loading_manage_carrier_contract_id` (`carrier_contract_id`) USING BTREE,
|
KEY `idx_loading_manage_carrier_contract_id` (`carrier_contract_id`) USING BTREE,
|
||||||
KEY `idx_loading_manage_dept` (`dept_id`) USING BTREE,
|
KEY `idx_loading_manage_dept` (`dept_id`) USING BTREE,
|
||||||
KEY `idx_loading_manage_create_time` (`create_time`) USING BTREE
|
KEY `idx_loading_manage_create_time` (`create_time`) USING BTREE,
|
||||||
|
KEY `idx_loading_manage_tenant_driver_id` (`tenant_id`,`driver_id`) USING BTREE
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='配载管理';
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='配载管理';
|
||||||
|
|
||||||
-- ----------------------------
|
-- ----------------------------
|
||||||
|
|||||||
@@ -24,8 +24,9 @@
|
|||||||
-- ⑤ 逻辑删除的运单同样回填:票面口径只有 driver_id IS NULL,不额外收窄范围;
|
-- ⑤ 逻辑删除的运单同样回填:票面口径只有 driver_id IS NULL,不额外收窄范围;
|
||||||
-- 这些单不会回到列表,回填对它们无副作用。
|
-- 这些单不会回到列表,回填对它们无副作用。
|
||||||
-- ⑥ 跨表比较显式 COLLATE:blade_waybill.driver_phone / tenant_id 是 utf8mb4_0900_ai_ci,
|
-- ⑥ 跨表比较显式 COLLATE:blade_waybill.driver_phone / tenant_id 是 utf8mb4_0900_ai_ci,
|
||||||
-- blade_transport_driver.mobile / tenant_id 是 utf8mb4_general_ci;
|
-- blade_transport_driver.mobile / tenant_id 与存档表都是 utf8mb4_general_ci;
|
||||||
-- 不显式 COLLATE 会抛 ERROR 1267 Illegal mix of collations,只有真跑库才会暴露。
|
-- 不显式 COLLATE 会抛 ERROR 1267 Illegal mix of collations,只有真跑库才会暴露。
|
||||||
|
-- 第 2.4 节拿存档表比 driver_phone 同样要带 COLLATE utf8mb4_0900_ai_ci。
|
||||||
-- ⑦ 取数与写入全在 SQL 内完成,不经 JSON / 客户端中转:19 位雪花 ID 过 JSON 会丢精度。
|
-- ⑦ 取数与写入全在 SQL 内完成,不经 JSON / 客户端中转:19 位雪花 ID 过 JSON 会丢精度。
|
||||||
-- ⑧ 分批执行(默认每批 500 行),每批独立提交,中断后重跑从剩余 NULL 行继续。
|
-- ⑧ 分批执行(默认每批 500 行),每批独立提交,中断后重跑从剩余 NULL 行继续。
|
||||||
--
|
--
|
||||||
@@ -44,11 +45,11 @@ CREATE TABLE IF NOT EXISTS blade_waybill_driver_id_bak_20261028 (
|
|||||||
waybill_id bigint NOT NULL COMMENT '运单ID',
|
waybill_id bigint NOT NULL COMMENT '运单ID',
|
||||||
driver_id_before bigint DEFAULT NULL COMMENT '回填前的司机ID(本脚本只处理 NULL)',
|
driver_id_before bigint DEFAULT NULL COMMENT '回填前的司机ID(本脚本只处理 NULL)',
|
||||||
driver_id_after bigint DEFAULT NULL COMMENT '回填写入的司机档案ID(blade_transport_driver.id)',
|
driver_id_after bigint DEFAULT NULL COMMENT '回填写入的司机档案ID(blade_transport_driver.id)',
|
||||||
driver_phone varchar(50) COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '回填前的手机号快照,用来证明没有被改写',
|
driver_phone varchar(50) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '回填前的手机号快照,用来证明没有被改写',
|
||||||
update_time_before datetime DEFAULT NULL COMMENT '回填前的更新时间,用来证明没有被改写',
|
update_time_before datetime DEFAULT NULL COMMENT '回填前的更新时间,用来证明没有被改写',
|
||||||
PRIMARY KEY (waybill_id),
|
PRIMARY KEY (waybill_id),
|
||||||
KEY idx_driver_id_after (driver_id_after)
|
KEY idx_driver_id_after (driver_id_after)
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='20261028 运单司机档案ID回填存档';
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='20261028 运单司机档案ID回填存档';
|
||||||
|
|
||||||
-- 命中映射:只收「号码唯一命中一条未删除档案」的 NULL 行。
|
-- 命中映射:只收「号码唯一命中一条未删除档案」的 NULL 行。
|
||||||
-- INSERT IGNORE + WHERE driver_id IS NULL:第二次执行不会重复建映射,已经填过的行不会再进映射。
|
-- INSERT IGNORE + WHERE driver_id IS NULL:第二次执行不会重复建映射,已经填过的行不会再进映射。
|
||||||
@@ -154,7 +155,7 @@ SELECT COUNT(*) AS wrong_driver_id
|
|||||||
SELECT COUNT(*) AS snapshot_rewritten
|
SELECT COUNT(*) AS snapshot_rewritten
|
||||||
FROM blade_waybill_driver_id_bak_20261028 b
|
FROM blade_waybill_driver_id_bak_20261028 b
|
||||||
JOIN blade_waybill w ON w.id = b.waybill_id
|
JOIN blade_waybill w ON w.id = b.waybill_id
|
||||||
WHERE NOT (w.driver_phone <=> b.driver_phone)
|
WHERE NOT (w.driver_phone <=> b.driver_phone COLLATE utf8mb4_0900_ai_ci)
|
||||||
OR NOT (w.update_time <=> b.update_time_before);
|
OR NOT (w.update_time <=> b.update_time_before);
|
||||||
|
|
||||||
-- 2.5 冲突清单:同号多档案,这些行被跳过(期望 0 行;有输出就是「为什么没填」的答案)
|
-- 2.5 冲突清单:同号多档案,这些行被跳过(期望 0 行;有输出就是「为什么没填」的答案)
|
||||||
|
|||||||
Reference in New Issue
Block a user