✨ 运单与配载单在派单、配载、导入时写入司机档案 ID
This commit is contained in:
+3
@@ -68,6 +68,9 @@ public class LoadingManage extends TenantEntity {
|
||||
@Schema(description = "联系电话")
|
||||
private String driverPhone;
|
||||
|
||||
@Schema(description = "司机ID")
|
||||
private Long driverId;
|
||||
|
||||
@Schema(description = "押运人")
|
||||
private String escortName;
|
||||
|
||||
|
||||
+15
@@ -29,6 +29,7 @@ import org.springblade.transport.pojo.vo.BusinessRemoveResultVO;
|
||||
import org.springblade.transport.pojo.vo.LoadingCarrierContractVO;
|
||||
import org.springblade.transport.pojo.vo.LoadingManageVO;
|
||||
import org.springblade.transport.service.IContractManageService;
|
||||
import org.springblade.transport.service.IDriverService;
|
||||
import org.springblade.transport.service.ILoadingManageService;
|
||||
import org.springblade.transport.service.IProcessConfigService;
|
||||
import org.springblade.transport.service.IReceivablePayableDetailService;
|
||||
@@ -89,6 +90,9 @@ public class LoadingManageServiceImpl extends BaseServiceImpl<LoadingManageMappe
|
||||
@Resource
|
||||
private IProcessConfigService processConfigService;
|
||||
|
||||
@Resource
|
||||
private IDriverService driverService;
|
||||
|
||||
@Override
|
||||
public IPage<LoadingManageVO> selectLoadingManagePage(IPage<LoadingManage> page, LoadingManageVO loadingManage) {
|
||||
IPage<LoadingManage> entityPage = page(page, buildQuery(loadingManage));
|
||||
@@ -319,6 +323,7 @@ public class LoadingManageServiceImpl extends BaseServiceImpl<LoadingManageMappe
|
||||
loadingManage.setCargoName(first.getCargoName());
|
||||
loadingManage.setVehicleNo(first.getVehicleNo());
|
||||
loadingManage.setTrailerVehicleNo(first.getTrailerVehicleNo());
|
||||
loadingManage.setDriverId(first.getDriverId());
|
||||
loadingManage.setDriverName(first.getDriverName());
|
||||
loadingManage.setDriverPhone(first.getDriverPhone());
|
||||
loadingManage.setEscortName(first.getEscortName());
|
||||
@@ -505,6 +510,8 @@ public class LoadingManageServiceImpl extends BaseServiceImpl<LoadingManageMappe
|
||||
target.setBusinessStatus(STATUS_DRAFT);
|
||||
target.setLoadingNo(nextCode());
|
||||
prepare(target);
|
||||
// 源单已有归属就沿用(手机号可能已被改过);没有才用刚解析出的值
|
||||
target.setDriverId(source.getDriverId() != null ? source.getDriverId() : target.getDriverId());
|
||||
validate(target, true);
|
||||
save(target);
|
||||
return detail(target.getId());
|
||||
@@ -749,6 +756,12 @@ public class LoadingManageServiceImpl extends BaseServiceImpl<LoadingManageMappe
|
||||
loadingManage.setTrailerVehicleNo(TransportBusinessSupport.trimToNull(loadingManage.getTrailerVehicleNo()));
|
||||
loadingManage.setDriverName(TransportBusinessSupport.trimToNull(loadingManage.getDriverName()));
|
||||
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.setEscortPhone(TransportBusinessSupport.trimToNull(loadingManage.getEscortPhone()));
|
||||
loadingManage.setCarrierType(TransportBusinessSupport.trimToNull(loadingManage.getCarrierType()));
|
||||
@@ -1150,6 +1163,7 @@ public class LoadingManageServiceImpl extends BaseServiceImpl<LoadingManageMappe
|
||||
.set(Waybill::getCarrierType, loadingManage.getCarrierType())
|
||||
.set(Waybill::getCarrierContractId, loadingManage.getCarrierContractId())
|
||||
.set(Waybill::getCarrierName, loadingManage.getCarrierName())
|
||||
.set(Waybill::getDriverId, loadingManage.getDriverId())
|
||||
.set(Waybill::getDriverName, loadingManage.getDriverName())
|
||||
.set(Waybill::getDriverPhone, loadingManage.getDriverPhone())
|
||||
.set(Waybill::getVehicleNo, loadingManage.getVehicleNo())
|
||||
@@ -1264,6 +1278,7 @@ public class LoadingManageServiceImpl extends BaseServiceImpl<LoadingManageMappe
|
||||
.set(Waybill::getCarrierType, loadingManage.getCarrierType())
|
||||
.set(Waybill::getCarrierContractId, loadingManage.getCarrierContractId())
|
||||
.set(Waybill::getCarrierName, loadingManage.getCarrierName())
|
||||
.set(Waybill::getDriverId, loadingManage.getDriverId())
|
||||
.set(Waybill::getDriverName, loadingManage.getDriverName())
|
||||
.set(Waybill::getDriverPhone, loadingManage.getDriverPhone())
|
||||
.set(Waybill::getVehicleNo, loadingManage.getVehicleNo())
|
||||
|
||||
+11
-1
@@ -24,6 +24,7 @@ import org.springblade.transport.pojo.vo.MasterOrderCarrierVO;
|
||||
import org.springblade.transport.pojo.vo.MasterOrderVO;
|
||||
import org.springblade.transport.service.IMasterOrderService;
|
||||
import org.springblade.transport.service.IContractManageService;
|
||||
import org.springblade.transport.service.IDriverService;
|
||||
import org.springblade.transport.service.IProjectApplyService;
|
||||
import org.springblade.transport.service.ITransportPlanService;
|
||||
import org.springblade.transport.service.IWaybillService;
|
||||
@@ -58,13 +59,15 @@ public class MasterOrderServiceImpl extends BaseServiceImpl<MasterOrderMapper, M
|
||||
private final ITransportPlanService transportPlanService;
|
||||
private final IProjectApplyService projectApplyService;
|
||||
private final IContractManageService contractManageService;
|
||||
private final IDriverService driverService;
|
||||
|
||||
public MasterOrderServiceImpl(IWaybillService waybillService, ITransportPlanService transportPlanService, IProjectApplyService projectApplyService,
|
||||
IContractManageService contractManageService) {
|
||||
IContractManageService contractManageService, IDriverService driverService) {
|
||||
this.waybillService = waybillService;
|
||||
this.transportPlanService = transportPlanService;
|
||||
this.projectApplyService = projectApplyService;
|
||||
this.contractManageService = contractManageService;
|
||||
this.driverService = driverService;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -263,6 +266,13 @@ public class MasterOrderServiceImpl extends BaseServiceImpl<MasterOrderMapper, M
|
||||
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.setDriverPhone(string(dispatch, "driverPhone")); waybill.setVehicleNo(string(dispatch, "vehicleNo")); waybill.setTrailerVehicleNo(string(dispatch, "trailerVehicleNo"));
|
||||
// 归属主键是档案 ID:调度带了就用它,否则按手机号解析;承运商司机解析为空也照常派单
|
||||
Long driverId = longValue(dispatch, "driverId");
|
||||
if (driverId == null || driverId <= 0) {
|
||||
Long resolvedDriverId = driverService.resolveDriverIdByMobile(waybill.getTenantId(), waybill.getDriverPhone());
|
||||
driverId = resolvedDriverId != null && resolvedDriverId > 0 ? resolvedDriverId : null;
|
||||
}
|
||||
waybill.setDriverId(driverId);
|
||||
waybill.setCaptainName(string(dispatch, "captainName")); waybill.setCabinNo(string(dispatch, "cabinNo")); waybill.setContainerNo(string(dispatch, "containerNo"));
|
||||
waybill.setEscortName(string(dispatch, "escortName")); waybill.setEscortPhone(string(dispatch, "escortPhone")); waybill.setMileage(nullableDecimal(dispatch, "mileage"));
|
||||
waybill.setDepartureName(string(dispatch, "departureName")); waybill.setDepartureAddress(string(dispatch, "departureAddress"));
|
||||
|
||||
+27
-1
@@ -10,6 +10,7 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springblade.common.excel.ImportFailureExcelUtil;
|
||||
import org.springblade.core.log.exception.ServiceException;
|
||||
import org.springblade.core.mp.base.BaseServiceImpl;
|
||||
@@ -41,6 +42,7 @@ import org.springblade.transport.pojo.vo.WaybillImportBatchVO;
|
||||
import org.springblade.transport.pojo.vo.WaybillImportRowErrorVO;
|
||||
import org.springblade.transport.pojo.vo.WaybillImportValidateResultVO;
|
||||
import org.springblade.transport.service.ICustomerArchiveService;
|
||||
import org.springblade.transport.service.IDriverService;
|
||||
import org.springblade.transport.service.IProjectApplyService;
|
||||
import org.springblade.transport.service.IReceivablePayableDetailService;
|
||||
import org.springblade.transport.service.ILoadingManageService;
|
||||
@@ -68,6 +70,7 @@ import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/** 运单批次服务实现。 */
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class WaybillImportBatchServiceImpl extends BaseServiceImpl<WaybillImportBatchMapper, WaybillImportBatch> implements IWaybillImportBatchService {
|
||||
@@ -101,6 +104,7 @@ public class WaybillImportBatchServiceImpl extends BaseServiceImpl<WaybillImport
|
||||
private final IReceivablePayableDetailService receivablePayableDetailService;
|
||||
private final ILoadingManageService loadingManageService;
|
||||
private final ISysClient sysClient;
|
||||
private final IDriverService driverService;
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@@ -207,7 +211,9 @@ public class WaybillImportBatchServiceImpl extends BaseServiceImpl<WaybillImport
|
||||
List<Waybill> rowWaybills = new ArrayList<>();
|
||||
for (int index = 0; index < rows.size(); index++) {
|
||||
try {
|
||||
rowWaybills.add(buildWaybill(rows.get(index), batch, request.getCarrierContractId(), draft));
|
||||
Waybill builtWaybill = buildWaybill(rows.get(index), batch, request.getCarrierContractId(), draft);
|
||||
fillDriverOwnership(builtWaybill, index + 1);
|
||||
rowWaybills.add(builtWaybill);
|
||||
} catch (Exception exception) {
|
||||
throw new ServiceException("第" + (index + 1) + "行" + (draft ? "保存" : "导入") + "失败:" + exception.getMessage());
|
||||
}
|
||||
@@ -485,6 +491,26 @@ public class WaybillImportBatchServiceImpl extends BaseServiceImpl<WaybillImport
|
||||
return id == null || id <= 0L ? null : id;
|
||||
}
|
||||
|
||||
/**
|
||||
* 补齐导入运单的司机档案 ID:行内有(老系统导出)就用,否则按手机号解析。
|
||||
* 解析不到不阻断导入,只留行级 WARN:承运商司机与未登录过小程序的司机本来就没有档案。
|
||||
*/
|
||||
private void fillDriverOwnership(Waybill waybill, int rowNo) {
|
||||
Long driverId = waybill.getDriverId();
|
||||
if (driverId != null && driverId > 0) {
|
||||
return;
|
||||
}
|
||||
Long resolvedDriverId = driverService.resolveDriverIdByMobile(waybill.getTenantId(), waybill.getDriverPhone());
|
||||
if (resolvedDriverId != null && resolvedDriverId > 0) {
|
||||
waybill.setDriverId(resolvedDriverId);
|
||||
return;
|
||||
}
|
||||
// driver_id 只有 >0 才算有主,0 / -1 都按无主落空
|
||||
waybill.setDriverId(null);
|
||||
log.warn("第{}行 运单 {} 的司机手机号未唯一匹配司机档案,driver_id 留空(不阻断导入)",
|
||||
rowNo, waybill.getWaybillNo());
|
||||
}
|
||||
|
||||
private Waybill buildWaybill(Map<String, Object> row, WaybillImportBatch batch, Long carrierContractId, boolean draft) {
|
||||
if (row == null) throw new ServiceException("运单数据不正确");
|
||||
Waybill waybill = new Waybill();
|
||||
|
||||
+13
-1
@@ -61,6 +61,7 @@ import org.springblade.transport.pojo.vo.WaybillPunchPhotoVO;
|
||||
import org.springblade.transport.pojo.vo.WaybillPunchRecordItemVO;
|
||||
import org.springblade.transport.pojo.vo.WaybillPunchRecordsVO;
|
||||
import org.springblade.transport.pojo.vo.WaybillVO;
|
||||
import org.springblade.transport.service.IDriverService;
|
||||
import org.springblade.transport.service.ILoadingManageService;
|
||||
import org.springblade.transport.service.IProcessConfigService;
|
||||
import org.springblade.transport.service.IProjectApplyService;
|
||||
@@ -110,6 +111,9 @@ public class WaybillServiceImpl extends BaseServiceImpl<WaybillMapper, Waybill>
|
||||
@jakarta.annotation.Resource
|
||||
private ILoadingManageService loadingManageService;
|
||||
|
||||
@jakarta.annotation.Resource
|
||||
private IDriverService driverService;
|
||||
|
||||
@jakarta.annotation.Resource
|
||||
private IProcessConfigService processConfigService;
|
||||
|
||||
@@ -1610,7 +1614,15 @@ public class WaybillServiceImpl extends BaseServiceImpl<WaybillMapper, Waybill>
|
||||
TransportBusinessSupport.validateRequired(driverPhone, "手机号不能为空");
|
||||
TransportBusinessSupport.validateRequired(vehicleNo, "车牌号不能为空");
|
||||
|
||||
waybill.setDriverId(request.getDriverId());
|
||||
// 归属主键是档案 ID,手机号只是派单时的号码快照:调用方带了档案 ID 就用它,
|
||||
// 否则按手机号解析;承运商司机、未建档司机解析为空,派单照旧成功,只留 WARN
|
||||
Long driverId = request.getDriverId();
|
||||
if (driverId == null || driverId <= 0) {
|
||||
Long resolvedDriverId = driverService.resolveDriverIdByMobile(waybill.getTenantId(), driverPhone);
|
||||
// driver_id 只有 >0 才算有主,0 / -1 都是「无主」的哨兵写法,落库统一为 NULL
|
||||
driverId = resolvedDriverId != null && resolvedDriverId > 0 ? resolvedDriverId : null;
|
||||
}
|
||||
waybill.setDriverId(driverId);
|
||||
waybill.setDriverName(driverName);
|
||||
waybill.setDriverPhone(driverPhone);
|
||||
waybill.setVehicleNo(vehicleNo);
|
||||
|
||||
+2
@@ -19,6 +19,7 @@ import org.springblade.transport.pojo.entity.ContractManage;
|
||||
import org.springblade.transport.pojo.entity.LoadingManage;
|
||||
import org.springblade.transport.pojo.entity.Waybill;
|
||||
import org.springblade.transport.service.IContractManageService;
|
||||
import org.springblade.transport.service.IDriverService;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.List;
|
||||
@@ -81,6 +82,7 @@ class LoadingManageAdmissionTest {
|
||||
inject("baseMapper", loadingManageMapper);
|
||||
inject("waybillMapper", waybillMapper);
|
||||
inject("contractManageService", contractManageService);
|
||||
inject("driverService", mock(IDriverService.class));
|
||||
authUtil = mockStatic(AuthUtil.class);
|
||||
authUtil.when(AuthUtil::getDeptId).thenReturn(String.valueOf(DEPT_ID));
|
||||
}
|
||||
|
||||
+152
-9
@@ -15,16 +15,19 @@ import org.mockito.ArgumentMatchers;
|
||||
import org.mockito.MockedStatic;
|
||||
import org.springblade.core.secure.utils.AuthUtil;
|
||||
import org.springblade.core.tool.jackson.JsonUtil;
|
||||
import org.springblade.transport.mapper.LoadingManageMapper;
|
||||
import org.springblade.transport.mapper.WaybillMapper;
|
||||
import org.springblade.transport.pojo.entity.LoadingManage;
|
||||
import org.springblade.transport.pojo.entity.ProcessConfig;
|
||||
import org.springblade.transport.pojo.entity.Waybill;
|
||||
import org.springblade.transport.service.IContractManageService;
|
||||
import org.springblade.transport.service.IDriverService;
|
||||
import org.springblade.transport.service.IProcessConfigService;
|
||||
import org.springblade.transport.service.IReceivablePayableDetailService;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
@@ -35,6 +38,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.atLeastOnce;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.mock;
|
||||
@@ -60,6 +64,9 @@ class LoadingManageChildStatusWriteTest {
|
||||
private static final String LOADING_NO = "PZ-20261018-001";
|
||||
private static final Long LOADING_ID = 1800000000000000001L;
|
||||
private static final String DRIVER_PHONE = "13800138000";
|
||||
private static final String TENANT_ID = "000000";
|
||||
private static final Long RESOLVED_DRIVER_ID = 9321L;
|
||||
private static final Long SOURCE_LOADING_ID = 1800000000000000002L;
|
||||
|
||||
private static final Long NEED_ACCEPT_WAYBILL_ID = 3101L;
|
||||
private static final Long NO_ACCEPT_WAYBILL_ID = 3102L;
|
||||
@@ -80,6 +87,7 @@ class LoadingManageChildStatusWriteTest {
|
||||
"carrier_type",
|
||||
"carrier_contract_id",
|
||||
"carrier_name",
|
||||
"driver_id",
|
||||
"driver_name",
|
||||
"driver_phone",
|
||||
"vehicle_no",
|
||||
@@ -104,6 +112,8 @@ class LoadingManageChildStatusWriteTest {
|
||||
private IProcessConfigService processConfigService;
|
||||
private IContractManageService contractManageService;
|
||||
private IReceivablePayableDetailService receivablePayableDetailService;
|
||||
private IDriverService driverService;
|
||||
private LoadingManageMapper loadingManageMapper;
|
||||
private LoadingManageServiceImpl service;
|
||||
private MockedStatic<AuthUtil> authUtil;
|
||||
|
||||
@@ -115,6 +125,7 @@ class LoadingManageChildStatusWriteTest {
|
||||
assistant.setCurrentNamespace("test");
|
||||
TableInfoHelper.initTableInfo(assistant, Waybill.class);
|
||||
TableInfoHelper.initTableInfo(assistant, ProcessConfig.class);
|
||||
TableInfoHelper.initTableInfo(assistant, LoadingManage.class);
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
@@ -123,14 +134,19 @@ class LoadingManageChildStatusWriteTest {
|
||||
processConfigService = mock(IProcessConfigService.class);
|
||||
contractManageService = mock(IContractManageService.class);
|
||||
receivablePayableDetailService = mock(IReceivablePayableDetailService.class);
|
||||
driverService = mock(IDriverService.class);
|
||||
loadingManageMapper = mock(LoadingManageMapper.class);
|
||||
service = spy(new LoadingManageServiceImpl());
|
||||
inject(service, "waybillMapper", waybillMapper);
|
||||
inject(service, "processConfigService", processConfigService);
|
||||
inject(service, "contractManageService", contractManageService);
|
||||
inject(service, "receivablePayableDetailService", receivablePayableDetailService);
|
||||
inject(service, "driverService", driverService);
|
||||
inject(service, "baseMapper", loadingManageMapper);
|
||||
doReturnTrue(service);
|
||||
authUtil = mockStatic(AuthUtil.class);
|
||||
authUtil.when(AuthUtil::getDeptId).thenReturn(DEPT_ID);
|
||||
authUtil.when(AuthUtil::getTenantId).thenReturn(TENANT_ID);
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
@@ -309,6 +325,75 @@ class LoadingManageChildStatusWriteTest {
|
||||
verify(processConfigService, never()).list(ArgumentMatchers.<Wrapper<ProcessConfig>>any());
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("提交配载单:按手机号解析到档案 ID 时,配载单与子单一起记住归属")
|
||||
void submitWritesResolvedDriverId() {
|
||||
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(RESOLVED_DRIVER_ID);
|
||||
|
||||
assertTrue(service.submit(loadingForm(NO_ACCEPT_WAYBILL_ID)));
|
||||
|
||||
assertEquals(RESOLVED_DRIVER_ID, capturedLoading().getDriverId());
|
||||
assertEquals(RESOLVED_DRIVER_ID, statusSyncUpdates().get(0).setValue("driver_id"),
|
||||
"子单必须与配载单写同一个归属,否则司机端按归属查不到这张票");
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("解析不到档案(承运商司机):提交照常成功,归属留空")
|
||||
void submitAllowsUnresolvedDriverId() {
|
||||
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);
|
||||
|
||||
assertTrue(service.submit(loadingForm(NO_ACCEPT_WAYBILL_ID)));
|
||||
|
||||
assertNull(capturedLoading().getDriverId());
|
||||
assertNull(statusSyncUpdates().get(0).setValue("driver_id"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("进行中编辑保留的子单:任务字段更新也带上司机归属,改派后不留旧值")
|
||||
void runningEditCarriesDriverIdToKeptWaybills() {
|
||||
LoadingManage record = runningRecord();
|
||||
stubLoadingRecord(record);
|
||||
stubWaybills(waybill(NEED_ACCEPT_WAYBILL_ID, NEED_ACCEPT_PROJECT_ID));
|
||||
when(driverService.resolveDriverIdByMobile(any(), eq(DRIVER_PHONE))).thenReturn(RESOLVED_DRIVER_ID);
|
||||
|
||||
assertTrue(service.submit(editForm(LOADING_ID, NEED_ACCEPT_WAYBILL_ID)));
|
||||
|
||||
CapturedUpdate taskUpdate = waybillUpdates().stream()
|
||||
.filter(update -> update.columns().contains("driver_name"))
|
||||
.findFirst()
|
||||
.orElseThrow();
|
||||
assertEquals(List.of(NEED_ACCEPT_WAYBILL_ID), taskUpdate.whereIds());
|
||||
assertEquals(RESOLVED_DRIVER_ID, taskUpdate.setValue("driver_id"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("复制配载单:沿用源单的司机归属,不按手机号重解析覆盖")
|
||||
void copyKeepsSourceDriverId() {
|
||||
LoadingManage source = copySource();
|
||||
source.setDriverId(555L);
|
||||
stubCopyDependencies(source);
|
||||
|
||||
service.copy(SOURCE_LOADING_ID);
|
||||
|
||||
assertEquals(555L, capturedSaved().getDriverId());
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("复制配载单:源单没有归属时,用手机号解析出的档案 ID")
|
||||
void copyFallsBackToResolvedDriverId() {
|
||||
LoadingManage source = copySource();
|
||||
stubCopyDependencies(source);
|
||||
when(driverService.resolveDriverIdByMobile(any(), eq(DRIVER_PHONE))).thenReturn(RESOLVED_DRIVER_ID);
|
||||
|
||||
service.copy(SOURCE_LOADING_ID);
|
||||
|
||||
assertEquals(RESOLVED_DRIVER_ID, capturedSaved().getDriverId());
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------ 夹具
|
||||
|
||||
private LoadingManage loadingForm(Long... waybillIds) {
|
||||
@@ -375,10 +460,46 @@ class LoadingManageChildStatusWriteTest {
|
||||
return waybill;
|
||||
}
|
||||
|
||||
private String capturedLoadingStatus() {
|
||||
private LoadingManage runningRecord() {
|
||||
LoadingManage record = loadingRecord("running", NEED_ACCEPT_WAYBILL_ID);
|
||||
record.setVehicleNo("桂A12345");
|
||||
record.setDriverName("张三");
|
||||
record.setDriverPhone(DRIVER_PHONE);
|
||||
return record;
|
||||
}
|
||||
|
||||
private LoadingManage copySource() {
|
||||
LoadingManage source = loadingRecord("pending", NEED_ACCEPT_WAYBILL_ID);
|
||||
source.setLoadingSubNos("YD-" + NEED_ACCEPT_WAYBILL_ID);
|
||||
source.setTransportType("公路运输");
|
||||
source.setVehicleNo("桂A12345");
|
||||
source.setDriverName("张三");
|
||||
source.setDriverPhone(DRIVER_PHONE);
|
||||
source.setDepartureAddress("南宁");
|
||||
source.setArrivalAddress("广州");
|
||||
return source;
|
||||
}
|
||||
|
||||
private void stubCopyDependencies(LoadingManage source) {
|
||||
source.setId(SOURCE_LOADING_ID);
|
||||
doReturn(source).when(service).getById(SOURCE_LOADING_ID);
|
||||
doReturn(null).when(service).detail(any());
|
||||
}
|
||||
|
||||
private LoadingManage capturedSaved() {
|
||||
ArgumentCaptor<LoadingManage> captor = ArgumentCaptor.forClass(LoadingManage.class);
|
||||
verify(service, atLeastOnce()).save(captor.capture());
|
||||
return captor.getValue();
|
||||
}
|
||||
|
||||
private LoadingManage capturedLoading() {
|
||||
ArgumentCaptor<LoadingManage> captor = ArgumentCaptor.forClass(LoadingManage.class);
|
||||
verify(service, atLeastOnce()).saveOrUpdate(captor.capture());
|
||||
return captor.getValue().getBusinessStatus();
|
||||
return captor.getValue();
|
||||
}
|
||||
|
||||
private String capturedLoadingStatus() {
|
||||
return capturedLoading().getBusinessStatus();
|
||||
}
|
||||
|
||||
private void stubWaybills(Waybill... waybills) {
|
||||
@@ -438,18 +559,28 @@ class LoadingManageChildStatusWriteTest {
|
||||
}
|
||||
|
||||
private static void inject(LoadingManageServiceImpl target, String fieldName, Object value) {
|
||||
try {
|
||||
Field field = LoadingManageServiceImpl.class.getDeclaredField(fieldName);
|
||||
field.setAccessible(true);
|
||||
field.set(target, value);
|
||||
} catch (ReflectiveOperationException exception) {
|
||||
throw new IllegalStateException("注入测试替身失败:" + fieldName, exception);
|
||||
Class<?> type = LoadingManageServiceImpl.class;
|
||||
while (type != null) {
|
||||
try {
|
||||
Field field = type.getDeclaredField(fieldName);
|
||||
field.setAccessible(true);
|
||||
field.set(target, value);
|
||||
return;
|
||||
} catch (NoSuchFieldException ignored) {
|
||||
type = type.getSuperclass();
|
||||
} catch (ReflectiveOperationException exception) {
|
||||
throw new IllegalStateException("注入测试替身失败:" + fieldName, exception);
|
||||
}
|
||||
}
|
||||
throw new IllegalStateException("注入测试替身失败:" + fieldName);
|
||||
}
|
||||
|
||||
/** 一条被捕获的批量更新:SET 的列 → 值、WHERE 的运单 id */
|
||||
private record CapturedUpdate(String sqlSet, String whereSql, Map<String, Object> params, List<String> columns) {
|
||||
|
||||
private static final java.util.regex.Pattern PARAM_REF =
|
||||
java.util.regex.Pattern.compile("#\\{ew\\.paramNameValuePairs\\.([^}]+)}");
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
static CapturedUpdate of(Wrapper<Waybill> wrapper) {
|
||||
LambdaUpdateWrapper<Waybill> update = (LambdaUpdateWrapper<Waybill>) wrapper;
|
||||
@@ -478,8 +609,20 @@ class LoadingManageChildStatusWriteTest {
|
||||
return null;
|
||||
}
|
||||
|
||||
/** 只认 WHERE 段用到的参数:SET 段的 driver_id 也是 Long,混进来会当成运单 id */
|
||||
List<Long> whereIds() {
|
||||
return params.values().stream().filter(Long.class::isInstance).map(Long.class::cast).toList();
|
||||
Set<String> setParamKeys = new java.util.HashSet<>();
|
||||
Matcher matcher = PARAM_REF.matcher(sqlSet);
|
||||
while (matcher.find()) {
|
||||
setParamKeys.add(matcher.group(1));
|
||||
}
|
||||
List<Long> ids = new java.util.ArrayList<>();
|
||||
for (Map.Entry<String, Object> entry : params.entrySet()) {
|
||||
if (entry.getValue() instanceof Long longValue && !setParamKeys.contains(entry.getKey())) {
|
||||
ids.add(longValue);
|
||||
}
|
||||
}
|
||||
return ids;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+120
@@ -0,0 +1,120 @@
|
||||
package org.springblade.transport.service.impl;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.springblade.transport.pojo.entity.MasterOrder;
|
||||
import org.springblade.transport.pojo.entity.Waybill;
|
||||
import org.springblade.transport.service.IContractManageService;
|
||||
import org.springblade.transport.service.IDriverService;
|
||||
import org.springblade.transport.service.IProjectApplyService;
|
||||
import org.springblade.transport.service.ITransportPlanService;
|
||||
import org.springblade.transport.service.IWaybillService;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
/**
|
||||
* 多联总单派单建运单时写司机档案 ID 的测试。
|
||||
* <p>
|
||||
* 派单请求可能来自调度(带档案 ID),也可能只填了姓名手机号(手工派单、承运商司机),
|
||||
* 后者按手机号解析;解析不到也不能挡住派单。
|
||||
*/
|
||||
class MasterOrderDriverIdTest {
|
||||
|
||||
private static final String DRIVER_PHONE = "13800138000";
|
||||
private static final Long RESOLVED_DRIVER_ID = 9321L;
|
||||
|
||||
private IWaybillService waybillService;
|
||||
private IDriverService driverService;
|
||||
private MasterOrderServiceImpl service;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
waybillService = mock(IWaybillService.class);
|
||||
driverService = mock(IDriverService.class);
|
||||
service = new MasterOrderServiceImpl(waybillService, mock(ITransportPlanService.class),
|
||||
mock(IProjectApplyService.class), mock(IContractManageService.class), driverService);
|
||||
when(waybillService.submit(any(Waybill.class))).thenReturn(true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("调度带了档案 ID:按它写,不再按手机号解析")
|
||||
void keepsExplicitDriverId() throws Exception {
|
||||
Map<String, Object> dispatch = dispatch();
|
||||
dispatch.put("driverId", 7001L);
|
||||
|
||||
assertTrue(createWaybill(dispatch));
|
||||
|
||||
assertEquals(7001L, submittedWaybill().getDriverId());
|
||||
verify(driverService, never()).resolveDriverIdByMobile(any(), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("只填了手机号:派单时解析出档案 ID 写入运单")
|
||||
void resolvesDriverIdFromPhone() throws Exception {
|
||||
when(driverService.resolveDriverIdByMobile(any(), eq(DRIVER_PHONE))).thenReturn(RESOLVED_DRIVER_ID);
|
||||
|
||||
assertTrue(createWaybill(dispatch()));
|
||||
|
||||
assertEquals(RESOLVED_DRIVER_ID, submittedWaybill().getDriverId());
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("解析不到档案(承运商司机):运单照常提交,归属留空")
|
||||
void allowsDispatchWithoutProfile() throws Exception {
|
||||
when(driverService.resolveDriverIdByMobile(any(), eq(DRIVER_PHONE))).thenReturn(null);
|
||||
|
||||
assertTrue(createWaybill(dispatch()));
|
||||
|
||||
assertNull(submittedWaybill().getDriverId());
|
||||
verify(waybillService).submit(any(Waybill.class));
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------ 夹具
|
||||
|
||||
private boolean createWaybill(Map<String, Object> dispatch) throws Exception {
|
||||
MasterOrder masterOrder = new MasterOrder();
|
||||
masterOrder.setId(1L);
|
||||
masterOrder.setMasterNo("ZD-20261027-001");
|
||||
masterOrder.setProjectId(2101L);
|
||||
masterOrder.setProjectName("测试项目");
|
||||
Method method = MasterOrderServiceImpl.class
|
||||
.getDeclaredMethod("createWaybill", MasterOrder.class, List.class);
|
||||
method.setAccessible(true);
|
||||
return (boolean) method.invoke(service, masterOrder, List.of(dispatch));
|
||||
}
|
||||
|
||||
private Map<String, Object> dispatch() {
|
||||
Map<String, Object> dispatch = new LinkedHashMap<>();
|
||||
dispatch.put("documentType", "运单");
|
||||
dispatch.put("transportType", "公路运输");
|
||||
dispatch.put("carrierType", "自运");
|
||||
dispatch.put("driverName", "张三");
|
||||
dispatch.put("driverPhone", DRIVER_PHONE);
|
||||
dispatch.put("vehicleNo", "桂A12345");
|
||||
dispatch.put("quantity", 1);
|
||||
dispatch.put("unitPrice", 100);
|
||||
return dispatch;
|
||||
}
|
||||
|
||||
private Waybill submittedWaybill() {
|
||||
ArgumentCaptor<Waybill> captor = ArgumentCaptor.forClass(Waybill.class);
|
||||
verify(waybillService).submit(captor.capture());
|
||||
return captor.getValue();
|
||||
}
|
||||
|
||||
}
|
||||
+3
-1
@@ -14,6 +14,7 @@ import org.springblade.transport.pojo.entity.TransportPlan;
|
||||
import org.springblade.transport.pojo.entity.Waybill;
|
||||
import org.springblade.transport.pojo.vo.MasterOrderVO;
|
||||
import org.springblade.transport.service.IContractManageService;
|
||||
import org.springblade.transport.service.IDriverService;
|
||||
import org.springblade.transport.service.IProjectApplyService;
|
||||
import org.springblade.transport.service.ITransportPlanService;
|
||||
import org.springblade.transport.service.IWaybillService;
|
||||
@@ -67,7 +68,8 @@ class MasterOrderProgressTest {
|
||||
waybillService,
|
||||
transportPlanService,
|
||||
mock(IProjectApplyService.class),
|
||||
mock(IContractManageService.class));
|
||||
mock(IContractManageService.class),
|
||||
mock(IDriverService.class));
|
||||
inject("baseMapper", masterOrderMapper);
|
||||
|
||||
when(transportPlanService.list(anyWrapper())).thenReturn(List.of());
|
||||
|
||||
+121
@@ -0,0 +1,121 @@
|
||||
package org.springblade.transport.service.impl;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springblade.system.feign.ISysClient;
|
||||
import org.springblade.transport.pojo.entity.Waybill;
|
||||
import org.springblade.transport.service.ICustomerArchiveService;
|
||||
import org.springblade.transport.service.IDriverService;
|
||||
import org.springblade.transport.service.ILoadingManageService;
|
||||
import org.springblade.transport.service.IProjectApplyService;
|
||||
import org.springblade.transport.service.IReceivablePayableDetailService;
|
||||
import org.springblade.transport.service.ITransportPlanService;
|
||||
import org.springblade.transport.service.IWaybillService;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
/**
|
||||
* 批量导入运单时写司机档案 ID 的测试。
|
||||
* <p>
|
||||
* 导入模板可能带档案 ID(老系统导出),也可能只有司机姓名手机号。
|
||||
* 解析不到档案时只留行级 WARN,该行照常导入(承运商司机本来就没有小程序档案)。
|
||||
*/
|
||||
class WaybillImportDriverIdTest {
|
||||
|
||||
private static final String DRIVER_PHONE = "13800138000";
|
||||
private static final Long RESOLVED_DRIVER_ID = 9321L;
|
||||
|
||||
private IDriverService driverService;
|
||||
private WaybillImportBatchServiceImpl service;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
driverService = mock(IDriverService.class);
|
||||
service = new WaybillImportBatchServiceImpl(
|
||||
mock(IWaybillService.class),
|
||||
mock(ICustomerArchiveService.class),
|
||||
mock(IProjectApplyService.class),
|
||||
mock(ITransportPlanService.class),
|
||||
mock(IReceivablePayableDetailService.class),
|
||||
mock(ILoadingManageService.class),
|
||||
mock(ISysClient.class),
|
||||
driverService);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("行内带了档案 ID:直接用,不再按手机号解析")
|
||||
void keepsDriverIdFromRow() throws Exception {
|
||||
Waybill waybill = importedWaybill(7001L);
|
||||
|
||||
fillDriverOwnership(waybill, 3);
|
||||
|
||||
assertEquals(7001L, waybill.getDriverId());
|
||||
verify(driverService, never()).resolveDriverIdByMobile(any(), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("行内只有手机号:按手机号解析出档案 ID 写入")
|
||||
void resolvesDriverIdFromRowPhone() throws Exception {
|
||||
when(driverService.resolveDriverIdByMobile(any(), eq(DRIVER_PHONE))).thenReturn(RESOLVED_DRIVER_ID);
|
||||
|
||||
Waybill waybill = importedWaybill(null);
|
||||
fillDriverOwnership(waybill, 3);
|
||||
|
||||
assertEquals(RESOLVED_DRIVER_ID, waybill.getDriverId());
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("解析不到档案:该行照常导入,归属留空(只留行级 WARN)")
|
||||
void keepsRowWithoutResolvedProfile() throws Exception {
|
||||
when(driverService.resolveDriverIdByMobile(any(), eq(DRIVER_PHONE))).thenReturn(null);
|
||||
|
||||
Waybill waybill = importedWaybill(null);
|
||||
assertDoesNotThrow(() -> fillDriverOwnership(waybill, 3));
|
||||
|
||||
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 {
|
||||
Method method = WaybillImportBatchServiceImpl.class.getDeclaredMethod("fillDriverOwnership", Waybill.class, int.class);
|
||||
method.setAccessible(true);
|
||||
try {
|
||||
method.invoke(service, waybill, rowNo);
|
||||
} catch (java.lang.reflect.InvocationTargetException exception) {
|
||||
throw (Exception) exception.getCause();
|
||||
}
|
||||
}
|
||||
|
||||
private Waybill importedWaybill(Long driverId) {
|
||||
Waybill waybill = new Waybill();
|
||||
waybill.setWaybillNo("YD-IMPORT-1");
|
||||
waybill.setDriverId(driverId);
|
||||
waybill.setDriverName("张三");
|
||||
waybill.setDriverPhone(DRIVER_PHONE);
|
||||
return waybill;
|
||||
}
|
||||
|
||||
}
|
||||
+173
@@ -0,0 +1,173 @@
|
||||
package org.springblade.transport.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.core.MybatisConfiguration;
|
||||
import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
|
||||
import org.apache.ibatis.builder.MapperBuilderAssistant;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.springblade.transport.mapper.WaybillMapper;
|
||||
import org.springblade.transport.pojo.entity.Waybill;
|
||||
import org.springblade.transport.service.IDriverService;
|
||||
import org.springblade.transport.service.IProcessConfigService;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Collections;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyBoolean;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
/**
|
||||
* 重新派单写司机档案 ID 的测试。
|
||||
* <p>
|
||||
* 派单是司机归属的唯一入口:调用方带了档案 ID(>0)就按它写,
|
||||
* 只带姓名手机号(承运商司机、手工派单)就按手机号解析;解析不到也不能挡住派单。
|
||||
*/
|
||||
class WaybillReassignDriverIdTest {
|
||||
|
||||
private static final Long WAYBILL_ID = 1900000000000000001L;
|
||||
private static final String TENANT_ID = "000000";
|
||||
private static final String DRIVER_PHONE = "13800138000";
|
||||
private static final Long RESOLVED_DRIVER_ID = 9321L;
|
||||
|
||||
private WaybillMapper waybillMapper;
|
||||
private IDriverService driverService;
|
||||
private WaybillServiceImpl service;
|
||||
|
||||
@BeforeAll
|
||||
static void initTableInfo() {
|
||||
MybatisConfiguration configuration = new MybatisConfiguration();
|
||||
MapperBuilderAssistant assistant = new MapperBuilderAssistant(configuration, "");
|
||||
assistant.setCurrentNamespace("test");
|
||||
TableInfoHelper.initTableInfo(assistant, Waybill.class);
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
void setUp() throws Exception {
|
||||
waybillMapper = mock(WaybillMapper.class);
|
||||
driverService = mock(IDriverService.class);
|
||||
service = new WaybillServiceImpl();
|
||||
inject("baseMapper", waybillMapper);
|
||||
inject("driverService", driverService);
|
||||
inject("processConfigService", processConfigService());
|
||||
when(waybillMapper.selectById(WAYBILL_ID)).thenReturn(pendingWaybill());
|
||||
when(waybillMapper.updateById(any(Waybill.class))).thenReturn(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("调用方带了档案 ID:按它写,不再按手机号解析")
|
||||
void keepsExplicitDriverId() {
|
||||
Waybill request = reassignRequest(7721L);
|
||||
|
||||
assertTrue(service.reassignWithoutDeptCheck(request));
|
||||
|
||||
assertEquals(7721L, capturedWaybill().getDriverId());
|
||||
verify(driverService, never()).resolveDriverIdByMobile(any(), anyString());
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("调用方只带手机号:按手机号解析出档案 ID 写入")
|
||||
void resolvesDriverIdFromPhone() {
|
||||
when(driverService.resolveDriverIdByMobile(TENANT_ID, DRIVER_PHONE)).thenReturn(RESOLVED_DRIVER_ID);
|
||||
|
||||
assertTrue(service.reassignWithoutDeptCheck(reassignRequest(null)));
|
||||
|
||||
assertEquals(RESOLVED_DRIVER_ID, capturedWaybill().getDriverId());
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("档案 ID 为 0 或 -1(无主哨兵):按手机号重新解析")
|
||||
void resolvesWhenDriverIdIsSentinel() throws Exception {
|
||||
when(driverService.resolveDriverIdByMobile(TENANT_ID, DRIVER_PHONE)).thenReturn(RESOLVED_DRIVER_ID);
|
||||
|
||||
assertTrue(service.reassignWithoutDeptCheck(reassignRequest(0L)));
|
||||
assertEquals(RESOLVED_DRIVER_ID, capturedWaybill().getDriverId());
|
||||
|
||||
setUpAgain();
|
||||
assertTrue(service.reassignWithoutDeptCheck(reassignRequest(-1L)));
|
||||
assertEquals(RESOLVED_DRIVER_ID, capturedWaybill().getDriverId());
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("解析不到档案(承运商司机):派单照常成功,归属留空")
|
||||
void allowsReassignWithoutResolvedProfile() {
|
||||
when(driverService.resolveDriverIdByMobile(TENANT_ID, DRIVER_PHONE)).thenReturn(null);
|
||||
|
||||
assertTrue(service.reassignWithoutDeptCheck(reassignRequest(null)));
|
||||
|
||||
assertNull(capturedWaybill().getDriverId());
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------ 夹具
|
||||
|
||||
private void setUpAgain() throws Exception {
|
||||
waybillMapper = mock(WaybillMapper.class);
|
||||
service = new WaybillServiceImpl();
|
||||
inject("baseMapper", waybillMapper);
|
||||
inject("driverService", driverService);
|
||||
inject("processConfigService", processConfigService());
|
||||
when(waybillMapper.selectById(WAYBILL_ID)).thenReturn(pendingWaybill());
|
||||
when(waybillMapper.updateById(any(Waybill.class))).thenReturn(1);
|
||||
}
|
||||
|
||||
private IProcessConfigService processConfigService() {
|
||||
IProcessConfigService processConfigService = mock(IProcessConfigService.class);
|
||||
when(processConfigService.listByIds(any())).thenReturn(Collections.emptyList());
|
||||
return processConfigService;
|
||||
}
|
||||
|
||||
private Waybill pendingWaybill() {
|
||||
Waybill waybill = new Waybill();
|
||||
waybill.setId(WAYBILL_ID);
|
||||
waybill.setIsDeleted(0);
|
||||
waybill.setTenantId(TENANT_ID);
|
||||
waybill.setBusinessStatus("pending");
|
||||
waybill.setTransportType("road");
|
||||
waybill.setDriverName("张三");
|
||||
waybill.setDriverPhone("13900139000");
|
||||
waybill.setVehicleNo("桂A12345");
|
||||
return waybill;
|
||||
}
|
||||
|
||||
private Waybill reassignRequest(Long driverId) {
|
||||
Waybill request = new Waybill();
|
||||
request.setId(WAYBILL_ID);
|
||||
request.setDriverId(driverId);
|
||||
request.setDriverName("李四");
|
||||
request.setDriverPhone(DRIVER_PHONE);
|
||||
request.setVehicleNo("桂A88888");
|
||||
return request;
|
||||
}
|
||||
|
||||
private Waybill capturedWaybill() {
|
||||
ArgumentCaptor<Waybill> captor = ArgumentCaptor.forClass(Waybill.class);
|
||||
verify(waybillMapper, org.mockito.Mockito.atLeastOnce()).updateById(captor.capture());
|
||||
return captor.getValue();
|
||||
}
|
||||
|
||||
private void inject(String field, Object value) throws Exception {
|
||||
Class<?> type = service.getClass();
|
||||
while (type != null) {
|
||||
try {
|
||||
Field declared = type.getDeclaredField(field);
|
||||
declared.setAccessible(true);
|
||||
declared.set(service, value);
|
||||
return;
|
||||
} catch (NoSuchFieldException ignored) {
|
||||
type = type.getSuperclass();
|
||||
}
|
||||
}
|
||||
throw new IllegalStateException("未找到字段:" + field);
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user